@kenkaiiii/gg-agent 4.2.13 → 4.2.15
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 +14 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
Agent: () => Agent,
|
|
24
24
|
AgentStream: () => AgentStream,
|
|
25
25
|
agentLoop: () => agentLoop,
|
|
26
|
+
isBillingError: () => isBillingError,
|
|
26
27
|
isContextOverflow: () => isContextOverflow
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -38,8 +39,14 @@ function isContextOverflow(err) {
|
|
|
38
39
|
const msg = err.message.toLowerCase();
|
|
39
40
|
return msg.includes("prompt is too long") || msg.includes("context_length_exceeded") || msg.includes("maximum context length") || msg.includes("token") && msg.includes("exceed");
|
|
40
41
|
}
|
|
42
|
+
function isBillingError(err) {
|
|
43
|
+
if (!(err instanceof Error)) return false;
|
|
44
|
+
const msg = err.message.toLowerCase();
|
|
45
|
+
return msg.includes("insufficient balance") || msg.includes("no resource package") || msg.includes("quota exceeded") || msg.includes("billing") || msg.includes("recharge");
|
|
46
|
+
}
|
|
41
47
|
function isOverloaded(err) {
|
|
42
48
|
if (!(err instanceof Error)) return false;
|
|
49
|
+
if (isBillingError(err)) return false;
|
|
43
50
|
const msg = err.message.toLowerCase();
|
|
44
51
|
return msg.includes("overloaded") || msg.includes("rate limit") || msg.includes("too many requests") || msg.includes("429") || msg.includes("529");
|
|
45
52
|
}
|
|
@@ -152,7 +159,8 @@ async function* agentLoop(messages, options) {
|
|
|
152
159
|
continue;
|
|
153
160
|
}
|
|
154
161
|
consecutivePauses = 0;
|
|
155
|
-
|
|
162
|
+
const allToolCalls = extractToolCalls(response.message.content);
|
|
163
|
+
if (response.stopReason !== "tool_use" && allToolCalls.length === 0) {
|
|
156
164
|
yield {
|
|
157
165
|
type: "agent_done",
|
|
158
166
|
totalTurns: turn,
|
|
@@ -164,7 +172,6 @@ async function* agentLoop(messages, options) {
|
|
|
164
172
|
totalUsage: { ...totalUsage }
|
|
165
173
|
};
|
|
166
174
|
}
|
|
167
|
-
const allToolCalls = extractToolCalls(response.message.content);
|
|
168
175
|
const toolCalls = [];
|
|
169
176
|
const toolResults = [];
|
|
170
177
|
for (const tc of allToolCalls) {
|
|
@@ -233,8 +240,9 @@ async function* agentLoop(messages, options) {
|
|
|
233
240
|
let toolResultsFinalized = false;
|
|
234
241
|
Promise.all(executions).then((results) => {
|
|
235
242
|
if (toolResultsFinalized) return;
|
|
243
|
+
const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));
|
|
236
244
|
for (const tc of toolCalls) {
|
|
237
|
-
const r =
|
|
245
|
+
const r = resultsMap.get(tc.id);
|
|
238
246
|
toolResults.push({
|
|
239
247
|
type: "tool_result",
|
|
240
248
|
toolCallId: tc.id,
|
|
@@ -251,8 +259,9 @@ async function* agentLoop(messages, options) {
|
|
|
251
259
|
} finally {
|
|
252
260
|
options.signal?.removeEventListener("abort", abortHandler);
|
|
253
261
|
toolResultsFinalized = true;
|
|
262
|
+
const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));
|
|
254
263
|
for (const tc of toolCalls) {
|
|
255
|
-
if (!
|
|
264
|
+
if (!resolvedIds.has(tc.id)) {
|
|
256
265
|
toolResults.push({
|
|
257
266
|
type: "tool_result",
|
|
258
267
|
toolCallId: tc.id,
|
|
@@ -368,6 +377,7 @@ var Agent = class {
|
|
|
368
377
|
Agent,
|
|
369
378
|
AgentStream,
|
|
370
379
|
agentLoop,
|
|
380
|
+
isBillingError,
|
|
371
381
|
isContextOverflow
|
|
372
382
|
});
|
|
373
383
|
//# sourceMappingURL=index.cjs.map
|
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, isContextOverflow } 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 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 overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n */\nexport function isOverloaded(err: unknown): boolean {\n if (!(err instanceof Error)) 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 const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\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 throw err;\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 // If not tool_use, we're done\n if (response.stopReason !== \"tool_use\") {\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\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\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 for (const tc of toolCalls) {\n const r = results.find((x) => x.toolCallId === 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 try {\n for await (const event of eventStream) {\n yield event;\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 for (const tc of toolCalls) {\n if (!toolResults.some((r) => r.toolCallId === 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\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"],"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, 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 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 const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\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 throw err;\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 try {\n for await (const event of eventStream) {\n yield event;\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\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"],"mappings":"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","names":["import_gg_ai"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -149,6 +149,11 @@ declare class Agent {
|
|
|
149
149
|
* OpenAI: "context_length_exceeded" / "maximum context length"
|
|
150
150
|
*/
|
|
151
151
|
declare function isContextOverflow(err: unknown): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Detect billing/quota errors — these should NOT be retried.
|
|
154
|
+
* GLM returns HTTP 429 with "Insufficient balance" for quota exhaustion.
|
|
155
|
+
*/
|
|
156
|
+
declare function isBillingError(err: unknown): boolean;
|
|
152
157
|
declare function agentLoop(messages: Message[], options: AgentOptions): AsyncGenerator<AgentEvent, AgentResult>;
|
|
153
158
|
|
|
154
|
-
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, isContextOverflow };
|
|
159
|
+
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, isBillingError, isContextOverflow };
|
package/dist/index.d.ts
CHANGED
|
@@ -149,6 +149,11 @@ declare class Agent {
|
|
|
149
149
|
* OpenAI: "context_length_exceeded" / "maximum context length"
|
|
150
150
|
*/
|
|
151
151
|
declare function isContextOverflow(err: unknown): boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Detect billing/quota errors — these should NOT be retried.
|
|
154
|
+
* GLM returns HTTP 429 with "Insufficient balance" for quota exhaustion.
|
|
155
|
+
*/
|
|
156
|
+
declare function isBillingError(err: unknown): boolean;
|
|
152
157
|
declare function agentLoop(messages: Message[], options: AgentOptions): AsyncGenerator<AgentEvent, AgentResult>;
|
|
153
158
|
|
|
154
|
-
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, isContextOverflow };
|
|
159
|
+
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, isBillingError, isContextOverflow };
|
package/dist/index.js
CHANGED
|
@@ -12,8 +12,14 @@ function isContextOverflow(err) {
|
|
|
12
12
|
const msg = err.message.toLowerCase();
|
|
13
13
|
return msg.includes("prompt is too long") || msg.includes("context_length_exceeded") || msg.includes("maximum context length") || msg.includes("token") && msg.includes("exceed");
|
|
14
14
|
}
|
|
15
|
+
function isBillingError(err) {
|
|
16
|
+
if (!(err instanceof Error)) return false;
|
|
17
|
+
const msg = err.message.toLowerCase();
|
|
18
|
+
return msg.includes("insufficient balance") || msg.includes("no resource package") || msg.includes("quota exceeded") || msg.includes("billing") || msg.includes("recharge");
|
|
19
|
+
}
|
|
15
20
|
function isOverloaded(err) {
|
|
16
21
|
if (!(err instanceof Error)) return false;
|
|
22
|
+
if (isBillingError(err)) return false;
|
|
17
23
|
const msg = err.message.toLowerCase();
|
|
18
24
|
return msg.includes("overloaded") || msg.includes("rate limit") || msg.includes("too many requests") || msg.includes("429") || msg.includes("529");
|
|
19
25
|
}
|
|
@@ -126,7 +132,8 @@ async function* agentLoop(messages, options) {
|
|
|
126
132
|
continue;
|
|
127
133
|
}
|
|
128
134
|
consecutivePauses = 0;
|
|
129
|
-
|
|
135
|
+
const allToolCalls = extractToolCalls(response.message.content);
|
|
136
|
+
if (response.stopReason !== "tool_use" && allToolCalls.length === 0) {
|
|
130
137
|
yield {
|
|
131
138
|
type: "agent_done",
|
|
132
139
|
totalTurns: turn,
|
|
@@ -138,7 +145,6 @@ async function* agentLoop(messages, options) {
|
|
|
138
145
|
totalUsage: { ...totalUsage }
|
|
139
146
|
};
|
|
140
147
|
}
|
|
141
|
-
const allToolCalls = extractToolCalls(response.message.content);
|
|
142
148
|
const toolCalls = [];
|
|
143
149
|
const toolResults = [];
|
|
144
150
|
for (const tc of allToolCalls) {
|
|
@@ -207,8 +213,9 @@ async function* agentLoop(messages, options) {
|
|
|
207
213
|
let toolResultsFinalized = false;
|
|
208
214
|
Promise.all(executions).then((results) => {
|
|
209
215
|
if (toolResultsFinalized) return;
|
|
216
|
+
const resultsMap = new Map(results.map((r) => [r.toolCallId, r]));
|
|
210
217
|
for (const tc of toolCalls) {
|
|
211
|
-
const r =
|
|
218
|
+
const r = resultsMap.get(tc.id);
|
|
212
219
|
toolResults.push({
|
|
213
220
|
type: "tool_result",
|
|
214
221
|
toolCallId: tc.id,
|
|
@@ -225,8 +232,9 @@ async function* agentLoop(messages, options) {
|
|
|
225
232
|
} finally {
|
|
226
233
|
options.signal?.removeEventListener("abort", abortHandler);
|
|
227
234
|
toolResultsFinalized = true;
|
|
235
|
+
const resolvedIds = new Set(toolResults.map((r) => r.toolCallId));
|
|
228
236
|
for (const tc of toolCalls) {
|
|
229
|
-
if (!
|
|
237
|
+
if (!resolvedIds.has(tc.id)) {
|
|
230
238
|
toolResults.push({
|
|
231
239
|
type: "tool_result",
|
|
232
240
|
toolCallId: tc.id,
|
|
@@ -341,6 +349,7 @@ export {
|
|
|
341
349
|
Agent,
|
|
342
350
|
AgentStream,
|
|
343
351
|
agentLoop,
|
|
352
|
+
isBillingError,
|
|
344
353
|
isContextOverflow
|
|
345
354
|
};
|
|
346
355
|
//# sourceMappingURL=index.js.map
|
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 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 overloaded/rate-limit errors from LLM providers.\n * HTTP 429 (rate limit) or 529/503 (overloaded).\n */\nexport function isOverloaded(err: unknown): boolean {\n if (!(err instanceof Error)) 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 const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\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 throw err;\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 // If not tool_use, we're done\n if (response.stopReason !== \"tool_use\") {\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\n // Extract tool calls — separate client-executed from provider built-in (e.g. Moonshot $web_search)\n const allToolCalls = extractToolCalls(response.message.content);\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 for (const tc of toolCalls) {\n const r = results.find((x) => x.toolCallId === 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 try {\n for await (const event of eventStream) {\n yield event;\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 for (const tc of toolCalls) {\n if (!toolResults.some((r) => r.toolCallId === 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\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"],"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 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 const MAX_OVERFLOW_RETRIES = 3;\n const MAX_OVERLOAD_RETRIES = 3;\n const OVERLOAD_RETRY_DELAY_MS = 3_000;\n\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 throw err;\n }\n\n // Reset retry counters after successful call\n overflowRetries = 0;\n overloadRetries = 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 try {\n for await (const event of eventStream) {\n yield event;\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\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"],"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.15",
|
|
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.15"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.9.3",
|