@caupulican/pi-agent-core 0.81.39 → 0.81.41
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/README.md +10 -5
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +77 -89
- package/dist/agent-loop.js.map +1 -1
- package/dist/compaction/branch-summarization.d.ts +4 -2
- package/dist/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/compaction/branch-summarization.js +4 -0
- package/dist/compaction/branch-summarization.js.map +1 -1
- package/dist/compaction/compaction.d.ts +32 -1
- package/dist/compaction/compaction.d.ts.map +1 -1
- package/dist/compaction/compaction.js +172 -101
- package/dist/compaction/compaction.js.map +1 -1
- package/dist/compaction/extraction.d.ts.map +1 -1
- package/dist/compaction/extraction.js +1 -1
- package/dist/compaction/extraction.js.map +1 -1
- package/dist/compaction/loop.d.ts +1 -1
- package/dist/compaction/loop.d.ts.map +1 -1
- package/dist/compaction/loop.js +24 -7
- package/dist/compaction/loop.js.map +1 -1
- package/dist/compaction/utils.d.ts.map +1 -1
- package/dist/compaction/utils.js +3 -1
- package/dist/compaction/utils.js.map +1 -1
- package/dist/compaction/verification.d.ts +11 -0
- package/dist/compaction/verification.d.ts.map +1 -1
- package/dist/compaction/verification.js +93 -11
- package/dist/compaction/verification.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +1 -1
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +1 -0
- package/dist/proxy.js.map +1 -1
- package/dist/reliability/classifier.d.ts.map +1 -1
- package/dist/reliability/classifier.js +3 -3
- package/dist/reliability/classifier.js.map +1 -1
- package/dist/session/session-manager.d.ts +18 -6
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manager.js +68 -61
- package/dist/session/session-manager.js.map +1 -1
- package/dist/tool-failure-memory.d.ts +35 -0
- package/dist/tool-failure-memory.d.ts.map +1 -0
- package/dist/tool-failure-memory.js +290 -0
- package/dist/tool-failure-memory.js.map +1 -0
- package/dist/types.d.ts +5 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/usage.d.ts +5 -0
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +32 -0
- package/dist/usage.js.map +1 -1
- package/dist/uuid.d.ts +1 -1
- package/dist/uuid.d.ts.map +1 -1
- package/dist/uuid.js +1 -49
- package/dist/uuid.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAC3B,iBAAiB;AACjB,cAAc,iBAAiB,CAAC;AAChC,yCAAyC;AACzC,cAAc,eAAe,CAAC;AAC9B,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,qBAAqB;AACrB,cAAc,wBAAwB,CAAC;AACvC,mCAAmC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,QAAQ;AACR,cAAc,YAAY,CAAC;AAC3B,yBAAyB;AACzB,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC","sourcesContent":["// Core Agent\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\n// Custom message types + LLM transformer\nexport * from \"./messages.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\n// Reliability kernel\nexport * from \"./reliability/index.ts\";\n// Session message retention (pure)\nexport * from \"./session/message-retention.ts\";\n// Types\nexport * from \"./types.ts\";\n// Shell output utilities\nexport * from \"./utils/shell-output.ts\";\nexport { uuidv7 } from \"./uuid.ts\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,YAAY,CAAC;AAC3B,iBAAiB;AACjB,cAAc,iBAAiB,CAAC;AAChC,yCAAyC;AACzC,cAAc,eAAe,CAAC;AAC9B,kBAAkB;AAClB,cAAc,YAAY,CAAC;AAC3B,qBAAqB;AACrB,cAAc,wBAAwB,CAAC;AACvC,mCAAmC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,qDAAqD;AACrD,cAAc,0BAA0B,CAAC;AACzC,QAAQ;AACR,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,yBAAyB;AACzB,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC","sourcesContent":["// Core Agent\nexport * from \"./agent.ts\";\n// Loop functions\nexport * from \"./agent-loop.ts\";\n// Custom message types + LLM transformer\nexport * from \"./messages.ts\";\n// Proxy utilities\nexport * from \"./proxy.ts\";\n// Reliability kernel\nexport * from \"./reliability/index.ts\";\n// Session message retention (pure)\nexport * from \"./session/message-retention.ts\";\n// Provider-neutral failed tool-call context boundary\nexport * from \"./tool-failure-memory.ts\";\n// Types\nexport * from \"./types.ts\";\nexport * from \"./usage.ts\";\n// Shell output utilities\nexport * from \"./utils/shell-output.ts\";\nexport { uuidv7 } from \"./uuid.ts\";\n"]}
|
package/dist/proxy.d.ts
CHANGED
|
@@ -55,7 +55,7 @@ export type ProxyAssistantMessageEvent = {
|
|
|
55
55
|
errorMessage?: string;
|
|
56
56
|
usage: AssistantMessage["usage"];
|
|
57
57
|
};
|
|
58
|
-
type ProxySerializableStreamOptions = Pick<SimpleStreamOptions, "temperature" | "maxTokens" | "reasoning" | "cacheRetention" | "sessionId" | "headers" | "metadata" | "transport" | "thinkingBudgets" | "maxRetryDelayMs">;
|
|
58
|
+
type ProxySerializableStreamOptions = Pick<SimpleStreamOptions, "temperature" | "maxTokens" | "interactionMode" | "reasoning" | "cacheRetention" | "sessionId" | "headers" | "metadata" | "transport" | "thinkingBudgets" | "maxRetryDelayMs">;
|
|
59
59
|
export interface ProxyStreamOptions extends ProxySerializableStreamOptions {
|
|
60
60
|
/** Local abort signal for the proxy request */
|
|
61
61
|
signal?: AbortSignal;
|
package/dist/proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,WAAW,EACX,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,KAAK,UAAU,EAEf,MAAM,mBAAmB,CAAC;AAI3B,cAAM,uBAAwB,SAAQ,WAAW,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;IACzF,cASC;CACD;AAED;;GAEG;AACH,MAAM,MAAM,0BAA0B,GACnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC9C;IACA,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAC3D,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,CAAC;AAEL,KAAK,8BAA8B,GAAG,IAAI,CACzC,mBAAmB,EACjB,aAAa,GACb,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,iBAAiB,CACnB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,8BAA8B;IACzE,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAoCD,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,GAAG,uBAAuB,CAgJrH","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@caupulican/pi-ai\";\nimport { StreamingLineDecoder } from \"./utils/streaming-lines.ts\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"maxTokens\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tmaxTokens: options.maxTokens,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"stop\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\t\tlet terminalPushed = false;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tconst lines = new StreamingLineDecoder(64 * 1024 * 1024);\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tfor (const line of lines.push(decoder.decode(value, { stream: true }))) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const line of lines.push(decoder.decode())) {\n\t\t\t\tif (!line.startsWith(\"data: \")) continue;\n\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\tif (!data) continue;\n\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\tif (event) {\n\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\tstream.push(event);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst finalLine = lines.finish();\n\t\t\tif (finalLine?.startsWith(\"data: \")) {\n\t\t\t\tconst data = finalLine.slice(6).trim();\n\t\t\t\tif (data) {\n\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\tif (event) {\n\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tif (!terminalPushed) {\n\t\t\t\tpartial.stopReason = \"error\";\n\t\t\t\tpartial.errorMessage = \"stream ended before terminal event\";\n\t\t\t\tstream.push({ type: \"error\", reason: \"error\", error: partial });\n\t\t\t}\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,OAAO,EACZ,WAAW,EACX,KAAK,KAAK,EAEV,KAAK,mBAAmB,EACxB,KAAK,UAAU,EAEf,MAAM,mBAAmB,CAAC;AAI3B,cAAM,uBAAwB,SAAQ,WAAW,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;IACzF,cASC;CACD;AAED;;GAEG;AACH,MAAM,MAAM,0BAA0B,GACnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC9C;IACA,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAC3D,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,GACD;IACA,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAChC,CAAC;AAEL,KAAK,8BAA8B,GAAG,IAAI,CACzC,mBAAmB,EACjB,aAAa,GACb,WAAW,GACX,iBAAiB,GACjB,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,SAAS,GACT,UAAU,GACV,WAAW,GACX,iBAAiB,GACjB,iBAAiB,CACnB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,8BAA8B;IACzE,+CAA+C;IAC/C,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAqCD,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,GAAG,uBAAuB,CAgJrH","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@caupulican/pi-ai\";\nimport { StreamingLineDecoder } from \"./utils/streaming-lines.ts\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"maxTokens\"\n\t| \"interactionMode\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tmaxTokens: options.maxTokens,\n\t\tinteractionMode: options.interactionMode,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"stop\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\t\tlet terminalPushed = false;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tconst lines = new StreamingLineDecoder(64 * 1024 * 1024);\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tfor (const line of lines.push(decoder.decode(value, { stream: true }))) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const line of lines.push(decoder.decode())) {\n\t\t\t\tif (!line.startsWith(\"data: \")) continue;\n\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\tif (!data) continue;\n\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\tif (event) {\n\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\tstream.push(event);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst finalLine = lines.finish();\n\t\t\tif (finalLine?.startsWith(\"data: \")) {\n\t\t\t\tconst data = finalLine.slice(6).trim();\n\t\t\t\tif (data) {\n\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\tif (event) {\n\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tif (!terminalPushed) {\n\t\t\t\tpartial.stopReason = \"error\";\n\t\t\t\tpartial.errorMessage = \"stream ended before terminal event\";\n\t\t\t\tstream.push({ type: \"error\", reason: \"error\", error: partial });\n\t\t\t}\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
package/dist/proxy.js
CHANGED
|
@@ -40,6 +40,7 @@ function buildProxyRequestOptions(options) {
|
|
|
40
40
|
return {
|
|
41
41
|
temperature: options.temperature,
|
|
42
42
|
maxTokens: options.maxTokens,
|
|
43
|
+
interactionMode: options.interactionMode,
|
|
43
44
|
reasoning: options.reasoning,
|
|
44
45
|
cacheRetention: options.cacheRetention,
|
|
45
46
|
sessionId: options.sessionId,
|
package/dist/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@caupulican/pi-ai\";\nimport { StreamingLineDecoder } from \"./utils/streaming-lines.ts\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"maxTokens\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tmaxTokens: options.maxTokens,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"stop\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\t\tlet terminalPushed = false;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tconst lines = new StreamingLineDecoder(64 * 1024 * 1024);\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tfor (const line of lines.push(decoder.decode(value, { stream: true }))) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const line of lines.push(decoder.decode())) {\n\t\t\t\tif (!line.startsWith(\"data: \")) continue;\n\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\tif (!data) continue;\n\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\tif (event) {\n\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\tstream.push(event);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst finalLine = lines.finish();\n\t\t\tif (finalLine?.startsWith(\"data: \")) {\n\t\t\t\tconst data = finalLine.slice(6).trim();\n\t\t\t\tif (data) {\n\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\tif (event) {\n\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tif (!terminalPushed) {\n\t\t\t\tpartial.stopReason = \"error\";\n\t\t\t\tpartial.errorMessage = \"stream ended before terminal event\";\n\t\t\t\tstream.push({ type: \"error\", reason: \"error\", error: partial });\n\t\t\t}\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../src/proxy.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Proxy stream function for apps that route LLM calls through a server.\n * The server manages auth and proxies requests to LLM providers.\n */\n\n// Internal import for JSON parsing utility\nimport {\n\ttype AssistantMessage,\n\ttype AssistantMessageEvent,\n\ttype Context,\n\tEventStream,\n\ttype Model,\n\tparseStreamingJson,\n\ttype SimpleStreamOptions,\n\ttype StopReason,\n\ttype ToolCall,\n} from \"@caupulican/pi-ai\";\nimport { StreamingLineDecoder } from \"./utils/streaming-lines.ts\";\n\n// Create stream class matching ProxyMessageEventStream\nclass ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {\n\tconstructor() {\n\t\tsuper(\n\t\t\t(event) => event.type === \"done\" || event.type === \"error\",\n\t\t\t(event) => {\n\t\t\t\tif (event.type === \"done\") return event.message;\n\t\t\t\tif (event.type === \"error\") return event.error;\n\t\t\t\tthrow new Error(\"Unexpected event type\");\n\t\t\t},\n\t\t);\n\t}\n}\n\n/**\n * Proxy event types - server sends these with partial field stripped to reduce bandwidth.\n */\nexport type ProxyAssistantMessageEvent =\n\t| { type: \"start\" }\n\t| { type: \"text_start\"; contentIndex: number }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| { type: \"thinking_end\"; contentIndex: number; contentSignature?: string }\n\t| { type: \"toolcall_start\"; contentIndex: number; id: string; toolName: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| { type: \"toolcall_end\"; contentIndex: number }\n\t| {\n\t\t\ttype: \"done\";\n\t\t\treason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t }\n\t| {\n\t\t\ttype: \"error\";\n\t\t\treason: Extract<StopReason, \"aborted\" | \"error\">;\n\t\t\terrorMessage?: string;\n\t\t\tusage: AssistantMessage[\"usage\"];\n\t };\n\ntype ProxySerializableStreamOptions = Pick<\n\tSimpleStreamOptions,\n\t| \"temperature\"\n\t| \"maxTokens\"\n\t| \"interactionMode\"\n\t| \"reasoning\"\n\t| \"cacheRetention\"\n\t| \"sessionId\"\n\t| \"headers\"\n\t| \"metadata\"\n\t| \"transport\"\n\t| \"thinkingBudgets\"\n\t| \"maxRetryDelayMs\"\n>;\n\nexport interface ProxyStreamOptions extends ProxySerializableStreamOptions {\n\t/** Local abort signal for the proxy request */\n\tsignal?: AbortSignal;\n\t/** Auth token for the proxy server */\n\tauthToken: string;\n\t/** Proxy server URL (e.g., \"https://genai.example.com\") */\n\tproxyUrl: string;\n}\n\n/**\n * Stream function that proxies through a server instead of calling LLM providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n *\n * Use this as the `streamFn` option when creating an Agent that needs to go through a proxy.\n *\n * @example\n * ```typescript\n * const agent = new Agent({\n * streamFn: (model, context, options) =>\n * streamProxy(model, context, {\n * ...options,\n * authToken: await getAuthToken(),\n * proxyUrl: \"https://genai.example.com\",\n * }),\n * });\n * ```\n */\nfunction buildProxyRequestOptions(options: ProxyStreamOptions): ProxySerializableStreamOptions {\n\treturn {\n\t\ttemperature: options.temperature,\n\t\tmaxTokens: options.maxTokens,\n\t\tinteractionMode: options.interactionMode,\n\t\treasoning: options.reasoning,\n\t\tcacheRetention: options.cacheRetention,\n\t\tsessionId: options.sessionId,\n\t\theaders: options.headers,\n\t\tmetadata: options.metadata,\n\t\ttransport: options.transport,\n\t\tthinkingBudgets: options.thinkingBudgets,\n\t\tmaxRetryDelayMs: options.maxRetryDelayMs,\n\t};\n}\n\nexport function streamProxy(model: Model<any>, context: Context, options: ProxyStreamOptions): ProxyMessageEventStream {\n\tconst stream = new ProxyMessageEventStream();\n\n\t(async () => {\n\t\t// Initialize the partial message that we'll build up from events\n\t\tconst partial: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tstopReason: \"stop\",\n\t\t\tcontent: [],\n\t\t\tapi: model.api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tlet reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n\t\tlet terminalPushed = false;\n\n\t\tconst abortHandler = () => {\n\t\t\tif (reader) {\n\t\t\t\treader.cancel(\"Request aborted by user\").catch(() => {});\n\t\t\t}\n\t\t};\n\n\t\tif (options.signal) {\n\t\t\toptions.signal.addEventListener(\"abort\", abortHandler);\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await fetch(`${options.proxyUrl}/api/stream`, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${options.authToken}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({\n\t\t\t\t\tmodel,\n\t\t\t\t\tcontext,\n\t\t\t\t\toptions: buildProxyRequestOptions(options),\n\t\t\t\t}),\n\t\t\t\tsignal: options.signal,\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tlet errorMessage = `Proxy error: ${response.status} ${response.statusText}`;\n\t\t\t\ttry {\n\t\t\t\t\tconst errorData = (await response.json()) as { error?: string };\n\t\t\t\t\tif (errorData.error) {\n\t\t\t\t\t\terrorMessage = `Proxy error: ${errorData.error}`;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Couldn't parse error response\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tconst lines = new StreamingLineDecoder(64 * 1024 * 1024);\n\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) break;\n\n\t\t\t\tif (options.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t\t}\n\n\t\t\t\tfor (const line of lines.push(decoder.decode(value, { stream: true }))) {\n\t\t\t\t\tif (line.startsWith(\"data: \")) {\n\t\t\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\t\t\tif (data) {\n\t\t\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const line of lines.push(decoder.decode())) {\n\t\t\t\tif (!line.startsWith(\"data: \")) continue;\n\t\t\t\tconst data = line.slice(6).trim();\n\t\t\t\tif (!data) continue;\n\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\tif (event) {\n\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\tstream.push(event);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst finalLine = lines.finish();\n\t\t\tif (finalLine?.startsWith(\"data: \")) {\n\t\t\t\tconst data = finalLine.slice(6).trim();\n\t\t\t\tif (data) {\n\t\t\t\t\tconst proxyEvent = JSON.parse(data) as ProxyAssistantMessageEvent;\n\t\t\t\t\tconst event = processProxyEvent(proxyEvent, partial);\n\t\t\t\t\tif (event) {\n\t\t\t\t\t\tif (event.type === \"done\" || event.type === \"error\") terminalPushed = true;\n\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request aborted by user\");\n\t\t\t}\n\n\t\t\tif (!terminalPushed) {\n\t\t\t\tpartial.stopReason = \"error\";\n\t\t\t\tpartial.errorMessage = \"stream ended before terminal event\";\n\t\t\t\tstream.push({ type: \"error\", reason: \"error\", error: partial });\n\t\t\t}\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tconst reason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.stopReason = reason;\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason,\n\t\t\t\terror: partial,\n\t\t\t});\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\tif (options.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", abortHandler);\n\t\t\t}\n\t\t}\n\t})();\n\n\treturn stream;\n}\n\n/**\n * Process a proxy event and update the partial message.\n */\nfunction processProxyEvent(\n\tproxyEvent: ProxyAssistantMessageEvent,\n\tpartial: AssistantMessage,\n): AssistantMessageEvent | undefined {\n\tswitch (proxyEvent.type) {\n\t\tcase \"start\":\n\t\t\treturn { type: \"start\", partial };\n\n\t\tcase \"text_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"text\", text: \"\" };\n\t\t\treturn { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"text_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t}\n\n\t\tcase \"text_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"text\") {\n\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.text,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t}\n\n\t\tcase \"thinking_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = { type: \"thinking\", thinking: \"\" };\n\t\t\treturn { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"thinking_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t}\n\n\t\tcase \"thinking_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t}\n\n\t\tcase \"toolcall_start\":\n\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\ttype: \"toolCall\",\n\t\t\t\tid: proxyEvent.id,\n\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\targuments: {},\n\t\t\t\tpartialJson: \"\",\n\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\treturn { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\n\t\tcase \"toolcall_delta\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t}\n\n\t\tcase \"toolcall_end\": {\n\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\ttoolCall: content,\n\t\t\t\t\tpartial,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\n\t\tcase \"done\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"done\", reason: proxyEvent.reason, message: partial };\n\n\t\tcase \"error\":\n\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\treturn { type: \"error\", reason: proxyEvent.reason, error: partial };\n\n\t\tdefault: {\n\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\tconsole.warn(`Unhandled proxy event type: ${(proxyEvent as any).type}`);\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../src/reliability/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,MAAM,aAAa,GACtB,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,SAAS,GACT,cAAc,GACd,kBAAkB,GAClB,MAAM,GACN,kBAAkB,GAClB,SAAS,GACT,SAAS,CAAC;AAEb,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,sBAAsB,EAAE,OAAO,CAAC;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;
|
|
1
|
+
{"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../src/reliability/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,MAAM,aAAa,GACtB,YAAY,GACZ,YAAY,GACZ,cAAc,GACd,SAAS,GACT,cAAc,GACd,kBAAkB,GAClB,MAAM,GACN,kBAAkB,GAClB,SAAS,GACT,SAAS,CAAC;AAEb,MAAM,WAAW,eAAe;IAC/B,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,sBAAsB,EAAE,OAAO,CAAC;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,gGAAgG;IAChG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAyBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,eAAe,CAuD5E","sourcesContent":["/**\n * Pure provider-failure classifier.\n *\n * One classification produces four independent action booleans (hermes-derived design):\n * the retry loop, compaction, credential rotation, and provider failover each read their\n * own flag, so one pipeline can route a 429 to rotation, an overflow to compaction, and a\n * billing error to failover without re-parsing error text at each site.\n *\n * Pattern sources: AgentSession._isRetryableError / _isNonRetryableProviderLimitError\n * (the live, battle-tested regexes), split by reason so each maps to distinct actions.\n * Detection of context overflow stays in @caupulican/pi-ai (needs model state); hosts pass\n * `contextOverflow` in.\n */\n\nimport { PROVIDER_FAILURE_SIGNATURES } from \"./provider-signatures.ts\";\n\nexport type FailureReason =\n\t| \"overloaded\"\n\t| \"rate_limit\"\n\t| \"server_error\"\n\t| \"network\"\n\t| \"stream_stall\"\n\t| \"context_overflow\"\n\t| \"auth\"\n\t| \"billing_or_quota\"\n\t| \"aborted\"\n\t| \"unknown\";\n\nexport interface ClassifiedError {\n\treason: FailureReason;\n\tretryable: boolean;\n\tshouldCompact: boolean;\n\tshouldRotateCredential: boolean;\n\tshouldFallback: boolean;\n\t/** Provider-suggested delay parsed from the message, capped by the retry policy at use site. */\n\tretryAfterMs?: number;\n\tmessage: string;\n}\n\nexport interface ClassifyFailureInput {\n\tmessage: string;\n\t/** Host-computed via pi-ai isContextOverflow(message, contextWindow). */\n\tcontextOverflow?: boolean;\n\t/** True when the failure came from an intentional abort (stopReason \"aborted\"). */\n\taborted?: boolean;\n\t/** Provider id; provider-specific signatures are checked before generic patterns. */\n\tprovider?: string;\n}\n\nconst BILLING_OR_QUOTA =\n\t/GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing|usage.?limit(?:s)?\\s*(?:reached|exceeded|hit)|usage_limit_reached|hit your usage limit|hit your ChatGPT usage limit/i;\nconst AUTH = /\\b401\\b|unauthorized|invalid.?api.?key|authentication.?error|forbidden|permission.?denied/i;\nconst RATE_LIMIT = /rate.?limit|too many requests|(?<![A-Za-z0-9])429(?![A-Za-z0-9])/i;\nconst OVERLOADED = /overloaded/i;\nconst STREAM_STALL =\n\t/stream stalled|ended without|stream ended before message_stop|stream ended before a terminal response event|reset before headers/i;\nconst SERVER_ERROR =\n\t/(?<![A-Za-z0-9])(?:500|502|503|504)(?![A-Za-z0-9])|service.?unavailable|server.?error|internal.?error|provider.?returned.?error|upstream.?connect|http2 request did not get a response|ResourceExhausted|retry delay|you can retry your request|try your request again|please retry your request/i;\nconst NETWORK =\n\t/network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|getaddrinfo|ENOTFOUND|EAI_AGAIN|socket hang up|socket connection was closed|timed? out|timeout|terminated/i;\n\nconst RETRY_AFTER_S = /retry.?(?:after|in)\\s+(\\d+(?:\\.\\d+)?)\\s*s\\b|\"retryDelay\"\\s*:\\s*\"(\\d+(?:\\.\\d+)?)s\"/i;\nconst RETRY_AFTER_MS = /retry.?(?:after|in)\\s+(\\d+)\\s*ms\\b/i;\n\nfunction parseRetryAfterMs(message: string): number | undefined {\n\tconst ms = RETRY_AFTER_MS.exec(message);\n\tif (ms) return Number(ms[1]);\n\tconst s = RETRY_AFTER_S.exec(message);\n\tif (s) return Math.round(Number(s[1] ?? s[2]) * 1000);\n\treturn undefined;\n}\n\nexport function classifyFailure(input: ClassifyFailureInput): ClassifiedError {\n\tconst message = input.message;\n\tconst retryAfterMs = parseRetryAfterMs(message);\n\n\tconst base = {\n\t\tretryable: false,\n\t\tshouldCompact: false,\n\t\tshouldRotateCredential: false,\n\t\tshouldFallback: false,\n\t\tmessage,\n\t};\n\n\tconst withRetry = <T extends { reason: FailureReason }>(obj: T): T | (T & { retryAfterMs: number }) =>\n\t\tretryAfterMs !== undefined ? { ...obj, retryAfterMs } : obj;\n\n\tif (input.aborted) return withRetry({ ...base, reason: \"aborted\" });\n\tif (input.contextOverflow) return withRetry({ ...base, reason: \"context_overflow\", shouldCompact: true });\n\tconst providerSignatures = input.provider ? (PROVIDER_FAILURE_SIGNATURES[input.provider] ?? []) : [];\n\tfor (const signature of providerSignatures) {\n\t\tif (signature.pattern.test(message)) {\n\t\t\treturn withRetry({\n\t\t\t\t...base,\n\t\t\t\treason: signature.reason,\n\t\t\t\tshouldFallback: signature.reason === \"billing_or_quota\" || signature.reason === \"auth\",\n\t\t\t\tshouldRotateCredential: signature.reason === \"auth\",\n\t\t\t\tretryable:\n\t\t\t\t\tsignature.reason === \"rate_limit\" ||\n\t\t\t\t\tsignature.reason === \"overloaded\" ||\n\t\t\t\t\tsignature.reason === \"server_error\" ||\n\t\t\t\t\tsignature.reason === \"network\" ||\n\t\t\t\t\tsignature.reason === \"stream_stall\",\n\t\t\t});\n\t\t}\n\t}\n\tif (BILLING_OR_QUOTA.test(message)) return withRetry({ ...base, reason: \"billing_or_quota\", shouldFallback: true });\n\tif (AUTH.test(message))\n\t\treturn withRetry({ ...base, reason: \"auth\", shouldRotateCredential: true, shouldFallback: true });\n\n\tconst isRateLimit = RATE_LIMIT.test(message);\n\tif (isRateLimit || OVERLOADED.test(message)) {\n\t\treturn withRetry({\n\t\t\t...base,\n\t\t\treason: isRateLimit ? \"rate_limit\" : \"overloaded\",\n\t\t\tretryable: true,\n\t\t\tshouldRotateCredential: true,\n\t\t\tshouldFallback: true,\n\t\t});\n\t}\n\tif (STREAM_STALL.test(message))\n\t\treturn withRetry({ ...base, reason: \"stream_stall\", retryable: true, shouldFallback: true });\n\tif (SERVER_ERROR.test(message))\n\t\treturn withRetry({ ...base, reason: \"server_error\", retryable: true, shouldFallback: true });\n\tif (NETWORK.test(message)) return withRetry({ ...base, reason: \"network\", retryable: true, shouldFallback: true });\n\n\treturn withRetry({ ...base, reason: \"unknown\" });\n}\n"]}
|
|
@@ -16,9 +16,9 @@ const BILLING_OR_QUOTA = /GoUsageLimitError|FreeUsageLimitError|Monthly usage li
|
|
|
16
16
|
const AUTH = /\b401\b|unauthorized|invalid.?api.?key|authentication.?error|forbidden|permission.?denied/i;
|
|
17
17
|
const RATE_LIMIT = /rate.?limit|too many requests|(?<![A-Za-z0-9])429(?![A-Za-z0-9])/i;
|
|
18
18
|
const OVERLOADED = /overloaded/i;
|
|
19
|
-
const STREAM_STALL = /stream stalled|ended without|stream ended before message_stop|reset before headers/i;
|
|
20
|
-
const SERVER_ERROR = /(?<![A-Za-z0-9])(?:500|502|503|504)(?![A-Za-z0-9])|service.?unavailable|server.?error|internal.?error|provider.?returned.?error|upstream.?connect|http2 request did not get a response|retry delay/i;
|
|
21
|
-
const NETWORK = /network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|socket hang up|socket connection was closed|timed? out|timeout|terminated/i;
|
|
19
|
+
const STREAM_STALL = /stream stalled|ended without|stream ended before message_stop|stream ended before a terminal response event|reset before headers/i;
|
|
20
|
+
const SERVER_ERROR = /(?<![A-Za-z0-9])(?:500|502|503|504)(?![A-Za-z0-9])|service.?unavailable|server.?error|internal.?error|provider.?returned.?error|upstream.?connect|http2 request did not get a response|ResourceExhausted|retry delay|you can retry your request|try your request again|please retry your request/i;
|
|
21
|
+
const NETWORK = /network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|getaddrinfo|ENOTFOUND|EAI_AGAIN|socket hang up|socket connection was closed|timed? out|timeout|terminated/i;
|
|
22
22
|
const RETRY_AFTER_S = /retry.?(?:after|in)\s+(\d+(?:\.\d+)?)\s*s\b|"retryDelay"\s*:\s*"(\d+(?:\.\d+)?)s"/i;
|
|
23
23
|
const RETRY_AFTER_MS = /retry.?(?:after|in)\s+(\d+)\s*ms\b/i;
|
|
24
24
|
function parseRetryAfterMs(message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../src/reliability/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAmCvE,MAAM,gBAAgB,GACrB,kQAAkQ,CAAC;AACpQ,MAAM,IAAI,GAAG,4FAA4F,CAAC;AAC1G,MAAM,UAAU,GAAG,mEAAmE,CAAC;AACvF,MAAM,UAAU,GAAG,aAAa,CAAC;AACjC,MAAM,YAAY,
|
|
1
|
+
{"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../src/reliability/classifier.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure provider-failure classifier.\n *\n * One classification produces four independent action booleans (hermes-derived design):\n * the retry loop, compaction, credential rotation, and provider failover each read their\n * own flag, so one pipeline can route a 429 to rotation, an overflow to compaction, and a\n * billing error to failover without re-parsing error text at each site.\n *\n * Pattern sources: AgentSession._isRetryableError / _isNonRetryableProviderLimitError\n * (the live, battle-tested regexes), split by reason so each maps to distinct actions.\n * Detection of context overflow stays in @caupulican/pi-ai (needs model state); hosts pass\n * `contextOverflow` in.\n */\n\nimport { PROVIDER_FAILURE_SIGNATURES } from \"./provider-signatures.ts\";\n\nexport type FailureReason =\n\t| \"overloaded\"\n\t| \"rate_limit\"\n\t| \"server_error\"\n\t| \"network\"\n\t| \"stream_stall\"\n\t| \"context_overflow\"\n\t| \"auth\"\n\t| \"billing_or_quota\"\n\t| \"aborted\"\n\t| \"unknown\";\n\nexport interface ClassifiedError {\n\treason: FailureReason;\n\tretryable: boolean;\n\tshouldCompact: boolean;\n\tshouldRotateCredential: boolean;\n\tshouldFallback: boolean;\n\t/** Provider-suggested delay parsed from the message, capped by the retry policy at use site. */\n\tretryAfterMs?: number;\n\tmessage: string;\n}\n\nexport interface ClassifyFailureInput {\n\tmessage: string;\n\t/** Host-computed via pi-ai isContextOverflow(message, contextWindow). */\n\tcontextOverflow?: boolean;\n\t/** True when the failure came from an intentional abort (stopReason \"aborted\"). */\n\taborted?: boolean;\n\t/** Provider id; provider-specific signatures are checked before generic patterns. */\n\tprovider?: string;\n}\n\nconst BILLING_OR_QUOTA =\n\t/GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing|usage.?limit(?:s)?\\s*(?:reached|exceeded|hit)|usage_limit_reached|hit your usage limit|hit your ChatGPT usage limit/i;\nconst AUTH = /\\b401\\b|unauthorized|invalid.?api.?key|authentication.?error|forbidden|permission.?denied/i;\nconst RATE_LIMIT = /rate.?limit|too many requests|(?<![A-Za-z0-9])429(?![A-Za-z0-9])/i;\nconst OVERLOADED = /overloaded/i;\nconst STREAM_STALL =\n\t/stream stalled|ended without|stream ended before message_stop|stream ended before a terminal response event|reset before headers/i;\nconst SERVER_ERROR =\n\t/(?<![A-Za-z0-9])(?:500|502|503|504)(?![A-Za-z0-9])|service.?unavailable|server.?error|internal.?error|provider.?returned.?error|upstream.?connect|http2 request did not get a response|ResourceExhausted|retry delay|you can retry your request|try your request again|please retry your request/i;\nconst NETWORK =\n\t/network.?error|connection.?error|connection.?refused|connection.?lost|websocket.?closed|websocket.?error|other side closed|fetch failed|getaddrinfo|ENOTFOUND|EAI_AGAIN|socket hang up|socket connection was closed|timed? out|timeout|terminated/i;\n\nconst RETRY_AFTER_S = /retry.?(?:after|in)\\s+(\\d+(?:\\.\\d+)?)\\s*s\\b|\"retryDelay\"\\s*:\\s*\"(\\d+(?:\\.\\d+)?)s\"/i;\nconst RETRY_AFTER_MS = /retry.?(?:after|in)\\s+(\\d+)\\s*ms\\b/i;\n\nfunction parseRetryAfterMs(message: string): number | undefined {\n\tconst ms = RETRY_AFTER_MS.exec(message);\n\tif (ms) return Number(ms[1]);\n\tconst s = RETRY_AFTER_S.exec(message);\n\tif (s) return Math.round(Number(s[1] ?? s[2]) * 1000);\n\treturn undefined;\n}\n\nexport function classifyFailure(input: ClassifyFailureInput): ClassifiedError {\n\tconst message = input.message;\n\tconst retryAfterMs = parseRetryAfterMs(message);\n\n\tconst base = {\n\t\tretryable: false,\n\t\tshouldCompact: false,\n\t\tshouldRotateCredential: false,\n\t\tshouldFallback: false,\n\t\tmessage,\n\t};\n\n\tconst withRetry = <T extends { reason: FailureReason }>(obj: T): T | (T & { retryAfterMs: number }) =>\n\t\tretryAfterMs !== undefined ? { ...obj, retryAfterMs } : obj;\n\n\tif (input.aborted) return withRetry({ ...base, reason: \"aborted\" });\n\tif (input.contextOverflow) return withRetry({ ...base, reason: \"context_overflow\", shouldCompact: true });\n\tconst providerSignatures = input.provider ? (PROVIDER_FAILURE_SIGNATURES[input.provider] ?? []) : [];\n\tfor (const signature of providerSignatures) {\n\t\tif (signature.pattern.test(message)) {\n\t\t\treturn withRetry({\n\t\t\t\t...base,\n\t\t\t\treason: signature.reason,\n\t\t\t\tshouldFallback: signature.reason === \"billing_or_quota\" || signature.reason === \"auth\",\n\t\t\t\tshouldRotateCredential: signature.reason === \"auth\",\n\t\t\t\tretryable:\n\t\t\t\t\tsignature.reason === \"rate_limit\" ||\n\t\t\t\t\tsignature.reason === \"overloaded\" ||\n\t\t\t\t\tsignature.reason === \"server_error\" ||\n\t\t\t\t\tsignature.reason === \"network\" ||\n\t\t\t\t\tsignature.reason === \"stream_stall\",\n\t\t\t});\n\t\t}\n\t}\n\tif (BILLING_OR_QUOTA.test(message)) return withRetry({ ...base, reason: \"billing_or_quota\", shouldFallback: true });\n\tif (AUTH.test(message))\n\t\treturn withRetry({ ...base, reason: \"auth\", shouldRotateCredential: true, shouldFallback: true });\n\n\tconst isRateLimit = RATE_LIMIT.test(message);\n\tif (isRateLimit || OVERLOADED.test(message)) {\n\t\treturn withRetry({\n\t\t\t...base,\n\t\t\treason: isRateLimit ? \"rate_limit\" : \"overloaded\",\n\t\t\tretryable: true,\n\t\t\tshouldRotateCredential: true,\n\t\t\tshouldFallback: true,\n\t\t});\n\t}\n\tif (STREAM_STALL.test(message))\n\t\treturn withRetry({ ...base, reason: \"stream_stall\", retryable: true, shouldFallback: true });\n\tif (SERVER_ERROR.test(message))\n\t\treturn withRetry({ ...base, reason: \"server_error\", retryable: true, shouldFallback: true });\n\tif (NETWORK.test(message)) return withRetry({ ...base, reason: \"network\", retryable: true, shouldFallback: true });\n\n\treturn withRetry({ ...base, reason: \"unknown\" });\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ImageContent, Message, TextContent } from "@caupulican/pi-ai";
|
|
1
|
+
import type { ImageContent, Message, TextContent, Usage } from "@caupulican/pi-ai";
|
|
2
2
|
import { type BashExecutionMessage, type CustomMessage } from "../messages.ts";
|
|
3
3
|
import type { AgentMessage } from "../types.ts";
|
|
4
4
|
export declare const CURRENT_SESSION_VERSION = 3;
|
|
@@ -40,6 +40,8 @@ export interface CompactionEntry<T = unknown> extends SessionEntryBase {
|
|
|
40
40
|
tokensBefore: number;
|
|
41
41
|
/** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
|
|
42
42
|
details?: T;
|
|
43
|
+
/** Usage from every LLM call that produced or verified this summary. */
|
|
44
|
+
usage?: Usage;
|
|
43
45
|
/** True if generated by an extension, undefined/false if pi-generated (backward compatible) */
|
|
44
46
|
fromHook?: boolean;
|
|
45
47
|
}
|
|
@@ -49,6 +51,8 @@ export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
|
|
|
49
51
|
summary: string;
|
|
50
52
|
/** Extension-specific data (not sent to LLM) */
|
|
51
53
|
details?: T;
|
|
54
|
+
/** Usage from every LLM call that produced this summary. */
|
|
55
|
+
usage?: Usage;
|
|
52
56
|
/** True if generated by an extension, false if pi-generated */
|
|
53
57
|
fromHook?: boolean;
|
|
54
58
|
}
|
|
@@ -194,6 +198,7 @@ export declare class SessionManager {
|
|
|
194
198
|
newSession(options?: NewSessionOptions): string | undefined;
|
|
195
199
|
private _resetEntryFileIndex;
|
|
196
200
|
private _buildIndex;
|
|
201
|
+
private _ensureSessionFileParent;
|
|
197
202
|
private _rewriteFile;
|
|
198
203
|
isPersisted(): boolean;
|
|
199
204
|
getCwd(): string;
|
|
@@ -220,7 +225,7 @@ export declare class SessionManager {
|
|
|
220
225
|
/** Append a model change as child of current leaf, then advance leaf. Returns entry id. */
|
|
221
226
|
appendModelChange(provider: string, modelId: string): string;
|
|
222
227
|
/** Append a compaction summary as child of current leaf, then advance leaf. Returns entry id. */
|
|
223
|
-
appendCompaction<T = unknown>(summary: string, firstKeptEntryId: string, tokensBefore: number, details?: T, fromHook?: boolean): string;
|
|
228
|
+
appendCompaction<T = unknown>(summary: string, firstKeptEntryId: string, tokensBefore: number, details?: T, fromHook?: boolean, usage?: Usage): string;
|
|
224
229
|
/** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */
|
|
225
230
|
appendCustomEntry(customType: string, data?: unknown): string;
|
|
226
231
|
/** Append a session info entry (e.g., display name). Returns entry id. */
|
|
@@ -316,11 +321,18 @@ export declare class SessionManager {
|
|
|
316
321
|
* Same as branch(), but also appends a branch_summary entry that captures
|
|
317
322
|
* context from the abandoned conversation path.
|
|
318
323
|
*/
|
|
319
|
-
branchWithSummary(branchFromId: string | null, summary: string, details?: unknown, fromHook?: boolean): string;
|
|
324
|
+
branchWithSummary(branchFromId: string | null, summary: string, details?: unknown, fromHook?: boolean, usage?: Usage): string;
|
|
320
325
|
/**
|
|
321
|
-
* Create
|
|
322
|
-
*
|
|
323
|
-
*
|
|
326
|
+
* Create an independent session manager containing only the path from root to the specified
|
|
327
|
+
* leaf. The source manager is not mutated, so callers can prepare a replacement runtime before
|
|
328
|
+
* retiring the current one.
|
|
329
|
+
*/
|
|
330
|
+
createBranchedSessionManager(leafId: string): SessionManager;
|
|
331
|
+
/**
|
|
332
|
+
* Create a branch and make it current on this manager.
|
|
333
|
+
*
|
|
334
|
+
* Prefer createBranchedSessionManager() when a caller is replacing a live runtime and needs to
|
|
335
|
+
* keep this manager intact until the replacement has been constructed successfully.
|
|
324
336
|
*/
|
|
325
337
|
createBranchedSession(leafId: string): string | undefined;
|
|
326
338
|
/**
|