@mariozechner/pi-agent-core 0.30.2 → 0.31.0
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 +297 -126
- package/dist/agent-loop.d.ts +21 -0
- package/dist/agent-loop.d.ts.map +1 -0
- package/dist/agent-loop.js +294 -0
- package/dist/agent-loop.js.map +1 -0
- package/dist/agent.d.ts +43 -29
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +83 -148
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +85 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +269 -0
- package/dist/proxy.js.map +1 -0
- package/dist/types.d.ts +88 -29
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/dist/transports/AppTransport.d.ts +0 -28
- package/dist/transports/AppTransport.d.ts.map +0 -1
- package/dist/transports/AppTransport.js +0 -330
- package/dist/transports/AppTransport.js.map +0 -1
- package/dist/transports/ProviderTransport.d.ts +0 -29
- package/dist/transports/ProviderTransport.d.ts.map +0 -1
- package/dist/transports/ProviderTransport.js +0 -54
- package/dist/transports/ProviderTransport.js.map +0 -1
- package/dist/transports/index.d.ts +0 -5
- package/dist/transports/index.d.ts.map +0 -1
- package/dist/transports/index.js +0 -3
- package/dist/transports/index.js.map +0 -1
- package/dist/transports/proxy-types.d.ts +0 -53
- package/dist/transports/proxy-types.d.ts.map +0 -1
- package/dist/transports/proxy-types.js +0 -2
- package/dist/transports/proxy-types.js.map +0 -1
- package/dist/transports/types.d.ts +0 -25
- package/dist/transports/types.d.ts.map +0 -1
- package/dist/transports/types.js +0 -2
- package/dist/transports/types.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AppTransport.d.ts","sourceRoot":"","sources":["../../src/transports/AppTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAOX,OAAO,EAKP,MAAM,qBAAqB,CAAC;AAK7B,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAuSjE,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7C;AAED;;;GAGG;AACH,qBAAa,YAAa,YAAW,cAAc;IAClD,OAAO,CAAC,OAAO,CAAsB;IAErC,YAAY,OAAO,EAAE,mBAAmB,EAEvC;YAEa,WAAW;IAczB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,eAAe;IAQhB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,2EAa9F;IAEM,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,2EAa7E;CACD","sourcesContent":["import type {\n\tAgentContext,\n\tAgentLoopConfig,\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tContext,\n\tMessage,\n\tModel,\n\tSimpleStreamOptions,\n\tToolCall,\n\tUserMessage,\n} from \"@mariozechner/pi-ai\";\nimport { agentLoop, agentLoopContinue } from \"@mariozechner/pi-ai\";\nimport { AssistantMessageEventStream } from \"@mariozechner/pi-ai/dist/utils/event-stream.js\";\nimport { parseStreamingJson } from \"@mariozechner/pi-ai/dist/utils/json-parse.js\";\nimport type { ProxyAssistantMessageEvent } from \"./proxy-types.js\";\nimport type { AgentRunConfig, AgentTransport } from \"./types.js\";\n\n/**\n * Stream function that proxies through a server instead of calling providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n */\nfunction streamSimpleProxy(\n\tmodel: Model<any>,\n\tcontext: Context,\n\toptions: SimpleStreamOptions & { authToken: string },\n\tproxyUrl: string,\n): AssistantMessageEventStream {\n\tconst stream = new AssistantMessageEventStream();\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\n\t\t// Set up abort handler to cancel the reader\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(`${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: {\n\t\t\t\t\t\ttemperature: options.temperature,\n\t\t\t\t\t\tmaxTokens: options.maxTokens,\n\t\t\t\t\t\treasoning: options.reasoning,\n\t\t\t\t\t\t// Don't send apiKey or signal - those are added server-side\n\t\t\t\t\t},\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, use default message\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\t// Parse SSE stream\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\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\t// Check if aborted after reading\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\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\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\tlet event: AssistantMessageEvent | undefined;\n\n\t\t\t\t\t\t\t// Handle different event types\n\t\t\t\t\t\t\t// Server sends events with partial for non-delta events,\n\t\t\t\t\t\t\t// and without partial for delta events\n\t\t\t\t\t\t\tswitch (proxyEvent.type) {\n\t\t\t\t\t\t\t\tcase \"start\":\n\t\t\t\t\t\t\t\t\tevent = { type: \"start\", partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"text_start\":\n\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: \"\",\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\tevent = { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"text_delta\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcase \"text_end\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tcontent: content.text,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"thinking_start\":\n\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\t\t\t\t\t\t\ttype: \"thinking\",\n\t\t\t\t\t\t\t\t\t\tthinking: \"\",\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\tevent = { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"thinking_delta\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\t\t\t\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"thinking_end\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\t\t\t\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"toolcall_start\":\n\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\t\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\t\t\t\t\tid: proxyEvent.id,\n\t\t\t\t\t\t\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\t\t\t\t\t\t\targuments: {},\n\t\t\t\t\t\t\t\t\t\tpartialJson: \"\",\n\t\t\t\t\t\t\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\t\t\t\t\t\t\tevent = { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"toolcall_delta\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t\t\t\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\t\t\t\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"toolcall_end\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t\t\t\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\ttoolCall: content,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"done\":\n\t\t\t\t\t\t\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\t\t\t\t\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\t\t\t\t\t\t\tevent = { type: \"done\", reason: proxyEvent.reason, message: partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\t\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\t\t\t\t\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\t\t\t\t\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\t\t\t\t\t\t\tevent = { type: \"error\", reason: proxyEvent.reason, error: partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t\t// Exhaustive check\n\t\t\t\t\t\t\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\t\t\t\t\t\t\tconsole.warn(`Unhandled event type: ${(proxyEvent as any).type}`);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Push the event to stream\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow new Error(\"Failed to create event from proxy 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\t// Check if aborted after reading\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\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tpartial.stopReason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: partial.stopReason,\n\t\t\t\terror: partial,\n\t\t\t} satisfies AssistantMessageEvent);\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\t// Clean up abort handler\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\nexport interface AppTransportOptions {\n\t/**\n\t * Proxy server URL. The server manages user accounts and proxies requests to LLM providers.\n\t * Example: \"https://genai.mariozechner.at\"\n\t */\n\tproxyUrl: string;\n\n\t/**\n\t * Function to retrieve auth token for the proxy server.\n\t * The token is used for user authentication and authorization.\n\t */\n\tgetAuthToken: () => Promise<string> | string;\n}\n\n/**\n * Transport that uses an app server with user authentication tokens.\n * The server manages user accounts and proxies requests to LLM providers.\n */\nexport class AppTransport implements AgentTransport {\n\tprivate options: AppTransportOptions;\n\n\tconstructor(options: AppTransportOptions) {\n\t\tthis.options = options;\n\t}\n\n\tprivate async getStreamFn(authToken: string) {\n\t\treturn <TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions) => {\n\t\t\treturn streamSimpleProxy(\n\t\t\t\tmodel,\n\t\t\t\tcontext,\n\t\t\t\t{\n\t\t\t\t\t...options,\n\t\t\t\t\tauthToken,\n\t\t\t\t},\n\t\t\t\tthis.options.proxyUrl,\n\t\t\t);\n\t\t};\n\t}\n\n\tprivate buildContext(messages: Message[], cfg: AgentRunConfig): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\t}\n\n\tprivate buildLoopConfig(cfg: AgentRunConfig): AgentLoopConfig {\n\t\treturn {\n\t\t\tmodel: cfg.model,\n\t\t\treasoning: cfg.reasoning,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\t}\n\n\tasync *run(messages: Message[], userMessage: Message, cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst authToken = await this.options.getAuthToken();\n\t\tif (!authToken) {\n\t\t\tthrow new Error(\"Auth token is required for AppTransport\");\n\t\t}\n\n\t\tconst streamFn = await this.getStreamFn(authToken);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(cfg);\n\n\t\tfor await (const ev of agentLoop(userMessage as unknown as UserMessage, context, pc, signal, streamFn as any)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n\n\tasync *continue(messages: Message[], cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst authToken = await this.options.getAuthToken();\n\t\tif (!authToken) {\n\t\t\tthrow new Error(\"Auth token is required for AppTransport\");\n\t\t}\n\n\t\tconst streamFn = await this.getStreamFn(authToken);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(cfg);\n\n\t\tfor await (const ev of agentLoopContinue(context, pc, signal, streamFn as any)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
import { agentLoop, agentLoopContinue } from "@mariozechner/pi-ai";
|
|
2
|
-
import { AssistantMessageEventStream } from "@mariozechner/pi-ai/dist/utils/event-stream.js";
|
|
3
|
-
import { parseStreamingJson } from "@mariozechner/pi-ai/dist/utils/json-parse.js";
|
|
4
|
-
/**
|
|
5
|
-
* Stream function that proxies through a server instead of calling providers directly.
|
|
6
|
-
* The server strips the partial field from delta events to reduce bandwidth.
|
|
7
|
-
* We reconstruct the partial message client-side.
|
|
8
|
-
*/
|
|
9
|
-
function streamSimpleProxy(model, context, options, proxyUrl) {
|
|
10
|
-
const stream = new AssistantMessageEventStream();
|
|
11
|
-
(async () => {
|
|
12
|
-
// Initialize the partial message that we'll build up from events
|
|
13
|
-
const partial = {
|
|
14
|
-
role: "assistant",
|
|
15
|
-
stopReason: "stop",
|
|
16
|
-
content: [],
|
|
17
|
-
api: model.api,
|
|
18
|
-
provider: model.provider,
|
|
19
|
-
model: model.id,
|
|
20
|
-
usage: {
|
|
21
|
-
input: 0,
|
|
22
|
-
output: 0,
|
|
23
|
-
cacheRead: 0,
|
|
24
|
-
cacheWrite: 0,
|
|
25
|
-
totalTokens: 0,
|
|
26
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
27
|
-
},
|
|
28
|
-
timestamp: Date.now(),
|
|
29
|
-
};
|
|
30
|
-
let reader;
|
|
31
|
-
// Set up abort handler to cancel the reader
|
|
32
|
-
const abortHandler = () => {
|
|
33
|
-
if (reader) {
|
|
34
|
-
reader.cancel("Request aborted by user").catch(() => { });
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
if (options.signal) {
|
|
38
|
-
options.signal.addEventListener("abort", abortHandler);
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
const response = await fetch(`${proxyUrl}/api/stream`, {
|
|
42
|
-
method: "POST",
|
|
43
|
-
headers: {
|
|
44
|
-
Authorization: `Bearer ${options.authToken}`,
|
|
45
|
-
"Content-Type": "application/json",
|
|
46
|
-
},
|
|
47
|
-
body: JSON.stringify({
|
|
48
|
-
model,
|
|
49
|
-
context,
|
|
50
|
-
options: {
|
|
51
|
-
temperature: options.temperature,
|
|
52
|
-
maxTokens: options.maxTokens,
|
|
53
|
-
reasoning: options.reasoning,
|
|
54
|
-
// Don't send apiKey or signal - those are added server-side
|
|
55
|
-
},
|
|
56
|
-
}),
|
|
57
|
-
signal: options.signal,
|
|
58
|
-
});
|
|
59
|
-
if (!response.ok) {
|
|
60
|
-
let errorMessage = `Proxy error: ${response.status} ${response.statusText}`;
|
|
61
|
-
try {
|
|
62
|
-
const errorData = (await response.json());
|
|
63
|
-
if (errorData.error) {
|
|
64
|
-
errorMessage = `Proxy error: ${errorData.error}`;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
// Couldn't parse error response, use default message
|
|
69
|
-
}
|
|
70
|
-
throw new Error(errorMessage);
|
|
71
|
-
}
|
|
72
|
-
// Parse SSE stream
|
|
73
|
-
reader = response.body.getReader();
|
|
74
|
-
const decoder = new TextDecoder();
|
|
75
|
-
let buffer = "";
|
|
76
|
-
while (true) {
|
|
77
|
-
const { done, value } = await reader.read();
|
|
78
|
-
if (done)
|
|
79
|
-
break;
|
|
80
|
-
// Check if aborted after reading
|
|
81
|
-
if (options.signal?.aborted) {
|
|
82
|
-
throw new Error("Request aborted by user");
|
|
83
|
-
}
|
|
84
|
-
buffer += decoder.decode(value, { stream: true });
|
|
85
|
-
const lines = buffer.split("\n");
|
|
86
|
-
buffer = lines.pop() || "";
|
|
87
|
-
for (const line of lines) {
|
|
88
|
-
if (line.startsWith("data: ")) {
|
|
89
|
-
const data = line.slice(6).trim();
|
|
90
|
-
if (data) {
|
|
91
|
-
const proxyEvent = JSON.parse(data);
|
|
92
|
-
let event;
|
|
93
|
-
// Handle different event types
|
|
94
|
-
// Server sends events with partial for non-delta events,
|
|
95
|
-
// and without partial for delta events
|
|
96
|
-
switch (proxyEvent.type) {
|
|
97
|
-
case "start":
|
|
98
|
-
event = { type: "start", partial };
|
|
99
|
-
break;
|
|
100
|
-
case "text_start":
|
|
101
|
-
partial.content[proxyEvent.contentIndex] = {
|
|
102
|
-
type: "text",
|
|
103
|
-
text: "",
|
|
104
|
-
};
|
|
105
|
-
event = { type: "text_start", contentIndex: proxyEvent.contentIndex, partial };
|
|
106
|
-
break;
|
|
107
|
-
case "text_delta": {
|
|
108
|
-
const content = partial.content[proxyEvent.contentIndex];
|
|
109
|
-
if (content?.type === "text") {
|
|
110
|
-
content.text += proxyEvent.delta;
|
|
111
|
-
event = {
|
|
112
|
-
type: "text_delta",
|
|
113
|
-
contentIndex: proxyEvent.contentIndex,
|
|
114
|
-
delta: proxyEvent.delta,
|
|
115
|
-
partial,
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
throw new Error("Received text_delta for non-text content");
|
|
120
|
-
}
|
|
121
|
-
break;
|
|
122
|
-
}
|
|
123
|
-
case "text_end": {
|
|
124
|
-
const content = partial.content[proxyEvent.contentIndex];
|
|
125
|
-
if (content?.type === "text") {
|
|
126
|
-
content.textSignature = proxyEvent.contentSignature;
|
|
127
|
-
event = {
|
|
128
|
-
type: "text_end",
|
|
129
|
-
contentIndex: proxyEvent.contentIndex,
|
|
130
|
-
content: content.text,
|
|
131
|
-
partial,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
throw new Error("Received text_end for non-text content");
|
|
136
|
-
}
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
case "thinking_start":
|
|
140
|
-
partial.content[proxyEvent.contentIndex] = {
|
|
141
|
-
type: "thinking",
|
|
142
|
-
thinking: "",
|
|
143
|
-
};
|
|
144
|
-
event = { type: "thinking_start", contentIndex: proxyEvent.contentIndex, partial };
|
|
145
|
-
break;
|
|
146
|
-
case "thinking_delta": {
|
|
147
|
-
const content = partial.content[proxyEvent.contentIndex];
|
|
148
|
-
if (content?.type === "thinking") {
|
|
149
|
-
content.thinking += proxyEvent.delta;
|
|
150
|
-
event = {
|
|
151
|
-
type: "thinking_delta",
|
|
152
|
-
contentIndex: proxyEvent.contentIndex,
|
|
153
|
-
delta: proxyEvent.delta,
|
|
154
|
-
partial,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
throw new Error("Received thinking_delta for non-thinking content");
|
|
159
|
-
}
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
case "thinking_end": {
|
|
163
|
-
const content = partial.content[proxyEvent.contentIndex];
|
|
164
|
-
if (content?.type === "thinking") {
|
|
165
|
-
content.thinkingSignature = proxyEvent.contentSignature;
|
|
166
|
-
event = {
|
|
167
|
-
type: "thinking_end",
|
|
168
|
-
contentIndex: proxyEvent.contentIndex,
|
|
169
|
-
content: content.thinking,
|
|
170
|
-
partial,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
throw new Error("Received thinking_end for non-thinking content");
|
|
175
|
-
}
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
case "toolcall_start":
|
|
179
|
-
partial.content[proxyEvent.contentIndex] = {
|
|
180
|
-
type: "toolCall",
|
|
181
|
-
id: proxyEvent.id,
|
|
182
|
-
name: proxyEvent.toolName,
|
|
183
|
-
arguments: {},
|
|
184
|
-
partialJson: "",
|
|
185
|
-
};
|
|
186
|
-
event = { type: "toolcall_start", contentIndex: proxyEvent.contentIndex, partial };
|
|
187
|
-
break;
|
|
188
|
-
case "toolcall_delta": {
|
|
189
|
-
const content = partial.content[proxyEvent.contentIndex];
|
|
190
|
-
if (content?.type === "toolCall") {
|
|
191
|
-
content.partialJson += proxyEvent.delta;
|
|
192
|
-
content.arguments = parseStreamingJson(content.partialJson) || {};
|
|
193
|
-
event = {
|
|
194
|
-
type: "toolcall_delta",
|
|
195
|
-
contentIndex: proxyEvent.contentIndex,
|
|
196
|
-
delta: proxyEvent.delta,
|
|
197
|
-
partial,
|
|
198
|
-
};
|
|
199
|
-
partial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
throw new Error("Received toolcall_delta for non-toolCall content");
|
|
203
|
-
}
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
case "toolcall_end": {
|
|
207
|
-
const content = partial.content[proxyEvent.contentIndex];
|
|
208
|
-
if (content?.type === "toolCall") {
|
|
209
|
-
delete content.partialJson;
|
|
210
|
-
event = {
|
|
211
|
-
type: "toolcall_end",
|
|
212
|
-
contentIndex: proxyEvent.contentIndex,
|
|
213
|
-
toolCall: content,
|
|
214
|
-
partial,
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
case "done":
|
|
220
|
-
partial.stopReason = proxyEvent.reason;
|
|
221
|
-
partial.usage = proxyEvent.usage;
|
|
222
|
-
event = { type: "done", reason: proxyEvent.reason, message: partial };
|
|
223
|
-
break;
|
|
224
|
-
case "error":
|
|
225
|
-
partial.stopReason = proxyEvent.reason;
|
|
226
|
-
partial.errorMessage = proxyEvent.errorMessage;
|
|
227
|
-
partial.usage = proxyEvent.usage;
|
|
228
|
-
event = { type: "error", reason: proxyEvent.reason, error: partial };
|
|
229
|
-
break;
|
|
230
|
-
default: {
|
|
231
|
-
// Exhaustive check
|
|
232
|
-
const _exhaustiveCheck = proxyEvent;
|
|
233
|
-
console.warn(`Unhandled event type: ${proxyEvent.type}`);
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
// Push the event to stream
|
|
238
|
-
if (event) {
|
|
239
|
-
stream.push(event);
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
throw new Error("Failed to create event from proxy event");
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
// Check if aborted after reading
|
|
249
|
-
if (options.signal?.aborted) {
|
|
250
|
-
throw new Error("Request aborted by user");
|
|
251
|
-
}
|
|
252
|
-
stream.end();
|
|
253
|
-
}
|
|
254
|
-
catch (error) {
|
|
255
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
256
|
-
partial.stopReason = options.signal?.aborted ? "aborted" : "error";
|
|
257
|
-
partial.errorMessage = errorMessage;
|
|
258
|
-
stream.push({
|
|
259
|
-
type: "error",
|
|
260
|
-
reason: partial.stopReason,
|
|
261
|
-
error: partial,
|
|
262
|
-
});
|
|
263
|
-
stream.end();
|
|
264
|
-
}
|
|
265
|
-
finally {
|
|
266
|
-
// Clean up abort handler
|
|
267
|
-
if (options.signal) {
|
|
268
|
-
options.signal.removeEventListener("abort", abortHandler);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
})();
|
|
272
|
-
return stream;
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* Transport that uses an app server with user authentication tokens.
|
|
276
|
-
* The server manages user accounts and proxies requests to LLM providers.
|
|
277
|
-
*/
|
|
278
|
-
export class AppTransport {
|
|
279
|
-
options;
|
|
280
|
-
constructor(options) {
|
|
281
|
-
this.options = options;
|
|
282
|
-
}
|
|
283
|
-
async getStreamFn(authToken) {
|
|
284
|
-
return (model, context, options) => {
|
|
285
|
-
return streamSimpleProxy(model, context, {
|
|
286
|
-
...options,
|
|
287
|
-
authToken,
|
|
288
|
-
}, this.options.proxyUrl);
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
buildContext(messages, cfg) {
|
|
292
|
-
return {
|
|
293
|
-
systemPrompt: cfg.systemPrompt,
|
|
294
|
-
messages,
|
|
295
|
-
tools: cfg.tools,
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
buildLoopConfig(cfg) {
|
|
299
|
-
return {
|
|
300
|
-
model: cfg.model,
|
|
301
|
-
reasoning: cfg.reasoning,
|
|
302
|
-
getQueuedMessages: cfg.getQueuedMessages,
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
async *run(messages, userMessage, cfg, signal) {
|
|
306
|
-
const authToken = await this.options.getAuthToken();
|
|
307
|
-
if (!authToken) {
|
|
308
|
-
throw new Error("Auth token is required for AppTransport");
|
|
309
|
-
}
|
|
310
|
-
const streamFn = await this.getStreamFn(authToken);
|
|
311
|
-
const context = this.buildContext(messages, cfg);
|
|
312
|
-
const pc = this.buildLoopConfig(cfg);
|
|
313
|
-
for await (const ev of agentLoop(userMessage, context, pc, signal, streamFn)) {
|
|
314
|
-
yield ev;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
async *continue(messages, cfg, signal) {
|
|
318
|
-
const authToken = await this.options.getAuthToken();
|
|
319
|
-
if (!authToken) {
|
|
320
|
-
throw new Error("Auth token is required for AppTransport");
|
|
321
|
-
}
|
|
322
|
-
const streamFn = await this.getStreamFn(authToken);
|
|
323
|
-
const context = this.buildContext(messages, cfg);
|
|
324
|
-
const pc = this.buildLoopConfig(cfg);
|
|
325
|
-
for await (const ev of agentLoopContinue(context, pc, signal, streamFn)) {
|
|
326
|
-
yield ev;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
//# sourceMappingURL=AppTransport.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AppTransport.js","sourceRoot":"","sources":["../../src/transports/AppTransport.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tAgentContext,\n\tAgentLoopConfig,\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tContext,\n\tMessage,\n\tModel,\n\tSimpleStreamOptions,\n\tToolCall,\n\tUserMessage,\n} from \"@mariozechner/pi-ai\";\nimport { agentLoop, agentLoopContinue } from \"@mariozechner/pi-ai\";\nimport { AssistantMessageEventStream } from \"@mariozechner/pi-ai/dist/utils/event-stream.js\";\nimport { parseStreamingJson } from \"@mariozechner/pi-ai/dist/utils/json-parse.js\";\nimport type { ProxyAssistantMessageEvent } from \"./proxy-types.js\";\nimport type { AgentRunConfig, AgentTransport } from \"./types.js\";\n\n/**\n * Stream function that proxies through a server instead of calling providers directly.\n * The server strips the partial field from delta events to reduce bandwidth.\n * We reconstruct the partial message client-side.\n */\nfunction streamSimpleProxy(\n\tmodel: Model<any>,\n\tcontext: Context,\n\toptions: SimpleStreamOptions & { authToken: string },\n\tproxyUrl: string,\n): AssistantMessageEventStream {\n\tconst stream = new AssistantMessageEventStream();\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\n\t\t// Set up abort handler to cancel the reader\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(`${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: {\n\t\t\t\t\t\ttemperature: options.temperature,\n\t\t\t\t\t\tmaxTokens: options.maxTokens,\n\t\t\t\t\t\treasoning: options.reasoning,\n\t\t\t\t\t\t// Don't send apiKey or signal - those are added server-side\n\t\t\t\t\t},\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, use default message\n\t\t\t\t}\n\t\t\t\tthrow new Error(errorMessage);\n\t\t\t}\n\n\t\t\t// Parse SSE stream\n\t\t\treader = response.body!.getReader();\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tlet buffer = \"\";\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\t// Check if aborted after reading\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\tbuffer += decoder.decode(value, { stream: true });\n\t\t\t\tconst lines = buffer.split(\"\\n\");\n\t\t\t\tbuffer = lines.pop() || \"\";\n\n\t\t\t\tfor (const line of lines) {\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\tlet event: AssistantMessageEvent | undefined;\n\n\t\t\t\t\t\t\t// Handle different event types\n\t\t\t\t\t\t\t// Server sends events with partial for non-delta events,\n\t\t\t\t\t\t\t// and without partial for delta events\n\t\t\t\t\t\t\tswitch (proxyEvent.type) {\n\t\t\t\t\t\t\t\tcase \"start\":\n\t\t\t\t\t\t\t\t\tevent = { type: \"start\", partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"text_start\":\n\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\t\t\t\ttext: \"\",\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\tevent = { type: \"text_start\", contentIndex: proxyEvent.contentIndex, partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"text_delta\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tcontent.text += proxyEvent.delta;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received text_delta for non-text content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcase \"text_end\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tcontent.textSignature = proxyEvent.contentSignature;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tcontent: content.text,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received text_end for non-text content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"thinking_start\":\n\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\t\t\t\t\t\t\ttype: \"thinking\",\n\t\t\t\t\t\t\t\t\t\tthinking: \"\",\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\tevent = { type: \"thinking_start\", contentIndex: proxyEvent.contentIndex, partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"thinking_delta\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\t\t\t\t\t\t\tcontent.thinking += proxyEvent.delta;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received thinking_delta for non-thinking content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"thinking_end\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"thinking\") {\n\t\t\t\t\t\t\t\t\t\tcontent.thinkingSignature = proxyEvent.contentSignature;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tcontent: content.thinking,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received thinking_end for non-thinking content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"toolcall_start\":\n\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = {\n\t\t\t\t\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\t\t\t\t\tid: proxyEvent.id,\n\t\t\t\t\t\t\t\t\t\tname: proxyEvent.toolName,\n\t\t\t\t\t\t\t\t\t\targuments: {},\n\t\t\t\t\t\t\t\t\t\tpartialJson: \"\",\n\t\t\t\t\t\t\t\t\t} satisfies ToolCall & { partialJson: string } as ToolCall;\n\t\t\t\t\t\t\t\t\tevent = { type: \"toolcall_start\", contentIndex: proxyEvent.contentIndex, partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"toolcall_delta\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t\t\t\t\t\t\t(content as any).partialJson += proxyEvent.delta;\n\t\t\t\t\t\t\t\t\t\tcontent.arguments = parseStreamingJson((content as any).partialJson) || {};\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\tdelta: proxyEvent.delta,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t\tpartial.content[proxyEvent.contentIndex] = { ...content }; // Trigger reactivity\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Received toolcall_delta for non-toolCall content\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"toolcall_end\": {\n\t\t\t\t\t\t\t\t\tconst content = partial.content[proxyEvent.contentIndex];\n\t\t\t\t\t\t\t\t\tif (content?.type === \"toolCall\") {\n\t\t\t\t\t\t\t\t\t\tdelete (content as any).partialJson;\n\t\t\t\t\t\t\t\t\t\tevent = {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: proxyEvent.contentIndex,\n\t\t\t\t\t\t\t\t\t\t\ttoolCall: content,\n\t\t\t\t\t\t\t\t\t\t\tpartial,\n\t\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcase \"done\":\n\t\t\t\t\t\t\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\t\t\t\t\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\t\t\t\t\t\t\tevent = { type: \"done\", reason: proxyEvent.reason, message: partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase \"error\":\n\t\t\t\t\t\t\t\t\tpartial.stopReason = proxyEvent.reason;\n\t\t\t\t\t\t\t\t\tpartial.errorMessage = proxyEvent.errorMessage;\n\t\t\t\t\t\t\t\t\tpartial.usage = proxyEvent.usage;\n\t\t\t\t\t\t\t\t\tevent = { type: \"error\", reason: proxyEvent.reason, error: partial };\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t\t\t// Exhaustive check\n\t\t\t\t\t\t\t\t\tconst _exhaustiveCheck: never = proxyEvent;\n\t\t\t\t\t\t\t\t\tconsole.warn(`Unhandled event type: ${(proxyEvent as any).type}`);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Push the event to stream\n\t\t\t\t\t\t\tif (event) {\n\t\t\t\t\t\t\t\tstream.push(event);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthrow new Error(\"Failed to create event from proxy 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\t// Check if aborted after reading\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\tstream.end();\n\t\t} catch (error) {\n\t\t\tconst errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tpartial.stopReason = options.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\tpartial.errorMessage = errorMessage;\n\t\t\tstream.push({\n\t\t\t\ttype: \"error\",\n\t\t\t\treason: partial.stopReason,\n\t\t\t\terror: partial,\n\t\t\t} satisfies AssistantMessageEvent);\n\t\t\tstream.end();\n\t\t} finally {\n\t\t\t// Clean up abort handler\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\nexport interface AppTransportOptions {\n\t/**\n\t * Proxy server URL. The server manages user accounts and proxies requests to LLM providers.\n\t * Example: \"https://genai.mariozechner.at\"\n\t */\n\tproxyUrl: string;\n\n\t/**\n\t * Function to retrieve auth token for the proxy server.\n\t * The token is used for user authentication and authorization.\n\t */\n\tgetAuthToken: () => Promise<string> | string;\n}\n\n/**\n * Transport that uses an app server with user authentication tokens.\n * The server manages user accounts and proxies requests to LLM providers.\n */\nexport class AppTransport implements AgentTransport {\n\tprivate options: AppTransportOptions;\n\n\tconstructor(options: AppTransportOptions) {\n\t\tthis.options = options;\n\t}\n\n\tprivate async getStreamFn(authToken: string) {\n\t\treturn <TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions) => {\n\t\t\treturn streamSimpleProxy(\n\t\t\t\tmodel,\n\t\t\t\tcontext,\n\t\t\t\t{\n\t\t\t\t\t...options,\n\t\t\t\t\tauthToken,\n\t\t\t\t},\n\t\t\t\tthis.options.proxyUrl,\n\t\t\t);\n\t\t};\n\t}\n\n\tprivate buildContext(messages: Message[], cfg: AgentRunConfig): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\t}\n\n\tprivate buildLoopConfig(cfg: AgentRunConfig): AgentLoopConfig {\n\t\treturn {\n\t\t\tmodel: cfg.model,\n\t\t\treasoning: cfg.reasoning,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\t}\n\n\tasync *run(messages: Message[], userMessage: Message, cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst authToken = await this.options.getAuthToken();\n\t\tif (!authToken) {\n\t\t\tthrow new Error(\"Auth token is required for AppTransport\");\n\t\t}\n\n\t\tconst streamFn = await this.getStreamFn(authToken);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(cfg);\n\n\t\tfor await (const ev of agentLoop(userMessage as unknown as UserMessage, context, pc, signal, streamFn as any)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n\n\tasync *continue(messages: Message[], cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst authToken = await this.options.getAuthToken();\n\t\tif (!authToken) {\n\t\t\tthrow new Error(\"Auth token is required for AppTransport\");\n\t\t}\n\n\t\tconst streamFn = await this.getStreamFn(authToken);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(cfg);\n\n\t\tfor await (const ev of agentLoopContinue(context, pc, signal, streamFn as any)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { type Message } from "@mariozechner/pi-ai";
|
|
2
|
-
import type { AgentRunConfig, AgentTransport } from "./types.js";
|
|
3
|
-
export interface ProviderTransportOptions {
|
|
4
|
-
/**
|
|
5
|
-
* Function to retrieve API key for a given provider.
|
|
6
|
-
* If not provided, transport will try to use environment variables.
|
|
7
|
-
*/
|
|
8
|
-
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
9
|
-
/**
|
|
10
|
-
* Optional CORS proxy URL for browser environments.
|
|
11
|
-
* If provided, all requests will be routed through this proxy.
|
|
12
|
-
* Format: "https://proxy.example.com"
|
|
13
|
-
*/
|
|
14
|
-
corsProxyUrl?: string;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Transport that calls LLM providers directly.
|
|
18
|
-
* Optionally routes calls through a CORS proxy if configured.
|
|
19
|
-
*/
|
|
20
|
-
export declare class ProviderTransport implements AgentTransport {
|
|
21
|
-
private options;
|
|
22
|
-
constructor(options?: ProviderTransportOptions);
|
|
23
|
-
private getModel;
|
|
24
|
-
private buildContext;
|
|
25
|
-
private buildLoopConfig;
|
|
26
|
-
run(messages: Message[], userMessage: Message, cfg: AgentRunConfig, signal?: AbortSignal): AsyncGenerator<import("@mariozechner/pi-ai").AgentEvent, void, unknown>;
|
|
27
|
-
continue(messages: Message[], cfg: AgentRunConfig, signal?: AbortSignal): AsyncGenerator<import("@mariozechner/pi-ai").AgentEvent, void, unknown>;
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=ProviderTransport.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderTransport.d.ts","sourceRoot":"","sources":["../../src/transports/ProviderTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,KAAK,OAAO,EAEZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,WAAW,wBAAwB;IACxC;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IAEnF;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,iBAAkB,YAAW,cAAc;IACvD,OAAO,CAAC,OAAO,CAA2B;IAE1C,YAAY,OAAO,GAAE,wBAA6B,EAEjD;IAED,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,eAAe;IAUhB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,2EAQ9F;IAEM,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,2EAQ7E;CACD","sourcesContent":["import {\n\ttype AgentContext,\n\ttype AgentLoopConfig,\n\tagentLoop,\n\tagentLoopContinue,\n\ttype Message,\n\ttype UserMessage,\n} from \"@mariozechner/pi-ai\";\nimport type { AgentRunConfig, AgentTransport } from \"./types.js\";\n\nexport interface ProviderTransportOptions {\n\t/**\n\t * Function to retrieve API key for a given provider.\n\t * If not provided, transport will try to use environment variables.\n\t */\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\n\t/**\n\t * Optional CORS proxy URL for browser environments.\n\t * If provided, all requests will be routed through this proxy.\n\t * Format: \"https://proxy.example.com\"\n\t */\n\tcorsProxyUrl?: string;\n}\n\n/**\n * Transport that calls LLM providers directly.\n * Optionally routes calls through a CORS proxy if configured.\n */\nexport class ProviderTransport implements AgentTransport {\n\tprivate options: ProviderTransportOptions;\n\n\tconstructor(options: ProviderTransportOptions = {}) {\n\t\tthis.options = options;\n\t}\n\n\tprivate getModel(cfg: AgentRunConfig) {\n\t\tlet model = cfg.model;\n\t\tif (this.options.corsProxyUrl && cfg.model.baseUrl) {\n\t\t\tmodel = {\n\t\t\t\t...cfg.model,\n\t\t\t\tbaseUrl: `${this.options.corsProxyUrl}/?url=${encodeURIComponent(cfg.model.baseUrl)}`,\n\t\t\t};\n\t\t}\n\t\treturn model;\n\t}\n\n\tprivate buildContext(messages: Message[], cfg: AgentRunConfig): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\t}\n\n\tprivate buildLoopConfig(model: AgentRunConfig[\"model\"], cfg: AgentRunConfig): AgentLoopConfig {\n\t\treturn {\n\t\t\tmodel,\n\t\t\treasoning: cfg.reasoning,\n\t\t\t// Resolve API key per assistant response (important for expiring OAuth tokens)\n\t\t\tgetApiKey: this.options.getApiKey,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\t}\n\n\tasync *run(messages: Message[], userMessage: Message, cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst model = this.getModel(cfg);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(model, cfg);\n\n\t\tfor await (const ev of agentLoop(userMessage as unknown as UserMessage, context, pc, signal)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n\n\tasync *continue(messages: Message[], cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst model = this.getModel(cfg);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(model, cfg);\n\n\t\tfor await (const ev of agentLoopContinue(context, pc, signal)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { agentLoop, agentLoopContinue, } from "@mariozechner/pi-ai";
|
|
2
|
-
/**
|
|
3
|
-
* Transport that calls LLM providers directly.
|
|
4
|
-
* Optionally routes calls through a CORS proxy if configured.
|
|
5
|
-
*/
|
|
6
|
-
export class ProviderTransport {
|
|
7
|
-
options;
|
|
8
|
-
constructor(options = {}) {
|
|
9
|
-
this.options = options;
|
|
10
|
-
}
|
|
11
|
-
getModel(cfg) {
|
|
12
|
-
let model = cfg.model;
|
|
13
|
-
if (this.options.corsProxyUrl && cfg.model.baseUrl) {
|
|
14
|
-
model = {
|
|
15
|
-
...cfg.model,
|
|
16
|
-
baseUrl: `${this.options.corsProxyUrl}/?url=${encodeURIComponent(cfg.model.baseUrl)}`,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
return model;
|
|
20
|
-
}
|
|
21
|
-
buildContext(messages, cfg) {
|
|
22
|
-
return {
|
|
23
|
-
systemPrompt: cfg.systemPrompt,
|
|
24
|
-
messages,
|
|
25
|
-
tools: cfg.tools,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
buildLoopConfig(model, cfg) {
|
|
29
|
-
return {
|
|
30
|
-
model,
|
|
31
|
-
reasoning: cfg.reasoning,
|
|
32
|
-
// Resolve API key per assistant response (important for expiring OAuth tokens)
|
|
33
|
-
getApiKey: this.options.getApiKey,
|
|
34
|
-
getQueuedMessages: cfg.getQueuedMessages,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
async *run(messages, userMessage, cfg, signal) {
|
|
38
|
-
const model = this.getModel(cfg);
|
|
39
|
-
const context = this.buildContext(messages, cfg);
|
|
40
|
-
const pc = this.buildLoopConfig(model, cfg);
|
|
41
|
-
for await (const ev of agentLoop(userMessage, context, pc, signal)) {
|
|
42
|
-
yield ev;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
async *continue(messages, cfg, signal) {
|
|
46
|
-
const model = this.getModel(cfg);
|
|
47
|
-
const context = this.buildContext(messages, cfg);
|
|
48
|
-
const pc = this.buildLoopConfig(model, cfg);
|
|
49
|
-
for await (const ev of agentLoopContinue(context, pc, signal)) {
|
|
50
|
-
yield ev;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=ProviderTransport.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderTransport.js","sourceRoot":"","sources":["../../src/transports/ProviderTransport.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,SAAS,EACT,iBAAiB,GAGjB,MAAM,qBAAqB,CAAC;AAkB7B;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IACrB,OAAO,CAA2B;IAE1C,YAAY,OAAO,GAA6B,EAAE,EAAE;QACnD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAAA,CACvB;IAEO,QAAQ,CAAC,GAAmB,EAAE;QACrC,IAAI,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;QACtB,IAAI,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACpD,KAAK,GAAG;gBACP,GAAG,GAAG,CAAC,KAAK;gBACZ,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,SAAS,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE;aACrF,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IAAA,CACb;IAEO,YAAY,CAAC,QAAmB,EAAE,GAAmB,EAAgB;QAC5E,OAAO;YACN,YAAY,EAAE,GAAG,CAAC,YAAY;YAC9B,QAAQ;YACR,KAAK,EAAE,GAAG,CAAC,KAAK;SAChB,CAAC;IAAA,CACF;IAEO,eAAe,CAAC,KAA8B,EAAE,GAAmB,EAAmB;QAC7F,OAAO;YACN,KAAK;YACL,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,+EAA+E;YAC/E,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YACjC,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;SACxC,CAAC;IAAA,CACF;IAED,KAAK,CAAC,CAAC,GAAG,CAAC,QAAmB,EAAE,WAAoB,EAAE,GAAmB,EAAE,MAAoB,EAAE;QAChG,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjD,MAAM,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAE5C,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,SAAS,CAAC,WAAqC,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;YAC9F,MAAM,EAAE,CAAC;QACV,CAAC;IAAA,CACD;IAED,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAmB,EAAE,GAAmB,EAAE,MAAoB,EAAE;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjD,MAAM,EAAE,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAE5C,IAAI,KAAK,EAAE,MAAM,EAAE,IAAI,iBAAiB,CAAC,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC;YAC/D,MAAM,EAAE,CAAC;QACV,CAAC;IAAA,CACD;CACD","sourcesContent":["import {\n\ttype AgentContext,\n\ttype AgentLoopConfig,\n\tagentLoop,\n\tagentLoopContinue,\n\ttype Message,\n\ttype UserMessage,\n} from \"@mariozechner/pi-ai\";\nimport type { AgentRunConfig, AgentTransport } from \"./types.js\";\n\nexport interface ProviderTransportOptions {\n\t/**\n\t * Function to retrieve API key for a given provider.\n\t * If not provided, transport will try to use environment variables.\n\t */\n\tgetApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;\n\n\t/**\n\t * Optional CORS proxy URL for browser environments.\n\t * If provided, all requests will be routed through this proxy.\n\t * Format: \"https://proxy.example.com\"\n\t */\n\tcorsProxyUrl?: string;\n}\n\n/**\n * Transport that calls LLM providers directly.\n * Optionally routes calls through a CORS proxy if configured.\n */\nexport class ProviderTransport implements AgentTransport {\n\tprivate options: ProviderTransportOptions;\n\n\tconstructor(options: ProviderTransportOptions = {}) {\n\t\tthis.options = options;\n\t}\n\n\tprivate getModel(cfg: AgentRunConfig) {\n\t\tlet model = cfg.model;\n\t\tif (this.options.corsProxyUrl && cfg.model.baseUrl) {\n\t\t\tmodel = {\n\t\t\t\t...cfg.model,\n\t\t\t\tbaseUrl: `${this.options.corsProxyUrl}/?url=${encodeURIComponent(cfg.model.baseUrl)}`,\n\t\t\t};\n\t\t}\n\t\treturn model;\n\t}\n\n\tprivate buildContext(messages: Message[], cfg: AgentRunConfig): AgentContext {\n\t\treturn {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\t}\n\n\tprivate buildLoopConfig(model: AgentRunConfig[\"model\"], cfg: AgentRunConfig): AgentLoopConfig {\n\t\treturn {\n\t\t\tmodel,\n\t\t\treasoning: cfg.reasoning,\n\t\t\t// Resolve API key per assistant response (important for expiring OAuth tokens)\n\t\t\tgetApiKey: this.options.getApiKey,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\t}\n\n\tasync *run(messages: Message[], userMessage: Message, cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst model = this.getModel(cfg);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(model, cfg);\n\n\t\tfor await (const ev of agentLoop(userMessage as unknown as UserMessage, context, pc, signal)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n\n\tasync *continue(messages: Message[], cfg: AgentRunConfig, signal?: AbortSignal) {\n\t\tconst model = this.getModel(cfg);\n\t\tconst context = this.buildContext(messages, cfg);\n\t\tconst pc = this.buildLoopConfig(model, cfg);\n\n\t\tfor await (const ev of agentLoopContinue(context, pc, signal)) {\n\t\t\tyield ev;\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { AppTransport, type AppTransportOptions } from "./AppTransport.js";
|
|
2
|
-
export { ProviderTransport, type ProviderTransportOptions } from "./ProviderTransport.js";
|
|
3
|
-
export type { ProxyAssistantMessageEvent } from "./proxy-types.js";
|
|
4
|
-
export type { AgentRunConfig, AgentTransport } from "./types.js";
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAC1F,YAAY,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AACnE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC","sourcesContent":["export { AppTransport, type AppTransportOptions } from \"./AppTransport.js\";\nexport { ProviderTransport, type ProviderTransportOptions } from \"./ProviderTransport.js\";\nexport type { ProxyAssistantMessageEvent } from \"./proxy-types.js\";\nexport type { AgentRunConfig, AgentTransport } from \"./types.js\";\n"]}
|
package/dist/transports/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transports/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA4B,MAAM,mBAAmB,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAiC,MAAM,wBAAwB,CAAC","sourcesContent":["export { AppTransport, type AppTransportOptions } from \"./AppTransport.js\";\nexport { ProviderTransport, type ProviderTransportOptions } from \"./ProviderTransport.js\";\nexport type { ProxyAssistantMessageEvent } from \"./proxy-types.js\";\nexport type { AgentRunConfig, AgentTransport } from \"./types.js\";\n"]}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { StopReason, Usage } from "@mariozechner/pi-ai";
|
|
2
|
-
/**
|
|
3
|
-
* Event types emitted by the proxy server.
|
|
4
|
-
* The server strips the `partial` field from delta events to reduce bandwidth.
|
|
5
|
-
* Clients reconstruct the partial message from these events.
|
|
6
|
-
*/
|
|
7
|
-
export type ProxyAssistantMessageEvent = {
|
|
8
|
-
type: "start";
|
|
9
|
-
} | {
|
|
10
|
-
type: "text_start";
|
|
11
|
-
contentIndex: number;
|
|
12
|
-
} | {
|
|
13
|
-
type: "text_delta";
|
|
14
|
-
contentIndex: number;
|
|
15
|
-
delta: string;
|
|
16
|
-
} | {
|
|
17
|
-
type: "text_end";
|
|
18
|
-
contentIndex: number;
|
|
19
|
-
contentSignature?: string;
|
|
20
|
-
} | {
|
|
21
|
-
type: "thinking_start";
|
|
22
|
-
contentIndex: number;
|
|
23
|
-
} | {
|
|
24
|
-
type: "thinking_delta";
|
|
25
|
-
contentIndex: number;
|
|
26
|
-
delta: string;
|
|
27
|
-
} | {
|
|
28
|
-
type: "thinking_end";
|
|
29
|
-
contentIndex: number;
|
|
30
|
-
contentSignature?: string;
|
|
31
|
-
} | {
|
|
32
|
-
type: "toolcall_start";
|
|
33
|
-
contentIndex: number;
|
|
34
|
-
id: string;
|
|
35
|
-
toolName: string;
|
|
36
|
-
} | {
|
|
37
|
-
type: "toolcall_delta";
|
|
38
|
-
contentIndex: number;
|
|
39
|
-
delta: string;
|
|
40
|
-
} | {
|
|
41
|
-
type: "toolcall_end";
|
|
42
|
-
contentIndex: number;
|
|
43
|
-
} | {
|
|
44
|
-
type: "done";
|
|
45
|
-
reason: Extract<StopReason, "stop" | "length" | "toolUse">;
|
|
46
|
-
usage: Usage;
|
|
47
|
-
} | {
|
|
48
|
-
type: "error";
|
|
49
|
-
reason: Extract<StopReason, "aborted" | "error">;
|
|
50
|
-
errorMessage: string;
|
|
51
|
-
usage: Usage;
|
|
52
|
-
};
|
|
53
|
-
//# sourceMappingURL=proxy-types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"proxy-types.d.ts","sourceRoot":"","sources":["../../src/transports/proxy-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE7D;;;;GAIG;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;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC1F;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC","sourcesContent":["import type { StopReason, Usage } from \"@mariozechner/pi-ai\";\n\n/**\n * Event types emitted by the proxy server.\n * The server strips the `partial` field from delta events to reduce bandwidth.\n * Clients reconstruct the partial message from these events.\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| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; usage: Usage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; errorMessage: string; usage: Usage };\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"proxy-types.js","sourceRoot":"","sources":["../../src/transports/proxy-types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StopReason, Usage } from \"@mariozechner/pi-ai\";\n\n/**\n * Event types emitted by the proxy server.\n * The server strips the `partial` field from delta events to reduce bandwidth.\n * Clients reconstruct the partial message from these events.\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| { type: \"done\"; reason: Extract<StopReason, \"stop\" | \"length\" | \"toolUse\">; usage: Usage }\n\t| { type: \"error\"; reason: Extract<StopReason, \"aborted\" | \"error\">; errorMessage: string; usage: Usage };\n"]}
|