@amodalai/runtime 0.1.25 → 0.2.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/src/__fixtures__/README.md +84 -0
- package/dist/src/__fixtures__/smoke-agent/amodal.json +11 -0
- package/dist/src/__fixtures__/smoke-agent/automations/test-auto.md +5 -0
- package/dist/src/__fixtures__/smoke-agent/connections/mock-api/access.json +11 -0
- package/dist/src/__fixtures__/smoke-agent/connections/mock-api/spec.json +4 -0
- package/dist/src/__fixtures__/smoke-agent/connections/mock-api/surface.md +9 -0
- package/dist/src/__fixtures__/smoke-agent/connections/mock-mcp/access.json +3 -0
- package/dist/src/__fixtures__/smoke-agent/connections/mock-mcp/spec.json +8 -0
- package/dist/src/__fixtures__/smoke-agent/evals/basic-eval.md +12 -0
- package/dist/src/__fixtures__/smoke-agent/knowledge/test-knowledge.md +3 -0
- package/dist/src/__fixtures__/smoke-agent/skills/test-skill/SKILL.md +11 -0
- package/dist/src/__fixtures__/smoke-agent/stores/test-items.json +11 -0
- package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.d.ts +18 -0
- package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.js +22 -0
- package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/handler.js.map +1 -0
- package/dist/src/__fixtures__/smoke-agent/tools/echo_tool/tool.json +17 -0
- package/dist/src/__fixtures__/smoke.test.js +718 -0
- package/dist/src/__fixtures__/smoke.test.js.map +1 -0
- package/dist/src/{agent/stores-e2e.test.d.ts → __tests__/providers.test.d.ts} +1 -1
- package/dist/src/__tests__/providers.test.js +209 -0
- package/dist/src/__tests__/providers.test.js.map +1 -0
- package/dist/src/__tests__/test-providers.d.ts +40 -0
- package/dist/src/__tests__/test-providers.js +61 -0
- package/dist/src/__tests__/test-providers.js.map +1 -0
- package/dist/src/agent/agent-types.d.ts +2 -2
- package/dist/src/agent/config-watcher.test.js +18 -14
- package/dist/src/agent/config-watcher.test.js.map +1 -1
- package/dist/src/agent/local-server.d.ts +3 -3
- package/dist/src/agent/local-server.js +213 -122
- package/dist/src/agent/local-server.js.map +1 -1
- package/dist/src/agent/local-server.test.js +17 -13
- package/dist/src/agent/local-server.test.js.map +1 -1
- package/dist/src/agent/loop-types.d.ts +175 -0
- package/dist/src/agent/loop-types.js +20 -0
- package/dist/src/agent/loop-types.js.map +1 -0
- package/dist/src/agent/loop.d.ts +31 -0
- package/dist/src/agent/loop.js +139 -0
- package/dist/src/agent/loop.js.map +1 -0
- package/dist/src/agent/{tool-context-builder.test.d.ts → loop.test.d.ts} +1 -1
- package/dist/src/agent/loop.test.js +1030 -0
- package/dist/src/agent/loop.test.js.map +1 -0
- package/dist/src/agent/mcp-config.d.ts +28 -0
- package/dist/src/agent/mcp-config.js +57 -0
- package/dist/src/agent/mcp-config.js.map +1 -0
- package/dist/src/agent/page-builder.js +6 -1
- package/dist/src/agent/page-builder.js.map +1 -1
- package/dist/src/agent/proactive/proactive-runner.d.ts +24 -8
- package/dist/src/agent/proactive/proactive-runner.js +36 -33
- package/dist/src/agent/proactive/proactive-runner.js.map +1 -1
- package/dist/src/agent/proactive/proactive-runner.test.d.ts +1 -1
- package/dist/src/agent/proactive/proactive-runner.test.js +75 -87
- package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -1
- package/dist/src/agent/routes/admin-chat.d.ts +15 -3
- package/dist/src/agent/routes/admin-chat.js +63 -17
- package/dist/src/agent/routes/admin-chat.js.map +1 -1
- package/dist/src/agent/routes/automations.js +5 -4
- package/dist/src/agent/routes/automations.js.map +1 -1
- package/dist/src/agent/routes/evals.d.ts +3 -2
- package/dist/src/agent/routes/evals.js +25 -11
- package/dist/src/agent/routes/evals.js.map +1 -1
- package/dist/src/agent/routes/files.js +7 -6
- package/dist/src/agent/routes/files.js.map +1 -1
- package/dist/src/agent/routes/inspect.d.ts +6 -2
- package/dist/src/agent/routes/inspect.js +32 -15
- package/dist/src/agent/routes/inspect.js.map +1 -1
- package/dist/src/agent/routes/inspect.test.js +18 -42
- package/dist/src/agent/routes/inspect.test.js.map +1 -1
- package/dist/src/agent/routes/stores.js +9 -8
- package/dist/src/agent/routes/stores.js.map +1 -1
- package/dist/src/agent/routes/task.d.ts +15 -3
- package/dist/src/agent/routes/task.js +16 -6
- package/dist/src/agent/routes/task.js.map +1 -1
- package/dist/src/agent/routes/task.test.d.ts +1 -1
- package/dist/src/agent/routes/task.test.js +70 -53
- package/dist/src/agent/routes/task.test.js.map +1 -1
- package/dist/src/agent/routes/webhooks.js +12 -2
- package/dist/src/agent/routes/webhooks.js.map +1 -1
- package/dist/src/agent/session-store.d.ts +11 -2
- package/dist/src/agent/session-store.js +1 -1
- package/dist/src/agent/session-store.js.map +1 -1
- package/dist/src/agent/snapshot-server.d.ts +2 -22
- package/dist/src/agent/snapshot-server.js +50 -27
- package/dist/src/agent/snapshot-server.js.map +1 -1
- package/dist/src/agent/states/compacting.d.ts +14 -0
- package/dist/src/agent/states/compacting.js +258 -0
- package/dist/src/agent/states/compacting.js.map +1 -0
- package/dist/src/agent/states/confirming.d.ts +10 -0
- package/dist/src/agent/states/confirming.js +76 -0
- package/dist/src/agent/states/confirming.js.map +1 -0
- package/dist/src/agent/states/dispatching.d.ts +18 -0
- package/dist/src/agent/states/dispatching.js +241 -0
- package/dist/src/agent/states/dispatching.js.map +1 -0
- package/dist/src/agent/states/executing.d.ts +21 -0
- package/dist/src/agent/states/executing.js +308 -0
- package/dist/src/agent/states/executing.js.map +1 -0
- package/dist/src/agent/states/streaming.d.ts +10 -0
- package/dist/src/agent/states/streaming.js +155 -0
- package/dist/src/agent/states/streaming.js.map +1 -0
- package/dist/src/agent/states/thinking.d.ts +13 -0
- package/dist/src/agent/states/thinking.js +233 -0
- package/dist/src/agent/states/thinking.js.map +1 -0
- package/dist/src/agent/token-estimate.d.ts +17 -0
- package/dist/src/agent/token-estimate.js +13 -0
- package/dist/src/agent/token-estimate.js.map +1 -0
- package/dist/src/agent/tool-executor-local.js +9 -18
- package/dist/src/agent/tool-executor-local.js.map +1 -1
- package/dist/src/agent/tool-executor-local.test.js +3 -5
- package/dist/src/agent/tool-executor-local.test.js.map +1 -1
- package/dist/src/api/create-agent.d.ts +15 -0
- package/dist/src/api/create-agent.js +137 -0
- package/dist/src/api/create-agent.js.map +1 -0
- package/dist/src/api/types.d.ts +68 -0
- package/dist/src/api/types.js +7 -0
- package/dist/src/api/types.js.map +1 -0
- package/dist/src/config.d.ts +96 -0
- package/dist/src/config.js +221 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/{agent/custom-tools-e2e.test.d.ts → config.test.d.ts} +1 -1
- package/dist/src/config.test.js +235 -0
- package/dist/src/config.test.js.map +1 -0
- package/dist/src/context/compiler.d.ts +13 -0
- package/dist/src/context/compiler.js +358 -0
- package/dist/src/context/compiler.js.map +1 -0
- package/dist/src/context/compiler.test.d.ts +6 -0
- package/dist/src/context/compiler.test.js +532 -0
- package/dist/src/context/compiler.test.js.map +1 -0
- package/dist/src/context/types.d.ts +110 -0
- package/dist/src/context/types.js +7 -0
- package/dist/src/context/types.js.map +1 -0
- package/dist/src/errors.d.ts +145 -0
- package/dist/src/errors.js +218 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/errors.test.d.ts +6 -0
- package/dist/src/errors.test.js +203 -0
- package/dist/src/errors.test.js.map +1 -0
- package/dist/src/index.d.ts +38 -6
- package/dist/src/index.js +40 -22
- package/dist/src/index.js.map +1 -1
- package/dist/src/logger.d.ts +15 -31
- package/dist/src/logger.js +19 -78
- package/dist/src/logger.js.map +1 -1
- package/dist/src/logger.test.d.ts +6 -0
- package/dist/src/logger.test.js +198 -0
- package/dist/src/logger.test.js.map +1 -0
- package/dist/src/providers/create-provider.d.ts +23 -0
- package/dist/src/providers/create-provider.js +185 -0
- package/dist/src/providers/create-provider.js.map +1 -0
- package/dist/src/providers/create-provider.test.d.ts +6 -0
- package/dist/src/providers/create-provider.test.js +95 -0
- package/dist/src/providers/create-provider.test.js.map +1 -0
- package/dist/src/providers/failover.d.ts +38 -0
- package/dist/src/providers/failover.js +147 -0
- package/dist/src/providers/failover.js.map +1 -0
- package/dist/src/providers/failover.test.d.ts +6 -0
- package/dist/src/providers/failover.test.js +169 -0
- package/dist/src/providers/failover.test.js.map +1 -0
- package/dist/src/providers/types.d.ts +110 -0
- package/dist/src/providers/types.js +7 -0
- package/dist/src/providers/types.js.map +1 -0
- package/dist/src/routes/ai-stream.d.ts +13 -10
- package/dist/src/routes/ai-stream.js +76 -38
- package/dist/src/routes/ai-stream.js.map +1 -1
- package/dist/src/routes/chat-new.test.d.ts +6 -0
- package/dist/src/routes/chat-new.test.js +107 -0
- package/dist/src/routes/chat-new.test.js.map +1 -0
- package/dist/src/routes/chat-stream-new.test.d.ts +6 -0
- package/dist/src/routes/chat-stream-new.test.js +135 -0
- package/dist/src/routes/chat-stream-new.test.js.map +1 -0
- package/dist/src/routes/chat-stream.d.ts +14 -4
- package/dist/src/routes/chat-stream.js +47 -27
- package/dist/src/routes/chat-stream.js.map +1 -1
- package/dist/src/routes/chat.d.ts +13 -4
- package/dist/src/routes/chat.js +60 -22
- package/dist/src/routes/chat.js.map +1 -1
- package/dist/src/routes/health.d.ts +3 -2
- package/dist/src/routes/health.js.map +1 -1
- package/dist/src/routes/route-helpers.d.ts +50 -0
- package/dist/src/routes/route-helpers.js +80 -0
- package/dist/src/routes/route-helpers.js.map +1 -0
- package/dist/src/routes/session-resolver.d.ts +72 -0
- package/dist/src/routes/session-resolver.js +123 -0
- package/dist/src/routes/session-resolver.js.map +1 -0
- package/dist/src/routes/session-resolver.test.d.ts +6 -0
- package/dist/src/routes/session-resolver.test.js +206 -0
- package/dist/src/routes/session-resolver.test.js.map +1 -0
- package/dist/src/routes/webhooks.d.ts +3 -1
- package/dist/src/routes/webhooks.js +12 -2
- package/dist/src/routes/webhooks.js.map +1 -1
- package/dist/src/security/permission-checker.d.ts +80 -0
- package/dist/src/security/permission-checker.js +75 -0
- package/dist/src/security/permission-checker.js.map +1 -0
- package/dist/src/security/permission-checker.test.d.ts +6 -0
- package/dist/src/security/permission-checker.test.js +208 -0
- package/dist/src/security/permission-checker.test.js.map +1 -0
- package/dist/src/server.d.ts +12 -11
- package/dist/src/server.js +44 -46
- package/dist/src/server.js.map +1 -1
- package/dist/src/server.test.d.ts +1 -1
- package/dist/src/server.test.js +6 -140
- package/dist/src/server.test.js.map +1 -1
- package/dist/src/session/manager.d.ts +98 -0
- package/dist/src/session/manager.js +364 -0
- package/dist/src/session/manager.js.map +1 -0
- package/dist/src/session/manager.test.d.ts +6 -0
- package/dist/src/session/manager.test.js +315 -0
- package/dist/src/session/manager.test.js.map +1 -0
- package/dist/src/session/session-builder.d.ts +71 -0
- package/dist/src/session/session-builder.js +364 -0
- package/dist/src/session/session-builder.js.map +1 -0
- package/dist/src/session/session-builder.test.d.ts +6 -0
- package/dist/src/session/session-builder.test.js +352 -0
- package/dist/src/session/session-builder.test.js.map +1 -0
- package/dist/src/session/store.d.ts +57 -0
- package/dist/src/session/store.js +167 -0
- package/dist/src/session/store.js.map +1 -0
- package/dist/src/session/store.test.d.ts +6 -0
- package/dist/src/session/store.test.js +145 -0
- package/dist/src/session/store.test.js.map +1 -0
- package/dist/src/session/stream-hooks.d.ts +39 -0
- package/dist/src/session/stream-hooks.js +7 -0
- package/dist/src/session/stream-hooks.js.map +1 -0
- package/dist/src/session/tool-context-factory.d.ts +60 -0
- package/dist/src/session/tool-context-factory.js +190 -0
- package/dist/src/session/tool-context-factory.js.map +1 -0
- package/dist/src/session/tool-context-factory.test.d.ts +6 -0
- package/dist/src/session/tool-context-factory.test.js +287 -0
- package/dist/src/session/tool-context-factory.test.js.map +1 -0
- package/dist/src/session/types.d.ts +188 -0
- package/dist/src/session/types.js +7 -0
- package/dist/src/session/types.js.map +1 -0
- package/dist/src/stores/drizzle-store-backend.d.ts +49 -0
- package/dist/src/stores/drizzle-store-backend.js +306 -0
- package/dist/src/stores/drizzle-store-backend.js.map +1 -0
- package/dist/src/stores/drizzle-store-backend.test.d.ts +6 -0
- package/dist/src/stores/drizzle-store-backend.test.js +215 -0
- package/dist/src/stores/drizzle-store-backend.test.js.map +1 -0
- package/dist/src/stores/index.d.ts +4 -0
- package/dist/src/stores/index.js +2 -0
- package/dist/src/stores/index.js.map +1 -1
- package/dist/src/stores/pglite-store-backend.d.ts +16 -19
- package/dist/src/stores/pglite-store-backend.js +85 -233
- package/dist/src/stores/pglite-store-backend.js.map +1 -1
- package/dist/src/stores/postgres-store-backend.d.ts +30 -0
- package/dist/src/stores/postgres-store-backend.js +100 -0
- package/dist/src/stores/postgres-store-backend.js.map +1 -0
- package/dist/src/stores/schema.d.ts +491 -0
- package/dist/src/stores/schema.js +57 -0
- package/dist/src/stores/schema.js.map +1 -0
- package/dist/src/tools/admin-file-tools.d.ts +13 -0
- package/dist/src/tools/admin-file-tools.js +200 -0
- package/dist/src/tools/admin-file-tools.js.map +1 -0
- package/dist/src/tools/admin-file-tools.test.d.ts +6 -0
- package/dist/src/tools/admin-file-tools.test.js +152 -0
- package/dist/src/tools/admin-file-tools.test.js.map +1 -0
- package/dist/src/tools/custom-tool-adapter.d.ts +41 -0
- package/dist/src/tools/custom-tool-adapter.js +190 -0
- package/dist/src/tools/custom-tool-adapter.js.map +1 -0
- package/dist/src/tools/custom-tool-adapter.test.d.ts +6 -0
- package/dist/src/tools/custom-tool-adapter.test.js +244 -0
- package/dist/src/tools/custom-tool-adapter.test.js.map +1 -0
- package/dist/src/tools/dispatch-tool.d.ts +52 -0
- package/dist/src/tools/dispatch-tool.js +71 -0
- package/dist/src/tools/dispatch-tool.js.map +1 -0
- package/dist/src/tools/dispatch-tool.test.d.ts +6 -0
- package/dist/src/tools/dispatch-tool.test.js +75 -0
- package/dist/src/tools/dispatch-tool.test.js.map +1 -0
- package/dist/src/tools/mcp-tool-adapter.d.ts +18 -0
- package/dist/src/tools/mcp-tool-adapter.js +135 -0
- package/dist/src/tools/mcp-tool-adapter.js.map +1 -0
- package/dist/src/tools/mcp-tool-adapter.test.d.ts +6 -0
- package/dist/src/tools/mcp-tool-adapter.test.js +227 -0
- package/dist/src/tools/mcp-tool-adapter.test.js.map +1 -0
- package/dist/src/tools/registry.d.ts +25 -0
- package/dist/src/tools/registry.js +72 -0
- package/dist/src/tools/registry.js.map +1 -0
- package/dist/src/tools/registry.test.d.ts +6 -0
- package/dist/src/tools/registry.test.js +121 -0
- package/dist/src/tools/registry.test.js.map +1 -0
- package/dist/src/tools/request-tool.d.ts +42 -0
- package/dist/src/tools/request-tool.js +190 -0
- package/dist/src/tools/request-tool.js.map +1 -0
- package/dist/src/tools/request-tool.test.d.ts +6 -0
- package/dist/src/tools/request-tool.test.js +254 -0
- package/dist/src/tools/request-tool.test.js.map +1 -0
- package/dist/src/tools/store-tools.d.ts +29 -0
- package/dist/src/tools/store-tools.js +224 -0
- package/dist/src/tools/store-tools.js.map +1 -0
- package/dist/src/tools/store-tools.test.d.ts +6 -0
- package/dist/src/tools/store-tools.test.js +216 -0
- package/dist/src/tools/store-tools.test.js.map +1 -0
- package/dist/src/tools/types.d.ts +111 -0
- package/dist/src/tools/types.js +7 -0
- package/dist/src/tools/types.js.map +1 -0
- package/dist/src/types.d.ts +20 -12
- package/dist/src/types.js +3 -2
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -3
- package/dist/src/agent/agent-runner.d.ts +0 -33
- package/dist/src/agent/agent-runner.js +0 -1040
- package/dist/src/agent/agent-runner.js.map +0 -1
- package/dist/src/agent/custom-tools-e2e.test.js +0 -566
- package/dist/src/agent/custom-tools-e2e.test.js.map +0 -1
- package/dist/src/agent/request-helper.d.ts +0 -16
- package/dist/src/agent/request-helper.js +0 -96
- package/dist/src/agent/request-helper.js.map +0 -1
- package/dist/src/agent/stores-e2e.test.js +0 -433
- package/dist/src/agent/stores-e2e.test.js.map +0 -1
- package/dist/src/agent/tool-context-builder.d.ts +0 -11
- package/dist/src/agent/tool-context-builder.js +0 -102
- package/dist/src/agent/tool-context-builder.js.map +0 -1
- package/dist/src/agent/tool-context-builder.test.js +0 -152
- package/dist/src/agent/tool-context-builder.test.js.map +0 -1
- package/dist/src/agent/write-repo-file.test.js +0 -270
- package/dist/src/agent/write-repo-file.test.js.map +0 -1
- package/dist/src/cron/heartbeat-runner.d.ts +0 -21
- package/dist/src/cron/heartbeat-runner.js +0 -79
- package/dist/src/cron/heartbeat-runner.js.map +0 -1
- package/dist/src/cron/heartbeat-runner.test.d.ts +0 -6
- package/dist/src/cron/heartbeat-runner.test.js +0 -120
- package/dist/src/cron/heartbeat-runner.test.js.map +0 -1
- package/dist/src/cron/heartbeat-scheduler.d.ts +0 -26
- package/dist/src/cron/heartbeat-scheduler.js +0 -55
- package/dist/src/cron/heartbeat-scheduler.js.map +0 -1
- package/dist/src/cron/heartbeat-scheduler.test.d.ts +0 -6
- package/dist/src/cron/heartbeat-scheduler.test.js +0 -61
- package/dist/src/cron/heartbeat-scheduler.test.js.map +0 -1
- package/dist/src/routes/ai-stream.test.d.ts +0 -6
- package/dist/src/routes/ai-stream.test.js +0 -586
- package/dist/src/routes/ai-stream.test.js.map +0 -1
- package/dist/src/routes/ask-user-response.d.ts +0 -30
- package/dist/src/routes/ask-user-response.js +0 -61
- package/dist/src/routes/ask-user-response.js.map +0 -1
- package/dist/src/routes/ask-user-response.test.d.ts +0 -6
- package/dist/src/routes/ask-user-response.test.js +0 -88
- package/dist/src/routes/ask-user-response.test.js.map +0 -1
- package/dist/src/routes/chat-stream.test.d.ts +0 -6
- package/dist/src/routes/chat-stream.test.js +0 -155
- package/dist/src/routes/chat-stream.test.js.map +0 -1
- package/dist/src/routes/chat.test.d.ts +0 -6
- package/dist/src/routes/chat.test.js +0 -99
- package/dist/src/routes/chat.test.js.map +0 -1
- package/dist/src/routes/widget-actions.d.ts +0 -49
- package/dist/src/routes/widget-actions.js +0 -78
- package/dist/src/routes/widget-actions.js.map +0 -1
- package/dist/src/session/custom-tool-adapter.d.ts +0 -74
- package/dist/src/session/custom-tool-adapter.js +0 -180
- package/dist/src/session/custom-tool-adapter.js.map +0 -1
- package/dist/src/session/history-converter.d.ts +0 -21
- package/dist/src/session/history-converter.js +0 -59
- package/dist/src/session/history-converter.js.map +0 -1
- package/dist/src/session/history-converter.test.d.ts +0 -6
- package/dist/src/session/history-converter.test.js +0 -130
- package/dist/src/session/history-converter.test.js.map +0 -1
- package/dist/src/session/session-manager.d.ts +0 -219
- package/dist/src/session/session-manager.js +0 -915
- package/dist/src/session/session-manager.js.map +0 -1
- package/dist/src/session/session-manager.test.d.ts +0 -6
- package/dist/src/session/session-manager.test.js +0 -451
- package/dist/src/session/session-manager.test.js.map +0 -1
- package/dist/src/session/session-runner.d.ts +0 -45
- package/dist/src/session/session-runner.js +0 -719
- package/dist/src/session/session-runner.js.map +0 -1
- package/dist/src/session/session-runner.test.d.ts +0 -6
- package/dist/src/session/session-runner.test.js +0 -830
- package/dist/src/session/session-runner.test.js.map +0 -1
- /package/dist/src/{agent/write-repo-file.test.d.ts → __fixtures__/smoke.test.d.ts} +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { createProvider } from './create-provider.js';
|
|
7
|
+
import { ProviderError } from '../errors.js';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// createFailoverProvider
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* Create an LLMProvider that tries a chain of providers in order.
|
|
13
|
+
*
|
|
14
|
+
* For generateText: tries each provider sequentially until one succeeds.
|
|
15
|
+
* For streamText: wraps the fullStream so that if a provider's stream
|
|
16
|
+
* fails before yielding any events, the next provider is tried. Once
|
|
17
|
+
* events have been yielded, mid-stream errors propagate (can't restart
|
|
18
|
+
* a partial stream).
|
|
19
|
+
*/
|
|
20
|
+
export function createFailoverProvider(config) {
|
|
21
|
+
const chain = [config.primary, ...(config.fallbacks ?? [])];
|
|
22
|
+
const providers = chain.map((c) => createProvider(c));
|
|
23
|
+
const primary = providers[0];
|
|
24
|
+
function logFailure(idx, errorMsg, failedAttempts) {
|
|
25
|
+
failedAttempts.push({
|
|
26
|
+
provider: chain[idx].provider,
|
|
27
|
+
model: chain[idx].model,
|
|
28
|
+
error: errorMsg,
|
|
29
|
+
});
|
|
30
|
+
config.logger.error('provider_call_failed', {
|
|
31
|
+
session: config.sessionId,
|
|
32
|
+
provider: `${chain[idx].provider}/${chain[idx].model}`,
|
|
33
|
+
error: errorMsg,
|
|
34
|
+
willRetry: idx < providers.length - 1,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function logSuccess(idx, failedAttempts) {
|
|
38
|
+
if (idx > 0) {
|
|
39
|
+
config.logger.warn('provider_failover_used', {
|
|
40
|
+
session: config.sessionId,
|
|
41
|
+
failed: failedAttempts.map((a) => `${a.provider}/${a.model}`),
|
|
42
|
+
succeeded: `${chain[idx].provider}/${chain[idx].model}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function throwAllFailed(failedAttempts, cause) {
|
|
47
|
+
throw new ProviderError('All providers failed', {
|
|
48
|
+
provider: 'failover',
|
|
49
|
+
context: { attempts: failedAttempts },
|
|
50
|
+
cause,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
model: primary.model,
|
|
55
|
+
provider: primary.provider,
|
|
56
|
+
languageModel: primary.languageModel,
|
|
57
|
+
streamText(opts) {
|
|
58
|
+
// Deferred promises for usage and text — resolved when stream completes.
|
|
59
|
+
let resolveUsage;
|
|
60
|
+
let rejectUsage;
|
|
61
|
+
const usagePromise = new Promise((res, rej) => {
|
|
62
|
+
resolveUsage = res;
|
|
63
|
+
rejectUsage = rej;
|
|
64
|
+
});
|
|
65
|
+
let resolveText;
|
|
66
|
+
let rejectText;
|
|
67
|
+
const textPromise = new Promise((res, rej) => {
|
|
68
|
+
resolveText = res;
|
|
69
|
+
rejectText = rej;
|
|
70
|
+
});
|
|
71
|
+
const failedAttempts = [];
|
|
72
|
+
const fullStream = (async function* () {
|
|
73
|
+
let lastUsage;
|
|
74
|
+
const textChunks = [];
|
|
75
|
+
for (let i = 0; i < providers.length; i++) {
|
|
76
|
+
let yieldedAny = false;
|
|
77
|
+
try {
|
|
78
|
+
const result = providers[i].streamText(opts);
|
|
79
|
+
for await (const event of result.fullStream) {
|
|
80
|
+
yieldedAny = true;
|
|
81
|
+
if (event.type === 'finish')
|
|
82
|
+
lastUsage = event.usage;
|
|
83
|
+
if (event.type === 'text-delta')
|
|
84
|
+
textChunks.push(event.textDelta);
|
|
85
|
+
yield event;
|
|
86
|
+
}
|
|
87
|
+
// Stream completed successfully
|
|
88
|
+
logSuccess(i, failedAttempts);
|
|
89
|
+
resolveUsage(lastUsage ?? { inputTokens: 0, outputTokens: 0, totalTokens: 0 });
|
|
90
|
+
resolveText(textChunks.join(''));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
95
|
+
// If we already yielded events, we can't retry — log and propagate
|
|
96
|
+
if (yieldedAny) {
|
|
97
|
+
logFailure(i, errorMsg, failedAttempts);
|
|
98
|
+
rejectUsage(err);
|
|
99
|
+
rejectText(err);
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
logFailure(i, errorMsg, failedAttempts);
|
|
103
|
+
if (i === providers.length - 1) {
|
|
104
|
+
rejectUsage(err);
|
|
105
|
+
rejectText(err);
|
|
106
|
+
throwAllFailed(failedAttempts, err);
|
|
107
|
+
}
|
|
108
|
+
// Try next provider
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
})();
|
|
112
|
+
return {
|
|
113
|
+
fullStream,
|
|
114
|
+
// textStream derived from fullStream — consumers should use one or the other
|
|
115
|
+
textStream: (async function* () {
|
|
116
|
+
for await (const event of fullStream) {
|
|
117
|
+
if (event.type === 'text-delta') {
|
|
118
|
+
yield event.textDelta;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
})(),
|
|
122
|
+
usage: usagePromise,
|
|
123
|
+
text: textPromise,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
async generateText(opts) {
|
|
127
|
+
const failedAttempts = [];
|
|
128
|
+
for (let i = 0; i < providers.length; i++) {
|
|
129
|
+
try {
|
|
130
|
+
const result = await providers[i].generateText(opts);
|
|
131
|
+
logSuccess(i, failedAttempts);
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
136
|
+
logFailure(i, errorMsg, failedAttempts);
|
|
137
|
+
if (i === providers.length - 1) {
|
|
138
|
+
throwAllFailed(failedAttempts, err);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// Unreachable — TypeScript needs this
|
|
143
|
+
throw new ProviderError('No providers configured', { provider: 'failover' });
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=failover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failover.js","sourceRoot":"","sources":["../../../src/providers/failover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Provider Failover Tests
|
|
8
|
+
*
|
|
9
|
+
* Integration tests against real providers (skipped when API keys are
|
|
10
|
+
* not available). No mocks — calls the real AI SDK through the real
|
|
11
|
+
* createProvider → createFailoverProvider chain.
|
|
12
|
+
*
|
|
13
|
+
* Scenarios:
|
|
14
|
+
* 1. Primary with invalid key + fallback with valid key → response from fallback
|
|
15
|
+
* 2. Valid primary → uses primary, no fallback
|
|
16
|
+
* 3. All providers fail → throws ProviderError with context about all attempts
|
|
17
|
+
*/
|
|
18
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
19
|
+
import { createFailoverProvider } from './failover.js';
|
|
20
|
+
import { ProviderError } from '../errors.js';
|
|
21
|
+
import { testProviders, hasAnyProvider } from '../__tests__/test-providers.js';
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Helpers
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
function makeMockLogger() {
|
|
26
|
+
return {
|
|
27
|
+
trace: vi.fn(),
|
|
28
|
+
debug: vi.fn(),
|
|
29
|
+
info: vi.fn(),
|
|
30
|
+
warn: vi.fn(),
|
|
31
|
+
error: vi.fn(),
|
|
32
|
+
fatal: vi.fn(),
|
|
33
|
+
child: vi.fn().mockReturnThis(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Unit tests (no API calls)
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
describe('createFailoverProvider (unit)', () => {
|
|
40
|
+
let logger;
|
|
41
|
+
beforeEach(() => {
|
|
42
|
+
logger = makeMockLogger();
|
|
43
|
+
});
|
|
44
|
+
it('exposes primary model and provider on the returned object', () => {
|
|
45
|
+
const provider = createFailoverProvider({
|
|
46
|
+
primary: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: 'fake' },
|
|
47
|
+
fallbacks: [{ provider: 'openai', model: 'gpt-4o', apiKey: 'fake' }],
|
|
48
|
+
logger,
|
|
49
|
+
});
|
|
50
|
+
expect(provider.model).toBe('claude-sonnet-4-20250514');
|
|
51
|
+
expect(provider.provider).toBe('anthropic');
|
|
52
|
+
expect(provider.languageModel).toBeDefined();
|
|
53
|
+
expect(typeof provider.streamText).toBe('function');
|
|
54
|
+
expect(typeof provider.generateText).toBe('function');
|
|
55
|
+
});
|
|
56
|
+
it('works with a single provider (no fallbacks)', () => {
|
|
57
|
+
const provider = createFailoverProvider({
|
|
58
|
+
primary: { provider: 'anthropic', model: 'claude-sonnet-4-20250514', apiKey: 'fake' },
|
|
59
|
+
logger,
|
|
60
|
+
});
|
|
61
|
+
expect(provider.model).toBe('claude-sonnet-4-20250514');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Integration tests (real API calls — skipped without keys)
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
describe.skipIf(!hasAnyProvider)('createFailoverProvider (integration)', () => {
|
|
68
|
+
let logger;
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
logger = makeMockLogger();
|
|
71
|
+
});
|
|
72
|
+
// ── 1. Primary fails (invalid key) + fallback succeeds ────────────────
|
|
73
|
+
it('uses fallback when primary has invalid API key', async () => {
|
|
74
|
+
const fallback = testProviders.cheapest();
|
|
75
|
+
const invalid = testProviders.invalid(fallback.provider);
|
|
76
|
+
const provider = createFailoverProvider({
|
|
77
|
+
primary: invalid,
|
|
78
|
+
fallbacks: [fallback],
|
|
79
|
+
logger,
|
|
80
|
+
sessionId: 'test-failover',
|
|
81
|
+
});
|
|
82
|
+
const result = await provider.generateText({
|
|
83
|
+
messages: [{ role: 'user', content: [{ type: 'text', text: 'Reply with exactly: pong' }] }],
|
|
84
|
+
maxOutputTokens: 10,
|
|
85
|
+
});
|
|
86
|
+
expect(result.text.toLowerCase()).toContain('pong');
|
|
87
|
+
expect(result.usage.inputTokens).toBeGreaterThan(0);
|
|
88
|
+
expect(result.usage.outputTokens).toBeGreaterThan(0);
|
|
89
|
+
expect(logger.error).toHaveBeenCalledWith('provider_call_failed', expect.objectContaining({ session: 'test-failover', willRetry: true }));
|
|
90
|
+
expect(logger.warn).toHaveBeenCalledWith('provider_failover_used', expect.objectContaining({
|
|
91
|
+
succeeded: `${fallback.provider}/${fallback.model}`,
|
|
92
|
+
}));
|
|
93
|
+
}, 30000);
|
|
94
|
+
// ── 2. Valid primary → uses primary, no fallback ──────────────────────
|
|
95
|
+
it('uses primary when it succeeds — fallback not touched', async () => {
|
|
96
|
+
const primary = testProviders.cheapest();
|
|
97
|
+
const provider = createFailoverProvider({
|
|
98
|
+
primary,
|
|
99
|
+
// Fallback has invalid key — would fail if reached
|
|
100
|
+
fallbacks: [testProviders.invalid(primary.provider)],
|
|
101
|
+
logger,
|
|
102
|
+
});
|
|
103
|
+
const result = await provider.generateText({
|
|
104
|
+
messages: [{ role: 'user', content: [{ type: 'text', text: 'Reply with exactly: ping' }] }],
|
|
105
|
+
maxOutputTokens: 10,
|
|
106
|
+
});
|
|
107
|
+
expect(result.text.toLowerCase()).toContain('ping');
|
|
108
|
+
expect(logger.error).not.toHaveBeenCalled();
|
|
109
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
110
|
+
}, 30000);
|
|
111
|
+
// ── 3. All providers fail → ProviderError with all attempts ───────────
|
|
112
|
+
it('throws ProviderError with context about all failed attempts', async () => {
|
|
113
|
+
const provider = createFailoverProvider({
|
|
114
|
+
primary: testProviders.invalid('anthropic'),
|
|
115
|
+
fallbacks: [testProviders.invalid('openai')],
|
|
116
|
+
logger,
|
|
117
|
+
sessionId: 'test-all-fail',
|
|
118
|
+
});
|
|
119
|
+
try {
|
|
120
|
+
await provider.generateText({
|
|
121
|
+
messages: [{ role: 'user', content: [{ type: 'text', text: 'hello' }] }],
|
|
122
|
+
maxOutputTokens: 10,
|
|
123
|
+
});
|
|
124
|
+
expect.unreachable('should have thrown');
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
expect(err).toBeInstanceOf(ProviderError);
|
|
128
|
+
const pe = err;
|
|
129
|
+
expect(pe.message).toBe('All providers failed');
|
|
130
|
+
expect(pe.provider).toBe('failover');
|
|
131
|
+
const attempts = pe.context['attempts'];
|
|
132
|
+
expect(attempts).toHaveLength(2);
|
|
133
|
+
expect(attempts[0].provider).toBe('anthropic');
|
|
134
|
+
expect(attempts[1].provider).toBe('openai');
|
|
135
|
+
}
|
|
136
|
+
expect(logger.error).toHaveBeenCalledTimes(2);
|
|
137
|
+
expect(logger.error).toHaveBeenCalledWith('provider_call_failed', expect.objectContaining({ session: 'test-all-fail', willRetry: true }));
|
|
138
|
+
expect(logger.error).toHaveBeenCalledWith('provider_call_failed', expect.objectContaining({ willRetry: false }));
|
|
139
|
+
}, 30000);
|
|
140
|
+
// ── 4. Streaming failover ─────────────────────────────────────────────
|
|
141
|
+
it('streaming: uses fallback when primary stream fails', async () => {
|
|
142
|
+
const fallback = testProviders.cheapest();
|
|
143
|
+
const invalid = testProviders.invalid(fallback.provider);
|
|
144
|
+
const provider = createFailoverProvider({
|
|
145
|
+
primary: invalid,
|
|
146
|
+
fallbacks: [fallback],
|
|
147
|
+
logger,
|
|
148
|
+
});
|
|
149
|
+
const result = provider.streamText({
|
|
150
|
+
messages: [{ role: 'user', content: [{ type: 'text', text: 'Reply with exactly: stream-ok' }] }],
|
|
151
|
+
maxOutputTokens: 10,
|
|
152
|
+
});
|
|
153
|
+
const events = [];
|
|
154
|
+
for await (const event of result.fullStream) {
|
|
155
|
+
events.push(event);
|
|
156
|
+
}
|
|
157
|
+
const textDeltas = events.filter((e) => e.type === 'text-delta');
|
|
158
|
+
expect(textDeltas.length).toBeGreaterThan(0);
|
|
159
|
+
const text = await result.text;
|
|
160
|
+
expect(text.length).toBeGreaterThan(0);
|
|
161
|
+
const usage = await result.usage;
|
|
162
|
+
expect(usage.inputTokens).toBeGreaterThan(0);
|
|
163
|
+
expect(logger.error).toHaveBeenCalledWith('provider_call_failed', expect.objectContaining({ willRetry: true }));
|
|
164
|
+
expect(logger.warn).toHaveBeenCalledWith('provider_failover_used', expect.objectContaining({
|
|
165
|
+
succeeded: `${fallback.provider}/${fallback.model}`,
|
|
166
|
+
}));
|
|
167
|
+
}, 30000);
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=failover.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failover.test.js","sourceRoot":"","sources":["../../../src/providers/failover.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Provider abstraction wrapping the Vercel AI SDK.
|
|
8
|
+
*
|
|
9
|
+
* This is the boundary between Amodal code and the AI SDK. The rest of
|
|
10
|
+
* the runtime talks to LLMProvider, never to the SDK directly. This lets
|
|
11
|
+
* us swap SDK versions, add new providers, or intercept calls (logging,
|
|
12
|
+
* retries, cost tracking) in one place.
|
|
13
|
+
*/
|
|
14
|
+
import type { LanguageModel, ModelMessage, Tool, ToolChoice, ToolSet } from 'ai';
|
|
15
|
+
export interface StreamTextOptions {
|
|
16
|
+
messages: ModelMessage[];
|
|
17
|
+
system?: string;
|
|
18
|
+
tools?: Record<string, Tool>;
|
|
19
|
+
toolChoice?: ToolChoice<ToolSet>;
|
|
20
|
+
maxOutputTokens?: number;
|
|
21
|
+
temperature?: number;
|
|
22
|
+
abortSignal?: AbortSignal;
|
|
23
|
+
}
|
|
24
|
+
export interface GenerateTextOptions {
|
|
25
|
+
messages: ModelMessage[];
|
|
26
|
+
system?: string;
|
|
27
|
+
tools?: Record<string, Tool>;
|
|
28
|
+
toolChoice?: ToolChoice<ToolSet>;
|
|
29
|
+
maxOutputTokens?: number;
|
|
30
|
+
temperature?: number;
|
|
31
|
+
abortSignal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
export interface TokenUsage {
|
|
34
|
+
inputTokens: number;
|
|
35
|
+
outputTokens: number;
|
|
36
|
+
cachedInputTokens?: number;
|
|
37
|
+
cacheCreationInputTokens?: number;
|
|
38
|
+
totalTokens: number;
|
|
39
|
+
}
|
|
40
|
+
export interface StreamTextResult {
|
|
41
|
+
/** The full text stream — yields string chunks */
|
|
42
|
+
textStream: AsyncIterable<string>;
|
|
43
|
+
/** The full event stream — yields structured events including tool calls */
|
|
44
|
+
fullStream: AsyncIterable<StreamEvent>;
|
|
45
|
+
/** Resolves when the stream is complete with final usage */
|
|
46
|
+
usage: PromiseLike<TokenUsage>;
|
|
47
|
+
/** Resolves with the complete response text */
|
|
48
|
+
text: PromiseLike<string>;
|
|
49
|
+
}
|
|
50
|
+
export type StreamEvent = {
|
|
51
|
+
type: 'text-delta';
|
|
52
|
+
textDelta: string;
|
|
53
|
+
} | {
|
|
54
|
+
type: 'tool-call';
|
|
55
|
+
toolCallId: string;
|
|
56
|
+
toolName: string;
|
|
57
|
+
args: Record<string, unknown>;
|
|
58
|
+
} | {
|
|
59
|
+
type: 'tool-result';
|
|
60
|
+
toolCallId: string;
|
|
61
|
+
toolName: string;
|
|
62
|
+
result: unknown;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'finish';
|
|
65
|
+
usage: TokenUsage;
|
|
66
|
+
} | {
|
|
67
|
+
type: 'error';
|
|
68
|
+
error: unknown;
|
|
69
|
+
};
|
|
70
|
+
export interface GenerateTextResult {
|
|
71
|
+
text: string;
|
|
72
|
+
toolCalls: Array<{
|
|
73
|
+
toolCallId: string;
|
|
74
|
+
toolName: string;
|
|
75
|
+
args: Record<string, unknown>;
|
|
76
|
+
}>;
|
|
77
|
+
usage: TokenUsage;
|
|
78
|
+
finishReason: 'stop' | 'length' | 'content-filter' | 'tool-calls' | 'error' | 'other';
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Unified LLM provider interface.
|
|
82
|
+
*
|
|
83
|
+
* Wraps the Vercel AI SDK so the rest of the runtime never imports `ai`
|
|
84
|
+
* directly. Implementations exist for Anthropic, OpenAI, Google, and
|
|
85
|
+
* any OpenAI-compatible provider (DeepSeek, Groq, Mistral, etc.).
|
|
86
|
+
*/
|
|
87
|
+
export interface LLMProvider {
|
|
88
|
+
/** Stream a text/tool response from the LLM */
|
|
89
|
+
streamText(opts: StreamTextOptions): StreamTextResult;
|
|
90
|
+
/** Generate a complete text response (non-streaming) */
|
|
91
|
+
generateText(opts: GenerateTextOptions): Promise<GenerateTextResult>;
|
|
92
|
+
/** The model identifier (e.g., 'claude-sonnet-4-20250514') */
|
|
93
|
+
readonly model: string;
|
|
94
|
+
/** The provider name (e.g., 'anthropic', 'openai', 'google') */
|
|
95
|
+
readonly provider: string;
|
|
96
|
+
/** The underlying AI SDK LanguageModel instance (for advanced use) */
|
|
97
|
+
readonly languageModel: LanguageModel;
|
|
98
|
+
}
|
|
99
|
+
export interface ProviderConfig {
|
|
100
|
+
/** Provider name: 'anthropic', 'openai', 'google', 'deepseek', etc. */
|
|
101
|
+
provider: string;
|
|
102
|
+
/** Model name: 'claude-sonnet-4-20250514', 'gpt-4o', etc. */
|
|
103
|
+
model: string;
|
|
104
|
+
/** API key (resolved from env or credentials) */
|
|
105
|
+
apiKey?: string;
|
|
106
|
+
/** Custom base URL (for self-hosted or proxy endpoints) */
|
|
107
|
+
baseUrl?: string;
|
|
108
|
+
/** AWS region (for Bedrock) */
|
|
109
|
+
region?: string;
|
|
110
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/providers/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* Vercel AI SDK UI Message Stream Protocol adapter.
|
|
8
8
|
*
|
|
9
9
|
* Accepts requests in the Vercel AI SDK format, feeds the user message into
|
|
10
|
-
* the
|
|
11
|
-
* `SSEEvent` into the UI Message Stream Protocol that `@ai-sdk/react`'s
|
|
10
|
+
* the standalone session manager's `runMessage()` generator, and translates
|
|
11
|
+
* every `SSEEvent` into the UI Message Stream Protocol that `@ai-sdk/react`'s
|
|
12
12
|
* `useChat` hook expects.
|
|
13
13
|
*
|
|
14
14
|
* Protocol spec: events are newline-delimited JSON objects prefixed with
|
|
@@ -18,9 +18,10 @@
|
|
|
18
18
|
import { Router } from 'express';
|
|
19
19
|
import { z } from 'zod';
|
|
20
20
|
import type { AuthContext } from '../middleware/auth.js';
|
|
21
|
-
import type {
|
|
22
|
-
import {
|
|
21
|
+
import type { StandaloneSessionManager } from '../session/manager.js';
|
|
22
|
+
import type { StreamHooks } from '../session/stream-hooks.js';
|
|
23
23
|
import { type SSEEvent } from '../types.js';
|
|
24
|
+
import type { BundleResolver, SharedResources } from './session-resolver.js';
|
|
24
25
|
export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
25
26
|
messages: z.ZodArray<z.ZodObject<{
|
|
26
27
|
role: z.ZodEnum<["user", "assistant", "system"]>;
|
|
@@ -36,14 +37,14 @@ export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
|
36
37
|
}>, "many">>;
|
|
37
38
|
content: z.ZodOptional<z.ZodString>;
|
|
38
39
|
}, "strip", z.ZodTypeAny, {
|
|
39
|
-
role: "
|
|
40
|
+
role: "system" | "user" | "assistant";
|
|
40
41
|
content?: string | undefined;
|
|
41
42
|
parts?: {
|
|
42
43
|
type: string;
|
|
43
44
|
text?: string | undefined;
|
|
44
45
|
}[] | undefined;
|
|
45
46
|
}, {
|
|
46
|
-
role: "
|
|
47
|
+
role: "system" | "user" | "assistant";
|
|
47
48
|
content?: string | undefined;
|
|
48
49
|
parts?: {
|
|
49
50
|
type: string;
|
|
@@ -55,7 +56,7 @@ export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
|
55
56
|
deploy_id: z.ZodOptional<z.ZodString>;
|
|
56
57
|
}, "strip", z.ZodTypeAny, {
|
|
57
58
|
messages: {
|
|
58
|
-
role: "
|
|
59
|
+
role: "system" | "user" | "assistant";
|
|
59
60
|
content?: string | undefined;
|
|
60
61
|
parts?: {
|
|
61
62
|
type: string;
|
|
@@ -67,7 +68,7 @@ export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
|
67
68
|
deploy_id?: string | undefined;
|
|
68
69
|
}, {
|
|
69
70
|
messages: {
|
|
70
|
-
role: "
|
|
71
|
+
role: "system" | "user" | "assistant";
|
|
71
72
|
content?: string | undefined;
|
|
72
73
|
parts?: {
|
|
73
74
|
type: string;
|
|
@@ -152,7 +153,9 @@ interface AdapterState {
|
|
|
152
153
|
export declare function translateEvent(event: SSEEvent, state: AdapterState): UIStreamEvent[];
|
|
153
154
|
export declare function extractUserMessage(messages: AIStreamRequest['messages']): string;
|
|
154
155
|
export interface AIStreamRouterOptions {
|
|
155
|
-
sessionManager:
|
|
156
|
+
sessionManager: StandaloneSessionManager;
|
|
157
|
+
bundleResolver: BundleResolver;
|
|
158
|
+
shared: SharedResources;
|
|
156
159
|
/** Factory that builds per-request stream hooks from the auth context */
|
|
157
160
|
createStreamHooks?: (auth?: AuthContext) => StreamHooks;
|
|
158
161
|
}
|