Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "oh-my-workers",
"version": "1.2.0",
"version": "1.3.1",
"description": "A personal AI agent that automates daily working tasks at workplace, eg: Cronjobs, KPI reporting and etc",
"type": "module",
"main": "index.js",
Expand All @@ -21,23 +21,30 @@
},
"keywords": [
"oh-my-workers",
"kpi",
"daily work diary",
"workplace automation",
"KPI",
"Daily work diary",
"Workplace automation",
"AI assistant",
"daily kpi reporting",
"cronjobs",
"Daily KPI reporting",
"Cronjob",
"AI news",
"Github trending",
"AI generated Github trending projects",
"automation",
"AI agent",
"langchain",
"langsmith",
"langgraph",
"Nvidia",
"nemotron",
"typescript",
"neon",
"postgresql",
"personal assistant",
"news search"
"news search",
"Pino",
"zod",
"LangChain AI agent"
],
"author": "damengrandom",
"license": "ISC",
Expand Down
7 changes: 0 additions & 7 deletions src/agent/kpi-record.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import { parseJson } from './utils.ts'
import type { KpiRecord } from '../schemas/index.ts'

// Lives in its own module so it can be tested without importing agent/index.ts,
// which pulls in the agents — and those call createLlm() at module load, so a
// test would need a live LLM_API_KEY just to check JSON parsing.
//
// Every field is defensive: the GitHub tool output is LLM-relayed, so any of it
// can be missing. Silently writing zeros is the failure nobody notices, which is
// exactly why this half is separated and covered.
export function toKpiRecord(githubOutput: string, now: string): KpiRecord {
const data = parseJson<{ summary?: string; commits?: unknown[]; pullRequests?: unknown[] }>(githubOutput, {})

Expand Down
6 changes: 0 additions & 6 deletions src/agent/llm.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { ChatOpenAI } from '@langchain/openai'
import { DEFAULT_LLM, DEFAULT_LLM_BASE_URL, LLM_FALLBACK_MODELS } from '../constants/index.js'

// ponytail: OpenRouter answers HTTP 200 with an {error} body and NO `choices`
// when the upstream provider is capacity-exhausted ("Worker local total request
// limit reached (32/32)"). The OpenAI SDK sees 200, doesn't throw, and hands back
// an empty result — which only blows up later inside LangChain as
// `Cannot read properties of undefined (reading 'message')`, nowhere near the
// real cause. Convert it to a real error here so retries and alerts can see it.
export const failLoudlyOnProviderError: typeof fetch = async (input, init) => {
const res = await fetch(input, init)

Expand Down
9 changes: 0 additions & 9 deletions src/agent/news-curator.agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { createLlm } from './llm.js'
import { TRENDING_CURATOR_PROMPT } from './prompt.js'
import type { TrendingRepo } from '../schemas/index.js'

// The model only writes prose. Star counts, URLs and ordering come from the
// scrape, so no amount of hallucination can corrupt the numbers on the digest.
const SummarySchema = z.object({
repos: z.array(
z.object({
Expand All @@ -15,9 +13,6 @@ const SummarySchema = z.object({
),
})

// Exported for testing: merges model prose back onto the authoritative scraped
// rows, preserving the caller's (star-growth) ordering and dropping any repo the
// model invented.
export function mergeSummaries(repos: TrendingRepo[], summaries: z.infer<typeof SummarySchema>['repos']) {
const byName = new Map(summaries.map((s) => [s.repo_name, s]))

Expand All @@ -41,10 +36,6 @@ export function mergeSummaries(repos: TrendingRepo[], summaries: z.infer<typeof
})
}

// ponytail: one structured-output call, not an agent. The old curate_trending_repos
// tool just echoed its own input back, so the tool loop bought nothing — and its
// post-tool "done" model call is what threw away a good 92s curation when the
// provider returned an error body with no choices. Retries live in curator.graph.
export async function curateTrending(repos: TrendingRepo[], feedback?: string): Promise<string> {
const listing = repos.map((r) => `${r.name} (${r.todayStars} stars today, ${r.stars} total, ${r.language}) — ${r.description}`).join('\n')

Expand Down
Loading