@amodalai/runtime 0.1.26 → 0.2.1
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 +88 -0
- package/dist/src/__fixtures__/e2e.test.js +211 -0
- package/dist/src/__fixtures__/e2e.test.js.map +1 -0
- package/dist/src/__fixtures__/smoke-agent/amodal.json +11 -0
- package/dist/src/__fixtures__/smoke-agent/automations/delivery-callback-test.json +9 -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 +1404 -0
- package/dist/src/__fixtures__/smoke.test.js.map +1 -0
- package/dist/src/__fixtures__/test-env.d.ts +27 -0
- package/dist/src/__fixtures__/test-env.js +64 -0
- package/dist/src/__fixtures__/test-env.js.map +1 -0
- package/dist/src/__fixtures__/test-helpers.d.ts +30 -0
- package/dist/src/__fixtures__/test-helpers.js +120 -0
- package/dist/src/__fixtures__/test-helpers.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 +22 -0
- package/dist/src/agent/agent-types.js.map +1 -1
- package/dist/src/agent/automation-bridge.d.ts +9 -0
- package/dist/src/agent/automation-bridge.js +26 -0
- package/dist/src/agent/automation-bridge.js.map +1 -1
- package/dist/src/agent/automation-bridge.test.js +63 -0
- package/dist/src/agent/automation-bridge.test.js.map +1 -1
- package/dist/src/agent/local-server.d.ts +1 -8
- package/dist/src/agent/local-server.js +398 -163
- package/dist/src/agent/local-server.js.map +1 -1
- package/dist/src/agent/local-server.test.js +14 -8
- package/dist/src/agent/local-server.test.js.map +1 -1
- package/dist/src/agent/loop-types.d.ts +254 -0
- package/dist/src/agent/loop-types.js +24 -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 +152 -0
- package/dist/src/agent/loop.js.map +1 -0
- package/dist/src/agent/loop.test.js +1594 -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/delivery-router.d.ts +68 -0
- package/dist/src/agent/proactive/delivery-router.js +337 -0
- package/dist/src/agent/proactive/delivery-router.js.map +1 -0
- package/dist/src/agent/{stores-e2e.test.d.ts → proactive/delivery-router.test.d.ts} +1 -1
- package/dist/src/agent/proactive/delivery-router.test.js +455 -0
- package/dist/src/agent/proactive/delivery-router.test.js.map +1 -0
- package/dist/src/agent/proactive/proactive-runner.d.ts +46 -8
- package/dist/src/agent/proactive/proactive-runner.js +67 -37
- 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 +73 -87
- package/dist/src/agent/proactive/proactive-runner.test.js.map +1 -1
- package/dist/src/agent/routes/admin-chat-abort.test.d.ts +6 -0
- package/dist/src/agent/routes/admin-chat-abort.test.js +206 -0
- package/dist/src/agent/routes/admin-chat-abort.test.js.map +1 -0
- package/dist/src/agent/routes/admin-chat.d.ts +15 -3
- package/dist/src/agent/routes/admin-chat.js +61 -18
- package/dist/src/agent/routes/admin-chat.js.map +1 -1
- package/dist/src/agent/routes/automations.js +5 -6
- 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 -12
- package/dist/src/agent/routes/evals.js.map +1 -1
- package/dist/src/agent/routes/files.js +7 -9
- 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 +31 -17
- 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 -12
- 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 -7
- 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 +68 -53
- package/dist/src/agent/routes/task.test.js.map +1 -1
- package/dist/src/agent/routes/webhooks.js +12 -3
- package/dist/src/agent/routes/webhooks.js.map +1 -1
- package/dist/src/agent/snapshot-server.d.ts +2 -22
- package/dist/src/agent/snapshot-server.js +48 -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 +260 -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 +79 -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 +285 -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 +452 -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 +169 -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 +450 -0
- package/dist/src/agent/states/thinking.js.map +1 -0
- package/dist/src/agent/token-estimate.d.ts +31 -0
- package/dist/src/agent/token-estimate.js +34 -0
- package/dist/src/agent/token-estimate.js.map +1 -0
- package/dist/src/agent/token-estimate.test.d.ts +6 -0
- package/dist/src/agent/token-estimate.test.js +44 -0
- package/dist/src/agent/token-estimate.test.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 +134 -0
- package/dist/src/api/create-agent.js.map +1 -0
- package/dist/src/api/types.d.ts +66 -0
- package/dist/src/api/types.js +7 -0
- package/dist/src/api/types.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/env-ref.d.ts +13 -0
- package/dist/src/env-ref.js +31 -0
- package/dist/src/env-ref.js.map +1 -0
- package/dist/src/env-ref.test.d.ts +6 -0
- package/dist/src/env-ref.test.js +34 -0
- package/dist/src/env-ref.test.js.map +1 -0
- package/dist/src/errors.d.ts +15 -0
- package/dist/src/errors.js +22 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/errors.test.js +2 -2
- package/dist/src/errors.test.js.map +1 -1
- package/dist/src/events/event-bus.d.ts +54 -0
- package/dist/src/events/event-bus.js +84 -0
- package/dist/src/events/event-bus.js.map +1 -0
- package/dist/src/events/event-bus.test.d.ts +6 -0
- package/dist/src/events/event-bus.test.js +112 -0
- package/dist/src/events/event-bus.test.js.map +1 -0
- package/dist/src/events/events-route.d.ts +36 -0
- package/dist/src/events/events-route.js +80 -0
- package/dist/src/events/events-route.js.map +1 -0
- package/dist/src/events/events-route.test.d.ts +6 -0
- package/dist/src/events/events-route.test.js +134 -0
- package/dist/src/events/events-route.test.js.map +1 -0
- package/dist/src/events/store-event-wrapper.d.ts +19 -0
- package/dist/src/events/store-event-wrapper.js +57 -0
- package/dist/src/events/store-event-wrapper.js.map +1 -0
- package/dist/src/events/store-event-wrapper.test.d.ts +6 -0
- package/dist/src/events/store-event-wrapper.test.js +91 -0
- package/dist/src/events/store-event-wrapper.test.js.map +1 -0
- package/dist/src/index.d.ts +33 -6
- package/dist/src/index.js +35 -21
- package/dist/src/index.js.map +1 -1
- package/dist/src/middleware/auth.d.ts +0 -2
- package/dist/src/middleware/auth.js.map +1 -1
- 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/search-provider.d.ts +64 -0
- package/dist/src/providers/search-provider.js +174 -0
- package/dist/src/providers/search-provider.js.map +1 -0
- package/dist/src/providers/types.d.ts +118 -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 +28 -10
- package/dist/src/routes/ai-stream.js +85 -41
- 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 +20 -4
- package/dist/src/routes/chat-stream.js +49 -29
- package/dist/src/routes/chat-stream.js.map +1 -1
- package/dist/src/routes/chat.d.ts +19 -4
- package/dist/src/routes/chat.js +62 -23
- 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 +77 -0
- package/dist/src/routes/session-resolver.js +109 -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 +207 -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 -4
- 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 +18 -11
- package/dist/src/server.js +46 -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 -144
- package/dist/src/server.test.js.map +1 -1
- package/dist/src/session/drizzle-session-store.d.ts +56 -0
- package/dist/src/session/drizzle-session-store.js +203 -0
- package/dist/src/session/drizzle-session-store.js.map +1 -0
- package/dist/src/session/manager.d.ts +101 -0
- package/dist/src/session/manager.js +394 -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 +309 -0
- package/dist/src/session/manager.test.js.map +1 -0
- package/dist/src/session/pglite-session-store.d.ts +23 -0
- package/dist/src/session/pglite-session-store.js +70 -0
- package/dist/src/session/pglite-session-store.js.map +1 -0
- package/dist/src/session/postgres-session-store.d.ts +44 -0
- package/dist/src/session/postgres-session-store.js +138 -0
- package/dist/src/session/postgres-session-store.js.map +1 -0
- package/dist/src/session/session-builder.d.ts +69 -0
- package/dist/src/session/session-builder.js +384 -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 +350 -0
- package/dist/src/session/session-builder.test.js.map +1 -0
- package/dist/src/session/session-store-selector.d.ts +49 -0
- package/dist/src/session/session-store-selector.js +60 -0
- package/dist/src/session/session-store-selector.js.map +1 -0
- package/dist/src/session/session-store-selector.test.d.ts +6 -0
- package/dist/src/session/session-store-selector.test.js +79 -0
- package/dist/src/session/session-store-selector.test.js.map +1 -0
- package/dist/src/session/store.d.ts +171 -0
- package/dist/src/session/store.js +155 -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 +423 -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 +61 -0
- package/dist/src/session/tool-context-factory.js +189 -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 +284 -0
- package/dist/src/session/tool-context-factory.test.js.map +1 -0
- package/dist/src/session/types.d.ts +195 -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 -239
- 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 +457 -0
- package/dist/src/stores/schema.js +59 -0
- package/dist/src/stores/schema.js.map +1 -0
- package/dist/src/tools/admin-file-tools.d.ts +42 -0
- package/dist/src/tools/admin-file-tools.js +714 -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 +521 -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 +243 -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/fetch-url-tool.d.ts +23 -0
- package/dist/src/tools/fetch-url-tool.js +333 -0
- package/dist/src/tools/fetch-url-tool.js.map +1 -0
- package/dist/src/tools/fetch-url-tool.test.d.ts +6 -0
- package/dist/src/tools/fetch-url-tool.test.js +228 -0
- package/dist/src/tools/fetch-url-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 +226 -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 +120 -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 +253 -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 +215 -0
- package/dist/src/tools/store-tools.test.js.map +1 -0
- package/dist/src/tools/types.d.ts +129 -0
- package/dist/src/tools/types.js +7 -0
- package/dist/src/tools/types.js.map +1 -0
- package/dist/src/tools/web-search-tool.d.ts +31 -0
- package/dist/src/tools/web-search-tool.js +170 -0
- package/dist/src/tools/web-search-tool.js.map +1 -0
- package/dist/src/tools/web-search-tool.test.d.ts +6 -0
- package/dist/src/tools/web-search-tool.test.js +153 -0
- package/dist/src/tools/web-search-tool.test.js.map +1 -0
- package/dist/src/tools/web-tools-shared.d.ts +21 -0
- package/dist/src/tools/web-tools-shared.js +32 -0
- package/dist/src/tools/web-tools-shared.js.map +1 -0
- package/dist/src/types.d.ts +40 -12
- package/dist/src/types.js +16 -2
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -4
- package/dist/src/__tests__/sse-contract.test.js +0 -464
- package/dist/src/__tests__/sse-contract.test.js.map +0 -1
- package/dist/src/__tests__/tools.test.js +0 -583
- package/dist/src/__tests__/tools.test.js.map +0 -1
- 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.d.ts +0 -6
- 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/session-store.d.ts +0 -62
- package/dist/src/agent/session-store.js +0 -151
- package/dist/src/agent/session-store.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.d.ts +0 -6
- 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/admin-file-tools.d.ts +0 -136
- package/dist/src/session/admin-file-tools.js +0 -240
- package/dist/src/session/admin-file-tools.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 -455
- 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 -834
- package/dist/src/session/session-runner.test.js.map +0 -1
- /package/dist/src/{__tests__/sse-contract.test.d.ts → __fixtures__/e2e.test.d.ts} +0 -0
- /package/dist/src/{__tests__/tools.test.d.ts → __fixtures__/smoke.test.d.ts} +0 -0
- /package/dist/src/agent/{write-repo-file.test.d.ts → loop.test.d.ts} +0 -0
|
@@ -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,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import type { WebToolsConfig } from '@amodalai/types';
|
|
7
|
+
/** Default Gemini model for search + urlContext when none is configured. */
|
|
8
|
+
export declare const DEFAULT_SEARCH_MODEL = "gemini-3-flash-preview";
|
|
9
|
+
/** A single grounded source citation (from googleSearch or urlContext). */
|
|
10
|
+
export interface SearchSource {
|
|
11
|
+
/** Fully-qualified source URL. */
|
|
12
|
+
uri: string;
|
|
13
|
+
/** Human-readable title if the provider supplied one. */
|
|
14
|
+
title?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Result of a grounded search query. */
|
|
17
|
+
export interface SearchResult {
|
|
18
|
+
/** Synthesized answer text from the model. */
|
|
19
|
+
text: string;
|
|
20
|
+
/** Source URLs the answer was grounded in (may be empty). */
|
|
21
|
+
sources: SearchSource[];
|
|
22
|
+
}
|
|
23
|
+
/** Result of a grounded URL fetch. */
|
|
24
|
+
export interface FetchResult {
|
|
25
|
+
/** Extracted page content as markdown (or summary if `prompt` was provided). */
|
|
26
|
+
text: string;
|
|
27
|
+
/** URLs that were actually retrieved by urlContext (usually 1, may be 0 on failure). */
|
|
28
|
+
retrievedUrls: string[];
|
|
29
|
+
}
|
|
30
|
+
/** Options for a single search call. */
|
|
31
|
+
export interface SearchOptions {
|
|
32
|
+
/** Abort signal for cancellation/timeout. */
|
|
33
|
+
signal?: AbortSignal;
|
|
34
|
+
}
|
|
35
|
+
/** Options for a single fetch call. */
|
|
36
|
+
export interface FetchOptions {
|
|
37
|
+
/** Extraction prompt — what to pull from the page. Defaults to "render as markdown". */
|
|
38
|
+
prompt?: string;
|
|
39
|
+
/** Abort signal for cancellation/timeout. */
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Narrow, purpose-specific interface for grounded search + fetch.
|
|
44
|
+
*
|
|
45
|
+
* Not an `LLMProvider` — it returns grounding metadata that `LLMProvider`
|
|
46
|
+
* doesn't surface. Tool executors (`web_search`, `fetch_url`) depend on
|
|
47
|
+
* this interface, not on the concrete AI SDK types.
|
|
48
|
+
*/
|
|
49
|
+
export interface SearchProvider {
|
|
50
|
+
/** Run a grounded search query. */
|
|
51
|
+
search(query: string, opts?: SearchOptions): Promise<SearchResult>;
|
|
52
|
+
/** Fetch + extract content from a URL using urlContext grounding. */
|
|
53
|
+
fetchUrl(url: string, opts?: FetchOptions): Promise<FetchResult>;
|
|
54
|
+
/** Model identifier used for introspection/logging. */
|
|
55
|
+
readonly model: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Create a SearchProvider from webTools config.
|
|
59
|
+
*
|
|
60
|
+
* Throws `ConfigError` when the provider string is unsupported. All
|
|
61
|
+
* current config values go through Zod validation at load time, so this
|
|
62
|
+
* is defensive rather than user-facing.
|
|
63
|
+
*/
|
|
64
|
+
export declare function createSearchProvider(config: WebToolsConfig): SearchProvider;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Search provider: dedicated Gemini Flash instance for web_search + fetch_url.
|
|
8
|
+
*
|
|
9
|
+
* This is SEPARATE from the main LLM provider. Regardless of what model the
|
|
10
|
+
* agent is using (Anthropic/OpenAI/Google), web search and URL fetch always
|
|
11
|
+
* route through a Gemini Flash call with Google Search + urlContext grounding
|
|
12
|
+
* enabled. That gives us synthesized answers with cited URLs without paying
|
|
13
|
+
* the main-model rate and without coupling search to the main provider.
|
|
14
|
+
*
|
|
15
|
+
* Deviation from the implementation plan: the plan said to return an
|
|
16
|
+
* `LLMProvider` wrapper, but `LLMProvider.generateText` doesn't expose
|
|
17
|
+
* `providerMetadata`, which is where grounding sources live. Rather than
|
|
18
|
+
* pollute `LLMProvider` with Google-specific fields, we return a narrow
|
|
19
|
+
* purpose-specific interface with `search()` and `fetchUrl()` methods that
|
|
20
|
+
* yield `{ text, sources }` shaped results.
|
|
21
|
+
*/
|
|
22
|
+
import { generateText } from 'ai';
|
|
23
|
+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
24
|
+
import { ConfigError, ProviderError } from '../errors.js';
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Constants
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/** Default Gemini model for search + urlContext when none is configured. */
|
|
29
|
+
export const DEFAULT_SEARCH_MODEL = 'gemini-3-flash-preview';
|
|
30
|
+
/**
|
|
31
|
+
* Preamble prepended to every grounded search query. Biases Gemini toward
|
|
32
|
+
* authoritative sources and precise citation. ~30 tokens per call.
|
|
33
|
+
*/
|
|
34
|
+
const SEARCH_SYSTEM_PREAMBLE = 'Prefer authoritative sources: official documentation, GitHub, package registries, release notes. ' +
|
|
35
|
+
'When asked for a version number, date, or other exact value, cite it directly from the source. ' +
|
|
36
|
+
'If sources disagree, say so.';
|
|
37
|
+
/** Tool names required by the Google provider — must match SDK expectations. */
|
|
38
|
+
const GOOGLE_SEARCH_TOOL_NAME = 'google_search';
|
|
39
|
+
const URL_CONTEXT_TOOL_NAME = 'url_context';
|
|
40
|
+
function extractGoogleMetadata(providerMetadata) {
|
|
41
|
+
if (!providerMetadata)
|
|
42
|
+
return undefined;
|
|
43
|
+
const google = providerMetadata['google'];
|
|
44
|
+
if (!google || typeof google !== 'object')
|
|
45
|
+
return undefined;
|
|
46
|
+
return google;
|
|
47
|
+
}
|
|
48
|
+
function extractSources(metadata) {
|
|
49
|
+
const chunks = metadata?.groundingMetadata?.groundingChunks;
|
|
50
|
+
if (!Array.isArray(chunks))
|
|
51
|
+
return [];
|
|
52
|
+
const sources = [];
|
|
53
|
+
for (const chunk of chunks) {
|
|
54
|
+
const uri = chunk.web?.uri;
|
|
55
|
+
if (typeof uri === 'string' && uri.length > 0) {
|
|
56
|
+
sources.push({
|
|
57
|
+
uri,
|
|
58
|
+
...(chunk.web?.title ? { title: chunk.web.title } : {}),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return sources;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Extract an HTTP status code from an AI SDK error if present. The SDK wraps
|
|
66
|
+
* provider failures in `AI_APICallError` which carries `statusCode`. We use
|
|
67
|
+
* this to classify failures into auth/quota/transient for the tool executors.
|
|
68
|
+
*/
|
|
69
|
+
function extractStatusCode(err) {
|
|
70
|
+
if (err && typeof err === 'object' && 'statusCode' in err) {
|
|
71
|
+
const code = err.statusCode;
|
|
72
|
+
if (typeof code === 'number')
|
|
73
|
+
return code;
|
|
74
|
+
}
|
|
75
|
+
// Error wrapper — check cause
|
|
76
|
+
if (err instanceof Error && err.cause)
|
|
77
|
+
return extractStatusCode(err.cause);
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
function extractRetrievedUrls(metadata) {
|
|
81
|
+
const entries = metadata?.urlContextMetadata?.urlMetadata;
|
|
82
|
+
if (!Array.isArray(entries))
|
|
83
|
+
return [];
|
|
84
|
+
const urls = [];
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
if (typeof entry.retrievedUrl === 'string' && entry.retrievedUrl.length > 0) {
|
|
87
|
+
urls.push(entry.retrievedUrl);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return urls;
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Factory
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
/**
|
|
96
|
+
* Create a SearchProvider from webTools config.
|
|
97
|
+
*
|
|
98
|
+
* Throws `ConfigError` when the provider string is unsupported. All
|
|
99
|
+
* current config values go through Zod validation at load time, so this
|
|
100
|
+
* is defensive rather than user-facing.
|
|
101
|
+
*/
|
|
102
|
+
export function createSearchProvider(config) {
|
|
103
|
+
if (config.provider !== 'google') {
|
|
104
|
+
throw new ConfigError(`Unsupported webTools provider: ${config.provider}`, {
|
|
105
|
+
key: 'webTools.provider',
|
|
106
|
+
suggestion: 'Only "google" is supported today.',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const google = createGoogleGenerativeAI({ apiKey: config.apiKey });
|
|
110
|
+
const modelId = config.model ?? DEFAULT_SEARCH_MODEL;
|
|
111
|
+
const model = google(modelId);
|
|
112
|
+
return {
|
|
113
|
+
model: modelId,
|
|
114
|
+
async search(query, opts) {
|
|
115
|
+
try {
|
|
116
|
+
const result = await generateText({
|
|
117
|
+
model,
|
|
118
|
+
system: SEARCH_SYSTEM_PREAMBLE,
|
|
119
|
+
prompt: query,
|
|
120
|
+
tools: {
|
|
121
|
+
[GOOGLE_SEARCH_TOOL_NAME]: google.tools.googleSearch({}),
|
|
122
|
+
},
|
|
123
|
+
...(opts?.signal ? { abortSignal: opts.signal } : {}),
|
|
124
|
+
});
|
|
125
|
+
const metadata = extractGoogleMetadata(result.providerMetadata);
|
|
126
|
+
return {
|
|
127
|
+
text: result.text,
|
|
128
|
+
sources: extractSources(metadata),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
const statusCode = extractStatusCode(err);
|
|
133
|
+
throw new ProviderError('Grounded search failed', {
|
|
134
|
+
provider: 'google',
|
|
135
|
+
...(statusCode !== undefined ? { statusCode } : {}),
|
|
136
|
+
retryable: statusCode !== undefined && statusCode >= 500,
|
|
137
|
+
context: { model: modelId, operation: 'search' },
|
|
138
|
+
cause: err,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
async fetchUrl(url, opts) {
|
|
143
|
+
const prompt = opts?.prompt
|
|
144
|
+
? `Fetch ${url} and ${opts.prompt}. Respond with the result.`
|
|
145
|
+
: `Fetch ${url} and render the page content as markdown. Preserve headings, links, and lists.`;
|
|
146
|
+
try {
|
|
147
|
+
const result = await generateText({
|
|
148
|
+
model,
|
|
149
|
+
prompt,
|
|
150
|
+
tools: {
|
|
151
|
+
[URL_CONTEXT_TOOL_NAME]: google.tools.urlContext({}),
|
|
152
|
+
},
|
|
153
|
+
...(opts?.signal ? { abortSignal: opts.signal } : {}),
|
|
154
|
+
});
|
|
155
|
+
const metadata = extractGoogleMetadata(result.providerMetadata);
|
|
156
|
+
return {
|
|
157
|
+
text: result.text,
|
|
158
|
+
retrievedUrls: extractRetrievedUrls(metadata),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
const statusCode = extractStatusCode(err);
|
|
163
|
+
throw new ProviderError('Grounded URL fetch failed', {
|
|
164
|
+
provider: 'google',
|
|
165
|
+
...(statusCode !== undefined ? { statusCode } : {}),
|
|
166
|
+
retryable: statusCode !== undefined && statusCode >= 500,
|
|
167
|
+
context: { model: modelId, operation: 'fetchUrl', url },
|
|
168
|
+
cause: err,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=search-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-provider.js","sourceRoot":"","sources":["../../../src/providers/search-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
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
|
+
* Optional provider-native token counter. When implemented, the runtime
|
|
100
|
+
* uses this to decide when to compact context (more accurate than the
|
|
101
|
+
* default 4-chars-per-token heuristic). Implementations should be cheap
|
|
102
|
+
* and synchronous — return an estimate based on a local tokenizer, not
|
|
103
|
+
* an API call.
|
|
104
|
+
*/
|
|
105
|
+
countTokens?(messages: ModelMessage[]): number;
|
|
106
|
+
}
|
|
107
|
+
export interface ProviderConfig {
|
|
108
|
+
/** Provider name: 'anthropic', 'openai', 'google', 'deepseek', etc. */
|
|
109
|
+
provider: string;
|
|
110
|
+
/** Model name: 'claude-sonnet-4-20250514', 'gpt-4o', etc. */
|
|
111
|
+
model: string;
|
|
112
|
+
/** API key (resolved from env or credentials) */
|
|
113
|
+
apiKey?: string;
|
|
114
|
+
/** Custom base URL (for self-hosted or proxy endpoints) */
|
|
115
|
+
baseUrl?: string;
|
|
116
|
+
/** AWS region (for Bedrock) */
|
|
117
|
+
region?: string;
|
|
118
|
+
}
|
|
@@ -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;
|
|
@@ -53,9 +54,16 @@ export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
|
53
54
|
session_id: z.ZodOptional<z.ZodString>;
|
|
54
55
|
role: z.ZodOptional<z.ZodString>;
|
|
55
56
|
deploy_id: z.ZodOptional<z.ZodString>;
|
|
57
|
+
/**
|
|
58
|
+
* Optional session-wide **token** budget cap (cumulative across all
|
|
59
|
+
* turns; soft ceiling — single turns can overshoot by maxOutputTokens
|
|
60
|
+
* + tool result sizes). Applied only when this request creates a new
|
|
61
|
+
* session. Distinct from the LLM-API per-call max_tokens.
|
|
62
|
+
*/
|
|
63
|
+
max_session_tokens: z.ZodOptional<z.ZodNumber>;
|
|
56
64
|
}, "strip", z.ZodTypeAny, {
|
|
57
65
|
messages: {
|
|
58
|
-
role: "
|
|
66
|
+
role: "system" | "user" | "assistant";
|
|
59
67
|
content?: string | undefined;
|
|
60
68
|
parts?: {
|
|
61
69
|
type: string;
|
|
@@ -65,9 +73,10 @@ export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
|
65
73
|
session_id?: string | undefined;
|
|
66
74
|
role?: string | undefined;
|
|
67
75
|
deploy_id?: string | undefined;
|
|
76
|
+
max_session_tokens?: number | undefined;
|
|
68
77
|
}, {
|
|
69
78
|
messages: {
|
|
70
|
-
role: "
|
|
79
|
+
role: "system" | "user" | "assistant";
|
|
71
80
|
content?: string | undefined;
|
|
72
81
|
parts?: {
|
|
73
82
|
type: string;
|
|
@@ -77,6 +86,7 @@ export declare const AIStreamRequestSchema: z.ZodObject<{
|
|
|
77
86
|
session_id?: string | undefined;
|
|
78
87
|
role?: string | undefined;
|
|
79
88
|
deploy_id?: string | undefined;
|
|
89
|
+
max_session_tokens?: number | undefined;
|
|
80
90
|
}>;
|
|
81
91
|
export type AIStreamRequest = z.infer<typeof AIStreamRequestSchema>;
|
|
82
92
|
interface UIMessageStart {
|
|
@@ -152,9 +162,17 @@ interface AdapterState {
|
|
|
152
162
|
export declare function translateEvent(event: SSEEvent, state: AdapterState): UIStreamEvent[];
|
|
153
163
|
export declare function extractUserMessage(messages: AIStreamRequest['messages']): string;
|
|
154
164
|
export interface AIStreamRouterOptions {
|
|
155
|
-
sessionManager:
|
|
165
|
+
sessionManager: StandaloneSessionManager;
|
|
166
|
+
bundleResolver: BundleResolver;
|
|
167
|
+
shared: SharedResources;
|
|
156
168
|
/** Factory that builds per-request stream hooks from the auth context */
|
|
157
169
|
createStreamHooks?: (auth?: AuthContext) => StreamHooks;
|
|
170
|
+
/** Server-side summarizer hook passed into every runMessage call. */
|
|
171
|
+
summarizeToolResult?: (opts: {
|
|
172
|
+
toolName: string;
|
|
173
|
+
content: string;
|
|
174
|
+
signal: AbortSignal;
|
|
175
|
+
}) => Promise<string>;
|
|
158
176
|
}
|
|
159
177
|
export declare function createAIStreamRouter(options: AIStreamRouterOptions): Router;
|
|
160
178
|
export {};
|