@mariozechner/pi-agent-core 0.12.14 → 0.13.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/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,OAAO,EAA8B,MAAM,qBAAqB,CAAC;AAE7F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiDhG,MAAM,WAAW,YAAY;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,cAAc,CAAC;IAE1B,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAEhF,SAAS,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;CACpC;AAED,qBAAa,KAAK;IACjB,OAAO,CAAC,MAAM,CAUZ;IACF,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,kBAAkB,CAA6D;IACvF,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,oBAAoB,CAAC,CAAa;IAE1C,YAAY,IAAI,EAAE,YAAY,EAK7B;IAED,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAGjD;IAGD,eAAe,CAAC,CAAC,EAAE,MAAM,QAExB;IAED,QAAQ,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,QAEnC;IAED,gBAAgB,CAAC,CAAC,EAAE,aAAa,QAEhC;IAED,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,QAEzC;IAED,YAAY,IAAI,KAAK,GAAG,eAAe,CAEtC;IAED,QAAQ,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,QAEnC;IAED,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,QAE/B;IAED,aAAa,CAAC,CAAC,EAAE,UAAU,QAE1B;IAEK,YAAY,CAAC,CAAC,EAAE,UAAU,iBAO/B;IAED,iBAAiB,SAEhB;IAED,aAAa,SAEZ;IAED,KAAK,SAEJ;IAED;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED;;OAEG;IACH,KAAK,SAOJ;IAEK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,EAAE,iBAuLrD;IAED,OAAO,CAAC,IAAI;CAKZ","sourcesContent":["import type { ImageContent, Message, QueuedMessage, TextContent } from \"@mariozechner/pi-ai\";\nimport { getModel } from \"@mariozechner/pi-ai\";\nimport type { AgentTransport } from \"./transports/types.js\";\nimport type { AgentEvent, AgentState, AppMessage, Attachment, ThinkingLevel } from \"./types.js\";\n\n/**\n * Default message transformer: Keep only LLM-compatible messages, strip app-specific fields.\n * Converts attachments to proper content blocks (images → ImageContent, documents → TextContent).\n */\nfunction defaultMessageTransformer(messages: AppMessage[]): Message[] {\n\treturn messages\n\t\t.filter((m) => {\n\t\t\t// Only keep standard LLM message roles\n\t\t\treturn m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\";\n\t\t})\n\t\t.map((m) => {\n\t\t\tif (m.role === \"user\") {\n\t\t\t\tconst { attachments, ...rest } = m as any;\n\n\t\t\t\t// If no attachments, return as-is\n\t\t\t\tif (!attachments || attachments.length === 0) {\n\t\t\t\t\treturn rest as Message;\n\t\t\t\t}\n\n\t\t\t\t// Convert attachments to content blocks\n\t\t\t\tconst content = Array.isArray(rest.content) ? [...rest.content] : [{ type: \"text\", text: rest.content }];\n\n\t\t\t\tfor (const attachment of attachments as Attachment[]) {\n\t\t\t\t\t// Add image blocks for image attachments\n\t\t\t\t\tif (attachment.type === \"image\") {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tdata: attachment.content,\n\t\t\t\t\t\t\tmimeType: attachment.mimeType,\n\t\t\t\t\t\t} as ImageContent);\n\t\t\t\t\t}\n\t\t\t\t\t// Add text blocks for documents with extracted text\n\t\t\t\t\telse if (attachment.type === \"document\" && attachment.extractedText) {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `\\n\\n[Document: ${attachment.fileName}]\\n${attachment.extractedText}`,\n\t\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t\t} as TextContent);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn { ...rest, content } as Message;\n\t\t\t}\n\t\t\treturn m as Message;\n\t\t});\n}\n\nexport interface AgentOptions {\n\tinitialState?: Partial<AgentState>;\n\ttransport: AgentTransport;\n\t// Transform app messages to LLM-compatible messages before sending to transport\n\tmessageTransformer?: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\t// Queue mode: \"all\" = send all queued messages at once, \"one-at-a-time\" = send one queued message per turn\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n}\n\nexport class Agent {\n\tprivate _state: AgentState = {\n\t\tsystemPrompt: \"\",\n\t\tmodel: getModel(\"google\", \"gemini-2.5-flash-lite-preview-06-17\"),\n\t\tthinkingLevel: \"off\",\n\t\ttools: [],\n\t\tmessages: [],\n\t\tisStreaming: false,\n\t\tstreamMessage: null,\n\t\tpendingToolCalls: new Set<string>(),\n\t\terror: undefined,\n\t};\n\tprivate listeners = new Set<(e: AgentEvent) => void>();\n\tprivate abortController?: AbortController;\n\tprivate transport: AgentTransport;\n\tprivate messageTransformer: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\tprivate messageQueue: Array<QueuedMessage<AppMessage>> = [];\n\tprivate queueMode: \"all\" | \"one-at-a-time\";\n\tprivate runningPrompt?: Promise<void>;\n\tprivate resolveRunningPrompt?: () => void;\n\n\tconstructor(opts: AgentOptions) {\n\t\tthis._state = { ...this._state, ...opts.initialState };\n\t\tthis.transport = opts.transport;\n\t\tthis.messageTransformer = opts.messageTransformer || defaultMessageTransformer;\n\t\tthis.queueMode = opts.queueMode || \"one-at-a-time\";\n\t}\n\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\tsubscribe(fn: (e: AgentEvent) => void): () => void {\n\t\tthis.listeners.add(fn);\n\t\treturn () => this.listeners.delete(fn);\n\t}\n\n\t// State mutators - update internal state without emitting events\n\tsetSystemPrompt(v: string) {\n\t\tthis._state.systemPrompt = v;\n\t}\n\n\tsetModel(m: typeof this._state.model) {\n\t\tthis._state.model = m;\n\t}\n\n\tsetThinkingLevel(l: ThinkingLevel) {\n\t\tthis._state.thinkingLevel = l;\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\") {\n\t\tthis.queueMode = mode;\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.queueMode;\n\t}\n\n\tsetTools(t: typeof this._state.tools) {\n\t\tthis._state.tools = t;\n\t}\n\n\treplaceMessages(ms: AppMessage[]) {\n\t\tthis._state.messages = ms.slice();\n\t}\n\n\tappendMessage(m: AppMessage) {\n\t\tthis._state.messages = [...this._state.messages, m];\n\t}\n\n\tasync queueMessage(m: AppMessage) {\n\t\t// Transform message and queue it for injection at next turn\n\t\tconst transformed = await this.messageTransformer([m]);\n\t\tthis.messageQueue.push({\n\t\t\toriginal: m,\n\t\t\tllm: transformed[0], // undefined if filtered out\n\t\t});\n\t}\n\n\tclearMessageQueue() {\n\t\tthis.messageQueue = [];\n\t}\n\n\tclearMessages() {\n\t\tthis._state.messages = [];\n\t}\n\n\tabort() {\n\t\tthis.abortController?.abort();\n\t}\n\n\t/**\n\t * Returns a promise that resolves when the current prompt completes.\n\t * Returns immediately resolved promise if no prompt is running.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.runningPrompt ?? Promise.resolve();\n\t}\n\n\t/**\n\t * Clear all messages and state. Call abort() first if a prompt is in flight.\n\t */\n\treset() {\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.error = undefined;\n\t\tthis.messageQueue = [];\n\t}\n\n\tasync prompt(input: string, attachments?: Attachment[]) {\n\t\tconst model = this._state.model;\n\t\tif (!model) {\n\t\t\tthrow new Error(\"No model configured\");\n\t\t}\n\n\t\t// Set up running prompt tracking\n\t\tthis.runningPrompt = new Promise<void>((resolve) => {\n\t\t\tthis.resolveRunningPrompt = resolve;\n\t\t});\n\n\t\t// Build user message with attachments\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (attachments?.length) {\n\t\t\tfor (const a of attachments) {\n\t\t\t\tif (a.type === \"image\") {\n\t\t\t\t\tcontent.push({ type: \"image\", data: a.content, mimeType: a.mimeType });\n\t\t\t\t} else if (a.type === \"document\" && a.extractedText) {\n\t\t\t\t\tcontent.push({\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `\\n\\n[Document: ${a.fileName}]\\n${a.extractedText}`,\n\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t} as TextContent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst userMessage: AppMessage = {\n\t\t\trole: \"user\",\n\t\t\tcontent,\n\t\t\tattachments: attachments?.length ? attachments : undefined,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tthis.abortController = new AbortController();\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.error = undefined;\n\n\t\tconst reasoning =\n\t\t\tthis._state.thinkingLevel === \"off\"\n\t\t\t\t? undefined\n\t\t\t\t: this._state.thinkingLevel === \"minimal\"\n\t\t\t\t\t? \"low\"\n\t\t\t\t\t: this._state.thinkingLevel;\n\n\t\tconst cfg = {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\ttools: this._state.tools,\n\t\t\tmodel,\n\t\t\treasoning,\n\t\t\tgetQueuedMessages: async <T>() => {\n\t\t\t\t// Return queued messages based on queue mode\n\t\t\t\tif (this.queueMode === \"one-at-a-time\") {\n\t\t\t\t\t// Return only first message\n\t\t\t\t\tif (this.messageQueue.length > 0) {\n\t\t\t\t\t\tconst first = this.messageQueue[0];\n\t\t\t\t\t\tthis.messageQueue = this.messageQueue.slice(1);\n\t\t\t\t\t\treturn [first] as QueuedMessage<T>[];\n\t\t\t\t\t}\n\t\t\t\t\treturn [];\n\t\t\t\t} else {\n\t\t\t\t\t// Return all queued messages at once\n\t\t\t\t\tconst queued = this.messageQueue.slice();\n\t\t\t\t\tthis.messageQueue = [];\n\t\t\t\t\treturn queued as QueuedMessage<T>[];\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\t// Track all messages generated in this prompt\n\t\tconst generatedMessages: AppMessage[] = [];\n\n\t\ttry {\n\t\t\tlet partial: Message | null = null;\n\n\t\t\t// Transform app messages to LLM-compatible messages (initial set)\n\t\t\tconst llmMessages = await this.messageTransformer(this._state.messages);\n\n\t\t\tfor await (const ev of this.transport.run(\n\t\t\t\tllmMessages,\n\t\t\t\tuserMessage as Message,\n\t\t\t\tcfg,\n\t\t\t\tthis.abortController.signal,\n\t\t\t)) {\n\t\t\t\t// Pass through all events directly\n\t\t\t\tthis.emit(ev as AgentEvent);\n\n\t\t\t\t// Update internal state as needed\n\t\t\t\tswitch (ev.type) {\n\t\t\t\t\tcase \"message_start\": {\n\t\t\t\t\t\t// Track streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_update\": {\n\t\t\t\t\t\t// Update streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_end\": {\n\t\t\t\t\t\t// Add completed message to state\n\t\t\t\t\t\tpartial = null;\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tthis.appendMessage(ev.message as AppMessage);\n\t\t\t\t\t\tgeneratedMessages.push(ev.message as AppMessage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_start\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.add(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_end\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.delete(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"turn_end\": {\n\t\t\t\t\t\t// Capture error from turn_end event\n\t\t\t\t\t\tif (ev.message.role === \"assistant\" && ev.message.errorMessage) {\n\t\t\t\t\t\t\tthis._state.error = ev.message.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"agent_end\": {\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle any remaining partial message\n\t\t\tif (partial && partial.role === \"assistant\" && partial.content.length > 0) {\n\t\t\t\tconst onlyEmpty = !partial.content.some(\n\t\t\t\t\t(c) =>\n\t\t\t\t\t\t(c.type === \"thinking\" && c.thinking.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"text\" && c.text.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"toolCall\" && c.name.trim().length > 0),\n\t\t\t\t);\n\t\t\t\tif (!onlyEmpty) {\n\t\t\t\t\tthis.appendMessage(partial as AppMessage);\n\t\t\t\t\tgeneratedMessages.push(partial as AppMessage);\n\t\t\t\t} else {\n\t\t\t\t\tif (this.abortController?.signal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\tconst msg: Message = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: [{ type: \"text\", text: \"\" }],\n\t\t\t\tapi: model.api,\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tusage: {\n\t\t\t\t\tinput: 0,\n\t\t\t\t\toutput: 0,\n\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t},\n\t\t\t\tstopReason: this.abortController?.signal.aborted ? \"aborted\" : \"error\",\n\t\t\t\terrorMessage: err?.message || String(err),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis.appendMessage(msg as AppMessage);\n\t\t\tgeneratedMessages.push(msg as AppMessage);\n\t\t\tthis._state.error = err?.message || String(err);\n\t\t} finally {\n\t\t\tthis._state.isStreaming = false;\n\t\t\tthis._state.streamMessage = null;\n\t\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\t\tthis.abortController = undefined;\n\t\t\tthis.resolveRunningPrompt?.();\n\t\t\tthis.runningPrompt = undefined;\n\t\t\tthis.resolveRunningPrompt = undefined;\n\t\t}\n\t}\n\n\tprivate emit(e: AgentEvent) {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener(e);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,OAAO,EAA8B,MAAM,qBAAqB,CAAC;AAE7F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAiDhG,MAAM,WAAW,YAAY;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,cAAc,CAAC;IAE1B,kBAAkB,CAAC,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAEhF,SAAS,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;CACpC;AAED,qBAAa,KAAK;IACjB,OAAO,CAAC,MAAM,CAUZ;IACF,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,kBAAkB,CAA6D;IACvF,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,oBAAoB,CAAC,CAAa;IAE1C,YAAY,IAAI,EAAE,YAAY,EAK7B;IAED,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAGjD;IAGD,eAAe,CAAC,CAAC,EAAE,MAAM,QAExB;IAED,QAAQ,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,QAEnC;IAED,gBAAgB,CAAC,CAAC,EAAE,aAAa,QAEhC;IAED,YAAY,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe,QAEzC;IAED,YAAY,IAAI,KAAK,GAAG,eAAe,CAEtC;IAED,QAAQ,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,QAEnC;IAED,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,QAE/B;IAED,aAAa,CAAC,CAAC,EAAE,UAAU,QAE1B;IAEK,YAAY,CAAC,CAAC,EAAE,UAAU,iBAO/B;IAED,iBAAiB,SAEhB;IAED,aAAa,SAEZ;IAED,KAAK,SAEJ;IAED;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED;;OAEG;IACH,KAAK,SAOJ;IAEK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,EAAE,iBAwLrD;IAED,OAAO,CAAC,IAAI;CAKZ","sourcesContent":["import type { ImageContent, Message, QueuedMessage, TextContent } from \"@mariozechner/pi-ai\";\nimport { getModel } from \"@mariozechner/pi-ai\";\nimport type { AgentTransport } from \"./transports/types.js\";\nimport type { AgentEvent, AgentState, AppMessage, Attachment, ThinkingLevel } from \"./types.js\";\n\n/**\n * Default message transformer: Keep only LLM-compatible messages, strip app-specific fields.\n * Converts attachments to proper content blocks (images → ImageContent, documents → TextContent).\n */\nfunction defaultMessageTransformer(messages: AppMessage[]): Message[] {\n\treturn messages\n\t\t.filter((m) => {\n\t\t\t// Only keep standard LLM message roles\n\t\t\treturn m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\";\n\t\t})\n\t\t.map((m) => {\n\t\t\tif (m.role === \"user\") {\n\t\t\t\tconst { attachments, ...rest } = m as any;\n\n\t\t\t\t// If no attachments, return as-is\n\t\t\t\tif (!attachments || attachments.length === 0) {\n\t\t\t\t\treturn rest as Message;\n\t\t\t\t}\n\n\t\t\t\t// Convert attachments to content blocks\n\t\t\t\tconst content = Array.isArray(rest.content) ? [...rest.content] : [{ type: \"text\", text: rest.content }];\n\n\t\t\t\tfor (const attachment of attachments as Attachment[]) {\n\t\t\t\t\t// Add image blocks for image attachments\n\t\t\t\t\tif (attachment.type === \"image\") {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tdata: attachment.content,\n\t\t\t\t\t\t\tmimeType: attachment.mimeType,\n\t\t\t\t\t\t} as ImageContent);\n\t\t\t\t\t}\n\t\t\t\t\t// Add text blocks for documents with extracted text\n\t\t\t\t\telse if (attachment.type === \"document\" && attachment.extractedText) {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `\\n\\n[Document: ${attachment.fileName}]\\n${attachment.extractedText}`,\n\t\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t\t} as TextContent);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn { ...rest, content } as Message;\n\t\t\t}\n\t\t\treturn m as Message;\n\t\t});\n}\n\nexport interface AgentOptions {\n\tinitialState?: Partial<AgentState>;\n\ttransport: AgentTransport;\n\t// Transform app messages to LLM-compatible messages before sending to transport\n\tmessageTransformer?: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\t// Queue mode: \"all\" = send all queued messages at once, \"one-at-a-time\" = send one queued message per turn\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n}\n\nexport class Agent {\n\tprivate _state: AgentState = {\n\t\tsystemPrompt: \"\",\n\t\tmodel: getModel(\"google\", \"gemini-2.5-flash-lite-preview-06-17\"),\n\t\tthinkingLevel: \"off\",\n\t\ttools: [],\n\t\tmessages: [],\n\t\tisStreaming: false,\n\t\tstreamMessage: null,\n\t\tpendingToolCalls: new Set<string>(),\n\t\terror: undefined,\n\t};\n\tprivate listeners = new Set<(e: AgentEvent) => void>();\n\tprivate abortController?: AbortController;\n\tprivate transport: AgentTransport;\n\tprivate messageTransformer: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\tprivate messageQueue: Array<QueuedMessage<AppMessage>> = [];\n\tprivate queueMode: \"all\" | \"one-at-a-time\";\n\tprivate runningPrompt?: Promise<void>;\n\tprivate resolveRunningPrompt?: () => void;\n\n\tconstructor(opts: AgentOptions) {\n\t\tthis._state = { ...this._state, ...opts.initialState };\n\t\tthis.transport = opts.transport;\n\t\tthis.messageTransformer = opts.messageTransformer || defaultMessageTransformer;\n\t\tthis.queueMode = opts.queueMode || \"one-at-a-time\";\n\t}\n\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\tsubscribe(fn: (e: AgentEvent) => void): () => void {\n\t\tthis.listeners.add(fn);\n\t\treturn () => this.listeners.delete(fn);\n\t}\n\n\t// State mutators - update internal state without emitting events\n\tsetSystemPrompt(v: string) {\n\t\tthis._state.systemPrompt = v;\n\t}\n\n\tsetModel(m: typeof this._state.model) {\n\t\tthis._state.model = m;\n\t}\n\n\tsetThinkingLevel(l: ThinkingLevel) {\n\t\tthis._state.thinkingLevel = l;\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\") {\n\t\tthis.queueMode = mode;\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.queueMode;\n\t}\n\n\tsetTools(t: typeof this._state.tools) {\n\t\tthis._state.tools = t;\n\t}\n\n\treplaceMessages(ms: AppMessage[]) {\n\t\tthis._state.messages = ms.slice();\n\t}\n\n\tappendMessage(m: AppMessage) {\n\t\tthis._state.messages = [...this._state.messages, m];\n\t}\n\n\tasync queueMessage(m: AppMessage) {\n\t\t// Transform message and queue it for injection at next turn\n\t\tconst transformed = await this.messageTransformer([m]);\n\t\tthis.messageQueue.push({\n\t\t\toriginal: m,\n\t\t\tllm: transformed[0], // undefined if filtered out\n\t\t});\n\t}\n\n\tclearMessageQueue() {\n\t\tthis.messageQueue = [];\n\t}\n\n\tclearMessages() {\n\t\tthis._state.messages = [];\n\t}\n\n\tabort() {\n\t\tthis.abortController?.abort();\n\t}\n\n\t/**\n\t * Returns a promise that resolves when the current prompt completes.\n\t * Returns immediately resolved promise if no prompt is running.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.runningPrompt ?? Promise.resolve();\n\t}\n\n\t/**\n\t * Clear all messages and state. Call abort() first if a prompt is in flight.\n\t */\n\treset() {\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.error = undefined;\n\t\tthis.messageQueue = [];\n\t}\n\n\tasync prompt(input: string, attachments?: Attachment[]) {\n\t\tconst model = this._state.model;\n\t\tif (!model) {\n\t\t\tthrow new Error(\"No model configured\");\n\t\t}\n\n\t\t// Set up running prompt tracking\n\t\tthis.runningPrompt = new Promise<void>((resolve) => {\n\t\t\tthis.resolveRunningPrompt = resolve;\n\t\t});\n\n\t\t// Build user message with attachments\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (attachments?.length) {\n\t\t\tfor (const a of attachments) {\n\t\t\t\tif (a.type === \"image\") {\n\t\t\t\t\tcontent.push({ type: \"image\", data: a.content, mimeType: a.mimeType });\n\t\t\t\t} else if (a.type === \"document\" && a.extractedText) {\n\t\t\t\t\tcontent.push({\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `\\n\\n[Document: ${a.fileName}]\\n${a.extractedText}`,\n\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t} as TextContent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst userMessage: AppMessage = {\n\t\t\trole: \"user\",\n\t\t\tcontent,\n\t\t\tattachments: attachments?.length ? attachments : undefined,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tthis.abortController = new AbortController();\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.error = undefined;\n\n\t\tconst reasoning =\n\t\t\tthis._state.thinkingLevel === \"off\"\n\t\t\t\t? undefined\n\t\t\t\t: this._state.thinkingLevel === \"minimal\"\n\t\t\t\t\t? \"low\"\n\t\t\t\t\t: this._state.thinkingLevel;\n\n\t\tconst cfg = {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\ttools: this._state.tools,\n\t\t\tmodel,\n\t\t\treasoning,\n\t\t\tgetQueuedMessages: async <T>() => {\n\t\t\t\t// Return queued messages based on queue mode\n\t\t\t\tif (this.queueMode === \"one-at-a-time\") {\n\t\t\t\t\t// Return only first message\n\t\t\t\t\tif (this.messageQueue.length > 0) {\n\t\t\t\t\t\tconst first = this.messageQueue[0];\n\t\t\t\t\t\tthis.messageQueue = this.messageQueue.slice(1);\n\t\t\t\t\t\treturn [first] as QueuedMessage<T>[];\n\t\t\t\t\t}\n\t\t\t\t\treturn [];\n\t\t\t\t} else {\n\t\t\t\t\t// Return all queued messages at once\n\t\t\t\t\tconst queued = this.messageQueue.slice();\n\t\t\t\t\tthis.messageQueue = [];\n\t\t\t\t\treturn queued as QueuedMessage<T>[];\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\t// Track all messages generated in this prompt\n\t\tconst generatedMessages: AppMessage[] = [];\n\n\t\ttry {\n\t\t\tlet partial: Message | null = null;\n\n\t\t\t// Transform app messages to LLM-compatible messages (initial set)\n\t\t\tconst llmMessages = await this.messageTransformer(this._state.messages);\n\n\t\t\tfor await (const ev of this.transport.run(\n\t\t\t\tllmMessages,\n\t\t\t\tuserMessage as Message,\n\t\t\t\tcfg,\n\t\t\t\tthis.abortController.signal,\n\t\t\t)) {\n\t\t\t\t// Pass through all events directly\n\t\t\t\tthis.emit(ev as AgentEvent);\n\n\t\t\t\t// Update internal state as needed\n\t\t\t\tswitch (ev.type) {\n\t\t\t\t\tcase \"message_start\": {\n\t\t\t\t\t\t// Track streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_update\": {\n\t\t\t\t\t\t// Update streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_end\": {\n\t\t\t\t\t\t// Add completed message to state\n\t\t\t\t\t\tpartial = null;\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tthis.appendMessage(ev.message as AppMessage);\n\t\t\t\t\t\tgeneratedMessages.push(ev.message as AppMessage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_start\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.add(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_end\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.delete(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"turn_end\": {\n\t\t\t\t\t\t// Capture error from turn_end event\n\t\t\t\t\t\tif (ev.message.role === \"assistant\" && ev.message.errorMessage) {\n\t\t\t\t\t\t\tthis._state.error = ev.message.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"agent_end\": {\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle any remaining partial message\n\t\t\tif (partial && partial.role === \"assistant\" && partial.content.length > 0) {\n\t\t\t\tconst onlyEmpty = !partial.content.some(\n\t\t\t\t\t(c) =>\n\t\t\t\t\t\t(c.type === \"thinking\" && c.thinking.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"text\" && c.text.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"toolCall\" && c.name.trim().length > 0),\n\t\t\t\t);\n\t\t\t\tif (!onlyEmpty) {\n\t\t\t\t\tthis.appendMessage(partial as AppMessage);\n\t\t\t\t\tgeneratedMessages.push(partial as AppMessage);\n\t\t\t\t} else {\n\t\t\t\t\tif (this.abortController?.signal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\tconst msg: Message = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: [{ type: \"text\", text: \"\" }],\n\t\t\t\tapi: model.api,\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tusage: {\n\t\t\t\t\tinput: 0,\n\t\t\t\t\toutput: 0,\n\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t},\n\t\t\t\tstopReason: this.abortController?.signal.aborted ? \"aborted\" : \"error\",\n\t\t\t\terrorMessage: err?.message || String(err),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis.appendMessage(msg as AppMessage);\n\t\t\tgeneratedMessages.push(msg as AppMessage);\n\t\t\tthis._state.error = err?.message || String(err);\n\t\t} finally {\n\t\t\tthis._state.isStreaming = false;\n\t\t\tthis._state.streamMessage = null;\n\t\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\t\tthis.abortController = undefined;\n\t\t\tthis.resolveRunningPrompt?.();\n\t\t\tthis.runningPrompt = undefined;\n\t\t\tthis.resolveRunningPrompt = undefined;\n\t\t}\n\t}\n\n\tprivate emit(e: AgentEvent) {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener(e);\n\t\t}\n\t}\n}\n"]}
|
package/dist/agent.js
CHANGED
package/dist/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, Message, QueuedMessage, TextContent } from \"@mariozechner/pi-ai\";\nimport { getModel } from \"@mariozechner/pi-ai\";\nimport type { AgentTransport } from \"./transports/types.js\";\nimport type { AgentEvent, AgentState, AppMessage, Attachment, ThinkingLevel } from \"./types.js\";\n\n/**\n * Default message transformer: Keep only LLM-compatible messages, strip app-specific fields.\n * Converts attachments to proper content blocks (images → ImageContent, documents → TextContent).\n */\nfunction defaultMessageTransformer(messages: AppMessage[]): Message[] {\n\treturn messages\n\t\t.filter((m) => {\n\t\t\t// Only keep standard LLM message roles\n\t\t\treturn m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\";\n\t\t})\n\t\t.map((m) => {\n\t\t\tif (m.role === \"user\") {\n\t\t\t\tconst { attachments, ...rest } = m as any;\n\n\t\t\t\t// If no attachments, return as-is\n\t\t\t\tif (!attachments || attachments.length === 0) {\n\t\t\t\t\treturn rest as Message;\n\t\t\t\t}\n\n\t\t\t\t// Convert attachments to content blocks\n\t\t\t\tconst content = Array.isArray(rest.content) ? [...rest.content] : [{ type: \"text\", text: rest.content }];\n\n\t\t\t\tfor (const attachment of attachments as Attachment[]) {\n\t\t\t\t\t// Add image blocks for image attachments\n\t\t\t\t\tif (attachment.type === \"image\") {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tdata: attachment.content,\n\t\t\t\t\t\t\tmimeType: attachment.mimeType,\n\t\t\t\t\t\t} as ImageContent);\n\t\t\t\t\t}\n\t\t\t\t\t// Add text blocks for documents with extracted text\n\t\t\t\t\telse if (attachment.type === \"document\" && attachment.extractedText) {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `\\n\\n[Document: ${attachment.fileName}]\\n${attachment.extractedText}`,\n\t\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t\t} as TextContent);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn { ...rest, content } as Message;\n\t\t\t}\n\t\t\treturn m as Message;\n\t\t});\n}\n\nexport interface AgentOptions {\n\tinitialState?: Partial<AgentState>;\n\ttransport: AgentTransport;\n\t// Transform app messages to LLM-compatible messages before sending to transport\n\tmessageTransformer?: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\t// Queue mode: \"all\" = send all queued messages at once, \"one-at-a-time\" = send one queued message per turn\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n}\n\nexport class Agent {\n\tprivate _state: AgentState = {\n\t\tsystemPrompt: \"\",\n\t\tmodel: getModel(\"google\", \"gemini-2.5-flash-lite-preview-06-17\"),\n\t\tthinkingLevel: \"off\",\n\t\ttools: [],\n\t\tmessages: [],\n\t\tisStreaming: false,\n\t\tstreamMessage: null,\n\t\tpendingToolCalls: new Set<string>(),\n\t\terror: undefined,\n\t};\n\tprivate listeners = new Set<(e: AgentEvent) => void>();\n\tprivate abortController?: AbortController;\n\tprivate transport: AgentTransport;\n\tprivate messageTransformer: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\tprivate messageQueue: Array<QueuedMessage<AppMessage>> = [];\n\tprivate queueMode: \"all\" | \"one-at-a-time\";\n\tprivate runningPrompt?: Promise<void>;\n\tprivate resolveRunningPrompt?: () => void;\n\n\tconstructor(opts: AgentOptions) {\n\t\tthis._state = { ...this._state, ...opts.initialState };\n\t\tthis.transport = opts.transport;\n\t\tthis.messageTransformer = opts.messageTransformer || defaultMessageTransformer;\n\t\tthis.queueMode = opts.queueMode || \"one-at-a-time\";\n\t}\n\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\tsubscribe(fn: (e: AgentEvent) => void): () => void {\n\t\tthis.listeners.add(fn);\n\t\treturn () => this.listeners.delete(fn);\n\t}\n\n\t// State mutators - update internal state without emitting events\n\tsetSystemPrompt(v: string) {\n\t\tthis._state.systemPrompt = v;\n\t}\n\n\tsetModel(m: typeof this._state.model) {\n\t\tthis._state.model = m;\n\t}\n\n\tsetThinkingLevel(l: ThinkingLevel) {\n\t\tthis._state.thinkingLevel = l;\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\") {\n\t\tthis.queueMode = mode;\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.queueMode;\n\t}\n\n\tsetTools(t: typeof this._state.tools) {\n\t\tthis._state.tools = t;\n\t}\n\n\treplaceMessages(ms: AppMessage[]) {\n\t\tthis._state.messages = ms.slice();\n\t}\n\n\tappendMessage(m: AppMessage) {\n\t\tthis._state.messages = [...this._state.messages, m];\n\t}\n\n\tasync queueMessage(m: AppMessage) {\n\t\t// Transform message and queue it for injection at next turn\n\t\tconst transformed = await this.messageTransformer([m]);\n\t\tthis.messageQueue.push({\n\t\t\toriginal: m,\n\t\t\tllm: transformed[0], // undefined if filtered out\n\t\t});\n\t}\n\n\tclearMessageQueue() {\n\t\tthis.messageQueue = [];\n\t}\n\n\tclearMessages() {\n\t\tthis._state.messages = [];\n\t}\n\n\tabort() {\n\t\tthis.abortController?.abort();\n\t}\n\n\t/**\n\t * Returns a promise that resolves when the current prompt completes.\n\t * Returns immediately resolved promise if no prompt is running.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.runningPrompt ?? Promise.resolve();\n\t}\n\n\t/**\n\t * Clear all messages and state. Call abort() first if a prompt is in flight.\n\t */\n\treset() {\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.error = undefined;\n\t\tthis.messageQueue = [];\n\t}\n\n\tasync prompt(input: string, attachments?: Attachment[]) {\n\t\tconst model = this._state.model;\n\t\tif (!model) {\n\t\t\tthrow new Error(\"No model configured\");\n\t\t}\n\n\t\t// Set up running prompt tracking\n\t\tthis.runningPrompt = new Promise<void>((resolve) => {\n\t\t\tthis.resolveRunningPrompt = resolve;\n\t\t});\n\n\t\t// Build user message with attachments\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (attachments?.length) {\n\t\t\tfor (const a of attachments) {\n\t\t\t\tif (a.type === \"image\") {\n\t\t\t\t\tcontent.push({ type: \"image\", data: a.content, mimeType: a.mimeType });\n\t\t\t\t} else if (a.type === \"document\" && a.extractedText) {\n\t\t\t\t\tcontent.push({\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `\\n\\n[Document: ${a.fileName}]\\n${a.extractedText}`,\n\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t} as TextContent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst userMessage: AppMessage = {\n\t\t\trole: \"user\",\n\t\t\tcontent,\n\t\t\tattachments: attachments?.length ? attachments : undefined,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tthis.abortController = new AbortController();\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.error = undefined;\n\n\t\tconst reasoning =\n\t\t\tthis._state.thinkingLevel === \"off\"\n\t\t\t\t? undefined\n\t\t\t\t: this._state.thinkingLevel === \"minimal\"\n\t\t\t\t\t? \"low\"\n\t\t\t\t\t: this._state.thinkingLevel;\n\n\t\tconst cfg = {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\ttools: this._state.tools,\n\t\t\tmodel,\n\t\t\treasoning,\n\t\t\tgetQueuedMessages: async <T>() => {\n\t\t\t\t// Return queued messages based on queue mode\n\t\t\t\tif (this.queueMode === \"one-at-a-time\") {\n\t\t\t\t\t// Return only first message\n\t\t\t\t\tif (this.messageQueue.length > 0) {\n\t\t\t\t\t\tconst first = this.messageQueue[0];\n\t\t\t\t\t\tthis.messageQueue = this.messageQueue.slice(1);\n\t\t\t\t\t\treturn [first] as QueuedMessage<T>[];\n\t\t\t\t\t}\n\t\t\t\t\treturn [];\n\t\t\t\t} else {\n\t\t\t\t\t// Return all queued messages at once\n\t\t\t\t\tconst queued = this.messageQueue.slice();\n\t\t\t\t\tthis.messageQueue = [];\n\t\t\t\t\treturn queued as QueuedMessage<T>[];\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\t// Track all messages generated in this prompt\n\t\tconst generatedMessages: AppMessage[] = [];\n\n\t\ttry {\n\t\t\tlet partial: Message | null = null;\n\n\t\t\t// Transform app messages to LLM-compatible messages (initial set)\n\t\t\tconst llmMessages = await this.messageTransformer(this._state.messages);\n\n\t\t\tfor await (const ev of this.transport.run(\n\t\t\t\tllmMessages,\n\t\t\t\tuserMessage as Message,\n\t\t\t\tcfg,\n\t\t\t\tthis.abortController.signal,\n\t\t\t)) {\n\t\t\t\t// Pass through all events directly\n\t\t\t\tthis.emit(ev as AgentEvent);\n\n\t\t\t\t// Update internal state as needed\n\t\t\t\tswitch (ev.type) {\n\t\t\t\t\tcase \"message_start\": {\n\t\t\t\t\t\t// Track streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_update\": {\n\t\t\t\t\t\t// Update streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_end\": {\n\t\t\t\t\t\t// Add completed message to state\n\t\t\t\t\t\tpartial = null;\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tthis.appendMessage(ev.message as AppMessage);\n\t\t\t\t\t\tgeneratedMessages.push(ev.message as AppMessage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_start\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.add(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_end\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.delete(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"turn_end\": {\n\t\t\t\t\t\t// Capture error from turn_end event\n\t\t\t\t\t\tif (ev.message.role === \"assistant\" && ev.message.errorMessage) {\n\t\t\t\t\t\t\tthis._state.error = ev.message.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"agent_end\": {\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle any remaining partial message\n\t\t\tif (partial && partial.role === \"assistant\" && partial.content.length > 0) {\n\t\t\t\tconst onlyEmpty = !partial.content.some(\n\t\t\t\t\t(c) =>\n\t\t\t\t\t\t(c.type === \"thinking\" && c.thinking.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"text\" && c.text.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"toolCall\" && c.name.trim().length > 0),\n\t\t\t\t);\n\t\t\t\tif (!onlyEmpty) {\n\t\t\t\t\tthis.appendMessage(partial as AppMessage);\n\t\t\t\t\tgeneratedMessages.push(partial as AppMessage);\n\t\t\t\t} else {\n\t\t\t\t\tif (this.abortController?.signal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\tconst msg: Message = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: [{ type: \"text\", text: \"\" }],\n\t\t\t\tapi: model.api,\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tusage: {\n\t\t\t\t\tinput: 0,\n\t\t\t\t\toutput: 0,\n\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t},\n\t\t\t\tstopReason: this.abortController?.signal.aborted ? \"aborted\" : \"error\",\n\t\t\t\terrorMessage: err?.message || String(err),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis.appendMessage(msg as AppMessage);\n\t\t\tgeneratedMessages.push(msg as AppMessage);\n\t\t\tthis._state.error = err?.message || String(err);\n\t\t} finally {\n\t\t\tthis._state.isStreaming = false;\n\t\t\tthis._state.streamMessage = null;\n\t\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\t\tthis.abortController = undefined;\n\t\t\tthis.resolveRunningPrompt?.();\n\t\t\tthis.runningPrompt = undefined;\n\t\t\tthis.resolveRunningPrompt = undefined;\n\t\t}\n\t}\n\n\tprivate emit(e: AgentEvent) {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener(e);\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ImageContent, Message, QueuedMessage, TextContent } from \"@mariozechner/pi-ai\";\nimport { getModel } from \"@mariozechner/pi-ai\";\nimport type { AgentTransport } from \"./transports/types.js\";\nimport type { AgentEvent, AgentState, AppMessage, Attachment, ThinkingLevel } from \"./types.js\";\n\n/**\n * Default message transformer: Keep only LLM-compatible messages, strip app-specific fields.\n * Converts attachments to proper content blocks (images → ImageContent, documents → TextContent).\n */\nfunction defaultMessageTransformer(messages: AppMessage[]): Message[] {\n\treturn messages\n\t\t.filter((m) => {\n\t\t\t// Only keep standard LLM message roles\n\t\t\treturn m.role === \"user\" || m.role === \"assistant\" || m.role === \"toolResult\";\n\t\t})\n\t\t.map((m) => {\n\t\t\tif (m.role === \"user\") {\n\t\t\t\tconst { attachments, ...rest } = m as any;\n\n\t\t\t\t// If no attachments, return as-is\n\t\t\t\tif (!attachments || attachments.length === 0) {\n\t\t\t\t\treturn rest as Message;\n\t\t\t\t}\n\n\t\t\t\t// Convert attachments to content blocks\n\t\t\t\tconst content = Array.isArray(rest.content) ? [...rest.content] : [{ type: \"text\", text: rest.content }];\n\n\t\t\t\tfor (const attachment of attachments as Attachment[]) {\n\t\t\t\t\t// Add image blocks for image attachments\n\t\t\t\t\tif (attachment.type === \"image\") {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"image\",\n\t\t\t\t\t\t\tdata: attachment.content,\n\t\t\t\t\t\t\tmimeType: attachment.mimeType,\n\t\t\t\t\t\t} as ImageContent);\n\t\t\t\t\t}\n\t\t\t\t\t// Add text blocks for documents with extracted text\n\t\t\t\t\telse if (attachment.type === \"document\" && attachment.extractedText) {\n\t\t\t\t\t\tcontent.push({\n\t\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\t\ttext: `\\n\\n[Document: ${attachment.fileName}]\\n${attachment.extractedText}`,\n\t\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t\t} as TextContent);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn { ...rest, content } as Message;\n\t\t\t}\n\t\t\treturn m as Message;\n\t\t});\n}\n\nexport interface AgentOptions {\n\tinitialState?: Partial<AgentState>;\n\ttransport: AgentTransport;\n\t// Transform app messages to LLM-compatible messages before sending to transport\n\tmessageTransformer?: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\t// Queue mode: \"all\" = send all queued messages at once, \"one-at-a-time\" = send one queued message per turn\n\tqueueMode?: \"all\" | \"one-at-a-time\";\n}\n\nexport class Agent {\n\tprivate _state: AgentState = {\n\t\tsystemPrompt: \"\",\n\t\tmodel: getModel(\"google\", \"gemini-2.5-flash-lite-preview-06-17\"),\n\t\tthinkingLevel: \"off\",\n\t\ttools: [],\n\t\tmessages: [],\n\t\tisStreaming: false,\n\t\tstreamMessage: null,\n\t\tpendingToolCalls: new Set<string>(),\n\t\terror: undefined,\n\t};\n\tprivate listeners = new Set<(e: AgentEvent) => void>();\n\tprivate abortController?: AbortController;\n\tprivate transport: AgentTransport;\n\tprivate messageTransformer: (messages: AppMessage[]) => Message[] | Promise<Message[]>;\n\tprivate messageQueue: Array<QueuedMessage<AppMessage>> = [];\n\tprivate queueMode: \"all\" | \"one-at-a-time\";\n\tprivate runningPrompt?: Promise<void>;\n\tprivate resolveRunningPrompt?: () => void;\n\n\tconstructor(opts: AgentOptions) {\n\t\tthis._state = { ...this._state, ...opts.initialState };\n\t\tthis.transport = opts.transport;\n\t\tthis.messageTransformer = opts.messageTransformer || defaultMessageTransformer;\n\t\tthis.queueMode = opts.queueMode || \"one-at-a-time\";\n\t}\n\n\tget state(): AgentState {\n\t\treturn this._state;\n\t}\n\n\tsubscribe(fn: (e: AgentEvent) => void): () => void {\n\t\tthis.listeners.add(fn);\n\t\treturn () => this.listeners.delete(fn);\n\t}\n\n\t// State mutators - update internal state without emitting events\n\tsetSystemPrompt(v: string) {\n\t\tthis._state.systemPrompt = v;\n\t}\n\n\tsetModel(m: typeof this._state.model) {\n\t\tthis._state.model = m;\n\t}\n\n\tsetThinkingLevel(l: ThinkingLevel) {\n\t\tthis._state.thinkingLevel = l;\n\t}\n\n\tsetQueueMode(mode: \"all\" | \"one-at-a-time\") {\n\t\tthis.queueMode = mode;\n\t}\n\n\tgetQueueMode(): \"all\" | \"one-at-a-time\" {\n\t\treturn this.queueMode;\n\t}\n\n\tsetTools(t: typeof this._state.tools) {\n\t\tthis._state.tools = t;\n\t}\n\n\treplaceMessages(ms: AppMessage[]) {\n\t\tthis._state.messages = ms.slice();\n\t}\n\n\tappendMessage(m: AppMessage) {\n\t\tthis._state.messages = [...this._state.messages, m];\n\t}\n\n\tasync queueMessage(m: AppMessage) {\n\t\t// Transform message and queue it for injection at next turn\n\t\tconst transformed = await this.messageTransformer([m]);\n\t\tthis.messageQueue.push({\n\t\t\toriginal: m,\n\t\t\tllm: transformed[0], // undefined if filtered out\n\t\t});\n\t}\n\n\tclearMessageQueue() {\n\t\tthis.messageQueue = [];\n\t}\n\n\tclearMessages() {\n\t\tthis._state.messages = [];\n\t}\n\n\tabort() {\n\t\tthis.abortController?.abort();\n\t}\n\n\t/**\n\t * Returns a promise that resolves when the current prompt completes.\n\t * Returns immediately resolved promise if no prompt is running.\n\t */\n\twaitForIdle(): Promise<void> {\n\t\treturn this.runningPrompt ?? Promise.resolve();\n\t}\n\n\t/**\n\t * Clear all messages and state. Call abort() first if a prompt is in flight.\n\t */\n\treset() {\n\t\tthis._state.messages = [];\n\t\tthis._state.isStreaming = false;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\tthis._state.error = undefined;\n\t\tthis.messageQueue = [];\n\t}\n\n\tasync prompt(input: string, attachments?: Attachment[]) {\n\t\tconst model = this._state.model;\n\t\tif (!model) {\n\t\t\tthrow new Error(\"No model configured\");\n\t\t}\n\n\t\t// Set up running prompt tracking\n\t\tthis.runningPrompt = new Promise<void>((resolve) => {\n\t\t\tthis.resolveRunningPrompt = resolve;\n\t\t});\n\n\t\t// Build user message with attachments\n\t\tconst content: Array<TextContent | ImageContent> = [{ type: \"text\", text: input }];\n\t\tif (attachments?.length) {\n\t\t\tfor (const a of attachments) {\n\t\t\t\tif (a.type === \"image\") {\n\t\t\t\t\tcontent.push({ type: \"image\", data: a.content, mimeType: a.mimeType });\n\t\t\t\t} else if (a.type === \"document\" && a.extractedText) {\n\t\t\t\t\tcontent.push({\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `\\n\\n[Document: ${a.fileName}]\\n${a.extractedText}`,\n\t\t\t\t\t\tisDocument: true,\n\t\t\t\t\t} as TextContent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst userMessage: AppMessage = {\n\t\t\trole: \"user\",\n\t\t\tcontent,\n\t\t\tattachments: attachments?.length ? attachments : undefined,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\tthis.abortController = new AbortController();\n\t\tthis._state.isStreaming = true;\n\t\tthis._state.streamMessage = null;\n\t\tthis._state.error = undefined;\n\n\t\tconst reasoning =\n\t\t\tthis._state.thinkingLevel === \"off\"\n\t\t\t\t? undefined\n\t\t\t\t: this._state.thinkingLevel === \"minimal\"\n\t\t\t\t\t? \"low\"\n\t\t\t\t\t: this._state.thinkingLevel;\n\n\t\tconst cfg = {\n\t\t\tsystemPrompt: this._state.systemPrompt,\n\t\t\ttools: this._state.tools,\n\t\t\tmodel,\n\t\t\treasoning,\n\t\t\tgetQueuedMessages: async <T>() => {\n\t\t\t\t// Return queued messages based on queue mode\n\t\t\t\tif (this.queueMode === \"one-at-a-time\") {\n\t\t\t\t\t// Return only first message\n\t\t\t\t\tif (this.messageQueue.length > 0) {\n\t\t\t\t\t\tconst first = this.messageQueue[0];\n\t\t\t\t\t\tthis.messageQueue = this.messageQueue.slice(1);\n\t\t\t\t\t\treturn [first] as QueuedMessage<T>[];\n\t\t\t\t\t}\n\t\t\t\t\treturn [];\n\t\t\t\t} else {\n\t\t\t\t\t// Return all queued messages at once\n\t\t\t\t\tconst queued = this.messageQueue.slice();\n\t\t\t\t\tthis.messageQueue = [];\n\t\t\t\t\treturn queued as QueuedMessage<T>[];\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\n\t\t// Track all messages generated in this prompt\n\t\tconst generatedMessages: AppMessage[] = [];\n\n\t\ttry {\n\t\t\tlet partial: Message | null = null;\n\n\t\t\t// Transform app messages to LLM-compatible messages (initial set)\n\t\t\tconst llmMessages = await this.messageTransformer(this._state.messages);\n\n\t\t\tfor await (const ev of this.transport.run(\n\t\t\t\tllmMessages,\n\t\t\t\tuserMessage as Message,\n\t\t\t\tcfg,\n\t\t\t\tthis.abortController.signal,\n\t\t\t)) {\n\t\t\t\t// Pass through all events directly\n\t\t\t\tthis.emit(ev as AgentEvent);\n\n\t\t\t\t// Update internal state as needed\n\t\t\t\tswitch (ev.type) {\n\t\t\t\t\tcase \"message_start\": {\n\t\t\t\t\t\t// Track streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_update\": {\n\t\t\t\t\t\t// Update streaming message\n\t\t\t\t\t\tpartial = ev.message;\n\t\t\t\t\t\tthis._state.streamMessage = ev.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"message_end\": {\n\t\t\t\t\t\t// Add completed message to state\n\t\t\t\t\t\tpartial = null;\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tthis.appendMessage(ev.message as AppMessage);\n\t\t\t\t\t\tgeneratedMessages.push(ev.message as AppMessage);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_start\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.add(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"tool_execution_end\": {\n\t\t\t\t\t\tconst s = new Set(this._state.pendingToolCalls);\n\t\t\t\t\t\ts.delete(ev.toolCallId);\n\t\t\t\t\t\tthis._state.pendingToolCalls = s;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"turn_end\": {\n\t\t\t\t\t\t// Capture error from turn_end event\n\t\t\t\t\t\tif (ev.message.role === \"assistant\" && ev.message.errorMessage) {\n\t\t\t\t\t\t\tthis._state.error = ev.message.errorMessage;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"agent_end\": {\n\t\t\t\t\t\tthis._state.streamMessage = null;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Handle any remaining partial message\n\t\t\tif (partial && partial.role === \"assistant\" && partial.content.length > 0) {\n\t\t\t\tconst onlyEmpty = !partial.content.some(\n\t\t\t\t\t(c) =>\n\t\t\t\t\t\t(c.type === \"thinking\" && c.thinking.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"text\" && c.text.trim().length > 0) ||\n\t\t\t\t\t\t(c.type === \"toolCall\" && c.name.trim().length > 0),\n\t\t\t\t);\n\t\t\t\tif (!onlyEmpty) {\n\t\t\t\t\tthis.appendMessage(partial as AppMessage);\n\t\t\t\t\tgeneratedMessages.push(partial as AppMessage);\n\t\t\t\t} else {\n\t\t\t\t\tif (this.abortController?.signal.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\tconst msg: Message = {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tcontent: [{ type: \"text\", text: \"\" }],\n\t\t\t\tapi: model.api,\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tusage: {\n\t\t\t\t\tinput: 0,\n\t\t\t\t\toutput: 0,\n\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\ttotalTokens: 0,\n\t\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t\t},\n\t\t\t\tstopReason: this.abortController?.signal.aborted ? \"aborted\" : \"error\",\n\t\t\t\terrorMessage: err?.message || String(err),\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t};\n\t\t\tthis.appendMessage(msg as AppMessage);\n\t\t\tgeneratedMessages.push(msg as AppMessage);\n\t\t\tthis._state.error = err?.message || String(err);\n\t\t} finally {\n\t\t\tthis._state.isStreaming = false;\n\t\t\tthis._state.streamMessage = null;\n\t\t\tthis._state.pendingToolCalls = new Set<string>();\n\t\t\tthis.abortController = undefined;\n\t\t\tthis.resolveRunningPrompt?.();\n\t\t\tthis.runningPrompt = undefined;\n\t\t\tthis.resolveRunningPrompt = undefined;\n\t\t}\n\t}\n\n\tprivate emit(e: AgentEvent) {\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener(e);\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
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;AAsSjE,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;IAEM,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,2EAqC9F;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 } 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\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\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\t// Use proxy - no local API key needed\n\t\tconst streamFn = <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\n\t\t// Messages are already LLM-compatible (filtered by Agent)\n\t\tconst context: AgentContext = {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\n\t\tconst pc: AgentLoopConfig = {\n\t\t\tmodel: cfg.model,\n\t\t\treasoning: cfg.reasoning,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\n\t\t// Yield events from the upstream agentLoop iterator\n\t\t// Pass streamFn as the 5th parameter to use proxy\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"]}
|
|
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;IAEM,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,WAAW,2EAqC9F;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 } 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\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\t// Use proxy - no local API key needed\n\t\tconst streamFn = <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\n\t\t// Messages are already LLM-compatible (filtered by Agent)\n\t\tconst context: AgentContext = {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\n\t\tconst pc: AgentLoopConfig = {\n\t\t\tmodel: cfg.model,\n\t\t\treasoning: cfg.reasoning,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\n\t\t// Yield events from the upstream agentLoop iterator\n\t\t// Pass streamFn as the 5th parameter to use proxy\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"]}
|
|
@@ -1 +1 @@
|
|
|
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 } 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\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\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\t// Use proxy - no local API key needed\n\t\tconst streamFn = <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\n\t\t// Messages are already LLM-compatible (filtered by Agent)\n\t\tconst context: AgentContext = {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\n\t\tconst pc: AgentLoopConfig = {\n\t\t\tmodel: cfg.model,\n\t\t\treasoning: cfg.reasoning,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\n\t\t// Yield events from the upstream agentLoop iterator\n\t\t// Pass streamFn as the 5th parameter to use proxy\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"]}
|
|
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 } 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\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\t// Use proxy - no local API key needed\n\t\tconst streamFn = <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\n\t\t// Messages are already LLM-compatible (filtered by Agent)\n\t\tconst context: AgentContext = {\n\t\t\tsystemPrompt: cfg.systemPrompt,\n\t\t\tmessages,\n\t\t\ttools: cfg.tools,\n\t\t};\n\n\t\tconst pc: AgentLoopConfig = {\n\t\t\tmodel: cfg.model,\n\t\t\treasoning: cfg.reasoning,\n\t\t\tgetQueuedMessages: cfg.getQueuedMessages,\n\t\t};\n\n\t\t// Yield events from the upstream agentLoop iterator\n\t\t// Pass streamFn as the 5th parameter to use proxy\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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mariozechner/pi-agent-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"prepublishOnly": "npm run clean && npm run build"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@mariozechner/pi-ai": "^0.
|
|
22
|
-
"@mariozechner/pi-tui": "^0.
|
|
21
|
+
"@mariozechner/pi-ai": "^0.13.0",
|
|
22
|
+
"@mariozechner/pi-tui": "^0.13.0"
|
|
23
23
|
},
|
|
24
24
|
"keywords": [
|
|
25
25
|
"ai",
|