@kenkaiiii/gg-agent 4.2.95 → 4.2.97
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +16 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +16 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -80,13 +80,13 @@ async function* agentLoop(messages, options) {
|
|
|
80
80
|
const MAX_OVERFLOW_RETRIES = 3;
|
|
81
81
|
const MAX_OVERLOAD_RETRIES = 10;
|
|
82
82
|
const MAX_EMPTY_RESPONSE_RETRIES = 2;
|
|
83
|
-
const MAX_STALL_RETRIES =
|
|
84
|
-
const
|
|
85
|
-
const STALL_MAX_DELAY_MS = 3e4;
|
|
83
|
+
const MAX_STALL_RETRIES = 5;
|
|
84
|
+
const STALL_DELAY_MS = 1e3;
|
|
86
85
|
const OVERLOAD_BASE_DELAY_MS = 2e3;
|
|
87
86
|
const OVERLOAD_MAX_DELAY_MS = 3e4;
|
|
88
|
-
const
|
|
89
|
-
const
|
|
87
|
+
const STREAM_FIRST_EVENT_TIMEOUT_MS = 45e3;
|
|
88
|
+
const STREAM_IDLE_TIMEOUT_MS = 1e4;
|
|
89
|
+
const STREAM_HARD_TIMEOUT_MS = 9e4;
|
|
90
90
|
try {
|
|
91
91
|
while (turn < maxTurns) {
|
|
92
92
|
options.signal?.throwIfAborted();
|
|
@@ -136,16 +136,19 @@ async function* agentLoop(messages, options) {
|
|
|
136
136
|
let streamCallStart = Date.now();
|
|
137
137
|
const forwardAbort = () => streamController.abort();
|
|
138
138
|
options.signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
139
|
+
let hasReceivedEvent = false;
|
|
139
140
|
const resetIdleTimer = () => {
|
|
140
141
|
if (idleTimer) clearTimeout(idleTimer);
|
|
142
|
+
const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
|
|
141
143
|
idleTimer = setTimeout(() => {
|
|
142
144
|
diag("idle_timeout_fired", {
|
|
143
|
-
events:
|
|
144
|
-
sinceLastEventMs:
|
|
145
|
+
events: streamEventCount,
|
|
146
|
+
sinceLastEventMs: Date.now() - lastEventTime,
|
|
147
|
+
phase: hasReceivedEvent ? "mid_stream" : "first_event"
|
|
145
148
|
});
|
|
146
149
|
idleTimedOut = true;
|
|
147
150
|
streamController.abort();
|
|
148
|
-
},
|
|
151
|
+
}, timeoutMs);
|
|
149
152
|
};
|
|
150
153
|
hardTimer = setTimeout(() => {
|
|
151
154
|
diag("hard_timeout_fired", {
|
|
@@ -179,11 +182,15 @@ async function* agentLoop(messages, options) {
|
|
|
179
182
|
result.response.catch(() => {
|
|
180
183
|
});
|
|
181
184
|
streamEventCount = 0;
|
|
185
|
+
hasReceivedEvent = false;
|
|
182
186
|
lastEventTime = Date.now();
|
|
183
187
|
streamCallStart = Date.now();
|
|
184
188
|
resetIdleTimer();
|
|
185
189
|
for await (const event of result) {
|
|
186
190
|
streamEventCount++;
|
|
191
|
+
if (!hasReceivedEvent) {
|
|
192
|
+
hasReceivedEvent = true;
|
|
193
|
+
}
|
|
187
194
|
const now = Date.now();
|
|
188
195
|
const gap = now - lastEventTime;
|
|
189
196
|
if (streamEventCount === 1) {
|
|
@@ -265,10 +272,7 @@ async function* agentLoop(messages, options) {
|
|
|
265
272
|
}
|
|
266
273
|
if (idleTimedOut && !options.signal?.aborted && stallRetries < MAX_STALL_RETRIES) {
|
|
267
274
|
stallRetries++;
|
|
268
|
-
const delayMs =
|
|
269
|
-
STALL_BASE_DELAY_MS * 2 ** (stallRetries - 1),
|
|
270
|
-
STALL_MAX_DELAY_MS
|
|
271
|
-
);
|
|
275
|
+
const delayMs = STALL_DELAY_MS;
|
|
272
276
|
yield {
|
|
273
277
|
type: "retry",
|
|
274
278
|
reason: "stream_stall",
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/agent-loop.ts"],"sourcesContent":["// Core\nexport { Agent, AgentStream } from \"./agent.js\";\nexport {\n agentLoop,\n isAbortError,\n isContextOverflow,\n isBillingError,\n setStreamDiagnostic,\n} from \"./agent-loop.js\";\nexport type { StreamDiagnosticFn } from \"./agent-loop.js\";\n\n// Types\nexport type {\n StructuredToolResult,\n ToolExecuteResult,\n ToolContext,\n AgentTool,\n AgentTextDeltaEvent,\n AgentThinkingDeltaEvent,\n AgentToolCallStartEvent,\n AgentToolCallUpdateEvent,\n AgentToolCallEndEvent,\n AgentServerToolCallEvent,\n AgentServerToolResultEvent,\n AgentSteeringMessageEvent,\n AgentFollowUpMessageEvent,\n AgentRetryEvent,\n AgentTurnEndEvent,\n AgentDoneEvent,\n AgentErrorEvent,\n AgentEvent,\n AgentOptions,\n AgentResult,\n} from \"./types.js\";\n","import { EventStream, type Message } from \"@kenkaiiii/gg-ai\";\nimport { agentLoop } from \"./agent-loop.js\";\nimport type { AgentEvent, AgentOptions, AgentResult } from \"./types.js\";\n\n// ── AgentStream ─────────────────────────────────────────────\n\n/**\n * Dual-nature result: async iterable for streaming events,\n * thenable for awaiting the final AgentResult.\n *\n * ```ts\n * // Stream events\n * for await (const event of agent.prompt(\"hello\")) { ... }\n *\n * // Or just await the result\n * const result = await agent.prompt(\"hello\");\n * ```\n */\nexport class AgentStream implements AsyncIterable<AgentEvent> {\n private events: EventStream<AgentEvent>;\n private resultPromise: Promise<AgentResult>;\n private resolveResult!: (r: AgentResult) => void;\n private rejectResult!: (e: Error) => void;\n private hasConsumer = false;\n\n constructor(generator: AsyncGenerator<AgentEvent, AgentResult>, onDone: () => void) {\n this.events = new EventStream<AgentEvent>();\n this.resultPromise = new Promise<AgentResult>((resolve, reject) => {\n this.resolveResult = resolve;\n this.rejectResult = reject;\n });\n this.pump(generator, onDone);\n }\n\n private async pump(\n generator: AsyncGenerator<AgentEvent, AgentResult>,\n onDone: () => void,\n ): Promise<void> {\n try {\n let next = await generator.next();\n while (!next.done) {\n this.events.push(next.value);\n next = await generator.next();\n }\n this.events.close();\n this.resolveResult(next.value);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.events.abort(error);\n this.rejectResult(error);\n } finally {\n onDone();\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n this.hasConsumer = true;\n return this.events[Symbol.asyncIterator]();\n }\n\n then<TResult1 = AgentResult, TResult2 = never>(\n onfulfilled?: ((value: AgentResult) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n this.drainEvents().catch(() => {});\n return this.resultPromise.then(onfulfilled, onrejected);\n }\n\n private async drainEvents(): Promise<void> {\n if (this.hasConsumer) return;\n this.hasConsumer = true;\n for await (const _ of this.events) {\n // consume silently\n }\n }\n}\n\n// ── Agent ───────────────────────────────────────────────────\n\nexport class Agent {\n private messages: Message[] = [];\n private _running = false;\n private options: AgentOptions;\n private steeringQueue: Message[] = [];\n private followUpQueue: Message[] = [];\n\n constructor(options: AgentOptions) {\n this.options = options;\n if (options.system) {\n this.messages.push({ role: \"system\", content: options.system });\n }\n }\n\n get running(): boolean {\n return this._running;\n }\n\n /** Queue a steering message for injection after current tool execution completes. */\n steer(msg: Message): void {\n this.steeringQueue.push(msg);\n }\n\n /** Queue a follow-up message for injection when the agent would otherwise stop. */\n followUp(msg: Message): void {\n this.followUpQueue.push(msg);\n }\n\n prompt(content: string): AgentStream {\n if (this._running) {\n throw new Error(\"Agent is already running\");\n }\n this._running = true;\n\n this.messages.push({ role: \"user\", content });\n\n const optionsWithQueues: AgentOptions = {\n ...this.options,\n getSteeringMessages: async () => {\n const callerResult = (await this.options.getSteeringMessages?.()) ?? [];\n const queued = this.steeringQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n getFollowUpMessages: async () => {\n const callerResult = (await this.options.getFollowUpMessages?.()) ?? [];\n const queued = this.followUpQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n };\n\n const generator = agentLoop(this.messages, optionsWithQueues);\n return new AgentStream(generator, () => {\n this._running = false;\n });\n }\n}\n","import {\n stream,\n EventStream,\n type Message,\n type ToolCall,\n type ToolResult,\n type Usage,\n type ContentPart,\n type AssistantMessage,\n} from \"@kenkaiiii/gg-ai\";\nimport type {\n AgentEvent,\n AgentOptions,\n AgentResult,\n AgentTool,\n ToolContext,\n ToolExecuteResult,\n StructuredToolResult,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_TURNS = 200;\n\n/**\n * Lightweight stream diagnostic callback. When set, the agent loop calls this\n * at every phase boundary with timing and state info. This lets the hosting\n * app (ggcoder, come-alive, etc.) log stall diagnostics without the agent\n * package needing fs/process dependencies.\n */\nexport type StreamDiagnosticFn = (phase: string, data?: Record<string, unknown>) => void;\n\n/** Global diagnostic hook — set by the hosting app before calling agentLoop. */\nlet _diagFn: StreamDiagnosticFn | null = null;\n\n/** Register a diagnostic callback for stream stall tracing. */\nexport function setStreamDiagnostic(fn: StreamDiagnosticFn | null): void {\n _diagFn = fn;\n}\n\nfunction diag(phase: string, data?: Record<string, unknown>): void {\n _diagFn?.(phase, data);\n}\n\n/**\n * Detect abort errors — user-initiated cancellation or AbortSignal.\n * These should be caught and handled gracefully, not re-thrown.\n */\nexport function isAbortError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n const msg = err.message.toLowerCase();\n return msg.includes(\"aborted\") || msg.includes(\"abort\");\n}\n\n/**\n * Detect context window overflow errors from LLM providers.\n * Anthropic: \"prompt is too long: N tokens > M maximum\"\n * OpenAI: \"context_length_exceeded\" / \"maximum context length\"\n */\nexport function isContextOverflow(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"prompt is too long\") ||\n msg.includes(\"context_length_exceeded\") ||\n msg.includes(\"maximum context length\") ||\n (msg.includes(\"token\") && msg.includes(\"exceed\"))\n );\n}\n\n/**\n * Detect billing/quota errors — these should NOT be retried.\n * GLM returns HTTP 429 with \"Insufficient balance\" for quota exhaustion.\n */\nexport function isBillingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"insufficient balance\") ||\n msg.includes(\"no resource package\") ||\n msg.includes(\"quota exceeded\") ||\n msg.includes(\"billing\") ||\n msg.includes(\"recharge\") ||\n msg.includes(\"subscription plan\") ||\n msg.includes(\"does not yet include access\")\n );\n}\n\n/**\n * Detect overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n * Excludes billing/quota errors which won't resolve with a retry.\n */\nexport function isOverloaded(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (isBillingError(err)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"overloaded\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"too many requests\") ||\n msg.includes(\"429\") ||\n msg.includes(\"529\")\n );\n}\n\nexport async function* agentLoop(\n messages: Message[],\n options: AgentOptions,\n): AsyncGenerator<AgentEvent, AgentResult> {\n const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\n const maxContinuations = options.maxContinuations ?? 5;\n const toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n let turn = 0;\n let firstTurn = true;\n let consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n let stallRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 10;\n const MAX_EMPTY_RESPONSE_RETRIES = 2;\n const MAX_STALL_RETRIES = 8;\n const STALL_BASE_DELAY_MS = 2_000;\n const STALL_MAX_DELAY_MS = 30_000;\n const OVERLOAD_BASE_DELAY_MS = 2_000;\n const OVERLOAD_MAX_DELAY_MS = 30_000;\n const STREAM_IDLE_TIMEOUT_MS = 45_000; // 45s without any stream event = stall\n const STREAM_HARD_TIMEOUT_MS = 120_000; // 2min absolute cap per LLM call\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // Estimate message payload size for diagnostics\n let msgChars = 0;\n for (const m of messages) {\n if (typeof m.content === \"string\") msgChars += m.content.length;\n else if (Array.isArray(m.content)) {\n for (const p of m.content) {\n if (\"text\" in p && typeof p.text === \"string\") msgChars += p.text.length;\n if (\"content\" in p && typeof p.content === \"string\") msgChars += p.content.length;\n }\n }\n }\n diag(\"turn_start\", { turn, messages: messages.length, chars: msgChars });\n\n // ── Initial steering poll: catch messages queued before the first LLM call ──\n if (firstTurn && options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n firstTurn = false;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n diag(\"transform_start\");\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n diag(\"transform_compacted\", {\n before: messages.length,\n after: transformed.length,\n });\n messages.length = 0;\n messages.push(...transformed);\n }\n diag(\"transform_end\");\n }\n\n // ── Repair tool pairing: ensure every tool_use has an adjacent tool_result ──\n repairToolPairingAdjacent(messages);\n\n // ── Call LLM with overflow recovery ──\n let response;\n // Per-attempt abort controller: allows idle timeout to abort the stream\n // without affecting the caller's signal. The caller's abort is forwarded.\n const streamController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let hardTimer: ReturnType<typeof setTimeout> | null = null;\n let idleTimedOut = false;\n\n // Stream event counters — declared here so timeout callbacks can access them\n let streamEventCount = 0;\n let lastEventTime = Date.now();\n let streamCallStart = Date.now();\n\n // Forward caller abort to the per-attempt controller\n const forwardAbort = () => streamController.abort();\n options.signal?.addEventListener(\"abort\", forwardAbort, { once: true });\n\n // Idle timeout: abort the stream if no events arrive within the window.\n // This catches mid-stream server stalls where the connection stays open\n // but the server stops sending data (overload, network issues, etc.).\n const resetIdleTimer = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => {\n diag(\"idle_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n sinceLastEventMs:\n typeof lastEventTime !== \"undefined\" ? Date.now() - lastEventTime : -1,\n });\n idleTimedOut = true;\n streamController.abort();\n }, STREAM_IDLE_TIMEOUT_MS);\n };\n\n // Hard timeout: absolute cap per LLM call. Safety net for streams that\n // keep sending sparse events (e.g. keep-alive pings) but never complete.\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n });\n idleTimedOut = true;\n streamController.abort();\n }, STREAM_HARD_TIMEOUT_MS);\n\n try {\n diag(\"stream_call\");\n streamCallStart = Date.now();\n const result = stream({\n provider: options.provider,\n model: options.model,\n messages,\n tools: options.tools,\n serverTools: options.serverTools,\n webSearch: options.webSearch,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n thinking: options.thinking,\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n signal: streamController.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n clearToolUses: options.clearToolUses,\n });\n diag(\"stream_created\", { setupMs: Date.now() - streamCallStart });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas — reset idle timer on each event\n streamEventCount = 0;\n lastEventTime = Date.now();\n streamCallStart = Date.now();\n resetIdleTimer();\n for await (const event of result) {\n streamEventCount++;\n const now = Date.now();\n const gap = now - lastEventTime;\n // Log first event and any suspiciously long gaps\n if (streamEventCount === 1) {\n diag(\"first_event\", { type: event.type, ttfMs: now - streamCallStart });\n } else if (gap > 3000) {\n diag(\"slow_gap\", {\n type: event.type,\n gapMs: gap,\n eventNum: streamEventCount,\n sinceStartMs: now - streamCallStart,\n });\n }\n lastEventTime = now;\n resetIdleTimer();\n if (event.type === \"text_delta\") {\n yield { type: \"text_delta\" as const, text: event.text };\n } else if (event.type === \"thinking_delta\") {\n yield { type: \"thinking_delta\" as const, text: event.text };\n } else if (event.type === \"server_toolcall\") {\n yield {\n type: \"server_tool_call\" as const,\n id: event.id,\n name: event.name,\n input: event.input,\n };\n } else if (event.type === \"server_toolresult\") {\n yield {\n type: \"server_tool_result\" as const,\n toolUseId: event.toolUseId,\n resultType: event.resultType,\n data: event.data,\n };\n }\n }\n\n diag(\"stream_done\", { events: streamEventCount, totalMs: Date.now() - streamCallStart });\n response = await result.response;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n diag(\"stream_error\", {\n error: errMsg.slice(0, 200),\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n idleTimedOut,\n aborted: !!options.signal?.aborted,\n });\n // Context overflow: force-compact via transformContext and retry (up to 3 times)\n if (\n overflowRetries < MAX_OVERFLOW_RETRIES &&\n isContextOverflow(err) &&\n options.transformContext\n ) {\n overflowRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"context_overflow\" as const,\n attempt: overflowRetries,\n maxAttempts: MAX_OVERFLOW_RETRIES,\n delayMs: 0,\n };\n const transformed = await options.transformContext(messages, { force: true });\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n turn--; // Don't count the failed turn\n continue;\n }\n // Overloaded / rate-limited: exponential backoff, retry up to 10 times\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n const delayMs = Math.min(\n OVERLOAD_BASE_DELAY_MS * 2 ** (overloadRetries - 1),\n OVERLOAD_MAX_DELAY_MS,\n );\n yield {\n type: \"retry\" as const,\n reason: \"overloaded\" as const,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall: the API connection hung mid-stream without closing.\n // Retry with exponential backoff — the server may need time to recover\n // (especially during Anthropic capacity issues that affect many clients).\n if (idleTimedOut && !options.signal?.aborted && stallRetries < MAX_STALL_RETRIES) {\n stallRetries++;\n const delayMs = Math.min(\n STALL_BASE_DELAY_MS * 2 ** (stallRetries - 1),\n STALL_MAX_DELAY_MS,\n );\n yield {\n type: \"retry\" as const,\n reason: \"stream_stall\" as const,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall retries exhausted — surface a clear error so the UI\n // can distinguish \"gave up after stalls\" from \"completed normally\".\n if (idleTimedOut && !options.signal?.aborted) {\n yield {\n type: \"error\" as const,\n error: new Error(\n `The API provider's stream stalled ${MAX_STALL_RETRIES} times — the provider may be experiencing capacity issues. ` +\n `Your conversation is preserved. Send another message to retry.`,\n ),\n };\n break;\n }\n // Abort errors (user cancellation) — exit loop cleanly instead of\n // crashing the process with an unhandled rejection.\n if (isAbortError(err) || options.signal?.aborted) {\n break;\n }\n throw err;\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n if (hardTimer) clearTimeout(hardTimer);\n options.signal?.removeEventListener(\"abort\", forwardAbort);\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 0;\n stallRetries = 0;\n\n // Detect empty/degenerate responses — the API occasionally returns 0 tokens\n // with no content (e.g. stream interruption, transient server issue).\n // Retry instead of treating as completion.\n if (\n response.usage.outputTokens === 0 &&\n (response.message.content === \"\" ||\n (Array.isArray(response.message.content) && response.message.content.length === 0))\n ) {\n if (emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES) {\n emptyResponseRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"empty_response\" as const,\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n delayMs: 0,\n };\n turn--; // Don't count the failed turn\n continue;\n }\n // Exhausted retries — fall through and let the agent finish\n }\n emptyResponseRetries = 0;\n\n // Accumulate usage\n totalUsage.inputTokens += response.usage.inputTokens;\n totalUsage.outputTokens += response.usage.outputTokens;\n if (response.usage.cacheRead) {\n totalUsage.cacheRead = (totalUsage.cacheRead ?? 0) + response.usage.cacheRead;\n }\n if (response.usage.cacheWrite) {\n totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;\n }\n\n // Append assistant message to conversation\n messages.push(response.message);\n\n yield {\n type: \"turn_end\" as const,\n turn,\n stopReason: response.stopReason,\n usage: response.usage,\n };\n\n // Server-side tool hit iteration limit — re-send to continue.\n // Do NOT add an extra user message; the API detects the trailing\n // server_tool_use block and resumes automatically.\n if (response.stopReason === \"pause_turn\") {\n consecutivePauses++;\n if (consecutivePauses >= maxContinuations) {\n break; // Safety limit — fall through to agent_done below\n }\n continue;\n }\n consecutivePauses = 0;\n\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\n\n // If no tool calls to execute, check for steering messages before stopping.\n // Check content (not just stopReason) because some providers (e.g. GLM)\n // return finish_reason=\"stop\" even when tool calls are present.\n if (response.stopReason !== \"tool_use\" && allToolCalls.length === 0) {\n // Check for queued steering messages — if present, inject and continue\n // the loop instead of returning (follow-up pattern).\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue; // Next iteration will call LLM with injected messages\n }\n }\n // Follow-up: lower priority than steering — only when agent would otherwise stop.\n if (options.getFollowUpMessages) {\n const followUp = await options.getFollowUpMessages();\n if (followUp && followUp.length > 0) {\n for (const msg of followUp) {\n yield { type: \"follow_up_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue;\n }\n }\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n return {\n message: response.message,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n }\n const toolCalls: ToolCall[] = [];\n const toolResults: ToolResult[] = [];\n\n for (const tc of allToolCalls) {\n if (tc.name.startsWith(\"$\")) {\n // Provider built-in tool (e.g. Moonshot $web_search) — not locally executed.\n // Still needs a tool_result for the message history round-trip.\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: JSON.stringify(tc.args),\n });\n } else {\n toolCalls.push(tc);\n }\n }\n const eventStream = new EventStream<AgentEvent>();\n\n // Launch all tool calls in parallel\n const executions = toolCalls.map(async (toolCall) => {\n const startTime = Date.now();\n\n eventStream.push({\n type: \"tool_call_start\" as const,\n toolCallId: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n\n let resultContent: string;\n let details: unknown;\n let isError = false;\n\n const tool = toolMap.get(toolCall.name);\n if (!tool) {\n resultContent = `Unknown tool: ${toolCall.name}`;\n isError = true;\n } else {\n try {\n const parsed = tool.parameters.parse(toolCall.args);\n const ctx: ToolContext = {\n signal: options.signal ?? AbortSignal.timeout(300_000),\n toolCallId: toolCall.id,\n onUpdate: (update: unknown) => {\n eventStream.push({\n type: \"tool_call_update\" as const,\n toolCallId: toolCall.id,\n update,\n });\n },\n };\n const raw = await tool.execute(parsed, ctx);\n const normalized = normalizeToolResult(raw);\n resultContent = normalized.content;\n details = normalized.details;\n } catch (err) {\n isError = true;\n resultContent = err instanceof Error ? err.message : String(err);\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n eventStream.push({\n type: \"tool_call_end\" as const,\n toolCallId: toolCall.id,\n result: resultContent,\n details,\n isError,\n durationMs,\n });\n\n return { toolCallId: toolCall.id, content: resultContent, isError };\n });\n\n // Abort the tool event stream when the signal fires so Ctrl+C\n // doesn't hang waiting for long-running tools to finish.\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n // Close event stream when all tools complete.\n // Track whether the finally block has already consumed toolResults\n // to prevent the race where .then() mutates toolResults after\n // messages.push() has already captured the array by reference.\n let toolResultsFinalized = false;\n\n Promise.all(executions)\n .then((results) => {\n if (toolResultsFinalized) return;\n const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));\n for (const tc of toolCalls) {\n const r = resultsMap.get(tc.id)!;\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: r.content,\n isError: r.isError || undefined,\n });\n }\n eventStream.close();\n })\n .catch((err) => eventStream.abort(err instanceof Error ? err : new Error(String(err))));\n\n // Yield events as they arrive from parallel tools\n let toolsAborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n // Tool event stream aborted (Ctrl+C) — don't propagate, just mark\n // so the finally block can clean up and the loop can exit.\n if (isAbortError(err) || options.signal?.aborted) {\n toolsAborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n\n // Prevent the Promise.all .then() from mutating toolResults after\n // we finalize and push them into messages.\n toolResultsFinalized = true;\n\n // Ensure every tool_use has a matching tool_result, even on abort.\n // Without this, an aborted turn leaves an orphaned tool_use in the\n // message history which causes Anthropic API 400 errors on the next\n // request.\n const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));\n for (const tc of toolCalls) {\n if (!resolvedIds.has(tc.id)) {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: \"Tool execution was aborted.\",\n isError: true,\n });\n }\n }\n // Guard: cap oversized tool results before they enter conversation history.\n // Uses head+tail strategy to preserve error messages / closing structure at the end.\n if (options.maxToolResultChars) {\n const HARD_MAX = 400_000; // absolute ceiling regardless of context window\n const max = Math.min(options.maxToolResultChars, HARD_MAX);\n for (const tr of toolResults) {\n if (tr.content.length > max) {\n // Keep 70% head + 30% tail to preserve errors/diagnostics at the end\n const headChars = Math.floor(max * 0.7);\n const tailChars = max - headChars;\n const head = tr.content.slice(0, headChars);\n const tail = tr.content.slice(-tailChars);\n const omitted = tr.content.length - headChars - tailChars;\n tr.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n }\n }\n }\n\n messages.push({ role: \"tool\", content: toolResults });\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\n\n // ── Steering messages: inject user messages queued during tool execution ──\n // Polled after tools complete so the next LLM call sees them in context.\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n }\n } finally {\n // Sanitize orphaned server_tool_use blocks on abort.\n // When a stream is aborted mid-server-tool (e.g. web_search), the\n // assistant message containing the server_tool_use may already be in\n // the messages array, but the corresponding web_search_tool_result\n // never arrived. The API rejects the next request with a 400 if it\n // finds an unmatched server_tool_use, so we strip it here.\n sanitizeOrphanedServerTools(messages);\n }\n\n // Exceeded max turns — return last assistant message\n let lastAssistant: AssistantMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"assistant\") {\n lastAssistant = messages[i] as AssistantMessage;\n break;\n }\n }\n\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n\n return {\n message: lastAssistant ?? { role: \"assistant\" as const, content: [] },\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n}\n\nfunction normalizeToolResult(raw: ToolExecuteResult): StructuredToolResult {\n return typeof raw === \"string\" ? { content: raw } : raw;\n}\n\nfunction extractToolCalls(content: string | ContentPart[]): ToolCall[] {\n if (typeof content === \"string\") return [];\n return content.filter((part): part is ToolCall => part.type === \"tool_call\");\n}\n\n/**\n * Remove orphaned server_tool_use blocks from the last assistant message.\n * When a stream is aborted mid-server-tool (e.g. web_search), the assistant\n * message may contain a server_tool_call without a matching server_tool_result.\n * The API rejects the next request if these are unmatched.\n */\nfunction sanitizeOrphanedServerTools(messages: Message[]): void {\n // Find the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) break;\n\n // Collect server_tool_call ids and matched server_tool_result ids\n const serverToolIds = new Set<string>();\n const resultToolIds = new Set<string>();\n for (const part of msg.content) {\n if (part.type === \"server_tool_call\") serverToolIds.add(part.id);\n if (part.type === \"server_tool_result\") resultToolIds.add(part.toolUseId);\n }\n\n // Find unmatched server_tool_call blocks\n const orphanedIds = new Set<string>();\n for (const id of serverToolIds) {\n if (!resultToolIds.has(id)) orphanedIds.add(id);\n }\n\n if (orphanedIds.size === 0) break;\n\n // Strip orphaned server_tool_call blocks from the content\n const filtered = msg.content.filter(\n (part) => !(part.type === \"server_tool_call\" && orphanedIds.has(part.id)),\n );\n\n if (filtered.length === 0) {\n // Nothing left — remove the entire message\n messages.splice(i, 1);\n } else {\n (msg as { content: ContentPart[] }).content = filtered;\n }\n break;\n }\n}\n\n/**\n * Ensure every assistant message with tool_call blocks is immediately followed\n * by a tool message with matching tool_result entries. This prevents Anthropic\n * API 400 errors (\"tool_use ids found without tool_result blocks immediately\n * after\") that can occur after compaction, session restore, or abort recovery.\n *\n * Repairs in-place by inserting synthetic tool_result messages where needed.\n */\nfunction repairToolPairingAdjacent(messages: Message[]): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) continue;\n\n const toolCallIds = (msg.content as ContentPart[])\n .filter((p) => p.type === \"tool_call\")\n .map((p) => (p as ContentPart & { type: \"tool_call\"; id: string }).id);\n if (toolCallIds.length === 0) continue;\n\n const next = messages[i + 1];\n if (next?.role === \"tool\" && Array.isArray(next.content)) {\n // Tool message exists — check for missing results\n const existingIds = new Set((next.content as ToolResult[]).map((r) => r.toolCallId));\n const missing = toolCallIds.filter((id) => !existingIds.has(id));\n if (missing.length > 0) {\n for (const id of missing) {\n (next.content as ToolResult[]).push({\n type: \"tool_result\",\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n });\n }\n }\n } else {\n // No tool message follows — insert a synthetic one\n messages.splice(i + 1, 0, {\n role: \"tool\" as const,\n content: toolCallIds.map((id) => ({\n type: \"tool_result\" as const,\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n })),\n });\n }\n }\n}\n"],"mappings":"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","names":["import_gg_ai"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/agent.ts","../src/agent-loop.ts"],"sourcesContent":["// Core\nexport { Agent, AgentStream } from \"./agent.js\";\nexport {\n agentLoop,\n isAbortError,\n isContextOverflow,\n isBillingError,\n setStreamDiagnostic,\n} from \"./agent-loop.js\";\nexport type { StreamDiagnosticFn } from \"./agent-loop.js\";\n\n// Types\nexport type {\n StructuredToolResult,\n ToolExecuteResult,\n ToolContext,\n AgentTool,\n AgentTextDeltaEvent,\n AgentThinkingDeltaEvent,\n AgentToolCallStartEvent,\n AgentToolCallUpdateEvent,\n AgentToolCallEndEvent,\n AgentServerToolCallEvent,\n AgentServerToolResultEvent,\n AgentSteeringMessageEvent,\n AgentFollowUpMessageEvent,\n AgentRetryEvent,\n AgentTurnEndEvent,\n AgentDoneEvent,\n AgentErrorEvent,\n AgentEvent,\n AgentOptions,\n AgentResult,\n} from \"./types.js\";\n","import { EventStream, type Message } from \"@kenkaiiii/gg-ai\";\nimport { agentLoop } from \"./agent-loop.js\";\nimport type { AgentEvent, AgentOptions, AgentResult } from \"./types.js\";\n\n// ── AgentStream ─────────────────────────────────────────────\n\n/**\n * Dual-nature result: async iterable for streaming events,\n * thenable for awaiting the final AgentResult.\n *\n * ```ts\n * // Stream events\n * for await (const event of agent.prompt(\"hello\")) { ... }\n *\n * // Or just await the result\n * const result = await agent.prompt(\"hello\");\n * ```\n */\nexport class AgentStream implements AsyncIterable<AgentEvent> {\n private events: EventStream<AgentEvent>;\n private resultPromise: Promise<AgentResult>;\n private resolveResult!: (r: AgentResult) => void;\n private rejectResult!: (e: Error) => void;\n private hasConsumer = false;\n\n constructor(generator: AsyncGenerator<AgentEvent, AgentResult>, onDone: () => void) {\n this.events = new EventStream<AgentEvent>();\n this.resultPromise = new Promise<AgentResult>((resolve, reject) => {\n this.resolveResult = resolve;\n this.rejectResult = reject;\n });\n this.pump(generator, onDone);\n }\n\n private async pump(\n generator: AsyncGenerator<AgentEvent, AgentResult>,\n onDone: () => void,\n ): Promise<void> {\n try {\n let next = await generator.next();\n while (!next.done) {\n this.events.push(next.value);\n next = await generator.next();\n }\n this.events.close();\n this.resolveResult(next.value);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.events.abort(error);\n this.rejectResult(error);\n } finally {\n onDone();\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n this.hasConsumer = true;\n return this.events[Symbol.asyncIterator]();\n }\n\n then<TResult1 = AgentResult, TResult2 = never>(\n onfulfilled?: ((value: AgentResult) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n this.drainEvents().catch(() => {});\n return this.resultPromise.then(onfulfilled, onrejected);\n }\n\n private async drainEvents(): Promise<void> {\n if (this.hasConsumer) return;\n this.hasConsumer = true;\n for await (const _ of this.events) {\n // consume silently\n }\n }\n}\n\n// ── Agent ───────────────────────────────────────────────────\n\nexport class Agent {\n private messages: Message[] = [];\n private _running = false;\n private options: AgentOptions;\n private steeringQueue: Message[] = [];\n private followUpQueue: Message[] = [];\n\n constructor(options: AgentOptions) {\n this.options = options;\n if (options.system) {\n this.messages.push({ role: \"system\", content: options.system });\n }\n }\n\n get running(): boolean {\n return this._running;\n }\n\n /** Queue a steering message for injection after current tool execution completes. */\n steer(msg: Message): void {\n this.steeringQueue.push(msg);\n }\n\n /** Queue a follow-up message for injection when the agent would otherwise stop. */\n followUp(msg: Message): void {\n this.followUpQueue.push(msg);\n }\n\n prompt(content: string): AgentStream {\n if (this._running) {\n throw new Error(\"Agent is already running\");\n }\n this._running = true;\n\n this.messages.push({ role: \"user\", content });\n\n const optionsWithQueues: AgentOptions = {\n ...this.options,\n getSteeringMessages: async () => {\n const callerResult = (await this.options.getSteeringMessages?.()) ?? [];\n const queued = this.steeringQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n getFollowUpMessages: async () => {\n const callerResult = (await this.options.getFollowUpMessages?.()) ?? [];\n const queued = this.followUpQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n };\n\n const generator = agentLoop(this.messages, optionsWithQueues);\n return new AgentStream(generator, () => {\n this._running = false;\n });\n }\n}\n","import {\n stream,\n EventStream,\n type Message,\n type ToolCall,\n type ToolResult,\n type Usage,\n type ContentPart,\n type AssistantMessage,\n} from \"@kenkaiiii/gg-ai\";\nimport type {\n AgentEvent,\n AgentOptions,\n AgentResult,\n AgentTool,\n ToolContext,\n ToolExecuteResult,\n StructuredToolResult,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_TURNS = 200;\n\n/**\n * Lightweight stream diagnostic callback. When set, the agent loop calls this\n * at every phase boundary with timing and state info. This lets the hosting\n * app (ggcoder, come-alive, etc.) log stall diagnostics without the agent\n * package needing fs/process dependencies.\n */\nexport type StreamDiagnosticFn = (phase: string, data?: Record<string, unknown>) => void;\n\n/** Global diagnostic hook — set by the hosting app before calling agentLoop. */\nlet _diagFn: StreamDiagnosticFn | null = null;\n\n/** Register a diagnostic callback for stream stall tracing. */\nexport function setStreamDiagnostic(fn: StreamDiagnosticFn | null): void {\n _diagFn = fn;\n}\n\nfunction diag(phase: string, data?: Record<string, unknown>): void {\n _diagFn?.(phase, data);\n}\n\n/**\n * Detect abort errors — user-initiated cancellation or AbortSignal.\n * These should be caught and handled gracefully, not re-thrown.\n */\nexport function isAbortError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n const msg = err.message.toLowerCase();\n return msg.includes(\"aborted\") || msg.includes(\"abort\");\n}\n\n/**\n * Detect context window overflow errors from LLM providers.\n * Anthropic: \"prompt is too long: N tokens > M maximum\"\n * OpenAI: \"context_length_exceeded\" / \"maximum context length\"\n */\nexport function isContextOverflow(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"prompt is too long\") ||\n msg.includes(\"context_length_exceeded\") ||\n msg.includes(\"maximum context length\") ||\n (msg.includes(\"token\") && msg.includes(\"exceed\"))\n );\n}\n\n/**\n * Detect billing/quota errors — these should NOT be retried.\n * GLM returns HTTP 429 with \"Insufficient balance\" for quota exhaustion.\n */\nexport function isBillingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"insufficient balance\") ||\n msg.includes(\"no resource package\") ||\n msg.includes(\"quota exceeded\") ||\n msg.includes(\"billing\") ||\n msg.includes(\"recharge\") ||\n msg.includes(\"subscription plan\") ||\n msg.includes(\"does not yet include access\")\n );\n}\n\n/**\n * Detect overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n * Excludes billing/quota errors which won't resolve with a retry.\n */\nexport function isOverloaded(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (isBillingError(err)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"overloaded\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"too many requests\") ||\n msg.includes(\"429\") ||\n msg.includes(\"529\")\n );\n}\n\nexport async function* agentLoop(\n messages: Message[],\n options: AgentOptions,\n): AsyncGenerator<AgentEvent, AgentResult> {\n const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\n const maxContinuations = options.maxContinuations ?? 5;\n const toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n let turn = 0;\n let firstTurn = true;\n let consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n let stallRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 10;\n const MAX_EMPTY_RESPONSE_RETRIES = 2;\n const MAX_STALL_RETRIES = 5;\n const STALL_DELAY_MS = 1_000; // Brief pause before retry — just enough to avoid tight loops\n const OVERLOAD_BASE_DELAY_MS = 2_000;\n const OVERLOAD_MAX_DELAY_MS = 30_000;\n const STREAM_FIRST_EVENT_TIMEOUT_MS = 45_000; // 45s to get first event (Opus thinks long)\n const STREAM_IDLE_TIMEOUT_MS = 10_000; // 10s between events once streaming starts\n const STREAM_HARD_TIMEOUT_MS = 90_000; // 90s absolute cap per LLM call\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // Estimate message payload size for diagnostics\n let msgChars = 0;\n for (const m of messages) {\n if (typeof m.content === \"string\") msgChars += m.content.length;\n else if (Array.isArray(m.content)) {\n for (const p of m.content) {\n if (\"text\" in p && typeof p.text === \"string\") msgChars += p.text.length;\n if (\"content\" in p && typeof p.content === \"string\") msgChars += p.content.length;\n }\n }\n }\n diag(\"turn_start\", { turn, messages: messages.length, chars: msgChars });\n\n // ── Initial steering poll: catch messages queued before the first LLM call ──\n if (firstTurn && options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n firstTurn = false;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n diag(\"transform_start\");\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n diag(\"transform_compacted\", {\n before: messages.length,\n after: transformed.length,\n });\n messages.length = 0;\n messages.push(...transformed);\n }\n diag(\"transform_end\");\n }\n\n // ── Repair tool pairing: ensure every tool_use has an adjacent tool_result ──\n repairToolPairingAdjacent(messages);\n\n // ── Call LLM with overflow recovery ──\n let response;\n // Per-attempt abort controller: allows idle timeout to abort the stream\n // without affecting the caller's signal. The caller's abort is forwarded.\n const streamController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let hardTimer: ReturnType<typeof setTimeout> | null = null;\n let idleTimedOut = false;\n\n // Stream event counters — declared here so timeout callbacks can access them\n let streamEventCount = 0;\n let lastEventTime = Date.now();\n let streamCallStart = Date.now();\n\n // Forward caller abort to the per-attempt controller\n const forwardAbort = () => streamController.abort();\n options.signal?.addEventListener(\"abort\", forwardAbort, { once: true });\n\n // Two-phase idle timeout:\n // - Before first event: STREAM_FIRST_EVENT_TIMEOUT_MS (45s) — Opus can\n // take 30s+ to start on large contexts, that's not a stall.\n // - After first event: STREAM_IDLE_TIMEOUT_MS (10s) — once streaming has\n // started, 10s of silence is a dead connection. Retry fast.\n let hasReceivedEvent = false;\n const resetIdleTimer = () => {\n if (idleTimer) clearTimeout(idleTimer);\n const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;\n idleTimer = setTimeout(() => {\n diag(\"idle_timeout_fired\", {\n events: streamEventCount,\n sinceLastEventMs: Date.now() - lastEventTime,\n phase: hasReceivedEvent ? \"mid_stream\" : \"first_event\",\n });\n idleTimedOut = true;\n streamController.abort();\n }, timeoutMs);\n };\n\n // Hard timeout: absolute cap per LLM call. Safety net for streams that\n // keep sending sparse events (e.g. keep-alive pings) but never complete.\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n });\n idleTimedOut = true;\n streamController.abort();\n }, STREAM_HARD_TIMEOUT_MS);\n\n try {\n diag(\"stream_call\");\n streamCallStart = Date.now();\n const result = stream({\n provider: options.provider,\n model: options.model,\n messages,\n tools: options.tools,\n serverTools: options.serverTools,\n webSearch: options.webSearch,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n thinking: options.thinking,\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n signal: streamController.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n clearToolUses: options.clearToolUses,\n });\n diag(\"stream_created\", { setupMs: Date.now() - streamCallStart });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas — reset idle timer on each event\n streamEventCount = 0;\n hasReceivedEvent = false;\n lastEventTime = Date.now();\n streamCallStart = Date.now();\n resetIdleTimer();\n for await (const event of result) {\n streamEventCount++;\n if (!hasReceivedEvent) {\n hasReceivedEvent = true;\n // Switch to the shorter mid-stream timeout now that events are flowing\n }\n const now = Date.now();\n const gap = now - lastEventTime;\n // Log first event and any suspiciously long gaps\n if (streamEventCount === 1) {\n diag(\"first_event\", { type: event.type, ttfMs: now - streamCallStart });\n } else if (gap > 3000) {\n diag(\"slow_gap\", {\n type: event.type,\n gapMs: gap,\n eventNum: streamEventCount,\n sinceStartMs: now - streamCallStart,\n });\n }\n lastEventTime = now;\n resetIdleTimer();\n if (event.type === \"text_delta\") {\n yield { type: \"text_delta\" as const, text: event.text };\n } else if (event.type === \"thinking_delta\") {\n yield { type: \"thinking_delta\" as const, text: event.text };\n } else if (event.type === \"server_toolcall\") {\n yield {\n type: \"server_tool_call\" as const,\n id: event.id,\n name: event.name,\n input: event.input,\n };\n } else if (event.type === \"server_toolresult\") {\n yield {\n type: \"server_tool_result\" as const,\n toolUseId: event.toolUseId,\n resultType: event.resultType,\n data: event.data,\n };\n }\n }\n\n diag(\"stream_done\", { events: streamEventCount, totalMs: Date.now() - streamCallStart });\n response = await result.response;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n diag(\"stream_error\", {\n error: errMsg.slice(0, 200),\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n idleTimedOut,\n aborted: !!options.signal?.aborted,\n });\n // Context overflow: force-compact via transformContext and retry (up to 3 times)\n if (\n overflowRetries < MAX_OVERFLOW_RETRIES &&\n isContextOverflow(err) &&\n options.transformContext\n ) {\n overflowRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"context_overflow\" as const,\n attempt: overflowRetries,\n maxAttempts: MAX_OVERFLOW_RETRIES,\n delayMs: 0,\n };\n const transformed = await options.transformContext(messages, { force: true });\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n turn--; // Don't count the failed turn\n continue;\n }\n // Overloaded / rate-limited: exponential backoff, retry up to 10 times\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n const delayMs = Math.min(\n OVERLOAD_BASE_DELAY_MS * 2 ** (overloadRetries - 1),\n OVERLOAD_MAX_DELAY_MS,\n );\n yield {\n type: \"retry\" as const,\n reason: \"overloaded\" as const,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall: the API connection hung mid-stream without closing.\n // Retry with exponential backoff — the server may need time to recover\n // (especially during Anthropic capacity issues that affect many clients).\n if (idleTimedOut && !options.signal?.aborted && stallRetries < MAX_STALL_RETRIES) {\n stallRetries++;\n const delayMs = STALL_DELAY_MS;\n yield {\n type: \"retry\" as const,\n reason: \"stream_stall\" as const,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall retries exhausted — surface a clear error so the UI\n // can distinguish \"gave up after stalls\" from \"completed normally\".\n if (idleTimedOut && !options.signal?.aborted) {\n yield {\n type: \"error\" as const,\n error: new Error(\n `The API provider's stream stalled ${MAX_STALL_RETRIES} times — the provider may be experiencing capacity issues. ` +\n `Your conversation is preserved. Send another message to retry.`,\n ),\n };\n break;\n }\n // Abort errors (user cancellation) — exit loop cleanly instead of\n // crashing the process with an unhandled rejection.\n if (isAbortError(err) || options.signal?.aborted) {\n break;\n }\n throw err;\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n if (hardTimer) clearTimeout(hardTimer);\n options.signal?.removeEventListener(\"abort\", forwardAbort);\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 0;\n stallRetries = 0;\n\n // Detect empty/degenerate responses — the API occasionally returns 0 tokens\n // with no content (e.g. stream interruption, transient server issue).\n // Retry instead of treating as completion.\n if (\n response.usage.outputTokens === 0 &&\n (response.message.content === \"\" ||\n (Array.isArray(response.message.content) && response.message.content.length === 0))\n ) {\n if (emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES) {\n emptyResponseRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"empty_response\" as const,\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n delayMs: 0,\n };\n turn--; // Don't count the failed turn\n continue;\n }\n // Exhausted retries — fall through and let the agent finish\n }\n emptyResponseRetries = 0;\n\n // Accumulate usage\n totalUsage.inputTokens += response.usage.inputTokens;\n totalUsage.outputTokens += response.usage.outputTokens;\n if (response.usage.cacheRead) {\n totalUsage.cacheRead = (totalUsage.cacheRead ?? 0) + response.usage.cacheRead;\n }\n if (response.usage.cacheWrite) {\n totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;\n }\n\n // Append assistant message to conversation\n messages.push(response.message);\n\n yield {\n type: \"turn_end\" as const,\n turn,\n stopReason: response.stopReason,\n usage: response.usage,\n };\n\n // Server-side tool hit iteration limit — re-send to continue.\n // Do NOT add an extra user message; the API detects the trailing\n // server_tool_use block and resumes automatically.\n if (response.stopReason === \"pause_turn\") {\n consecutivePauses++;\n if (consecutivePauses >= maxContinuations) {\n break; // Safety limit — fall through to agent_done below\n }\n continue;\n }\n consecutivePauses = 0;\n\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\n\n // If no tool calls to execute, check for steering messages before stopping.\n // Check content (not just stopReason) because some providers (e.g. GLM)\n // return finish_reason=\"stop\" even when tool calls are present.\n if (response.stopReason !== \"tool_use\" && allToolCalls.length === 0) {\n // Check for queued steering messages — if present, inject and continue\n // the loop instead of returning (follow-up pattern).\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue; // Next iteration will call LLM with injected messages\n }\n }\n // Follow-up: lower priority than steering — only when agent would otherwise stop.\n if (options.getFollowUpMessages) {\n const followUp = await options.getFollowUpMessages();\n if (followUp && followUp.length > 0) {\n for (const msg of followUp) {\n yield { type: \"follow_up_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue;\n }\n }\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n return {\n message: response.message,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n }\n const toolCalls: ToolCall[] = [];\n const toolResults: ToolResult[] = [];\n\n for (const tc of allToolCalls) {\n if (tc.name.startsWith(\"$\")) {\n // Provider built-in tool (e.g. Moonshot $web_search) — not locally executed.\n // Still needs a tool_result for the message history round-trip.\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: JSON.stringify(tc.args),\n });\n } else {\n toolCalls.push(tc);\n }\n }\n const eventStream = new EventStream<AgentEvent>();\n\n // Launch all tool calls in parallel\n const executions = toolCalls.map(async (toolCall) => {\n const startTime = Date.now();\n\n eventStream.push({\n type: \"tool_call_start\" as const,\n toolCallId: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n\n let resultContent: string;\n let details: unknown;\n let isError = false;\n\n const tool = toolMap.get(toolCall.name);\n if (!tool) {\n resultContent = `Unknown tool: ${toolCall.name}`;\n isError = true;\n } else {\n try {\n const parsed = tool.parameters.parse(toolCall.args);\n const ctx: ToolContext = {\n signal: options.signal ?? AbortSignal.timeout(300_000),\n toolCallId: toolCall.id,\n onUpdate: (update: unknown) => {\n eventStream.push({\n type: \"tool_call_update\" as const,\n toolCallId: toolCall.id,\n update,\n });\n },\n };\n const raw = await tool.execute(parsed, ctx);\n const normalized = normalizeToolResult(raw);\n resultContent = normalized.content;\n details = normalized.details;\n } catch (err) {\n isError = true;\n resultContent = err instanceof Error ? err.message : String(err);\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n eventStream.push({\n type: \"tool_call_end\" as const,\n toolCallId: toolCall.id,\n result: resultContent,\n details,\n isError,\n durationMs,\n });\n\n return { toolCallId: toolCall.id, content: resultContent, isError };\n });\n\n // Abort the tool event stream when the signal fires so Ctrl+C\n // doesn't hang waiting for long-running tools to finish.\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n // Close event stream when all tools complete.\n // Track whether the finally block has already consumed toolResults\n // to prevent the race where .then() mutates toolResults after\n // messages.push() has already captured the array by reference.\n let toolResultsFinalized = false;\n\n Promise.all(executions)\n .then((results) => {\n if (toolResultsFinalized) return;\n const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));\n for (const tc of toolCalls) {\n const r = resultsMap.get(tc.id)!;\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: r.content,\n isError: r.isError || undefined,\n });\n }\n eventStream.close();\n })\n .catch((err) => eventStream.abort(err instanceof Error ? err : new Error(String(err))));\n\n // Yield events as they arrive from parallel tools\n let toolsAborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n // Tool event stream aborted (Ctrl+C) — don't propagate, just mark\n // so the finally block can clean up and the loop can exit.\n if (isAbortError(err) || options.signal?.aborted) {\n toolsAborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n\n // Prevent the Promise.all .then() from mutating toolResults after\n // we finalize and push them into messages.\n toolResultsFinalized = true;\n\n // Ensure every tool_use has a matching tool_result, even on abort.\n // Without this, an aborted turn leaves an orphaned tool_use in the\n // message history which causes Anthropic API 400 errors on the next\n // request.\n const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));\n for (const tc of toolCalls) {\n if (!resolvedIds.has(tc.id)) {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: \"Tool execution was aborted.\",\n isError: true,\n });\n }\n }\n // Guard: cap oversized tool results before they enter conversation history.\n // Uses head+tail strategy to preserve error messages / closing structure at the end.\n if (options.maxToolResultChars) {\n const HARD_MAX = 400_000; // absolute ceiling regardless of context window\n const max = Math.min(options.maxToolResultChars, HARD_MAX);\n for (const tr of toolResults) {\n if (tr.content.length > max) {\n // Keep 70% head + 30% tail to preserve errors/diagnostics at the end\n const headChars = Math.floor(max * 0.7);\n const tailChars = max - headChars;\n const head = tr.content.slice(0, headChars);\n const tail = tr.content.slice(-tailChars);\n const omitted = tr.content.length - headChars - tailChars;\n tr.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n }\n }\n }\n\n messages.push({ role: \"tool\", content: toolResults });\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\n\n // ── Steering messages: inject user messages queued during tool execution ──\n // Polled after tools complete so the next LLM call sees them in context.\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n }\n } finally {\n // Sanitize orphaned server_tool_use blocks on abort.\n // When a stream is aborted mid-server-tool (e.g. web_search), the\n // assistant message containing the server_tool_use may already be in\n // the messages array, but the corresponding web_search_tool_result\n // never arrived. The API rejects the next request with a 400 if it\n // finds an unmatched server_tool_use, so we strip it here.\n sanitizeOrphanedServerTools(messages);\n }\n\n // Exceeded max turns — return last assistant message\n let lastAssistant: AssistantMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"assistant\") {\n lastAssistant = messages[i] as AssistantMessage;\n break;\n }\n }\n\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n\n return {\n message: lastAssistant ?? { role: \"assistant\" as const, content: [] },\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n}\n\nfunction normalizeToolResult(raw: ToolExecuteResult): StructuredToolResult {\n return typeof raw === \"string\" ? { content: raw } : raw;\n}\n\nfunction extractToolCalls(content: string | ContentPart[]): ToolCall[] {\n if (typeof content === \"string\") return [];\n return content.filter((part): part is ToolCall => part.type === \"tool_call\");\n}\n\n/**\n * Remove orphaned server_tool_use blocks from the last assistant message.\n * When a stream is aborted mid-server-tool (e.g. web_search), the assistant\n * message may contain a server_tool_call without a matching server_tool_result.\n * The API rejects the next request if these are unmatched.\n */\nfunction sanitizeOrphanedServerTools(messages: Message[]): void {\n // Find the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) break;\n\n // Collect server_tool_call ids and matched server_tool_result ids\n const serverToolIds = new Set<string>();\n const resultToolIds = new Set<string>();\n for (const part of msg.content) {\n if (part.type === \"server_tool_call\") serverToolIds.add(part.id);\n if (part.type === \"server_tool_result\") resultToolIds.add(part.toolUseId);\n }\n\n // Find unmatched server_tool_call blocks\n const orphanedIds = new Set<string>();\n for (const id of serverToolIds) {\n if (!resultToolIds.has(id)) orphanedIds.add(id);\n }\n\n if (orphanedIds.size === 0) break;\n\n // Strip orphaned server_tool_call blocks from the content\n const filtered = msg.content.filter(\n (part) => !(part.type === \"server_tool_call\" && orphanedIds.has(part.id)),\n );\n\n if (filtered.length === 0) {\n // Nothing left — remove the entire message\n messages.splice(i, 1);\n } else {\n (msg as { content: ContentPart[] }).content = filtered;\n }\n break;\n }\n}\n\n/**\n * Ensure every assistant message with tool_call blocks is immediately followed\n * by a tool message with matching tool_result entries. This prevents Anthropic\n * API 400 errors (\"tool_use ids found without tool_result blocks immediately\n * after\") that can occur after compaction, session restore, or abort recovery.\n *\n * Repairs in-place by inserting synthetic tool_result messages where needed.\n */\nfunction repairToolPairingAdjacent(messages: Message[]): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) continue;\n\n const toolCallIds = (msg.content as ContentPart[])\n .filter((p) => p.type === \"tool_call\")\n .map((p) => (p as ContentPart & { type: \"tool_call\"; id: string }).id);\n if (toolCallIds.length === 0) continue;\n\n const next = messages[i + 1];\n if (next?.role === \"tool\" && Array.isArray(next.content)) {\n // Tool message exists — check for missing results\n const existingIds = new Set((next.content as ToolResult[]).map((r) => r.toolCallId));\n const missing = toolCallIds.filter((id) => !existingIds.has(id));\n if (missing.length > 0) {\n for (const id of missing) {\n (next.content as ToolResult[]).push({\n type: \"tool_result\",\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n });\n }\n }\n } else {\n // No tool message follows — insert a synthetic one\n messages.splice(i + 1, 0, {\n role: \"tool\" as const,\n content: toolCallIds.map((id) => ({\n type: \"tool_result\" as const,\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n })),\n });\n }\n }\n}\n"],"mappings":"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","names":["import_gg_ai"]}
|
package/dist/index.js
CHANGED
|
@@ -51,13 +51,13 @@ async function* agentLoop(messages, options) {
|
|
|
51
51
|
const MAX_OVERFLOW_RETRIES = 3;
|
|
52
52
|
const MAX_OVERLOAD_RETRIES = 10;
|
|
53
53
|
const MAX_EMPTY_RESPONSE_RETRIES = 2;
|
|
54
|
-
const MAX_STALL_RETRIES =
|
|
55
|
-
const
|
|
56
|
-
const STALL_MAX_DELAY_MS = 3e4;
|
|
54
|
+
const MAX_STALL_RETRIES = 5;
|
|
55
|
+
const STALL_DELAY_MS = 1e3;
|
|
57
56
|
const OVERLOAD_BASE_DELAY_MS = 2e3;
|
|
58
57
|
const OVERLOAD_MAX_DELAY_MS = 3e4;
|
|
59
|
-
const
|
|
60
|
-
const
|
|
58
|
+
const STREAM_FIRST_EVENT_TIMEOUT_MS = 45e3;
|
|
59
|
+
const STREAM_IDLE_TIMEOUT_MS = 1e4;
|
|
60
|
+
const STREAM_HARD_TIMEOUT_MS = 9e4;
|
|
61
61
|
try {
|
|
62
62
|
while (turn < maxTurns) {
|
|
63
63
|
options.signal?.throwIfAborted();
|
|
@@ -107,16 +107,19 @@ async function* agentLoop(messages, options) {
|
|
|
107
107
|
let streamCallStart = Date.now();
|
|
108
108
|
const forwardAbort = () => streamController.abort();
|
|
109
109
|
options.signal?.addEventListener("abort", forwardAbort, { once: true });
|
|
110
|
+
let hasReceivedEvent = false;
|
|
110
111
|
const resetIdleTimer = () => {
|
|
111
112
|
if (idleTimer) clearTimeout(idleTimer);
|
|
113
|
+
const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;
|
|
112
114
|
idleTimer = setTimeout(() => {
|
|
113
115
|
diag("idle_timeout_fired", {
|
|
114
|
-
events:
|
|
115
|
-
sinceLastEventMs:
|
|
116
|
+
events: streamEventCount,
|
|
117
|
+
sinceLastEventMs: Date.now() - lastEventTime,
|
|
118
|
+
phase: hasReceivedEvent ? "mid_stream" : "first_event"
|
|
116
119
|
});
|
|
117
120
|
idleTimedOut = true;
|
|
118
121
|
streamController.abort();
|
|
119
|
-
},
|
|
122
|
+
}, timeoutMs);
|
|
120
123
|
};
|
|
121
124
|
hardTimer = setTimeout(() => {
|
|
122
125
|
diag("hard_timeout_fired", {
|
|
@@ -150,11 +153,15 @@ async function* agentLoop(messages, options) {
|
|
|
150
153
|
result.response.catch(() => {
|
|
151
154
|
});
|
|
152
155
|
streamEventCount = 0;
|
|
156
|
+
hasReceivedEvent = false;
|
|
153
157
|
lastEventTime = Date.now();
|
|
154
158
|
streamCallStart = Date.now();
|
|
155
159
|
resetIdleTimer();
|
|
156
160
|
for await (const event of result) {
|
|
157
161
|
streamEventCount++;
|
|
162
|
+
if (!hasReceivedEvent) {
|
|
163
|
+
hasReceivedEvent = true;
|
|
164
|
+
}
|
|
158
165
|
const now = Date.now();
|
|
159
166
|
const gap = now - lastEventTime;
|
|
160
167
|
if (streamEventCount === 1) {
|
|
@@ -236,10 +243,7 @@ async function* agentLoop(messages, options) {
|
|
|
236
243
|
}
|
|
237
244
|
if (idleTimedOut && !options.signal?.aborted && stallRetries < MAX_STALL_RETRIES) {
|
|
238
245
|
stallRetries++;
|
|
239
|
-
const delayMs =
|
|
240
|
-
STALL_BASE_DELAY_MS * 2 ** (stallRetries - 1),
|
|
241
|
-
STALL_MAX_DELAY_MS
|
|
242
|
-
);
|
|
246
|
+
const delayMs = STALL_DELAY_MS;
|
|
243
247
|
yield {
|
|
244
248
|
type: "retry",
|
|
245
249
|
reason: "stream_stall",
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent.ts","../src/agent-loop.ts"],"sourcesContent":["import { EventStream, type Message } from \"@kenkaiiii/gg-ai\";\nimport { agentLoop } from \"./agent-loop.js\";\nimport type { AgentEvent, AgentOptions, AgentResult } from \"./types.js\";\n\n// ── AgentStream ─────────────────────────────────────────────\n\n/**\n * Dual-nature result: async iterable for streaming events,\n * thenable for awaiting the final AgentResult.\n *\n * ```ts\n * // Stream events\n * for await (const event of agent.prompt(\"hello\")) { ... }\n *\n * // Or just await the result\n * const result = await agent.prompt(\"hello\");\n * ```\n */\nexport class AgentStream implements AsyncIterable<AgentEvent> {\n private events: EventStream<AgentEvent>;\n private resultPromise: Promise<AgentResult>;\n private resolveResult!: (r: AgentResult) => void;\n private rejectResult!: (e: Error) => void;\n private hasConsumer = false;\n\n constructor(generator: AsyncGenerator<AgentEvent, AgentResult>, onDone: () => void) {\n this.events = new EventStream<AgentEvent>();\n this.resultPromise = new Promise<AgentResult>((resolve, reject) => {\n this.resolveResult = resolve;\n this.rejectResult = reject;\n });\n this.pump(generator, onDone);\n }\n\n private async pump(\n generator: AsyncGenerator<AgentEvent, AgentResult>,\n onDone: () => void,\n ): Promise<void> {\n try {\n let next = await generator.next();\n while (!next.done) {\n this.events.push(next.value);\n next = await generator.next();\n }\n this.events.close();\n this.resolveResult(next.value);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.events.abort(error);\n this.rejectResult(error);\n } finally {\n onDone();\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n this.hasConsumer = true;\n return this.events[Symbol.asyncIterator]();\n }\n\n then<TResult1 = AgentResult, TResult2 = never>(\n onfulfilled?: ((value: AgentResult) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n this.drainEvents().catch(() => {});\n return this.resultPromise.then(onfulfilled, onrejected);\n }\n\n private async drainEvents(): Promise<void> {\n if (this.hasConsumer) return;\n this.hasConsumer = true;\n for await (const _ of this.events) {\n // consume silently\n }\n }\n}\n\n// ── Agent ───────────────────────────────────────────────────\n\nexport class Agent {\n private messages: Message[] = [];\n private _running = false;\n private options: AgentOptions;\n private steeringQueue: Message[] = [];\n private followUpQueue: Message[] = [];\n\n constructor(options: AgentOptions) {\n this.options = options;\n if (options.system) {\n this.messages.push({ role: \"system\", content: options.system });\n }\n }\n\n get running(): boolean {\n return this._running;\n }\n\n /** Queue a steering message for injection after current tool execution completes. */\n steer(msg: Message): void {\n this.steeringQueue.push(msg);\n }\n\n /** Queue a follow-up message for injection when the agent would otherwise stop. */\n followUp(msg: Message): void {\n this.followUpQueue.push(msg);\n }\n\n prompt(content: string): AgentStream {\n if (this._running) {\n throw new Error(\"Agent is already running\");\n }\n this._running = true;\n\n this.messages.push({ role: \"user\", content });\n\n const optionsWithQueues: AgentOptions = {\n ...this.options,\n getSteeringMessages: async () => {\n const callerResult = (await this.options.getSteeringMessages?.()) ?? [];\n const queued = this.steeringQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n getFollowUpMessages: async () => {\n const callerResult = (await this.options.getFollowUpMessages?.()) ?? [];\n const queued = this.followUpQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n };\n\n const generator = agentLoop(this.messages, optionsWithQueues);\n return new AgentStream(generator, () => {\n this._running = false;\n });\n }\n}\n","import {\n stream,\n EventStream,\n type Message,\n type ToolCall,\n type ToolResult,\n type Usage,\n type ContentPart,\n type AssistantMessage,\n} from \"@kenkaiiii/gg-ai\";\nimport type {\n AgentEvent,\n AgentOptions,\n AgentResult,\n AgentTool,\n ToolContext,\n ToolExecuteResult,\n StructuredToolResult,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_TURNS = 200;\n\n/**\n * Lightweight stream diagnostic callback. When set, the agent loop calls this\n * at every phase boundary with timing and state info. This lets the hosting\n * app (ggcoder, come-alive, etc.) log stall diagnostics without the agent\n * package needing fs/process dependencies.\n */\nexport type StreamDiagnosticFn = (phase: string, data?: Record<string, unknown>) => void;\n\n/** Global diagnostic hook — set by the hosting app before calling agentLoop. */\nlet _diagFn: StreamDiagnosticFn | null = null;\n\n/** Register a diagnostic callback for stream stall tracing. */\nexport function setStreamDiagnostic(fn: StreamDiagnosticFn | null): void {\n _diagFn = fn;\n}\n\nfunction diag(phase: string, data?: Record<string, unknown>): void {\n _diagFn?.(phase, data);\n}\n\n/**\n * Detect abort errors — user-initiated cancellation or AbortSignal.\n * These should be caught and handled gracefully, not re-thrown.\n */\nexport function isAbortError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n const msg = err.message.toLowerCase();\n return msg.includes(\"aborted\") || msg.includes(\"abort\");\n}\n\n/**\n * Detect context window overflow errors from LLM providers.\n * Anthropic: \"prompt is too long: N tokens > M maximum\"\n * OpenAI: \"context_length_exceeded\" / \"maximum context length\"\n */\nexport function isContextOverflow(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"prompt is too long\") ||\n msg.includes(\"context_length_exceeded\") ||\n msg.includes(\"maximum context length\") ||\n (msg.includes(\"token\") && msg.includes(\"exceed\"))\n );\n}\n\n/**\n * Detect billing/quota errors — these should NOT be retried.\n * GLM returns HTTP 429 with \"Insufficient balance\" for quota exhaustion.\n */\nexport function isBillingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"insufficient balance\") ||\n msg.includes(\"no resource package\") ||\n msg.includes(\"quota exceeded\") ||\n msg.includes(\"billing\") ||\n msg.includes(\"recharge\") ||\n msg.includes(\"subscription plan\") ||\n msg.includes(\"does not yet include access\")\n );\n}\n\n/**\n * Detect overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n * Excludes billing/quota errors which won't resolve with a retry.\n */\nexport function isOverloaded(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (isBillingError(err)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"overloaded\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"too many requests\") ||\n msg.includes(\"429\") ||\n msg.includes(\"529\")\n );\n}\n\nexport async function* agentLoop(\n messages: Message[],\n options: AgentOptions,\n): AsyncGenerator<AgentEvent, AgentResult> {\n const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\n const maxContinuations = options.maxContinuations ?? 5;\n const toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n let turn = 0;\n let firstTurn = true;\n let consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n let stallRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 10;\n const MAX_EMPTY_RESPONSE_RETRIES = 2;\n const MAX_STALL_RETRIES = 8;\n const STALL_BASE_DELAY_MS = 2_000;\n const STALL_MAX_DELAY_MS = 30_000;\n const OVERLOAD_BASE_DELAY_MS = 2_000;\n const OVERLOAD_MAX_DELAY_MS = 30_000;\n const STREAM_IDLE_TIMEOUT_MS = 45_000; // 45s without any stream event = stall\n const STREAM_HARD_TIMEOUT_MS = 120_000; // 2min absolute cap per LLM call\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // Estimate message payload size for diagnostics\n let msgChars = 0;\n for (const m of messages) {\n if (typeof m.content === \"string\") msgChars += m.content.length;\n else if (Array.isArray(m.content)) {\n for (const p of m.content) {\n if (\"text\" in p && typeof p.text === \"string\") msgChars += p.text.length;\n if (\"content\" in p && typeof p.content === \"string\") msgChars += p.content.length;\n }\n }\n }\n diag(\"turn_start\", { turn, messages: messages.length, chars: msgChars });\n\n // ── Initial steering poll: catch messages queued before the first LLM call ──\n if (firstTurn && options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n firstTurn = false;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n diag(\"transform_start\");\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n diag(\"transform_compacted\", {\n before: messages.length,\n after: transformed.length,\n });\n messages.length = 0;\n messages.push(...transformed);\n }\n diag(\"transform_end\");\n }\n\n // ── Repair tool pairing: ensure every tool_use has an adjacent tool_result ──\n repairToolPairingAdjacent(messages);\n\n // ── Call LLM with overflow recovery ──\n let response;\n // Per-attempt abort controller: allows idle timeout to abort the stream\n // without affecting the caller's signal. The caller's abort is forwarded.\n const streamController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let hardTimer: ReturnType<typeof setTimeout> | null = null;\n let idleTimedOut = false;\n\n // Stream event counters — declared here so timeout callbacks can access them\n let streamEventCount = 0;\n let lastEventTime = Date.now();\n let streamCallStart = Date.now();\n\n // Forward caller abort to the per-attempt controller\n const forwardAbort = () => streamController.abort();\n options.signal?.addEventListener(\"abort\", forwardAbort, { once: true });\n\n // Idle timeout: abort the stream if no events arrive within the window.\n // This catches mid-stream server stalls where the connection stays open\n // but the server stops sending data (overload, network issues, etc.).\n const resetIdleTimer = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => {\n diag(\"idle_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n sinceLastEventMs:\n typeof lastEventTime !== \"undefined\" ? Date.now() - lastEventTime : -1,\n });\n idleTimedOut = true;\n streamController.abort();\n }, STREAM_IDLE_TIMEOUT_MS);\n };\n\n // Hard timeout: absolute cap per LLM call. Safety net for streams that\n // keep sending sparse events (e.g. keep-alive pings) but never complete.\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n });\n idleTimedOut = true;\n streamController.abort();\n }, STREAM_HARD_TIMEOUT_MS);\n\n try {\n diag(\"stream_call\");\n streamCallStart = Date.now();\n const result = stream({\n provider: options.provider,\n model: options.model,\n messages,\n tools: options.tools,\n serverTools: options.serverTools,\n webSearch: options.webSearch,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n thinking: options.thinking,\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n signal: streamController.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n clearToolUses: options.clearToolUses,\n });\n diag(\"stream_created\", { setupMs: Date.now() - streamCallStart });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas — reset idle timer on each event\n streamEventCount = 0;\n lastEventTime = Date.now();\n streamCallStart = Date.now();\n resetIdleTimer();\n for await (const event of result) {\n streamEventCount++;\n const now = Date.now();\n const gap = now - lastEventTime;\n // Log first event and any suspiciously long gaps\n if (streamEventCount === 1) {\n diag(\"first_event\", { type: event.type, ttfMs: now - streamCallStart });\n } else if (gap > 3000) {\n diag(\"slow_gap\", {\n type: event.type,\n gapMs: gap,\n eventNum: streamEventCount,\n sinceStartMs: now - streamCallStart,\n });\n }\n lastEventTime = now;\n resetIdleTimer();\n if (event.type === \"text_delta\") {\n yield { type: \"text_delta\" as const, text: event.text };\n } else if (event.type === \"thinking_delta\") {\n yield { type: \"thinking_delta\" as const, text: event.text };\n } else if (event.type === \"server_toolcall\") {\n yield {\n type: \"server_tool_call\" as const,\n id: event.id,\n name: event.name,\n input: event.input,\n };\n } else if (event.type === \"server_toolresult\") {\n yield {\n type: \"server_tool_result\" as const,\n toolUseId: event.toolUseId,\n resultType: event.resultType,\n data: event.data,\n };\n }\n }\n\n diag(\"stream_done\", { events: streamEventCount, totalMs: Date.now() - streamCallStart });\n response = await result.response;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n diag(\"stream_error\", {\n error: errMsg.slice(0, 200),\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n idleTimedOut,\n aborted: !!options.signal?.aborted,\n });\n // Context overflow: force-compact via transformContext and retry (up to 3 times)\n if (\n overflowRetries < MAX_OVERFLOW_RETRIES &&\n isContextOverflow(err) &&\n options.transformContext\n ) {\n overflowRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"context_overflow\" as const,\n attempt: overflowRetries,\n maxAttempts: MAX_OVERFLOW_RETRIES,\n delayMs: 0,\n };\n const transformed = await options.transformContext(messages, { force: true });\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n turn--; // Don't count the failed turn\n continue;\n }\n // Overloaded / rate-limited: exponential backoff, retry up to 10 times\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n const delayMs = Math.min(\n OVERLOAD_BASE_DELAY_MS * 2 ** (overloadRetries - 1),\n OVERLOAD_MAX_DELAY_MS,\n );\n yield {\n type: \"retry\" as const,\n reason: \"overloaded\" as const,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall: the API connection hung mid-stream without closing.\n // Retry with exponential backoff — the server may need time to recover\n // (especially during Anthropic capacity issues that affect many clients).\n if (idleTimedOut && !options.signal?.aborted && stallRetries < MAX_STALL_RETRIES) {\n stallRetries++;\n const delayMs = Math.min(\n STALL_BASE_DELAY_MS * 2 ** (stallRetries - 1),\n STALL_MAX_DELAY_MS,\n );\n yield {\n type: \"retry\" as const,\n reason: \"stream_stall\" as const,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall retries exhausted — surface a clear error so the UI\n // can distinguish \"gave up after stalls\" from \"completed normally\".\n if (idleTimedOut && !options.signal?.aborted) {\n yield {\n type: \"error\" as const,\n error: new Error(\n `The API provider's stream stalled ${MAX_STALL_RETRIES} times — the provider may be experiencing capacity issues. ` +\n `Your conversation is preserved. Send another message to retry.`,\n ),\n };\n break;\n }\n // Abort errors (user cancellation) — exit loop cleanly instead of\n // crashing the process with an unhandled rejection.\n if (isAbortError(err) || options.signal?.aborted) {\n break;\n }\n throw err;\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n if (hardTimer) clearTimeout(hardTimer);\n options.signal?.removeEventListener(\"abort\", forwardAbort);\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 0;\n stallRetries = 0;\n\n // Detect empty/degenerate responses — the API occasionally returns 0 tokens\n // with no content (e.g. stream interruption, transient server issue).\n // Retry instead of treating as completion.\n if (\n response.usage.outputTokens === 0 &&\n (response.message.content === \"\" ||\n (Array.isArray(response.message.content) && response.message.content.length === 0))\n ) {\n if (emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES) {\n emptyResponseRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"empty_response\" as const,\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n delayMs: 0,\n };\n turn--; // Don't count the failed turn\n continue;\n }\n // Exhausted retries — fall through and let the agent finish\n }\n emptyResponseRetries = 0;\n\n // Accumulate usage\n totalUsage.inputTokens += response.usage.inputTokens;\n totalUsage.outputTokens += response.usage.outputTokens;\n if (response.usage.cacheRead) {\n totalUsage.cacheRead = (totalUsage.cacheRead ?? 0) + response.usage.cacheRead;\n }\n if (response.usage.cacheWrite) {\n totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;\n }\n\n // Append assistant message to conversation\n messages.push(response.message);\n\n yield {\n type: \"turn_end\" as const,\n turn,\n stopReason: response.stopReason,\n usage: response.usage,\n };\n\n // Server-side tool hit iteration limit — re-send to continue.\n // Do NOT add an extra user message; the API detects the trailing\n // server_tool_use block and resumes automatically.\n if (response.stopReason === \"pause_turn\") {\n consecutivePauses++;\n if (consecutivePauses >= maxContinuations) {\n break; // Safety limit — fall through to agent_done below\n }\n continue;\n }\n consecutivePauses = 0;\n\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\n\n // If no tool calls to execute, check for steering messages before stopping.\n // Check content (not just stopReason) because some providers (e.g. GLM)\n // return finish_reason=\"stop\" even when tool calls are present.\n if (response.stopReason !== \"tool_use\" && allToolCalls.length === 0) {\n // Check for queued steering messages — if present, inject and continue\n // the loop instead of returning (follow-up pattern).\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue; // Next iteration will call LLM with injected messages\n }\n }\n // Follow-up: lower priority than steering — only when agent would otherwise stop.\n if (options.getFollowUpMessages) {\n const followUp = await options.getFollowUpMessages();\n if (followUp && followUp.length > 0) {\n for (const msg of followUp) {\n yield { type: \"follow_up_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue;\n }\n }\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n return {\n message: response.message,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n }\n const toolCalls: ToolCall[] = [];\n const toolResults: ToolResult[] = [];\n\n for (const tc of allToolCalls) {\n if (tc.name.startsWith(\"$\")) {\n // Provider built-in tool (e.g. Moonshot $web_search) — not locally executed.\n // Still needs a tool_result for the message history round-trip.\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: JSON.stringify(tc.args),\n });\n } else {\n toolCalls.push(tc);\n }\n }\n const eventStream = new EventStream<AgentEvent>();\n\n // Launch all tool calls in parallel\n const executions = toolCalls.map(async (toolCall) => {\n const startTime = Date.now();\n\n eventStream.push({\n type: \"tool_call_start\" as const,\n toolCallId: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n\n let resultContent: string;\n let details: unknown;\n let isError = false;\n\n const tool = toolMap.get(toolCall.name);\n if (!tool) {\n resultContent = `Unknown tool: ${toolCall.name}`;\n isError = true;\n } else {\n try {\n const parsed = tool.parameters.parse(toolCall.args);\n const ctx: ToolContext = {\n signal: options.signal ?? AbortSignal.timeout(300_000),\n toolCallId: toolCall.id,\n onUpdate: (update: unknown) => {\n eventStream.push({\n type: \"tool_call_update\" as const,\n toolCallId: toolCall.id,\n update,\n });\n },\n };\n const raw = await tool.execute(parsed, ctx);\n const normalized = normalizeToolResult(raw);\n resultContent = normalized.content;\n details = normalized.details;\n } catch (err) {\n isError = true;\n resultContent = err instanceof Error ? err.message : String(err);\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n eventStream.push({\n type: \"tool_call_end\" as const,\n toolCallId: toolCall.id,\n result: resultContent,\n details,\n isError,\n durationMs,\n });\n\n return { toolCallId: toolCall.id, content: resultContent, isError };\n });\n\n // Abort the tool event stream when the signal fires so Ctrl+C\n // doesn't hang waiting for long-running tools to finish.\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n // Close event stream when all tools complete.\n // Track whether the finally block has already consumed toolResults\n // to prevent the race where .then() mutates toolResults after\n // messages.push() has already captured the array by reference.\n let toolResultsFinalized = false;\n\n Promise.all(executions)\n .then((results) => {\n if (toolResultsFinalized) return;\n const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));\n for (const tc of toolCalls) {\n const r = resultsMap.get(tc.id)!;\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: r.content,\n isError: r.isError || undefined,\n });\n }\n eventStream.close();\n })\n .catch((err) => eventStream.abort(err instanceof Error ? err : new Error(String(err))));\n\n // Yield events as they arrive from parallel tools\n let toolsAborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n // Tool event stream aborted (Ctrl+C) — don't propagate, just mark\n // so the finally block can clean up and the loop can exit.\n if (isAbortError(err) || options.signal?.aborted) {\n toolsAborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n\n // Prevent the Promise.all .then() from mutating toolResults after\n // we finalize and push them into messages.\n toolResultsFinalized = true;\n\n // Ensure every tool_use has a matching tool_result, even on abort.\n // Without this, an aborted turn leaves an orphaned tool_use in the\n // message history which causes Anthropic API 400 errors on the next\n // request.\n const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));\n for (const tc of toolCalls) {\n if (!resolvedIds.has(tc.id)) {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: \"Tool execution was aborted.\",\n isError: true,\n });\n }\n }\n // Guard: cap oversized tool results before they enter conversation history.\n // Uses head+tail strategy to preserve error messages / closing structure at the end.\n if (options.maxToolResultChars) {\n const HARD_MAX = 400_000; // absolute ceiling regardless of context window\n const max = Math.min(options.maxToolResultChars, HARD_MAX);\n for (const tr of toolResults) {\n if (tr.content.length > max) {\n // Keep 70% head + 30% tail to preserve errors/diagnostics at the end\n const headChars = Math.floor(max * 0.7);\n const tailChars = max - headChars;\n const head = tr.content.slice(0, headChars);\n const tail = tr.content.slice(-tailChars);\n const omitted = tr.content.length - headChars - tailChars;\n tr.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n }\n }\n }\n\n messages.push({ role: \"tool\", content: toolResults });\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\n\n // ── Steering messages: inject user messages queued during tool execution ──\n // Polled after tools complete so the next LLM call sees them in context.\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n }\n } finally {\n // Sanitize orphaned server_tool_use blocks on abort.\n // When a stream is aborted mid-server-tool (e.g. web_search), the\n // assistant message containing the server_tool_use may already be in\n // the messages array, but the corresponding web_search_tool_result\n // never arrived. The API rejects the next request with a 400 if it\n // finds an unmatched server_tool_use, so we strip it here.\n sanitizeOrphanedServerTools(messages);\n }\n\n // Exceeded max turns — return last assistant message\n let lastAssistant: AssistantMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"assistant\") {\n lastAssistant = messages[i] as AssistantMessage;\n break;\n }\n }\n\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n\n return {\n message: lastAssistant ?? { role: \"assistant\" as const, content: [] },\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n}\n\nfunction normalizeToolResult(raw: ToolExecuteResult): StructuredToolResult {\n return typeof raw === \"string\" ? { content: raw } : raw;\n}\n\nfunction extractToolCalls(content: string | ContentPart[]): ToolCall[] {\n if (typeof content === \"string\") return [];\n return content.filter((part): part is ToolCall => part.type === \"tool_call\");\n}\n\n/**\n * Remove orphaned server_tool_use blocks from the last assistant message.\n * When a stream is aborted mid-server-tool (e.g. web_search), the assistant\n * message may contain a server_tool_call without a matching server_tool_result.\n * The API rejects the next request if these are unmatched.\n */\nfunction sanitizeOrphanedServerTools(messages: Message[]): void {\n // Find the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) break;\n\n // Collect server_tool_call ids and matched server_tool_result ids\n const serverToolIds = new Set<string>();\n const resultToolIds = new Set<string>();\n for (const part of msg.content) {\n if (part.type === \"server_tool_call\") serverToolIds.add(part.id);\n if (part.type === \"server_tool_result\") resultToolIds.add(part.toolUseId);\n }\n\n // Find unmatched server_tool_call blocks\n const orphanedIds = new Set<string>();\n for (const id of serverToolIds) {\n if (!resultToolIds.has(id)) orphanedIds.add(id);\n }\n\n if (orphanedIds.size === 0) break;\n\n // Strip orphaned server_tool_call blocks from the content\n const filtered = msg.content.filter(\n (part) => !(part.type === \"server_tool_call\" && orphanedIds.has(part.id)),\n );\n\n if (filtered.length === 0) {\n // Nothing left — remove the entire message\n messages.splice(i, 1);\n } else {\n (msg as { content: ContentPart[] }).content = filtered;\n }\n break;\n }\n}\n\n/**\n * Ensure every assistant message with tool_call blocks is immediately followed\n * by a tool message with matching tool_result entries. This prevents Anthropic\n * API 400 errors (\"tool_use ids found without tool_result blocks immediately\n * after\") that can occur after compaction, session restore, or abort recovery.\n *\n * Repairs in-place by inserting synthetic tool_result messages where needed.\n */\nfunction repairToolPairingAdjacent(messages: Message[]): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) continue;\n\n const toolCallIds = (msg.content as ContentPart[])\n .filter((p) => p.type === \"tool_call\")\n .map((p) => (p as ContentPart & { type: \"tool_call\"; id: string }).id);\n if (toolCallIds.length === 0) continue;\n\n const next = messages[i + 1];\n if (next?.role === \"tool\" && Array.isArray(next.content)) {\n // Tool message exists — check for missing results\n const existingIds = new Set((next.content as ToolResult[]).map((r) => r.toolCallId));\n const missing = toolCallIds.filter((id) => !existingIds.has(id));\n if (missing.length > 0) {\n for (const id of missing) {\n (next.content as ToolResult[]).push({\n type: \"tool_result\",\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n });\n }\n }\n } else {\n // No tool message follows — insert a synthetic one\n messages.splice(i + 1, 0, {\n role: \"tool\" as const,\n content: toolCallIds.map((id) => ({\n type: \"tool_result\" as const,\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n })),\n });\n }\n }\n}\n"],"mappings":"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","names":["EventStream","EventStream"]}
|
|
1
|
+
{"version":3,"sources":["../src/agent.ts","../src/agent-loop.ts"],"sourcesContent":["import { EventStream, type Message } from \"@kenkaiiii/gg-ai\";\nimport { agentLoop } from \"./agent-loop.js\";\nimport type { AgentEvent, AgentOptions, AgentResult } from \"./types.js\";\n\n// ── AgentStream ─────────────────────────────────────────────\n\n/**\n * Dual-nature result: async iterable for streaming events,\n * thenable for awaiting the final AgentResult.\n *\n * ```ts\n * // Stream events\n * for await (const event of agent.prompt(\"hello\")) { ... }\n *\n * // Or just await the result\n * const result = await agent.prompt(\"hello\");\n * ```\n */\nexport class AgentStream implements AsyncIterable<AgentEvent> {\n private events: EventStream<AgentEvent>;\n private resultPromise: Promise<AgentResult>;\n private resolveResult!: (r: AgentResult) => void;\n private rejectResult!: (e: Error) => void;\n private hasConsumer = false;\n\n constructor(generator: AsyncGenerator<AgentEvent, AgentResult>, onDone: () => void) {\n this.events = new EventStream<AgentEvent>();\n this.resultPromise = new Promise<AgentResult>((resolve, reject) => {\n this.resolveResult = resolve;\n this.rejectResult = reject;\n });\n this.pump(generator, onDone);\n }\n\n private async pump(\n generator: AsyncGenerator<AgentEvent, AgentResult>,\n onDone: () => void,\n ): Promise<void> {\n try {\n let next = await generator.next();\n while (!next.done) {\n this.events.push(next.value);\n next = await generator.next();\n }\n this.events.close();\n this.resolveResult(next.value);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.events.abort(error);\n this.rejectResult(error);\n } finally {\n onDone();\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<AgentEvent> {\n this.hasConsumer = true;\n return this.events[Symbol.asyncIterator]();\n }\n\n then<TResult1 = AgentResult, TResult2 = never>(\n onfulfilled?: ((value: AgentResult) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n this.drainEvents().catch(() => {});\n return this.resultPromise.then(onfulfilled, onrejected);\n }\n\n private async drainEvents(): Promise<void> {\n if (this.hasConsumer) return;\n this.hasConsumer = true;\n for await (const _ of this.events) {\n // consume silently\n }\n }\n}\n\n// ── Agent ───────────────────────────────────────────────────\n\nexport class Agent {\n private messages: Message[] = [];\n private _running = false;\n private options: AgentOptions;\n private steeringQueue: Message[] = [];\n private followUpQueue: Message[] = [];\n\n constructor(options: AgentOptions) {\n this.options = options;\n if (options.system) {\n this.messages.push({ role: \"system\", content: options.system });\n }\n }\n\n get running(): boolean {\n return this._running;\n }\n\n /** Queue a steering message for injection after current tool execution completes. */\n steer(msg: Message): void {\n this.steeringQueue.push(msg);\n }\n\n /** Queue a follow-up message for injection when the agent would otherwise stop. */\n followUp(msg: Message): void {\n this.followUpQueue.push(msg);\n }\n\n prompt(content: string): AgentStream {\n if (this._running) {\n throw new Error(\"Agent is already running\");\n }\n this._running = true;\n\n this.messages.push({ role: \"user\", content });\n\n const optionsWithQueues: AgentOptions = {\n ...this.options,\n getSteeringMessages: async () => {\n const callerResult = (await this.options.getSteeringMessages?.()) ?? [];\n const queued = this.steeringQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n getFollowUpMessages: async () => {\n const callerResult = (await this.options.getFollowUpMessages?.()) ?? [];\n const queued = this.followUpQueue.splice(0);\n const all = [...(callerResult ?? []), ...queued];\n return all.length > 0 ? all : null;\n },\n };\n\n const generator = agentLoop(this.messages, optionsWithQueues);\n return new AgentStream(generator, () => {\n this._running = false;\n });\n }\n}\n","import {\n stream,\n EventStream,\n type Message,\n type ToolCall,\n type ToolResult,\n type Usage,\n type ContentPart,\n type AssistantMessage,\n} from \"@kenkaiiii/gg-ai\";\nimport type {\n AgentEvent,\n AgentOptions,\n AgentResult,\n AgentTool,\n ToolContext,\n ToolExecuteResult,\n StructuredToolResult,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_TURNS = 200;\n\n/**\n * Lightweight stream diagnostic callback. When set, the agent loop calls this\n * at every phase boundary with timing and state info. This lets the hosting\n * app (ggcoder, come-alive, etc.) log stall diagnostics without the agent\n * package needing fs/process dependencies.\n */\nexport type StreamDiagnosticFn = (phase: string, data?: Record<string, unknown>) => void;\n\n/** Global diagnostic hook — set by the hosting app before calling agentLoop. */\nlet _diagFn: StreamDiagnosticFn | null = null;\n\n/** Register a diagnostic callback for stream stall tracing. */\nexport function setStreamDiagnostic(fn: StreamDiagnosticFn | null): void {\n _diagFn = fn;\n}\n\nfunction diag(phase: string, data?: Record<string, unknown>): void {\n _diagFn?.(phase, data);\n}\n\n/**\n * Detect abort errors — user-initiated cancellation or AbortSignal.\n * These should be caught and handled gracefully, not re-thrown.\n */\nexport function isAbortError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (err.name === \"AbortError\") return true;\n const msg = err.message.toLowerCase();\n return msg.includes(\"aborted\") || msg.includes(\"abort\");\n}\n\n/**\n * Detect context window overflow errors from LLM providers.\n * Anthropic: \"prompt is too long: N tokens > M maximum\"\n * OpenAI: \"context_length_exceeded\" / \"maximum context length\"\n */\nexport function isContextOverflow(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"prompt is too long\") ||\n msg.includes(\"context_length_exceeded\") ||\n msg.includes(\"maximum context length\") ||\n (msg.includes(\"token\") && msg.includes(\"exceed\"))\n );\n}\n\n/**\n * Detect billing/quota errors — these should NOT be retried.\n * GLM returns HTTP 429 with \"Insufficient balance\" for quota exhaustion.\n */\nexport function isBillingError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"insufficient balance\") ||\n msg.includes(\"no resource package\") ||\n msg.includes(\"quota exceeded\") ||\n msg.includes(\"billing\") ||\n msg.includes(\"recharge\") ||\n msg.includes(\"subscription plan\") ||\n msg.includes(\"does not yet include access\")\n );\n}\n\n/**\n * Detect overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n * Excludes billing/quota errors which won't resolve with a retry.\n */\nexport function isOverloaded(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n if (isBillingError(err)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes(\"overloaded\") ||\n msg.includes(\"rate limit\") ||\n msg.includes(\"too many requests\") ||\n msg.includes(\"429\") ||\n msg.includes(\"529\")\n );\n}\n\nexport async function* agentLoop(\n messages: Message[],\n options: AgentOptions,\n): AsyncGenerator<AgentEvent, AgentResult> {\n const maxTurns = options.maxTurns ?? DEFAULT_MAX_TURNS;\n const maxContinuations = options.maxContinuations ?? 5;\n const toolMap = new Map<string, AgentTool>((options.tools ?? []).map((t) => [t.name, t]));\n\n const totalUsage: Usage = { inputTokens: 0, outputTokens: 0 };\n let turn = 0;\n let firstTurn = true;\n let consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n let stallRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 10;\n const MAX_EMPTY_RESPONSE_RETRIES = 2;\n const MAX_STALL_RETRIES = 5;\n const STALL_DELAY_MS = 1_000; // Brief pause before retry — just enough to avoid tight loops\n const OVERLOAD_BASE_DELAY_MS = 2_000;\n const OVERLOAD_MAX_DELAY_MS = 30_000;\n const STREAM_FIRST_EVENT_TIMEOUT_MS = 45_000; // 45s to get first event (Opus thinks long)\n const STREAM_IDLE_TIMEOUT_MS = 10_000; // 10s between events once streaming starts\n const STREAM_HARD_TIMEOUT_MS = 90_000; // 90s absolute cap per LLM call\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // Estimate message payload size for diagnostics\n let msgChars = 0;\n for (const m of messages) {\n if (typeof m.content === \"string\") msgChars += m.content.length;\n else if (Array.isArray(m.content)) {\n for (const p of m.content) {\n if (\"text\" in p && typeof p.text === \"string\") msgChars += p.text.length;\n if (\"content\" in p && typeof p.content === \"string\") msgChars += p.content.length;\n }\n }\n }\n diag(\"turn_start\", { turn, messages: messages.length, chars: msgChars });\n\n // ── Initial steering poll: catch messages queued before the first LLM call ──\n if (firstTurn && options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n firstTurn = false;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n diag(\"transform_start\");\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n diag(\"transform_compacted\", {\n before: messages.length,\n after: transformed.length,\n });\n messages.length = 0;\n messages.push(...transformed);\n }\n diag(\"transform_end\");\n }\n\n // ── Repair tool pairing: ensure every tool_use has an adjacent tool_result ──\n repairToolPairingAdjacent(messages);\n\n // ── Call LLM with overflow recovery ──\n let response;\n // Per-attempt abort controller: allows idle timeout to abort the stream\n // without affecting the caller's signal. The caller's abort is forwarded.\n const streamController = new AbortController();\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let hardTimer: ReturnType<typeof setTimeout> | null = null;\n let idleTimedOut = false;\n\n // Stream event counters — declared here so timeout callbacks can access them\n let streamEventCount = 0;\n let lastEventTime = Date.now();\n let streamCallStart = Date.now();\n\n // Forward caller abort to the per-attempt controller\n const forwardAbort = () => streamController.abort();\n options.signal?.addEventListener(\"abort\", forwardAbort, { once: true });\n\n // Two-phase idle timeout:\n // - Before first event: STREAM_FIRST_EVENT_TIMEOUT_MS (45s) — Opus can\n // take 30s+ to start on large contexts, that's not a stall.\n // - After first event: STREAM_IDLE_TIMEOUT_MS (10s) — once streaming has\n // started, 10s of silence is a dead connection. Retry fast.\n let hasReceivedEvent = false;\n const resetIdleTimer = () => {\n if (idleTimer) clearTimeout(idleTimer);\n const timeoutMs = hasReceivedEvent ? STREAM_IDLE_TIMEOUT_MS : STREAM_FIRST_EVENT_TIMEOUT_MS;\n idleTimer = setTimeout(() => {\n diag(\"idle_timeout_fired\", {\n events: streamEventCount,\n sinceLastEventMs: Date.now() - lastEventTime,\n phase: hasReceivedEvent ? \"mid_stream\" : \"first_event\",\n });\n idleTimedOut = true;\n streamController.abort();\n }, timeoutMs);\n };\n\n // Hard timeout: absolute cap per LLM call. Safety net for streams that\n // keep sending sparse events (e.g. keep-alive pings) but never complete.\n hardTimer = setTimeout(() => {\n diag(\"hard_timeout_fired\", {\n events: typeof streamEventCount !== \"undefined\" ? streamEventCount : 0,\n });\n idleTimedOut = true;\n streamController.abort();\n }, STREAM_HARD_TIMEOUT_MS);\n\n try {\n diag(\"stream_call\");\n streamCallStart = Date.now();\n const result = stream({\n provider: options.provider,\n model: options.model,\n messages,\n tools: options.tools,\n serverTools: options.serverTools,\n webSearch: options.webSearch,\n maxTokens: options.maxTokens,\n temperature: options.temperature,\n thinking: options.thinking,\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n signal: streamController.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n clearToolUses: options.clearToolUses,\n });\n diag(\"stream_created\", { setupMs: Date.now() - streamCallStart });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas — reset idle timer on each event\n streamEventCount = 0;\n hasReceivedEvent = false;\n lastEventTime = Date.now();\n streamCallStart = Date.now();\n resetIdleTimer();\n for await (const event of result) {\n streamEventCount++;\n if (!hasReceivedEvent) {\n hasReceivedEvent = true;\n // Switch to the shorter mid-stream timeout now that events are flowing\n }\n const now = Date.now();\n const gap = now - lastEventTime;\n // Log first event and any suspiciously long gaps\n if (streamEventCount === 1) {\n diag(\"first_event\", { type: event.type, ttfMs: now - streamCallStart });\n } else if (gap > 3000) {\n diag(\"slow_gap\", {\n type: event.type,\n gapMs: gap,\n eventNum: streamEventCount,\n sinceStartMs: now - streamCallStart,\n });\n }\n lastEventTime = now;\n resetIdleTimer();\n if (event.type === \"text_delta\") {\n yield { type: \"text_delta\" as const, text: event.text };\n } else if (event.type === \"thinking_delta\") {\n yield { type: \"thinking_delta\" as const, text: event.text };\n } else if (event.type === \"server_toolcall\") {\n yield {\n type: \"server_tool_call\" as const,\n id: event.id,\n name: event.name,\n input: event.input,\n };\n } else if (event.type === \"server_toolresult\") {\n yield {\n type: \"server_tool_result\" as const,\n toolUseId: event.toolUseId,\n resultType: event.resultType,\n data: event.data,\n };\n }\n }\n\n diag(\"stream_done\", { events: streamEventCount, totalMs: Date.now() - streamCallStart });\n response = await result.response;\n } catch (err) {\n const errMsg = err instanceof Error ? err.message : String(err);\n diag(\"stream_error\", {\n error: errMsg.slice(0, 200),\n events: streamEventCount,\n totalMs: Date.now() - streamCallStart,\n idleTimedOut,\n aborted: !!options.signal?.aborted,\n });\n // Context overflow: force-compact via transformContext and retry (up to 3 times)\n if (\n overflowRetries < MAX_OVERFLOW_RETRIES &&\n isContextOverflow(err) &&\n options.transformContext\n ) {\n overflowRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"context_overflow\" as const,\n attempt: overflowRetries,\n maxAttempts: MAX_OVERFLOW_RETRIES,\n delayMs: 0,\n };\n const transformed = await options.transformContext(messages, { force: true });\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n turn--; // Don't count the failed turn\n continue;\n }\n // Overloaded / rate-limited: exponential backoff, retry up to 10 times\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n const delayMs = Math.min(\n OVERLOAD_BASE_DELAY_MS * 2 ** (overloadRetries - 1),\n OVERLOAD_MAX_DELAY_MS,\n );\n yield {\n type: \"retry\" as const,\n reason: \"overloaded\" as const,\n attempt: overloadRetries,\n maxAttempts: MAX_OVERLOAD_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall: the API connection hung mid-stream without closing.\n // Retry with exponential backoff — the server may need time to recover\n // (especially during Anthropic capacity issues that affect many clients).\n if (idleTimedOut && !options.signal?.aborted && stallRetries < MAX_STALL_RETRIES) {\n stallRetries++;\n const delayMs = STALL_DELAY_MS;\n yield {\n type: \"retry\" as const,\n reason: \"stream_stall\" as const,\n attempt: stallRetries,\n maxAttempts: MAX_STALL_RETRIES,\n delayMs,\n };\n await new Promise((r) => setTimeout(r, delayMs));\n turn--; // Don't count the failed turn\n continue;\n }\n // Stream stall retries exhausted — surface a clear error so the UI\n // can distinguish \"gave up after stalls\" from \"completed normally\".\n if (idleTimedOut && !options.signal?.aborted) {\n yield {\n type: \"error\" as const,\n error: new Error(\n `The API provider's stream stalled ${MAX_STALL_RETRIES} times — the provider may be experiencing capacity issues. ` +\n `Your conversation is preserved. Send another message to retry.`,\n ),\n };\n break;\n }\n // Abort errors (user cancellation) — exit loop cleanly instead of\n // crashing the process with an unhandled rejection.\n if (isAbortError(err) || options.signal?.aborted) {\n break;\n }\n throw err;\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n if (hardTimer) clearTimeout(hardTimer);\n options.signal?.removeEventListener(\"abort\", forwardAbort);\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 0;\n stallRetries = 0;\n\n // Detect empty/degenerate responses — the API occasionally returns 0 tokens\n // with no content (e.g. stream interruption, transient server issue).\n // Retry instead of treating as completion.\n if (\n response.usage.outputTokens === 0 &&\n (response.message.content === \"\" ||\n (Array.isArray(response.message.content) && response.message.content.length === 0))\n ) {\n if (emptyResponseRetries < MAX_EMPTY_RESPONSE_RETRIES) {\n emptyResponseRetries++;\n yield {\n type: \"retry\" as const,\n reason: \"empty_response\" as const,\n attempt: emptyResponseRetries,\n maxAttempts: MAX_EMPTY_RESPONSE_RETRIES,\n delayMs: 0,\n };\n turn--; // Don't count the failed turn\n continue;\n }\n // Exhausted retries — fall through and let the agent finish\n }\n emptyResponseRetries = 0;\n\n // Accumulate usage\n totalUsage.inputTokens += response.usage.inputTokens;\n totalUsage.outputTokens += response.usage.outputTokens;\n if (response.usage.cacheRead) {\n totalUsage.cacheRead = (totalUsage.cacheRead ?? 0) + response.usage.cacheRead;\n }\n if (response.usage.cacheWrite) {\n totalUsage.cacheWrite = (totalUsage.cacheWrite ?? 0) + response.usage.cacheWrite;\n }\n\n // Append assistant message to conversation\n messages.push(response.message);\n\n yield {\n type: \"turn_end\" as const,\n turn,\n stopReason: response.stopReason,\n usage: response.usage,\n };\n\n // Server-side tool hit iteration limit — re-send to continue.\n // Do NOT add an extra user message; the API detects the trailing\n // server_tool_use block and resumes automatically.\n if (response.stopReason === \"pause_turn\") {\n consecutivePauses++;\n if (consecutivePauses >= maxContinuations) {\n break; // Safety limit — fall through to agent_done below\n }\n continue;\n }\n consecutivePauses = 0;\n\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\n\n // If no tool calls to execute, check for steering messages before stopping.\n // Check content (not just stopReason) because some providers (e.g. GLM)\n // return finish_reason=\"stop\" even when tool calls are present.\n if (response.stopReason !== \"tool_use\" && allToolCalls.length === 0) {\n // Check for queued steering messages — if present, inject and continue\n // the loop instead of returning (follow-up pattern).\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue; // Next iteration will call LLM with injected messages\n }\n }\n // Follow-up: lower priority than steering — only when agent would otherwise stop.\n if (options.getFollowUpMessages) {\n const followUp = await options.getFollowUpMessages();\n if (followUp && followUp.length > 0) {\n for (const msg of followUp) {\n yield { type: \"follow_up_message\" as const, content: msg.content };\n messages.push(msg);\n }\n continue;\n }\n }\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n return {\n message: response.message,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n }\n const toolCalls: ToolCall[] = [];\n const toolResults: ToolResult[] = [];\n\n for (const tc of allToolCalls) {\n if (tc.name.startsWith(\"$\")) {\n // Provider built-in tool (e.g. Moonshot $web_search) — not locally executed.\n // Still needs a tool_result for the message history round-trip.\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: JSON.stringify(tc.args),\n });\n } else {\n toolCalls.push(tc);\n }\n }\n const eventStream = new EventStream<AgentEvent>();\n\n // Launch all tool calls in parallel\n const executions = toolCalls.map(async (toolCall) => {\n const startTime = Date.now();\n\n eventStream.push({\n type: \"tool_call_start\" as const,\n toolCallId: toolCall.id,\n name: toolCall.name,\n args: toolCall.args,\n });\n\n let resultContent: string;\n let details: unknown;\n let isError = false;\n\n const tool = toolMap.get(toolCall.name);\n if (!tool) {\n resultContent = `Unknown tool: ${toolCall.name}`;\n isError = true;\n } else {\n try {\n const parsed = tool.parameters.parse(toolCall.args);\n const ctx: ToolContext = {\n signal: options.signal ?? AbortSignal.timeout(300_000),\n toolCallId: toolCall.id,\n onUpdate: (update: unknown) => {\n eventStream.push({\n type: \"tool_call_update\" as const,\n toolCallId: toolCall.id,\n update,\n });\n },\n };\n const raw = await tool.execute(parsed, ctx);\n const normalized = normalizeToolResult(raw);\n resultContent = normalized.content;\n details = normalized.details;\n } catch (err) {\n isError = true;\n resultContent = err instanceof Error ? err.message : String(err);\n }\n }\n\n const durationMs = Date.now() - startTime;\n\n eventStream.push({\n type: \"tool_call_end\" as const,\n toolCallId: toolCall.id,\n result: resultContent,\n details,\n isError,\n durationMs,\n });\n\n return { toolCallId: toolCall.id, content: resultContent, isError };\n });\n\n // Abort the tool event stream when the signal fires so Ctrl+C\n // doesn't hang waiting for long-running tools to finish.\n const abortHandler = () => eventStream.abort(new Error(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abortHandler, { once: true });\n\n // Close event stream when all tools complete.\n // Track whether the finally block has already consumed toolResults\n // to prevent the race where .then() mutates toolResults after\n // messages.push() has already captured the array by reference.\n let toolResultsFinalized = false;\n\n Promise.all(executions)\n .then((results) => {\n if (toolResultsFinalized) return;\n const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));\n for (const tc of toolCalls) {\n const r = resultsMap.get(tc.id)!;\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: r.content,\n isError: r.isError || undefined,\n });\n }\n eventStream.close();\n })\n .catch((err) => eventStream.abort(err instanceof Error ? err : new Error(String(err))));\n\n // Yield events as they arrive from parallel tools\n let toolsAborted = false;\n try {\n for await (const event of eventStream) {\n yield event;\n }\n } catch (err) {\n // Tool event stream aborted (Ctrl+C) — don't propagate, just mark\n // so the finally block can clean up and the loop can exit.\n if (isAbortError(err) || options.signal?.aborted) {\n toolsAborted = true;\n } else {\n throw err;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", abortHandler);\n\n // Prevent the Promise.all .then() from mutating toolResults after\n // we finalize and push them into messages.\n toolResultsFinalized = true;\n\n // Ensure every tool_use has a matching tool_result, even on abort.\n // Without this, an aborted turn leaves an orphaned tool_use in the\n // message history which causes Anthropic API 400 errors on the next\n // request.\n const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));\n for (const tc of toolCalls) {\n if (!resolvedIds.has(tc.id)) {\n toolResults.push({\n type: \"tool_result\",\n toolCallId: tc.id,\n content: \"Tool execution was aborted.\",\n isError: true,\n });\n }\n }\n // Guard: cap oversized tool results before they enter conversation history.\n // Uses head+tail strategy to preserve error messages / closing structure at the end.\n if (options.maxToolResultChars) {\n const HARD_MAX = 400_000; // absolute ceiling regardless of context window\n const max = Math.min(options.maxToolResultChars, HARD_MAX);\n for (const tr of toolResults) {\n if (tr.content.length > max) {\n // Keep 70% head + 30% tail to preserve errors/diagnostics at the end\n const headChars = Math.floor(max * 0.7);\n const tailChars = max - headChars;\n const head = tr.content.slice(0, headChars);\n const tail = tr.content.slice(-tailChars);\n const omitted = tr.content.length - headChars - tailChars;\n tr.content = head + `\\n\\n[... ${omitted} characters omitted ...]\\n\\n` + tail;\n }\n }\n }\n\n messages.push({ role: \"tool\", content: toolResults });\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\n\n // ── Steering messages: inject user messages queued during tool execution ──\n // Polled after tools complete so the next LLM call sees them in context.\n if (options.getSteeringMessages) {\n const steering = await options.getSteeringMessages();\n if (steering && steering.length > 0) {\n for (const msg of steering) {\n yield { type: \"steering_message\" as const, content: msg.content };\n messages.push(msg);\n }\n }\n }\n }\n } finally {\n // Sanitize orphaned server_tool_use blocks on abort.\n // When a stream is aborted mid-server-tool (e.g. web_search), the\n // assistant message containing the server_tool_use may already be in\n // the messages array, but the corresponding web_search_tool_result\n // never arrived. The API rejects the next request with a 400 if it\n // finds an unmatched server_tool_use, so we strip it here.\n sanitizeOrphanedServerTools(messages);\n }\n\n // Exceeded max turns — return last assistant message\n let lastAssistant: AssistantMessage | undefined;\n for (let i = messages.length - 1; i >= 0; i--) {\n if (messages[i]!.role === \"assistant\") {\n lastAssistant = messages[i] as AssistantMessage;\n break;\n }\n }\n\n yield {\n type: \"agent_done\" as const,\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n\n return {\n message: lastAssistant ?? { role: \"assistant\" as const, content: [] },\n totalTurns: turn,\n totalUsage: { ...totalUsage },\n };\n}\n\nfunction normalizeToolResult(raw: ToolExecuteResult): StructuredToolResult {\n return typeof raw === \"string\" ? { content: raw } : raw;\n}\n\nfunction extractToolCalls(content: string | ContentPart[]): ToolCall[] {\n if (typeof content === \"string\") return [];\n return content.filter((part): part is ToolCall => part.type === \"tool_call\");\n}\n\n/**\n * Remove orphaned server_tool_use blocks from the last assistant message.\n * When a stream is aborted mid-server-tool (e.g. web_search), the assistant\n * message may contain a server_tool_call without a matching server_tool_result.\n * The API rejects the next request if these are unmatched.\n */\nfunction sanitizeOrphanedServerTools(messages: Message[]): void {\n // Find the last assistant message\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) break;\n\n // Collect server_tool_call ids and matched server_tool_result ids\n const serverToolIds = new Set<string>();\n const resultToolIds = new Set<string>();\n for (const part of msg.content) {\n if (part.type === \"server_tool_call\") serverToolIds.add(part.id);\n if (part.type === \"server_tool_result\") resultToolIds.add(part.toolUseId);\n }\n\n // Find unmatched server_tool_call blocks\n const orphanedIds = new Set<string>();\n for (const id of serverToolIds) {\n if (!resultToolIds.has(id)) orphanedIds.add(id);\n }\n\n if (orphanedIds.size === 0) break;\n\n // Strip orphaned server_tool_call blocks from the content\n const filtered = msg.content.filter(\n (part) => !(part.type === \"server_tool_call\" && orphanedIds.has(part.id)),\n );\n\n if (filtered.length === 0) {\n // Nothing left — remove the entire message\n messages.splice(i, 1);\n } else {\n (msg as { content: ContentPart[] }).content = filtered;\n }\n break;\n }\n}\n\n/**\n * Ensure every assistant message with tool_call blocks is immediately followed\n * by a tool message with matching tool_result entries. This prevents Anthropic\n * API 400 errors (\"tool_use ids found without tool_result blocks immediately\n * after\") that can occur after compaction, session restore, or abort recovery.\n *\n * Repairs in-place by inserting synthetic tool_result messages where needed.\n */\nfunction repairToolPairingAdjacent(messages: Message[]): void {\n for (let i = 0; i < messages.length; i++) {\n const msg = messages[i]!;\n if (msg.role !== \"assistant\") continue;\n if (typeof msg.content === \"string\" || !Array.isArray(msg.content)) continue;\n\n const toolCallIds = (msg.content as ContentPart[])\n .filter((p) => p.type === \"tool_call\")\n .map((p) => (p as ContentPart & { type: \"tool_call\"; id: string }).id);\n if (toolCallIds.length === 0) continue;\n\n const next = messages[i + 1];\n if (next?.role === \"tool\" && Array.isArray(next.content)) {\n // Tool message exists — check for missing results\n const existingIds = new Set((next.content as ToolResult[]).map((r) => r.toolCallId));\n const missing = toolCallIds.filter((id) => !existingIds.has(id));\n if (missing.length > 0) {\n for (const id of missing) {\n (next.content as ToolResult[]).push({\n type: \"tool_result\",\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n });\n }\n }\n } else {\n // No tool message follows — insert a synthetic one\n messages.splice(i + 1, 0, {\n role: \"tool\" as const,\n content: toolCallIds.map((id) => ({\n type: \"tool_result\" as const,\n toolCallId: id,\n content: \"Tool execution was interrupted.\",\n isError: true,\n })),\n });\n }\n }\n}\n"],"mappings":"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","names":["EventStream","EventStream"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenkaiiii/gg-agent",
|
|
3
|
-
"version": "4.2.
|
|
3
|
+
"version": "4.2.97",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Agentic loop system with tool execution for LLMs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"zod": "^4.3.6",
|
|
27
|
-
"@kenkaiiii/gg-ai": "4.2.
|
|
27
|
+
"@kenkaiiii/gg-ai": "4.2.97"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.9.3",
|