@copilotkit/runtime 1.54.1-next.6 → 1.55.0-next.7
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/.eslintrc.js +4 -4
- package/CHANGELOG.md +117 -106
- package/dist/_virtual/_rolldown/runtime.mjs +25 -1
- package/dist/agent/index.cjs +643 -0
- package/dist/agent/index.cjs.map +1 -0
- package/dist/agent/index.d.cts +263 -0
- package/dist/agent/index.d.cts.map +1 -0
- package/dist/agent/index.d.mts +263 -0
- package/dist/agent/index.d.mts.map +1 -0
- package/dist/agent/index.mjs +635 -0
- package/dist/agent/index.mjs.map +1 -0
- package/dist/graphql/message-conversion/agui-to-gql.cjs.map +1 -1
- package/dist/graphql/message-conversion/agui-to-gql.mjs.map +1 -1
- package/dist/lib/integrations/nextjs/app-router.cjs +2 -2
- package/dist/lib/integrations/nextjs/app-router.cjs.map +1 -1
- package/dist/lib/integrations/nextjs/app-router.mjs +1 -1
- package/dist/lib/integrations/nextjs/app-router.mjs.map +1 -1
- package/dist/lib/integrations/node-http/index.cjs +2 -3
- package/dist/lib/integrations/node-http/index.cjs.map +1 -1
- package/dist/lib/integrations/node-http/index.mjs +1 -1
- package/dist/lib/integrations/node-http/index.mjs.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.cjs +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts +2 -2
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.cts.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts +3 -3
- package/dist/lib/runtime/agent-integrations/langgraph/agent.d.mts.map +1 -1
- package/dist/lib/runtime/agent-integrations/langgraph/agent.mjs +1 -1
- package/dist/lib/runtime/copilot-runtime.cjs +7 -5
- package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.cts +10 -8
- package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.d.mts +10 -8
- package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
- package/dist/lib/runtime/copilot-runtime.mjs +7 -5
- package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.cjs +2 -2
- package/dist/lib/runtime/telemetry-agent-runner.cjs.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.cts +2 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.cts.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.mts +2 -1
- package/dist/lib/runtime/telemetry-agent-runner.d.mts.map +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.mjs +1 -1
- package/dist/lib/runtime/telemetry-agent-runner.mjs.map +1 -1
- package/dist/lib/telemetry-client.cjs +1 -1
- package/dist/lib/telemetry-client.mjs +1 -1
- package/dist/package.cjs +21 -4
- package/dist/package.mjs +21 -4
- package/dist/service-adapters/anthropic/anthropic-adapter.d.mts +1 -1
- package/dist/v2/index.cjs +41 -15
- package/dist/v2/index.d.cts +14 -2
- package/dist/v2/index.d.mts +14 -2
- package/dist/v2/index.mjs +13 -4
- package/dist/v2/runtime/endpoints/express-single.cjs +190 -0
- package/dist/v2/runtime/endpoints/express-single.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/express-single.d.cts +16 -0
- package/dist/v2/runtime/endpoints/express-single.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/express-single.d.mts +16 -0
- package/dist/v2/runtime/endpoints/express-single.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/express-single.mjs +187 -0
- package/dist/v2/runtime/endpoints/express-single.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/express-utils.cjs +119 -0
- package/dist/v2/runtime/endpoints/express-utils.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/express-utils.mjs +117 -0
- package/dist/v2/runtime/endpoints/express-utils.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/express.cjs +217 -0
- package/dist/v2/runtime/endpoints/express.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/express.d.cts +16 -0
- package/dist/v2/runtime/endpoints/express.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/express.d.mts +16 -0
- package/dist/v2/runtime/endpoints/express.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/express.mjs +214 -0
- package/dist/v2/runtime/endpoints/express.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.cjs +141 -0
- package/dist/v2/runtime/endpoints/hono-single.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.d.cts +41 -0
- package/dist/v2/runtime/endpoints/hono-single.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.d.mts +41 -0
- package/dist/v2/runtime/endpoints/hono-single.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/hono-single.mjs +140 -0
- package/dist/v2/runtime/endpoints/hono-single.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono.cjs +248 -0
- package/dist/v2/runtime/endpoints/hono.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/hono.d.cts +164 -0
- package/dist/v2/runtime/endpoints/hono.d.cts.map +1 -0
- package/dist/v2/runtime/endpoints/hono.d.mts +164 -0
- package/dist/v2/runtime/endpoints/hono.d.mts.map +1 -0
- package/dist/v2/runtime/endpoints/hono.mjs +247 -0
- package/dist/v2/runtime/endpoints/hono.mjs.map +1 -0
- package/dist/v2/runtime/endpoints/index.d.cts +5 -0
- package/dist/v2/runtime/endpoints/index.d.mts +5 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.cjs +68 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.cjs.map +1 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.mjs +65 -0
- package/dist/v2/runtime/endpoints/single-route-helpers.mjs.map +1 -0
- package/dist/v2/runtime/handlers/get-runtime-info.cjs +51 -0
- package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -0
- package/dist/v2/runtime/handlers/get-runtime-info.mjs +51 -0
- package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-connect.cjs +49 -0
- package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-connect.mjs +49 -0
- package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.cjs +61 -0
- package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-run.mjs +61 -0
- package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-stop.cjs +47 -0
- package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-stop.mjs +46 -0
- package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-transcribe.cjs +112 -0
- package/dist/v2/runtime/handlers/handle-transcribe.cjs.map +1 -0
- package/dist/v2/runtime/handlers/handle-transcribe.mjs +111 -0
- package/dist/v2/runtime/handlers/handle-transcribe.mjs.map +1 -0
- package/dist/v2/runtime/handlers/header-utils.cjs +26 -0
- package/dist/v2/runtime/handlers/header-utils.cjs.map +1 -0
- package/dist/v2/runtime/handlers/header-utils.mjs +25 -0
- package/dist/v2/runtime/handlers/header-utils.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/connect.cjs +37 -0
- package/dist/v2/runtime/handlers/intelligence/connect.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/connect.mjs +37 -0
- package/dist/v2/runtime/handlers/intelligence/connect.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs +89 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs +88 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs +146 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs +145 -0
- package/dist/v2/runtime/handlers/intelligence/thread-names.mjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/threads.cjs +159 -0
- package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +1 -0
- package/dist/v2/runtime/handlers/intelligence/threads.mjs +154 -0
- package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs +74 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs +70 -0
- package/dist/v2/runtime/handlers/shared/agent-utils.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs +21 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs +20 -0
- package/dist/v2/runtime/handlers/shared/intelligence-utils.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/json-response.cjs +12 -0
- package/dist/v2/runtime/handlers/shared/json-response.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/json-response.mjs +10 -0
- package/dist/v2/runtime/handlers/shared/json-response.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +20 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +20 -0
- package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/sse-response.cjs +69 -0
- package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -0
- package/dist/v2/runtime/handlers/shared/sse-response.mjs +68 -0
- package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/connect.cjs +18 -0
- package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/connect.mjs +18 -0
- package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/run.cjs +18 -0
- package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -0
- package/dist/v2/runtime/handlers/sse/run.mjs +18 -0
- package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -0
- package/dist/v2/runtime/index.d.cts +13 -0
- package/dist/v2/runtime/index.d.mts +14 -0
- package/dist/v2/runtime/intelligence-platform/client.cjs +333 -0
- package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.d.cts +336 -0
- package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.d.mts +336 -0
- package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -0
- package/dist/v2/runtime/intelligence-platform/client.mjs +331 -0
- package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -0
- package/dist/v2/runtime/intelligence-platform/index.d.mts +2 -0
- package/dist/v2/runtime/middleware-sse-parser.cjs +138 -0
- package/dist/v2/runtime/middleware-sse-parser.cjs.map +1 -0
- package/dist/v2/runtime/middleware-sse-parser.d.cts +22 -0
- package/dist/v2/runtime/middleware-sse-parser.d.cts.map +1 -0
- package/dist/v2/runtime/middleware-sse-parser.d.mts +22 -0
- package/dist/v2/runtime/middleware-sse-parser.d.mts.map +1 -0
- package/dist/v2/runtime/middleware-sse-parser.mjs +137 -0
- package/dist/v2/runtime/middleware-sse-parser.mjs.map +1 -0
- package/dist/v2/runtime/middleware.cjs +35 -0
- package/dist/v2/runtime/middleware.cjs.map +1 -0
- package/dist/v2/runtime/middleware.d.cts +32 -0
- package/dist/v2/runtime/middleware.d.cts.map +1 -0
- package/dist/v2/runtime/middleware.d.mts +32 -0
- package/dist/v2/runtime/middleware.d.mts.map +1 -0
- package/dist/v2/runtime/middleware.mjs +33 -0
- package/dist/v2/runtime/middleware.mjs.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.cjs +8 -0
- package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.d.cts +32 -0
- package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.d.mts +32 -0
- package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -0
- package/dist/v2/runtime/runner/agent-runner.mjs +7 -0
- package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -0
- package/dist/v2/runtime/runner/in-memory.cjs +223 -0
- package/dist/v2/runtime/runner/in-memory.cjs.map +1 -0
- package/dist/v2/runtime/runner/in-memory.d.cts +15 -0
- package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -0
- package/dist/v2/runtime/runner/in-memory.d.mts +15 -0
- package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -0
- package/dist/v2/runtime/runner/in-memory.mjs +222 -0
- package/dist/v2/runtime/runner/in-memory.mjs.map +1 -0
- package/dist/v2/runtime/runner/index.d.cts +6 -0
- package/dist/v2/runtime/runner/index.d.mts +6 -0
- package/dist/v2/runtime/runner/index.mjs +7 -0
- package/dist/v2/runtime/runner/intelligence.cjs +246 -0
- package/dist/v2/runtime/runner/intelligence.cjs.map +1 -0
- package/dist/v2/runtime/runner/intelligence.d.cts +57 -0
- package/dist/v2/runtime/runner/intelligence.d.cts.map +1 -0
- package/dist/v2/runtime/runner/intelligence.d.mts +57 -0
- package/dist/v2/runtime/runner/intelligence.d.mts.map +1 -0
- package/dist/v2/runtime/runner/intelligence.mjs +245 -0
- package/dist/v2/runtime/runner/intelligence.mjs.map +1 -0
- package/dist/v2/runtime/runtime.cjs +101 -0
- package/dist/v2/runtime/runtime.cjs.map +1 -0
- package/dist/v2/runtime/runtime.d.cts +132 -0
- package/dist/v2/runtime/runtime.d.cts.map +1 -0
- package/dist/v2/runtime/runtime.d.mts +133 -0
- package/dist/v2/runtime/runtime.d.mts.map +1 -0
- package/dist/v2/runtime/runtime.mjs +97 -0
- package/dist/v2/runtime/runtime.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/scarf-client.cjs +32 -0
- package/dist/v2/runtime/telemetry/scarf-client.cjs.map +1 -0
- package/dist/v2/runtime/telemetry/scarf-client.mjs +32 -0
- package/dist/v2/runtime/telemetry/scarf-client.mjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs +35 -0
- package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -0
- package/dist/v2/runtime/telemetry/telemetry-client.mjs +35 -0
- package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.cjs +8 -0
- package/dist/v2/runtime/transcription-service/transcription-service.cjs.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.cts +15 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.cts.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.mts +15 -0
- package/dist/v2/runtime/transcription-service/transcription-service.d.mts.map +1 -0
- package/dist/v2/runtime/transcription-service/transcription-service.mjs +7 -0
- package/dist/v2/runtime/transcription-service/transcription-service.mjs.map +1 -0
- package/package.json +22 -5
- package/src/agent/__tests__/ai-sdk-v6-compat.test.ts +116 -0
- package/src/agent/__tests__/basic-agent.test.ts +1248 -0
- package/src/agent/__tests__/config-tools-execution.test.ts +516 -0
- package/src/agent/__tests__/mcp-clients.test.ts +260 -0
- package/src/agent/__tests__/property-overrides.test.ts +598 -0
- package/src/agent/__tests__/standard-schema-tools.test.ts +313 -0
- package/src/agent/__tests__/standard-schema-types.test.ts +158 -0
- package/src/agent/__tests__/state-tools.test.ts +436 -0
- package/src/agent/__tests__/test-helpers.ts +178 -0
- package/src/agent/__tests__/utils.test.ts +536 -0
- package/src/agent/__tests__/zod-regression.test.ts +350 -0
- package/src/agent/index.ts +1305 -0
- package/src/graphql/message-conversion/agui-to-gql.test.ts +1 -1
- package/src/graphql/message-conversion/agui-to-gql.ts +1 -1
- package/src/graphql/message-conversion/gql-to-agui.ts +1 -1
- package/src/graphql/message-conversion/roundtrip-conversion.test.ts +1 -1
- package/src/lib/integrations/nextjs/app-router.ts +2 -2
- package/src/lib/integrations/node-http/index.ts +2 -2
- package/src/lib/runtime/copilot-runtime.ts +3 -5
- package/src/lib/runtime/telemetry-agent-runner.ts +1 -1
- package/src/service-adapters/conversion.test.ts +1 -1
- package/src/service-adapters/conversion.ts +1 -28
- package/src/v2/index.ts +5 -2
- package/src/v2/runtime/__tests__/cors-credentials.test.ts +320 -0
- package/src/v2/runtime/__tests__/express-abort-signal.test.ts +25 -0
- package/src/v2/runtime/__tests__/express-body-order.test.ts +76 -0
- package/src/v2/runtime/__tests__/express-single-sse.test.ts +122 -0
- package/src/v2/runtime/__tests__/get-runtime-info.test.ts +141 -0
- package/src/v2/runtime/__tests__/handle-connect.test.ts +423 -0
- package/src/v2/runtime/__tests__/handle-run.test.ts +910 -0
- package/src/v2/runtime/__tests__/handle-threads.test.ts +388 -0
- package/src/v2/runtime/__tests__/handle-transcribe.test.ts +301 -0
- package/src/v2/runtime/__tests__/header-utils.test.ts +88 -0
- package/src/v2/runtime/__tests__/in-process-agent-runner-messages.test.ts +230 -0
- package/src/v2/runtime/__tests__/in-process-agent-runner.test.ts +1030 -0
- package/src/v2/runtime/__tests__/middleware-express.test.ts +206 -0
- package/src/v2/runtime/__tests__/middleware-single-express.test.ts +211 -0
- package/src/v2/runtime/__tests__/middleware-single.test.ts +225 -0
- package/src/v2/runtime/__tests__/middleware-sse-parser.test.ts +187 -0
- package/src/v2/runtime/__tests__/middleware.test.ts +251 -0
- package/src/v2/runtime/__tests__/routing-express.test.ts +174 -0
- package/src/v2/runtime/__tests__/routing-single-express.test.ts +168 -0
- package/src/v2/runtime/__tests__/routing-single.test.ts +193 -0
- package/src/v2/runtime/__tests__/routing.test.ts +257 -0
- package/src/v2/runtime/__tests__/runtime.test.ts +123 -0
- package/src/v2/runtime/__tests__/telemetry.test.ts +167 -0
- package/src/v2/runtime/__tests__/thread-names.test.ts +188 -0
- package/src/v2/runtime/endpoints/express-single.ts +231 -0
- package/src/v2/runtime/endpoints/express-utils.ts +182 -0
- package/src/v2/runtime/endpoints/express.ts +275 -0
- package/src/v2/runtime/endpoints/hono-single.ts +212 -0
- package/src/v2/runtime/endpoints/hono.ts +314 -0
- package/src/v2/runtime/endpoints/index.ts +4 -0
- package/src/v2/runtime/endpoints/single-route-helpers.ts +125 -0
- package/src/v2/runtime/express.ts +2 -0
- package/src/v2/runtime/handler.ts +3 -0
- package/src/v2/runtime/handlers/get-runtime-info.ts +79 -0
- package/src/v2/runtime/handlers/handle-connect.ts +76 -0
- package/src/v2/runtime/handlers/handle-run.ts +89 -0
- package/src/v2/runtime/handlers/handle-stop.ts +76 -0
- package/src/v2/runtime/handlers/handle-threads.ts +7 -0
- package/src/v2/runtime/handlers/handle-transcribe.ts +256 -0
- package/src/v2/runtime/handlers/header-utils.ts +24 -0
- package/src/v2/runtime/handlers/intelligence/connect.ts +65 -0
- package/src/v2/runtime/handlers/intelligence/run.ts +152 -0
- package/src/v2/runtime/handlers/intelligence/thread-names.ts +246 -0
- package/src/v2/runtime/handlers/intelligence/threads.ts +233 -0
- package/src/v2/runtime/handlers/shared/agent-utils.ts +136 -0
- package/src/v2/runtime/handlers/shared/intelligence-utils.ts +21 -0
- package/src/v2/runtime/handlers/shared/json-response.ts +6 -0
- package/src/v2/runtime/handlers/shared/resolve-intelligence-user.ts +25 -0
- package/src/v2/runtime/handlers/shared/sse-response.ts +100 -0
- package/src/v2/runtime/handlers/sse/connect.ts +24 -0
- package/src/v2/runtime/handlers/sse/run.ts +27 -0
- package/src/v2/runtime/index.ts +20 -0
- package/src/v2/runtime/intelligence-platform/__tests__/client.test.ts +605 -0
- package/src/v2/runtime/intelligence-platform/client.ts +659 -0
- package/src/v2/runtime/intelligence-platform/index.ts +10 -0
- package/src/v2/runtime/middleware-sse-parser.ts +200 -0
- package/src/v2/runtime/middleware.ts +115 -0
- package/src/v2/runtime/runner/__tests__/finalize-events.test.ts +109 -0
- package/src/v2/runtime/runner/__tests__/in-memory-runner.e2e.test.ts +775 -0
- package/src/v2/runtime/runner/__tests__/in-memory-runner.test.ts +363 -0
- package/src/v2/runtime/runner/__tests__/intelligence-runner.test.ts +981 -0
- package/src/v2/runtime/runner/agent-runner.ts +36 -0
- package/src/v2/runtime/runner/in-memory.ts +381 -0
- package/src/v2/runtime/runner/index.ts +4 -0
- package/src/v2/runtime/runner/intelligence.ts +429 -0
- package/src/v2/runtime/runtime.ts +260 -0
- package/src/v2/runtime/telemetry/events.ts +35 -0
- package/src/v2/runtime/telemetry/index.ts +7 -0
- package/src/v2/runtime/telemetry/scarf-client.ts +39 -0
- package/src/v2/runtime/telemetry/telemetry-client.ts +70 -0
- package/src/v2/runtime/transcription-service/transcription-service.ts +11 -0
- package/tsconfig.json +9 -2
- package/tsdown.config.ts +1 -0
|
@@ -0,0 +1,1248 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { BasicAgent, defineTool, type ToolDefinition } from "../index";
|
|
4
|
+
import { EventType, type RunAgentInput } from "@ag-ui/client";
|
|
5
|
+
import { streamText } from "ai";
|
|
6
|
+
import {
|
|
7
|
+
mockStreamTextResponse,
|
|
8
|
+
textStart,
|
|
9
|
+
textDelta,
|
|
10
|
+
finish,
|
|
11
|
+
collectEvents,
|
|
12
|
+
toolCallStreamingStart,
|
|
13
|
+
toolCallDelta,
|
|
14
|
+
toolCall,
|
|
15
|
+
toolResult,
|
|
16
|
+
reasoningStart,
|
|
17
|
+
reasoningDelta,
|
|
18
|
+
reasoningEnd,
|
|
19
|
+
} from "./test-helpers";
|
|
20
|
+
|
|
21
|
+
// Mock the ai module
|
|
22
|
+
vi.mock("ai", () => ({
|
|
23
|
+
streamText: vi.fn(),
|
|
24
|
+
tool: vi.fn((config) => config),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
// Mock the SDK clients
|
|
28
|
+
vi.mock("@ai-sdk/openai", () => ({
|
|
29
|
+
createOpenAI: vi.fn(() => (modelId: string) => ({
|
|
30
|
+
modelId,
|
|
31
|
+
provider: "openai",
|
|
32
|
+
})),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
vi.mock("@ai-sdk/anthropic", () => ({
|
|
36
|
+
createAnthropic: vi.fn(() => (modelId: string) => ({
|
|
37
|
+
modelId,
|
|
38
|
+
provider: "anthropic",
|
|
39
|
+
})),
|
|
40
|
+
}));
|
|
41
|
+
|
|
42
|
+
vi.mock("@ai-sdk/google", () => ({
|
|
43
|
+
createGoogleGenerativeAI: vi.fn(() => (modelId: string) => ({
|
|
44
|
+
modelId,
|
|
45
|
+
provider: "google",
|
|
46
|
+
})),
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
describe("BasicAgent", () => {
|
|
50
|
+
const originalEnv = process.env;
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
vi.clearAllMocks();
|
|
54
|
+
process.env = { ...originalEnv };
|
|
55
|
+
process.env.OPENAI_API_KEY = "test-key";
|
|
56
|
+
process.env.ANTHROPIC_API_KEY = "test-key";
|
|
57
|
+
process.env.GOOGLE_API_KEY = "test-key";
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
afterEach(() => {
|
|
61
|
+
process.env = originalEnv;
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("Basic Event Emission", () => {
|
|
65
|
+
it("should emit RUN_STARTED and RUN_FINISHED events", async () => {
|
|
66
|
+
const agent = new BasicAgent({
|
|
67
|
+
model: "openai/gpt-4o",
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
vi.mocked(streamText).mockReturnValue(
|
|
71
|
+
mockStreamTextResponse([textDelta("Hello"), finish()]) as any,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const input: RunAgentInput = {
|
|
75
|
+
threadId: "thread1",
|
|
76
|
+
runId: "run1",
|
|
77
|
+
messages: [],
|
|
78
|
+
tools: [],
|
|
79
|
+
context: [],
|
|
80
|
+
state: {},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const events = await collectEvents(agent["run"](input));
|
|
84
|
+
|
|
85
|
+
expect(events[0]).toMatchObject({
|
|
86
|
+
type: EventType.RUN_STARTED,
|
|
87
|
+
threadId: "thread1",
|
|
88
|
+
runId: "run1",
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
expect(events[events.length - 1]).toMatchObject({
|
|
92
|
+
type: EventType.RUN_FINISHED,
|
|
93
|
+
threadId: "thread1",
|
|
94
|
+
runId: "run1",
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should emit TEXT_MESSAGE_CHUNK events for text deltas", async () => {
|
|
99
|
+
const agent = new BasicAgent({
|
|
100
|
+
model: "openai/gpt-4o",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
vi.mocked(streamText).mockReturnValue(
|
|
104
|
+
mockStreamTextResponse([
|
|
105
|
+
textDelta("Hello"),
|
|
106
|
+
textDelta(" world"),
|
|
107
|
+
finish(),
|
|
108
|
+
]) as any,
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const input: RunAgentInput = {
|
|
112
|
+
threadId: "thread1",
|
|
113
|
+
runId: "run1",
|
|
114
|
+
messages: [],
|
|
115
|
+
tools: [],
|
|
116
|
+
context: [],
|
|
117
|
+
state: {},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const events = await collectEvents(agent["run"](input));
|
|
121
|
+
|
|
122
|
+
const textEvents = events.filter(
|
|
123
|
+
(e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
124
|
+
);
|
|
125
|
+
expect(textEvents).toHaveLength(2);
|
|
126
|
+
expect(textEvents[0]).toMatchObject({
|
|
127
|
+
type: EventType.TEXT_MESSAGE_CHUNK,
|
|
128
|
+
role: "assistant",
|
|
129
|
+
delta: "Hello",
|
|
130
|
+
});
|
|
131
|
+
expect(textEvents[1]).toMatchObject({
|
|
132
|
+
type: EventType.TEXT_MESSAGE_CHUNK,
|
|
133
|
+
delta: " world",
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should generate unique messageId when provider returns id '0'", async () => {
|
|
138
|
+
const agent = new BasicAgent({
|
|
139
|
+
model: "openai/gpt-4o",
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
vi.mocked(streamText).mockReturnValue(
|
|
143
|
+
mockStreamTextResponse([
|
|
144
|
+
textStart("0"), // Simulate Google Gemini returning "0"
|
|
145
|
+
textDelta("First message"),
|
|
146
|
+
finish(),
|
|
147
|
+
]) as any,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const input: RunAgentInput = {
|
|
151
|
+
threadId: "thread1",
|
|
152
|
+
runId: "run1",
|
|
153
|
+
messages: [],
|
|
154
|
+
tools: [],
|
|
155
|
+
context: [],
|
|
156
|
+
state: {},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const events = await collectEvents(agent["run"](input));
|
|
160
|
+
|
|
161
|
+
const textEvents = events.filter(
|
|
162
|
+
(e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
163
|
+
);
|
|
164
|
+
expect(textEvents).toHaveLength(1);
|
|
165
|
+
|
|
166
|
+
// Verify that messageId is NOT "0" - should be a UUID
|
|
167
|
+
expect(textEvents[0].messageId).not.toBe("0");
|
|
168
|
+
expect(textEvents[0].messageId).toMatch(
|
|
169
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("should use provider-supplied messageId when it's not '0'", async () => {
|
|
174
|
+
const agent = new BasicAgent({
|
|
175
|
+
model: "openai/gpt-4o",
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const validId = "msg_abc123";
|
|
179
|
+
vi.mocked(streamText).mockReturnValue(
|
|
180
|
+
mockStreamTextResponse([
|
|
181
|
+
textStart(validId), // Valid ID from provider
|
|
182
|
+
textDelta("Test message"),
|
|
183
|
+
finish(),
|
|
184
|
+
]) as any,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const input: RunAgentInput = {
|
|
188
|
+
threadId: "thread1",
|
|
189
|
+
runId: "run1",
|
|
190
|
+
messages: [],
|
|
191
|
+
tools: [],
|
|
192
|
+
context: [],
|
|
193
|
+
state: {},
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const events = await collectEvents(agent["run"](input));
|
|
197
|
+
|
|
198
|
+
const textEvents = events.filter(
|
|
199
|
+
(e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
200
|
+
);
|
|
201
|
+
expect(textEvents).toHaveLength(1);
|
|
202
|
+
|
|
203
|
+
// Verify that the valid ID from provider is used
|
|
204
|
+
expect(textEvents[0].messageId).toBe(validId);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe("Tool Call Events", () => {
|
|
209
|
+
it("should emit tool call lifecycle events", async () => {
|
|
210
|
+
const agent = new BasicAgent({
|
|
211
|
+
model: "openai/gpt-4o",
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
vi.mocked(streamText).mockReturnValue(
|
|
215
|
+
mockStreamTextResponse([
|
|
216
|
+
toolCallStreamingStart("call1", "testTool"),
|
|
217
|
+
toolCallDelta("call1", '{"arg'),
|
|
218
|
+
toolCallDelta("call1", '":"val"}'),
|
|
219
|
+
toolCall("call1", "testTool", { arg: "val" }),
|
|
220
|
+
toolResult("call1", "testTool", { result: "success" }),
|
|
221
|
+
finish(),
|
|
222
|
+
]) as any,
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const input: RunAgentInput = {
|
|
226
|
+
threadId: "thread1",
|
|
227
|
+
runId: "run1",
|
|
228
|
+
messages: [],
|
|
229
|
+
tools: [],
|
|
230
|
+
context: [],
|
|
231
|
+
state: {},
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const events = await collectEvents(agent["run"](input));
|
|
235
|
+
|
|
236
|
+
// Check for TOOL_CALL_START
|
|
237
|
+
const startEvent = events.find(
|
|
238
|
+
(e: any) => e.type === EventType.TOOL_CALL_START,
|
|
239
|
+
);
|
|
240
|
+
expect(startEvent).toMatchObject({
|
|
241
|
+
type: EventType.TOOL_CALL_START,
|
|
242
|
+
toolCallId: "call1",
|
|
243
|
+
toolCallName: "testTool",
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Check for TOOL_CALL_ARGS
|
|
247
|
+
const argsEvents = events.filter(
|
|
248
|
+
(e: any) => e.type === EventType.TOOL_CALL_ARGS,
|
|
249
|
+
);
|
|
250
|
+
expect(argsEvents).toHaveLength(2);
|
|
251
|
+
|
|
252
|
+
// Check for TOOL_CALL_END
|
|
253
|
+
const endEvent = events.find(
|
|
254
|
+
(e: any) => e.type === EventType.TOOL_CALL_END,
|
|
255
|
+
);
|
|
256
|
+
expect(endEvent).toMatchObject({
|
|
257
|
+
type: EventType.TOOL_CALL_END,
|
|
258
|
+
toolCallId: "call1",
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Check for TOOL_CALL_RESULT
|
|
262
|
+
const resultEvent = events.find(
|
|
263
|
+
(e: any) => e.type === EventType.TOOL_CALL_RESULT,
|
|
264
|
+
);
|
|
265
|
+
expect(resultEvent).toMatchObject({
|
|
266
|
+
type: EventType.TOOL_CALL_RESULT,
|
|
267
|
+
role: "tool",
|
|
268
|
+
toolCallId: "call1",
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe("Prompt Building", () => {
|
|
274
|
+
it("should not add system message when no prompt, context, or state", async () => {
|
|
275
|
+
const agent = new BasicAgent({
|
|
276
|
+
model: "openai/gpt-4o",
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
vi.mocked(streamText).mockReturnValue(
|
|
280
|
+
mockStreamTextResponse([finish()]) as any,
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
const input: RunAgentInput = {
|
|
284
|
+
threadId: "thread1",
|
|
285
|
+
runId: "run1",
|
|
286
|
+
messages: [{ id: "1", role: "user", content: "Hello" }],
|
|
287
|
+
tools: [],
|
|
288
|
+
context: [],
|
|
289
|
+
state: {},
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
await collectEvents(agent["run"](input));
|
|
293
|
+
|
|
294
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
295
|
+
expect(callArgs.messages).toHaveLength(1);
|
|
296
|
+
expect(callArgs.messages[0].role).toBe("user");
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("should prepend system message with config prompt", async () => {
|
|
300
|
+
const agent = new BasicAgent({
|
|
301
|
+
model: "openai/gpt-4o",
|
|
302
|
+
prompt: "You are a helpful assistant.",
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
vi.mocked(streamText).mockReturnValue(
|
|
306
|
+
mockStreamTextResponse([finish()]) as any,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
const input: RunAgentInput = {
|
|
310
|
+
threadId: "thread1",
|
|
311
|
+
runId: "run1",
|
|
312
|
+
messages: [{ id: "1", role: "user", content: "Hello" }],
|
|
313
|
+
tools: [],
|
|
314
|
+
context: [],
|
|
315
|
+
state: {},
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
await collectEvents(agent["run"](input));
|
|
319
|
+
|
|
320
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
321
|
+
expect(callArgs.messages).toHaveLength(2);
|
|
322
|
+
expect(callArgs.messages[0]).toMatchObject({
|
|
323
|
+
role: "system",
|
|
324
|
+
content: "You are a helpful assistant.",
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("should include context in system message", async () => {
|
|
329
|
+
const agent = new BasicAgent({
|
|
330
|
+
model: "openai/gpt-4o",
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
vi.mocked(streamText).mockReturnValue(
|
|
334
|
+
mockStreamTextResponse([finish()]) as any,
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
const input: RunAgentInput = {
|
|
338
|
+
threadId: "thread1",
|
|
339
|
+
runId: "run1",
|
|
340
|
+
messages: [],
|
|
341
|
+
tools: [],
|
|
342
|
+
context: [
|
|
343
|
+
{ description: "User Name", value: "John Doe" },
|
|
344
|
+
{ description: "Location", value: "New York" },
|
|
345
|
+
],
|
|
346
|
+
state: {},
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
await collectEvents(agent["run"](input));
|
|
350
|
+
|
|
351
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
352
|
+
const systemMessage = callArgs.messages[0];
|
|
353
|
+
expect(systemMessage.role).toBe("system");
|
|
354
|
+
expect(systemMessage.content).toContain("Context from the application");
|
|
355
|
+
expect(systemMessage.content).toContain("User Name");
|
|
356
|
+
expect(systemMessage.content).toContain("John Doe");
|
|
357
|
+
expect(systemMessage.content).toContain("Location");
|
|
358
|
+
expect(systemMessage.content).toContain("New York");
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it("should include state in system message", async () => {
|
|
362
|
+
const agent = new BasicAgent({
|
|
363
|
+
model: "openai/gpt-4o",
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
vi.mocked(streamText).mockReturnValue(
|
|
367
|
+
mockStreamTextResponse([finish()]) as any,
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
const input: RunAgentInput = {
|
|
371
|
+
threadId: "thread1",
|
|
372
|
+
runId: "run1",
|
|
373
|
+
messages: [],
|
|
374
|
+
tools: [],
|
|
375
|
+
context: [],
|
|
376
|
+
state: { counter: 0, items: ["a", "b"] },
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
await collectEvents(agent["run"](input));
|
|
380
|
+
|
|
381
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
382
|
+
const systemMessage = callArgs.messages[0];
|
|
383
|
+
expect(systemMessage.role).toBe("system");
|
|
384
|
+
expect(systemMessage.content).toContain("Application State");
|
|
385
|
+
expect(systemMessage.content).toContain("AGUISendStateSnapshot");
|
|
386
|
+
expect(systemMessage.content).toContain("AGUISendStateDelta");
|
|
387
|
+
expect(systemMessage.content).toContain('"counter": 0');
|
|
388
|
+
expect(systemMessage.content).toContain('"items"');
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it("should combine prompt, context, and state", async () => {
|
|
392
|
+
const agent = new BasicAgent({
|
|
393
|
+
model: "openai/gpt-4o",
|
|
394
|
+
prompt: "You are helpful.",
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
vi.mocked(streamText).mockReturnValue(
|
|
398
|
+
mockStreamTextResponse([finish()]) as any,
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
const input: RunAgentInput = {
|
|
402
|
+
threadId: "thread1",
|
|
403
|
+
runId: "run1",
|
|
404
|
+
messages: [],
|
|
405
|
+
tools: [],
|
|
406
|
+
context: [{ description: "Context", value: "Data" }],
|
|
407
|
+
state: { value: 1 },
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
await collectEvents(agent["run"](input));
|
|
411
|
+
|
|
412
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
413
|
+
const systemMessage = callArgs.messages[0];
|
|
414
|
+
expect(systemMessage.content).toContain("You are helpful.");
|
|
415
|
+
expect(systemMessage.content).toContain("Context from the application");
|
|
416
|
+
expect(systemMessage.content).toContain("Application State");
|
|
417
|
+
|
|
418
|
+
// Check order: prompt, then context, then state
|
|
419
|
+
const promptIndex = systemMessage.content.indexOf("You are helpful.");
|
|
420
|
+
const contextIndex = systemMessage.content.indexOf(
|
|
421
|
+
"Context from the application",
|
|
422
|
+
);
|
|
423
|
+
const stateIndex = systemMessage.content.indexOf("Application State");
|
|
424
|
+
|
|
425
|
+
expect(promptIndex).toBeLessThan(contextIndex);
|
|
426
|
+
expect(contextIndex).toBeLessThan(stateIndex);
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
describe("Forward System/Developer Messages", () => {
|
|
431
|
+
it("should ignore system messages by default", async () => {
|
|
432
|
+
const agent = new BasicAgent({
|
|
433
|
+
model: "openai/gpt-4o",
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
vi.mocked(streamText).mockReturnValue(
|
|
437
|
+
mockStreamTextResponse([finish()]) as any,
|
|
438
|
+
);
|
|
439
|
+
|
|
440
|
+
const input: RunAgentInput = {
|
|
441
|
+
threadId: "thread1",
|
|
442
|
+
runId: "run1",
|
|
443
|
+
messages: [
|
|
444
|
+
{ id: "sys1", role: "system", content: "System instruction" },
|
|
445
|
+
{ id: "user1", role: "user", content: "Hello" },
|
|
446
|
+
],
|
|
447
|
+
tools: [],
|
|
448
|
+
context: [],
|
|
449
|
+
state: {},
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
await collectEvents(agent["run"](input));
|
|
453
|
+
|
|
454
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
455
|
+
// Should only have the user message, system message ignored
|
|
456
|
+
expect(callArgs.messages).toHaveLength(1);
|
|
457
|
+
expect(callArgs.messages[0].role).toBe("user");
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it("should ignore developer messages by default", async () => {
|
|
461
|
+
const agent = new BasicAgent({
|
|
462
|
+
model: "openai/gpt-4o",
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
vi.mocked(streamText).mockReturnValue(
|
|
466
|
+
mockStreamTextResponse([finish()]) as any,
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const input: RunAgentInput = {
|
|
470
|
+
threadId: "thread1",
|
|
471
|
+
runId: "run1",
|
|
472
|
+
messages: [
|
|
473
|
+
{ id: "dev1", role: "developer", content: "Developer hint" },
|
|
474
|
+
{ id: "user1", role: "user", content: "Hello" },
|
|
475
|
+
],
|
|
476
|
+
tools: [],
|
|
477
|
+
context: [],
|
|
478
|
+
state: {},
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
await collectEvents(agent["run"](input));
|
|
482
|
+
|
|
483
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
484
|
+
// Should only have the user message, developer message ignored
|
|
485
|
+
expect(callArgs.messages).toHaveLength(1);
|
|
486
|
+
expect(callArgs.messages[0].role).toBe("user");
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
it("should forward system messages when forwardSystemMessages is true", async () => {
|
|
490
|
+
const agent = new BasicAgent({
|
|
491
|
+
model: "openai/gpt-4o",
|
|
492
|
+
forwardSystemMessages: true,
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
vi.mocked(streamText).mockReturnValue(
|
|
496
|
+
mockStreamTextResponse([finish()]) as any,
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
const input: RunAgentInput = {
|
|
500
|
+
threadId: "thread1",
|
|
501
|
+
runId: "run1",
|
|
502
|
+
messages: [
|
|
503
|
+
{ id: "sys1", role: "system", content: "System instruction" },
|
|
504
|
+
{ id: "user1", role: "user", content: "Hello" },
|
|
505
|
+
],
|
|
506
|
+
tools: [],
|
|
507
|
+
context: [],
|
|
508
|
+
state: {},
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
await collectEvents(agent["run"](input));
|
|
512
|
+
|
|
513
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
514
|
+
expect(callArgs.messages).toHaveLength(2);
|
|
515
|
+
expect(callArgs.messages[0]).toMatchObject({
|
|
516
|
+
role: "system",
|
|
517
|
+
content: "System instruction",
|
|
518
|
+
});
|
|
519
|
+
expect(callArgs.messages[1].role).toBe("user");
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
it("should forward developer messages as system when forwardDeveloperMessages is true", async () => {
|
|
523
|
+
const agent = new BasicAgent({
|
|
524
|
+
model: "openai/gpt-4o",
|
|
525
|
+
forwardDeveloperMessages: true,
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
vi.mocked(streamText).mockReturnValue(
|
|
529
|
+
mockStreamTextResponse([finish()]) as any,
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
const input: RunAgentInput = {
|
|
533
|
+
threadId: "thread1",
|
|
534
|
+
runId: "run1",
|
|
535
|
+
messages: [
|
|
536
|
+
{ id: "dev1", role: "developer", content: "Developer hint" },
|
|
537
|
+
{ id: "user1", role: "user", content: "Hello" },
|
|
538
|
+
],
|
|
539
|
+
tools: [],
|
|
540
|
+
context: [],
|
|
541
|
+
state: {},
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
await collectEvents(agent["run"](input));
|
|
545
|
+
|
|
546
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
547
|
+
expect(callArgs.messages).toHaveLength(2);
|
|
548
|
+
// Developer messages are converted to system role
|
|
549
|
+
expect(callArgs.messages[0]).toMatchObject({
|
|
550
|
+
role: "system",
|
|
551
|
+
content: "Developer hint",
|
|
552
|
+
});
|
|
553
|
+
expect(callArgs.messages[1].role).toBe("user");
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it("should forward both system and developer messages when both flags are true", async () => {
|
|
557
|
+
const agent = new BasicAgent({
|
|
558
|
+
model: "openai/gpt-4o",
|
|
559
|
+
forwardSystemMessages: true,
|
|
560
|
+
forwardDeveloperMessages: true,
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
vi.mocked(streamText).mockReturnValue(
|
|
564
|
+
mockStreamTextResponse([finish()]) as any,
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
const input: RunAgentInput = {
|
|
568
|
+
threadId: "thread1",
|
|
569
|
+
runId: "run1",
|
|
570
|
+
messages: [
|
|
571
|
+
{ id: "sys1", role: "system", content: "System instruction" },
|
|
572
|
+
{ id: "dev1", role: "developer", content: "Developer hint" },
|
|
573
|
+
{ id: "user1", role: "user", content: "Hello" },
|
|
574
|
+
],
|
|
575
|
+
tools: [],
|
|
576
|
+
context: [],
|
|
577
|
+
state: {},
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
await collectEvents(agent["run"](input));
|
|
581
|
+
|
|
582
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
583
|
+
expect(callArgs.messages).toHaveLength(3);
|
|
584
|
+
expect(callArgs.messages[0]).toMatchObject({
|
|
585
|
+
role: "system",
|
|
586
|
+
content: "System instruction",
|
|
587
|
+
});
|
|
588
|
+
expect(callArgs.messages[1]).toMatchObject({
|
|
589
|
+
role: "system",
|
|
590
|
+
content: "Developer hint",
|
|
591
|
+
});
|
|
592
|
+
expect(callArgs.messages[2].role).toBe("user");
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
it("should place config prompt before forwarded system/developer messages", async () => {
|
|
596
|
+
const agent = new BasicAgent({
|
|
597
|
+
model: "openai/gpt-4o",
|
|
598
|
+
prompt: "You are a helpful assistant.",
|
|
599
|
+
forwardSystemMessages: true,
|
|
600
|
+
forwardDeveloperMessages: true,
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
vi.mocked(streamText).mockReturnValue(
|
|
604
|
+
mockStreamTextResponse([finish()]) as any,
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
const input: RunAgentInput = {
|
|
608
|
+
threadId: "thread1",
|
|
609
|
+
runId: "run1",
|
|
610
|
+
messages: [
|
|
611
|
+
{ id: "sys1", role: "system", content: "System instruction" },
|
|
612
|
+
{ id: "dev1", role: "developer", content: "Developer hint" },
|
|
613
|
+
{ id: "user1", role: "user", content: "Hello" },
|
|
614
|
+
],
|
|
615
|
+
tools: [],
|
|
616
|
+
context: [],
|
|
617
|
+
state: {},
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
await collectEvents(agent["run"](input));
|
|
621
|
+
|
|
622
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
623
|
+
// Config prompt is prepended as first system message
|
|
624
|
+
expect(callArgs.messages).toHaveLength(4);
|
|
625
|
+
expect(callArgs.messages[0]).toMatchObject({
|
|
626
|
+
role: "system",
|
|
627
|
+
content: "You are a helpful assistant.",
|
|
628
|
+
});
|
|
629
|
+
expect(callArgs.messages[1]).toMatchObject({
|
|
630
|
+
role: "system",
|
|
631
|
+
content: "System instruction",
|
|
632
|
+
});
|
|
633
|
+
expect(callArgs.messages[2]).toMatchObject({
|
|
634
|
+
role: "system",
|
|
635
|
+
content: "Developer hint",
|
|
636
|
+
});
|
|
637
|
+
expect(callArgs.messages[3].role).toBe("user");
|
|
638
|
+
});
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
describe("Tool Configuration", () => {
|
|
642
|
+
it("should include tools from config", async () => {
|
|
643
|
+
const tool1 = defineTool({
|
|
644
|
+
name: "configTool",
|
|
645
|
+
description: "A config tool",
|
|
646
|
+
parameters: z.object({ input: z.string() }),
|
|
647
|
+
execute: async () => ({ result: "ok" }),
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
const agent = new BasicAgent({
|
|
651
|
+
model: "openai/gpt-4o",
|
|
652
|
+
tools: [tool1],
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
vi.mocked(streamText).mockReturnValue(
|
|
656
|
+
mockStreamTextResponse([finish()]) as any,
|
|
657
|
+
);
|
|
658
|
+
|
|
659
|
+
const input: RunAgentInput = {
|
|
660
|
+
threadId: "thread1",
|
|
661
|
+
runId: "run1",
|
|
662
|
+
messages: [],
|
|
663
|
+
tools: [],
|
|
664
|
+
context: [],
|
|
665
|
+
state: {},
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
await collectEvents(agent["run"](input));
|
|
669
|
+
|
|
670
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
671
|
+
expect(callArgs.tools).toHaveProperty("configTool");
|
|
672
|
+
});
|
|
673
|
+
|
|
674
|
+
it("should merge config tools with input tools", async () => {
|
|
675
|
+
const configTool = defineTool({
|
|
676
|
+
name: "configTool",
|
|
677
|
+
description: "From config",
|
|
678
|
+
parameters: z.object({}),
|
|
679
|
+
execute: async () => ({ result: "ok" }),
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
const agent = new BasicAgent({
|
|
683
|
+
model: "openai/gpt-4o",
|
|
684
|
+
tools: [configTool],
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
vi.mocked(streamText).mockReturnValue(
|
|
688
|
+
mockStreamTextResponse([finish()]) as any,
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
const input: RunAgentInput = {
|
|
692
|
+
threadId: "thread1",
|
|
693
|
+
runId: "run1",
|
|
694
|
+
messages: [],
|
|
695
|
+
tools: [
|
|
696
|
+
{
|
|
697
|
+
name: "inputTool",
|
|
698
|
+
description: "From input",
|
|
699
|
+
parameters: { type: "object", properties: {} },
|
|
700
|
+
},
|
|
701
|
+
],
|
|
702
|
+
context: [],
|
|
703
|
+
state: {},
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
await collectEvents(agent["run"](input));
|
|
707
|
+
|
|
708
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
709
|
+
expect(callArgs.tools).toHaveProperty("configTool");
|
|
710
|
+
expect(callArgs.tools).toHaveProperty("inputTool");
|
|
711
|
+
});
|
|
712
|
+
|
|
713
|
+
it("should always include state update tools", async () => {
|
|
714
|
+
const agent = new BasicAgent({
|
|
715
|
+
model: "openai/gpt-4o",
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
vi.mocked(streamText).mockReturnValue(
|
|
719
|
+
mockStreamTextResponse([finish()]) as any,
|
|
720
|
+
);
|
|
721
|
+
|
|
722
|
+
const input: RunAgentInput = {
|
|
723
|
+
threadId: "thread1",
|
|
724
|
+
runId: "run1",
|
|
725
|
+
messages: [],
|
|
726
|
+
tools: [],
|
|
727
|
+
context: [],
|
|
728
|
+
state: {},
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
await collectEvents(agent["run"](input));
|
|
732
|
+
|
|
733
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
734
|
+
expect(callArgs.tools).toHaveProperty("AGUISendStateSnapshot");
|
|
735
|
+
expect(callArgs.tools).toHaveProperty("AGUISendStateDelta");
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
|
|
739
|
+
describe("Property Overrides", () => {
|
|
740
|
+
it("should respect overridable properties", async () => {
|
|
741
|
+
const agent = new BasicAgent({
|
|
742
|
+
model: "openai/gpt-4o",
|
|
743
|
+
temperature: 0.5,
|
|
744
|
+
overridableProperties: ["temperature"],
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
vi.mocked(streamText).mockReturnValue(
|
|
748
|
+
mockStreamTextResponse([finish()]) as any,
|
|
749
|
+
);
|
|
750
|
+
|
|
751
|
+
const input: RunAgentInput = {
|
|
752
|
+
threadId: "thread1",
|
|
753
|
+
runId: "run1",
|
|
754
|
+
messages: [],
|
|
755
|
+
tools: [],
|
|
756
|
+
context: [],
|
|
757
|
+
state: {},
|
|
758
|
+
forwardedProps: { temperature: 0.9 },
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
await collectEvents(agent["run"](input));
|
|
762
|
+
|
|
763
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
764
|
+
expect(callArgs.temperature).toBe(0.9);
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
it("should ignore non-overridable properties", async () => {
|
|
768
|
+
const agent = new BasicAgent({
|
|
769
|
+
model: "openai/gpt-4o",
|
|
770
|
+
temperature: 0.5,
|
|
771
|
+
overridableProperties: [], // No properties can be overridden
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
vi.mocked(streamText).mockReturnValue(
|
|
775
|
+
mockStreamTextResponse([finish()]) as any,
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
const input: RunAgentInput = {
|
|
779
|
+
threadId: "thread1",
|
|
780
|
+
runId: "run1",
|
|
781
|
+
messages: [],
|
|
782
|
+
tools: [],
|
|
783
|
+
context: [],
|
|
784
|
+
state: {},
|
|
785
|
+
forwardedProps: { temperature: 0.9 },
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
await collectEvents(agent["run"](input));
|
|
789
|
+
|
|
790
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
791
|
+
expect(callArgs.temperature).toBe(0.5); // Original value, not overridden
|
|
792
|
+
});
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
describe("Error Handling", () => {
|
|
796
|
+
it("should emit RUN_ERROR event on failure", async () => {
|
|
797
|
+
const agent = new BasicAgent({
|
|
798
|
+
model: "openai/gpt-4o",
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
vi.mocked(streamText).mockImplementation(() => {
|
|
802
|
+
throw new Error("Test error");
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
const input: RunAgentInput = {
|
|
806
|
+
threadId: "thread1",
|
|
807
|
+
runId: "run1",
|
|
808
|
+
messages: [],
|
|
809
|
+
tools: [],
|
|
810
|
+
context: [],
|
|
811
|
+
state: {},
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
try {
|
|
815
|
+
await collectEvents(agent["run"](input));
|
|
816
|
+
expect.fail("Should have thrown");
|
|
817
|
+
} catch (error: any) {
|
|
818
|
+
// Error is expected - check that we got a RUN_ERROR event
|
|
819
|
+
// Note: The error is thrown after emitting the event
|
|
820
|
+
expect(error.message).toContain("Test error");
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
describe("Reasoning Event Emission", () => {
|
|
826
|
+
it("should emit full reasoning lifecycle events", async () => {
|
|
827
|
+
const agent = new BasicAgent({
|
|
828
|
+
model: "openai/gpt-4o",
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
vi.mocked(streamText).mockReturnValue(
|
|
832
|
+
mockStreamTextResponse([
|
|
833
|
+
reasoningStart(),
|
|
834
|
+
reasoningDelta("Let me think..."),
|
|
835
|
+
reasoningDelta(" about this."),
|
|
836
|
+
reasoningEnd(),
|
|
837
|
+
finish(),
|
|
838
|
+
]) as any,
|
|
839
|
+
);
|
|
840
|
+
|
|
841
|
+
const input: RunAgentInput = {
|
|
842
|
+
threadId: "thread1",
|
|
843
|
+
runId: "run1",
|
|
844
|
+
messages: [],
|
|
845
|
+
tools: [],
|
|
846
|
+
context: [],
|
|
847
|
+
state: {},
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
const events = await collectEvents(agent["run"](input));
|
|
851
|
+
|
|
852
|
+
// Verify event order
|
|
853
|
+
const eventTypes = events.map((e: any) => e.type);
|
|
854
|
+
expect(eventTypes[0]).toBe(EventType.RUN_STARTED);
|
|
855
|
+
|
|
856
|
+
const reasoningStartIdx = eventTypes.indexOf(EventType.REASONING_START);
|
|
857
|
+
const reasoningMsgStartIdx = eventTypes.indexOf(
|
|
858
|
+
EventType.REASONING_MESSAGE_START,
|
|
859
|
+
);
|
|
860
|
+
const reasoningContentIndices = eventTypes.reduce(
|
|
861
|
+
(acc: number[], type: string, idx: number) =>
|
|
862
|
+
type === EventType.REASONING_MESSAGE_CONTENT ? [...acc, idx] : acc,
|
|
863
|
+
[],
|
|
864
|
+
);
|
|
865
|
+
const reasoningMsgEndIdx = eventTypes.indexOf(
|
|
866
|
+
EventType.REASONING_MESSAGE_END,
|
|
867
|
+
);
|
|
868
|
+
const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
|
|
869
|
+
|
|
870
|
+
expect(reasoningStartIdx).toBeGreaterThan(0);
|
|
871
|
+
expect(reasoningMsgStartIdx).toBeGreaterThan(reasoningStartIdx);
|
|
872
|
+
expect(reasoningContentIndices).toHaveLength(2);
|
|
873
|
+
expect(reasoningContentIndices[0]).toBeGreaterThan(reasoningMsgStartIdx);
|
|
874
|
+
expect(reasoningMsgEndIdx).toBeGreaterThan(
|
|
875
|
+
reasoningContentIndices[reasoningContentIndices.length - 1],
|
|
876
|
+
);
|
|
877
|
+
expect(reasoningEndIdx).toBeGreaterThan(reasoningMsgEndIdx);
|
|
878
|
+
|
|
879
|
+
// Verify consistent messageId across all reasoning events
|
|
880
|
+
const reasoningEvents = events.filter((e: any) =>
|
|
881
|
+
[
|
|
882
|
+
EventType.REASONING_START,
|
|
883
|
+
EventType.REASONING_MESSAGE_START,
|
|
884
|
+
EventType.REASONING_MESSAGE_CONTENT,
|
|
885
|
+
EventType.REASONING_MESSAGE_END,
|
|
886
|
+
EventType.REASONING_END,
|
|
887
|
+
].includes(e.type),
|
|
888
|
+
);
|
|
889
|
+
const messageIds = reasoningEvents.map((e: any) => e.messageId);
|
|
890
|
+
expect(new Set(messageIds).size).toBe(1);
|
|
891
|
+
|
|
892
|
+
// Verify REASONING_MESSAGE_START has role "reasoning"
|
|
893
|
+
const msgStartEvent = events.find(
|
|
894
|
+
(e: any) => e.type === EventType.REASONING_MESSAGE_START,
|
|
895
|
+
);
|
|
896
|
+
expect(msgStartEvent).toMatchObject({ role: "reasoning" });
|
|
897
|
+
|
|
898
|
+
// Verify content deltas
|
|
899
|
+
const contentEvents = events.filter(
|
|
900
|
+
(e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
|
|
901
|
+
);
|
|
902
|
+
expect(contentEvents[0]).toMatchObject({ delta: "Let me think..." });
|
|
903
|
+
expect(contentEvents[1]).toMatchObject({ delta: " about this." });
|
|
904
|
+
|
|
905
|
+
// Verify last event is RUN_FINISHED
|
|
906
|
+
expect(eventTypes[eventTypes.length - 1]).toBe(EventType.RUN_FINISHED);
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
it("should emit reasoning events followed by text events", async () => {
|
|
910
|
+
const agent = new BasicAgent({
|
|
911
|
+
model: "openai/gpt-4o",
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
vi.mocked(streamText).mockReturnValue(
|
|
915
|
+
mockStreamTextResponse([
|
|
916
|
+
reasoningStart(),
|
|
917
|
+
reasoningDelta("thinking"),
|
|
918
|
+
reasoningEnd(),
|
|
919
|
+
textDelta("Hello"),
|
|
920
|
+
finish(),
|
|
921
|
+
]) as any,
|
|
922
|
+
);
|
|
923
|
+
|
|
924
|
+
const input: RunAgentInput = {
|
|
925
|
+
threadId: "thread1",
|
|
926
|
+
runId: "run1",
|
|
927
|
+
messages: [],
|
|
928
|
+
tools: [],
|
|
929
|
+
context: [],
|
|
930
|
+
state: {},
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
const events = await collectEvents(agent["run"](input));
|
|
934
|
+
const eventTypes = events.map((e: any) => e.type);
|
|
935
|
+
|
|
936
|
+
// Reasoning events should come before text events
|
|
937
|
+
const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
|
|
938
|
+
const textChunkIdx = eventTypes.indexOf(EventType.TEXT_MESSAGE_CHUNK);
|
|
939
|
+
expect(reasoningEndIdx).toBeLessThan(textChunkIdx);
|
|
940
|
+
|
|
941
|
+
// Reasoning messageId should differ from text messageId
|
|
942
|
+
const reasoningEvent = events.find(
|
|
943
|
+
(e: any) => e.type === EventType.REASONING_START,
|
|
944
|
+
);
|
|
945
|
+
const textEvent = events.find(
|
|
946
|
+
(e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
947
|
+
);
|
|
948
|
+
expect(reasoningEvent.messageId).not.toBe(textEvent.messageId);
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
it("should use provider-supplied reasoning id", async () => {
|
|
952
|
+
const agent = new BasicAgent({
|
|
953
|
+
model: "openai/gpt-4o",
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
vi.mocked(streamText).mockReturnValue(
|
|
957
|
+
mockStreamTextResponse([
|
|
958
|
+
reasoningStart("reasoning-msg-123"),
|
|
959
|
+
reasoningDelta("content"),
|
|
960
|
+
reasoningEnd(),
|
|
961
|
+
finish(),
|
|
962
|
+
]) as any,
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
const input: RunAgentInput = {
|
|
966
|
+
threadId: "thread1",
|
|
967
|
+
runId: "run1",
|
|
968
|
+
messages: [],
|
|
969
|
+
tools: [],
|
|
970
|
+
context: [],
|
|
971
|
+
state: {},
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
const events = await collectEvents(agent["run"](input));
|
|
975
|
+
|
|
976
|
+
const reasoningEvents = events.filter((e: any) =>
|
|
977
|
+
[
|
|
978
|
+
EventType.REASONING_START,
|
|
979
|
+
EventType.REASONING_MESSAGE_START,
|
|
980
|
+
EventType.REASONING_MESSAGE_CONTENT,
|
|
981
|
+
EventType.REASONING_MESSAGE_END,
|
|
982
|
+
EventType.REASONING_END,
|
|
983
|
+
].includes(e.type),
|
|
984
|
+
);
|
|
985
|
+
|
|
986
|
+
for (const event of reasoningEvents) {
|
|
987
|
+
expect(event.messageId).toBe("reasoning-msg-123");
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
it("should generate unique reasoningMessageId when provider returns id '0'", async () => {
|
|
992
|
+
const agent = new BasicAgent({
|
|
993
|
+
model: "openai/gpt-4o",
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
vi.mocked(streamText).mockReturnValue(
|
|
997
|
+
mockStreamTextResponse([
|
|
998
|
+
reasoningStart("0"),
|
|
999
|
+
reasoningDelta("content"),
|
|
1000
|
+
reasoningEnd(),
|
|
1001
|
+
finish(),
|
|
1002
|
+
]) as any,
|
|
1003
|
+
);
|
|
1004
|
+
|
|
1005
|
+
const input: RunAgentInput = {
|
|
1006
|
+
threadId: "thread1",
|
|
1007
|
+
runId: "run1",
|
|
1008
|
+
messages: [],
|
|
1009
|
+
tools: [],
|
|
1010
|
+
context: [],
|
|
1011
|
+
state: {},
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
const events = await collectEvents(agent["run"](input));
|
|
1015
|
+
|
|
1016
|
+
const reasoningEvent = events.find(
|
|
1017
|
+
(e: any) => e.type === EventType.REASONING_START,
|
|
1018
|
+
);
|
|
1019
|
+
expect(reasoningEvent.messageId).not.toBe("0");
|
|
1020
|
+
expect(reasoningEvent.messageId).toMatch(
|
|
1021
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
|
1022
|
+
);
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
it("should handle empty reasoning content", async () => {
|
|
1026
|
+
const agent = new BasicAgent({
|
|
1027
|
+
model: "openai/gpt-4o",
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
vi.mocked(streamText).mockReturnValue(
|
|
1031
|
+
mockStreamTextResponse([
|
|
1032
|
+
reasoningStart(),
|
|
1033
|
+
reasoningDelta(""),
|
|
1034
|
+
reasoningEnd(),
|
|
1035
|
+
finish(),
|
|
1036
|
+
]) as any,
|
|
1037
|
+
);
|
|
1038
|
+
|
|
1039
|
+
const input: RunAgentInput = {
|
|
1040
|
+
threadId: "thread1",
|
|
1041
|
+
runId: "run1",
|
|
1042
|
+
messages: [],
|
|
1043
|
+
tools: [],
|
|
1044
|
+
context: [],
|
|
1045
|
+
state: {},
|
|
1046
|
+
};
|
|
1047
|
+
|
|
1048
|
+
const events = await collectEvents(agent["run"](input));
|
|
1049
|
+
|
|
1050
|
+
const contentEvent = events.find(
|
|
1051
|
+
(e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
|
|
1052
|
+
);
|
|
1053
|
+
expect(contentEvent).toMatchObject({ delta: "" });
|
|
1054
|
+
|
|
1055
|
+
// Full lifecycle should still complete
|
|
1056
|
+
const eventTypes = events.map((e: any) => e.type);
|
|
1057
|
+
expect(eventTypes).toContain(EventType.REASONING_START);
|
|
1058
|
+
expect(eventTypes).toContain(EventType.REASONING_MESSAGE_START);
|
|
1059
|
+
expect(eventTypes).toContain(EventType.REASONING_MESSAGE_END);
|
|
1060
|
+
expect(eventTypes).toContain(EventType.REASONING_END);
|
|
1061
|
+
expect(eventTypes).toContain(EventType.RUN_FINISHED);
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
it("should handle reasoning-only stream (no text output)", async () => {
|
|
1065
|
+
const agent = new BasicAgent({
|
|
1066
|
+
model: "openai/gpt-4o",
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
vi.mocked(streamText).mockReturnValue(
|
|
1070
|
+
mockStreamTextResponse([
|
|
1071
|
+
reasoningStart(),
|
|
1072
|
+
reasoningDelta("Deep thought"),
|
|
1073
|
+
reasoningEnd(),
|
|
1074
|
+
finish(),
|
|
1075
|
+
]) as any,
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
const input: RunAgentInput = {
|
|
1079
|
+
threadId: "thread1",
|
|
1080
|
+
runId: "run1",
|
|
1081
|
+
messages: [],
|
|
1082
|
+
tools: [],
|
|
1083
|
+
context: [],
|
|
1084
|
+
state: {},
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
const events = await collectEvents(agent["run"](input));
|
|
1088
|
+
|
|
1089
|
+
// No TEXT_MESSAGE_CHUNK events
|
|
1090
|
+
const textEvents = events.filter(
|
|
1091
|
+
(e: any) => e.type === EventType.TEXT_MESSAGE_CHUNK,
|
|
1092
|
+
);
|
|
1093
|
+
expect(textEvents).toHaveLength(0);
|
|
1094
|
+
|
|
1095
|
+
// Reasoning events are present
|
|
1096
|
+
const reasoningContentEvents = events.filter(
|
|
1097
|
+
(e: any) => e.type === EventType.REASONING_MESSAGE_CONTENT,
|
|
1098
|
+
);
|
|
1099
|
+
expect(reasoningContentEvents).toHaveLength(1);
|
|
1100
|
+
expect(reasoningContentEvents[0]).toMatchObject({
|
|
1101
|
+
delta: "Deep thought",
|
|
1102
|
+
});
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
it("should handle reasoning interleaved with tool calls", async () => {
|
|
1106
|
+
const agent = new BasicAgent({
|
|
1107
|
+
model: "openai/gpt-4o",
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
vi.mocked(streamText).mockReturnValue(
|
|
1111
|
+
mockStreamTextResponse([
|
|
1112
|
+
reasoningStart(),
|
|
1113
|
+
reasoningDelta("I need to call a tool"),
|
|
1114
|
+
reasoningEnd(),
|
|
1115
|
+
toolCallStreamingStart("call1", "testTool"),
|
|
1116
|
+
toolCallDelta("call1", '{"arg":"val"}'),
|
|
1117
|
+
toolCall("call1", "testTool", { arg: "val" }),
|
|
1118
|
+
toolResult("call1", "testTool", { result: "success" }),
|
|
1119
|
+
finish(),
|
|
1120
|
+
]) as any,
|
|
1121
|
+
);
|
|
1122
|
+
|
|
1123
|
+
const input: RunAgentInput = {
|
|
1124
|
+
threadId: "thread1",
|
|
1125
|
+
runId: "run1",
|
|
1126
|
+
messages: [],
|
|
1127
|
+
tools: [],
|
|
1128
|
+
context: [],
|
|
1129
|
+
state: {},
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
const events = await collectEvents(agent["run"](input));
|
|
1133
|
+
const eventTypes = events.map((e: any) => e.type);
|
|
1134
|
+
|
|
1135
|
+
// Reasoning events precede tool call events
|
|
1136
|
+
const reasoningEndIdx = eventTypes.indexOf(EventType.REASONING_END);
|
|
1137
|
+
const toolCallStartIdx = eventTypes.indexOf(EventType.TOOL_CALL_START);
|
|
1138
|
+
expect(reasoningEndIdx).toBeLessThan(toolCallStartIdx);
|
|
1139
|
+
|
|
1140
|
+
// Both lifecycles complete
|
|
1141
|
+
expect(eventTypes).toContain(EventType.REASONING_START);
|
|
1142
|
+
expect(eventTypes).toContain(EventType.REASONING_END);
|
|
1143
|
+
expect(eventTypes).toContain(EventType.TOOL_CALL_START);
|
|
1144
|
+
expect(eventTypes).toContain(EventType.TOOL_CALL_END);
|
|
1145
|
+
});
|
|
1146
|
+
});
|
|
1147
|
+
|
|
1148
|
+
describe("Provider Options", () => {
|
|
1149
|
+
it("should pass providerOptions to streamText", async () => {
|
|
1150
|
+
const agent = new BasicAgent({
|
|
1151
|
+
model: "openai/gpt-4o",
|
|
1152
|
+
providerOptions: {
|
|
1153
|
+
openai: { reasoningEffort: "high", reasoningSummary: "detailed" },
|
|
1154
|
+
},
|
|
1155
|
+
});
|
|
1156
|
+
|
|
1157
|
+
vi.mocked(streamText).mockReturnValue(
|
|
1158
|
+
mockStreamTextResponse([finish()]) as any,
|
|
1159
|
+
);
|
|
1160
|
+
|
|
1161
|
+
const input: RunAgentInput = {
|
|
1162
|
+
threadId: "thread1",
|
|
1163
|
+
runId: "run1",
|
|
1164
|
+
messages: [],
|
|
1165
|
+
tools: [],
|
|
1166
|
+
context: [],
|
|
1167
|
+
state: {},
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
await collectEvents(agent["run"](input));
|
|
1171
|
+
|
|
1172
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
1173
|
+
expect(callArgs.providerOptions).toEqual({
|
|
1174
|
+
openai: { reasoningEffort: "high", reasoningSummary: "detailed" },
|
|
1175
|
+
});
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
it("should allow providerOptions override via forwardedProps when overridable", async () => {
|
|
1179
|
+
const agent = new BasicAgent({
|
|
1180
|
+
model: "openai/gpt-4o",
|
|
1181
|
+
providerOptions: {
|
|
1182
|
+
openai: { reasoningEffort: "low" },
|
|
1183
|
+
},
|
|
1184
|
+
overridableProperties: ["providerOptions"],
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
vi.mocked(streamText).mockReturnValue(
|
|
1188
|
+
mockStreamTextResponse([finish()]) as any,
|
|
1189
|
+
);
|
|
1190
|
+
|
|
1191
|
+
const input: RunAgentInput = {
|
|
1192
|
+
threadId: "thread1",
|
|
1193
|
+
runId: "run1",
|
|
1194
|
+
messages: [],
|
|
1195
|
+
tools: [],
|
|
1196
|
+
context: [],
|
|
1197
|
+
state: {},
|
|
1198
|
+
forwardedProps: {
|
|
1199
|
+
providerOptions: {
|
|
1200
|
+
openai: { reasoningEffort: "high" },
|
|
1201
|
+
},
|
|
1202
|
+
},
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
await collectEvents(agent["run"](input));
|
|
1206
|
+
|
|
1207
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
1208
|
+
expect(callArgs.providerOptions).toEqual({
|
|
1209
|
+
openai: { reasoningEffort: "high" },
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1212
|
+
|
|
1213
|
+
it("should NOT allow providerOptions override when not in overridableProperties", async () => {
|
|
1214
|
+
const agent = new BasicAgent({
|
|
1215
|
+
model: "openai/gpt-4o",
|
|
1216
|
+
providerOptions: {
|
|
1217
|
+
openai: { reasoningEffort: "low" },
|
|
1218
|
+
},
|
|
1219
|
+
overridableProperties: [],
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
vi.mocked(streamText).mockReturnValue(
|
|
1223
|
+
mockStreamTextResponse([finish()]) as any,
|
|
1224
|
+
);
|
|
1225
|
+
|
|
1226
|
+
const input: RunAgentInput = {
|
|
1227
|
+
threadId: "thread1",
|
|
1228
|
+
runId: "run1",
|
|
1229
|
+
messages: [],
|
|
1230
|
+
tools: [],
|
|
1231
|
+
context: [],
|
|
1232
|
+
state: {},
|
|
1233
|
+
forwardedProps: {
|
|
1234
|
+
providerOptions: {
|
|
1235
|
+
openai: { reasoningEffort: "high" },
|
|
1236
|
+
},
|
|
1237
|
+
},
|
|
1238
|
+
};
|
|
1239
|
+
|
|
1240
|
+
await collectEvents(agent["run"](input));
|
|
1241
|
+
|
|
1242
|
+
const callArgs = vi.mocked(streamText).mock.calls[0][0];
|
|
1243
|
+
expect(callArgs.providerOptions).toEqual({
|
|
1244
|
+
openai: { reasoningEffort: "low" },
|
|
1245
|
+
});
|
|
1246
|
+
});
|
|
1247
|
+
});
|
|
1248
|
+
});
|