@kenkaiiii/gg-agent 4.2.38 → 4.2.40
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 +19 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -182,6 +182,16 @@ async function* agentLoop(messages, options) {
|
|
|
182
182
|
consecutivePauses = 0;
|
|
183
183
|
const allToolCalls = extractToolCalls(response.message.content);
|
|
184
184
|
if (response.stopReason !== "tool_use" && allToolCalls.length === 0) {
|
|
185
|
+
if (options.getSteeringMessages) {
|
|
186
|
+
const steering = await options.getSteeringMessages();
|
|
187
|
+
if (steering && steering.length > 0) {
|
|
188
|
+
for (const msg of steering) {
|
|
189
|
+
yield { type: "steering_message", content: msg.content };
|
|
190
|
+
messages.push(msg);
|
|
191
|
+
}
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
185
195
|
yield {
|
|
186
196
|
type: "agent_done",
|
|
187
197
|
totalTurns: turn,
|
|
@@ -301,6 +311,15 @@ async function* agentLoop(messages, options) {
|
|
|
301
311
|
messages.push({ role: "tool", content: toolResults });
|
|
302
312
|
}
|
|
303
313
|
if (toolsAborted) break;
|
|
314
|
+
if (options.getSteeringMessages) {
|
|
315
|
+
const steering = await options.getSteeringMessages();
|
|
316
|
+
if (steering && steering.length > 0) {
|
|
317
|
+
for (const msg of steering) {
|
|
318
|
+
yield { type: "steering_message", content: msg.content };
|
|
319
|
+
messages.push(msg);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
304
323
|
}
|
|
305
324
|
} finally {
|
|
306
325
|
sanitizeOrphanedServerTools(messages);
|
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 { agentLoop, isAbortError, isContextOverflow, isBillingError } 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 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\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 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 generator = agentLoop(this.messages, this.options);\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 = 100;\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 );\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 consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const MAX_EMPTY_RESPONSE_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n }\n\n // ── Call LLM with overflow recovery ──\n let response;\n try {\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: options.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas\n for await (const event of result) {\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 response = await result.response;\n } catch (err) {\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 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: wait 3s and retry (up to 3 times)\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n await new Promise((r) => setTimeout(r, OVERLOAD_RETRY_DELAY_MS));\n turn--; // Don't count the failed turn\n continue;\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 }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 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, we're done.\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 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 messages.push({ role: \"tool\", content: toolResults });\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\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"],"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 { agentLoop, isAbortError, isContextOverflow, isBillingError } 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 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\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 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 generator = agentLoop(this.messages, this.options);\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 = 100;\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 );\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 consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const MAX_EMPTY_RESPONSE_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n }\n\n // ── Call LLM with overflow recovery ──\n let response;\n try {\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: options.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas\n for await (const event of result) {\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 response = await result.response;\n } catch (err) {\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 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: wait 3s and retry (up to 3 times)\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n await new Promise((r) => setTimeout(r, OVERLOAD_RETRY_DELAY_MS));\n turn--; // Don't count the failed turn\n continue;\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 }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 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 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 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"],"mappings":"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","names":["import_gg_ai"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -69,7 +69,11 @@ interface AgentServerToolResultEvent {
|
|
|
69
69
|
resultType: string;
|
|
70
70
|
data: unknown;
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
interface AgentSteeringMessageEvent {
|
|
73
|
+
type: "steering_message";
|
|
74
|
+
content: Message["content"];
|
|
75
|
+
}
|
|
76
|
+
type AgentEvent = AgentTextDeltaEvent | AgentThinkingDeltaEvent | AgentToolCallStartEvent | AgentToolCallUpdateEvent | AgentToolCallEndEvent | AgentServerToolCallEvent | AgentServerToolResultEvent | AgentSteeringMessageEvent | AgentTurnEndEvent | AgentDoneEvent | AgentErrorEvent;
|
|
73
77
|
interface AgentOptions {
|
|
74
78
|
provider: StreamOptions["provider"];
|
|
75
79
|
model: string;
|
|
@@ -103,6 +107,13 @@ interface AgentOptions {
|
|
|
103
107
|
transformContext?: (messages: Message[], options?: {
|
|
104
108
|
force?: boolean;
|
|
105
109
|
}) => Message[] | Promise<Message[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Polled after tool execution completes each turn. Returns user messages
|
|
112
|
+
* to inject into the conversation before the next LLM call (steering).
|
|
113
|
+
* Return null/empty to inject nothing. Messages are consumed (cleared)
|
|
114
|
+
* on read.
|
|
115
|
+
*/
|
|
116
|
+
getSteeringMessages?: () => Promise<Message[] | null> | Message[] | null;
|
|
106
117
|
}
|
|
107
118
|
interface AgentResult {
|
|
108
119
|
message: AssistantMessage;
|
|
@@ -161,4 +172,4 @@ declare function isContextOverflow(err: unknown): boolean;
|
|
|
161
172
|
declare function isBillingError(err: unknown): boolean;
|
|
162
173
|
declare function agentLoop(messages: Message[], options: AgentOptions): AsyncGenerator<AgentEvent, AgentResult>;
|
|
163
174
|
|
|
164
|
-
export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentOptions, type AgentResult, type AgentServerToolCallEvent, type AgentServerToolResultEvent, AgentStream, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type StructuredToolResult, type ToolContext, type ToolExecuteResult, agentLoop, isAbortError, isBillingError, isContextOverflow };
|
|
175
|
+
export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentOptions, type AgentResult, type AgentServerToolCallEvent, type AgentServerToolResultEvent, type AgentSteeringMessageEvent, AgentStream, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type StructuredToolResult, type ToolContext, type ToolExecuteResult, agentLoop, isAbortError, isBillingError, isContextOverflow };
|
package/dist/index.d.ts
CHANGED
|
@@ -69,7 +69,11 @@ interface AgentServerToolResultEvent {
|
|
|
69
69
|
resultType: string;
|
|
70
70
|
data: unknown;
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
interface AgentSteeringMessageEvent {
|
|
73
|
+
type: "steering_message";
|
|
74
|
+
content: Message["content"];
|
|
75
|
+
}
|
|
76
|
+
type AgentEvent = AgentTextDeltaEvent | AgentThinkingDeltaEvent | AgentToolCallStartEvent | AgentToolCallUpdateEvent | AgentToolCallEndEvent | AgentServerToolCallEvent | AgentServerToolResultEvent | AgentSteeringMessageEvent | AgentTurnEndEvent | AgentDoneEvent | AgentErrorEvent;
|
|
73
77
|
interface AgentOptions {
|
|
74
78
|
provider: StreamOptions["provider"];
|
|
75
79
|
model: string;
|
|
@@ -103,6 +107,13 @@ interface AgentOptions {
|
|
|
103
107
|
transformContext?: (messages: Message[], options?: {
|
|
104
108
|
force?: boolean;
|
|
105
109
|
}) => Message[] | Promise<Message[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Polled after tool execution completes each turn. Returns user messages
|
|
112
|
+
* to inject into the conversation before the next LLM call (steering).
|
|
113
|
+
* Return null/empty to inject nothing. Messages are consumed (cleared)
|
|
114
|
+
* on read.
|
|
115
|
+
*/
|
|
116
|
+
getSteeringMessages?: () => Promise<Message[] | null> | Message[] | null;
|
|
106
117
|
}
|
|
107
118
|
interface AgentResult {
|
|
108
119
|
message: AssistantMessage;
|
|
@@ -161,4 +172,4 @@ declare function isContextOverflow(err: unknown): boolean;
|
|
|
161
172
|
declare function isBillingError(err: unknown): boolean;
|
|
162
173
|
declare function agentLoop(messages: Message[], options: AgentOptions): AsyncGenerator<AgentEvent, AgentResult>;
|
|
163
174
|
|
|
164
|
-
export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentOptions, type AgentResult, type AgentServerToolCallEvent, type AgentServerToolResultEvent, AgentStream, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type StructuredToolResult, type ToolContext, type ToolExecuteResult, agentLoop, isAbortError, isBillingError, isContextOverflow };
|
|
175
|
+
export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentOptions, type AgentResult, type AgentServerToolCallEvent, type AgentServerToolResultEvent, type AgentSteeringMessageEvent, AgentStream, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type StructuredToolResult, type ToolContext, type ToolExecuteResult, agentLoop, isAbortError, isBillingError, isContextOverflow };
|
package/dist/index.js
CHANGED
|
@@ -154,6 +154,16 @@ async function* agentLoop(messages, options) {
|
|
|
154
154
|
consecutivePauses = 0;
|
|
155
155
|
const allToolCalls = extractToolCalls(response.message.content);
|
|
156
156
|
if (response.stopReason !== "tool_use" && allToolCalls.length === 0) {
|
|
157
|
+
if (options.getSteeringMessages) {
|
|
158
|
+
const steering = await options.getSteeringMessages();
|
|
159
|
+
if (steering && steering.length > 0) {
|
|
160
|
+
for (const msg of steering) {
|
|
161
|
+
yield { type: "steering_message", content: msg.content };
|
|
162
|
+
messages.push(msg);
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
157
167
|
yield {
|
|
158
168
|
type: "agent_done",
|
|
159
169
|
totalTurns: turn,
|
|
@@ -273,6 +283,15 @@ async function* agentLoop(messages, options) {
|
|
|
273
283
|
messages.push({ role: "tool", content: toolResults });
|
|
274
284
|
}
|
|
275
285
|
if (toolsAborted) break;
|
|
286
|
+
if (options.getSteeringMessages) {
|
|
287
|
+
const steering = await options.getSteeringMessages();
|
|
288
|
+
if (steering && steering.length > 0) {
|
|
289
|
+
for (const msg of steering) {
|
|
290
|
+
yield { type: "steering_message", content: msg.content };
|
|
291
|
+
messages.push(msg);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
276
295
|
}
|
|
277
296
|
} finally {
|
|
278
297
|
sanitizeOrphanedServerTools(messages);
|
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\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 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 generator = agentLoop(this.messages, this.options);\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 = 100;\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 );\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 consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const MAX_EMPTY_RESPONSE_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n }\n\n // ── Call LLM with overflow recovery ──\n let response;\n try {\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: options.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas\n for await (const event of result) {\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 response = await result.response;\n } catch (err) {\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 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: wait 3s and retry (up to 3 times)\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n await new Promise((r) => setTimeout(r, OVERLOAD_RETRY_DELAY_MS));\n turn--; // Don't count the failed turn\n continue;\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 }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 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, we're done.\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 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 messages.push({ role: \"tool\", content: toolResults });\n }\n\n // Exit loop after cleaning up aborted tools\n if (toolsAborted) break;\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"],"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\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 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 generator = agentLoop(this.messages, this.options);\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 = 100;\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 );\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 consecutivePauses = 0;\n let overflowRetries = 0;\n let overloadRetries = 0;\n let emptyResponseRetries = 0;\n const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const MAX_EMPTY_RESPONSE_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\n try {\n while (turn < maxTurns) {\n options.signal?.throwIfAborted();\n turn++;\n\n // ── Mid-loop context transform (compaction / truncation) ──\n if (options.transformContext) {\n const transformed = await options.transformContext(messages);\n if (transformed !== messages) {\n messages.length = 0;\n messages.push(...transformed);\n }\n }\n\n // ── Call LLM with overflow recovery ──\n let response;\n try {\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: options.signal,\n accountId: options.accountId,\n cacheRetention: options.cacheRetention,\n compaction: options.compaction,\n });\n\n // Suppress unhandled rejection if the iterator path throws first\n result.response.catch(() => {});\n\n // Forward streaming deltas\n for await (const event of result) {\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 response = await result.response;\n } catch (err) {\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 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: wait 3s and retry (up to 3 times)\n if (overloadRetries < MAX_OVERLOAD_RETRIES && isOverloaded(err)) {\n overloadRetries++;\n await new Promise((r) => setTimeout(r, OVERLOAD_RETRY_DELAY_MS));\n turn--; // Don't count the failed turn\n continue;\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 }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 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 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 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"],"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.40",
|
|
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.40"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.9.3",
|