From 2a3386b706bd6590bff743c876e7b1a95d6d817e Mon Sep 17 00:00:00 2001 From: Mason Hall Date: Tue, 15 Sep 2026 11:36:06 -0400 Subject: [PATCH] Upgrade eve to 0.55.0 and adopt native channel behavior --- agent/channels/eve.ts | 5 +- agent/channels/scheduled-run.ts | 3 ++ .../instructions/content/role/interactive.md | 2 +- .../content/role/scheduled-report.md | 2 +- agent/lib/tests/profile-memory.test.ts | 1 + agent/tools/task_update.ts | 1 - package.json | 2 +- ...9ec96cc99f65a80.patch => eve@0.55.0.patch} | 0 pnpm-lock.yaml | 32 ++++++------- pnpm-workspace.yaml | 3 +- tests/agent-tool-boundaries.test.ts | 1 - tests/agent/agent.test.ts | 1 + tests/agent/capabilities.test.ts | 1 + .../channels/channel-compatibility.test.ts | 47 +++++++++++++++++++ tests/agent/instructions.test.ts | 1 + tests/agent/tools/schedules.test.ts | 1 + tests/agent/workstreams.test.ts | 1 + tests/worker-input-bubbling.test.ts | 1 + 18 files changed, 79 insertions(+), 26 deletions(-) delete mode 100644 agent/tools/task_update.ts rename patches/{eve@0.52.2+main.59ec96cc99f65a80.patch => eve@0.55.0.patch} (100%) create mode 100644 tests/agent/channels/channel-compatibility.test.ts diff --git a/agent/channels/eve.ts b/agent/channels/eve.ts index b27624a5..aa0c5581 100644 --- a/agent/channels/eve.ts +++ b/agent/channels/eve.ts @@ -1,4 +1,3 @@ -import { defineChannel } from "eve/channels"; import { eveChannel } from "eve/channels/eve"; import { ForbiddenError, @@ -111,7 +110,7 @@ const ownedCallbackRoutes = new Set([ "/eve/v1/task-input/:token", ]); -export default defineChannel({ +export default { ...channel, // oxlint-disable-next-line oxc/no-map-spread -- Keep Eve's original route definitions intact when adding the app authorization boundary. routes: channel.routes.map((route) => { @@ -130,7 +129,7 @@ export default defineChannel({ }, }; }), -}); +} satisfies typeof channel; // Routes without a session subject. Every other eve route must name a session // this caller owns, either in the path or inside a hook token. diff --git a/agent/channels/scheduled-run.ts b/agent/channels/scheduled-run.ts index aa1b39e3..f0ac4653 100644 --- a/agent/channels/scheduled-run.ts +++ b/agent/channels/scheduled-run.ts @@ -22,6 +22,9 @@ const respondSchema = z.strictObject({ const internalRouteAuth = [vercelOidc(), localDev()]; export default defineChannel({ + audience({ auth }) { + return auth?.principalType === "user" ? "private" : "unknown"; + }, async receive(input, { from }) { const target = scheduledRunTargetSchema.parse(input.target); const source = from(`scheduled-run:${target.runId}`); diff --git a/agent/instructions/content/role/interactive.md b/agent/instructions/content/role/interactive.md index d391e0f4..1cf6d44c 100644 --- a/agent/instructions/content/role/interactive.md +++ b/agent/instructions/content/role/interactive.md @@ -66,5 +66,5 @@ The main conversation is the control plane. Coordinate the user's work there and - Worker images are private, user-scoped artifacts. Ask the worker for and include visual artifacts when they materially help the user verify a completed outcome, compare genuinely visual options, or understand a concrete result. Choose the smallest useful set: one image for a single result, or two to four distinct images when a compact gallery adds real comparison or verification value. Useful cases include showing a purchased item or safe, non-sensitive confirmation state and comparing clothing, food, product, or other visually differentiated options. Put two to four selected artifact references in the same `send_message` call so Linq can present them as one native media gallery; keep its text to one short caption, identify images by order only when the mapping matters, and use a separate short selection question when needed. Do not use a gallery for text-heavy comparisons such as flights, schedules, or prices unless the images materially improve the decision. Skip decorative, repetitive, text-only, or sensitive visuals. Render every selected artifact in order with its exact descriptor as `![label](/artifacts/id)`. Never invent an artifact, change its id or URL, expose a private Blob URL, or claim an internal screenshot was delivered. - When a visually selected product is unavailable, treat images as part of the replacement outcome even if the user does not ask for them again. Find the strongest viable alternatives, ask the worker for one clear artifact per recommendation, and return a compact two-to-four-image gallery with the concrete availability details. - When the worker returns a missing vault item, call `request_vault_setup` and give its link to the user before ending the turn; do not surface any live browser URL from that result. For a purchase decision, authentication challenge after vault fill, unresolved CAPTCHA after Kernel's managed solver wait, ambiguous choice, or human-takeover blocker, ask the user in the root conversation. Preserve the worker's `agentId` and live browser URL when available, then continue that same parked worker after the user responds so it re-reads the current page before acting. -- Treat a new user message as current steering. Preserve unrelated work. When it revises an active worker task, never call `browser-agent` while that `agentId` is busy: call `task_cancel` with its `taskId`, then call `browser-agent` with the same `agentId` and the complete revised assignment. Reuse an available worker only when its prior browser state and context remain useful. Cancellation is cooperative and does not roll back external effects, so do not promise atomic interruption. +- Treat a new user message as current steering. Preserve unrelated work. When it revises an active worker task, call `browser-agent` with the same `agentId` and the complete revised assignment. Eve cancels the previous task and starts its replacement in the same child session. Use `task_cancel` when the user wants work stopped without a replacement assignment. Reuse an available worker only when its prior browser state and context remain useful. Cancellation is cooperative and does not roll back external effects, so do not promise atomic interruption. - Do not create overlapping workers for the same assignment. Do not delegate non-browser work merely to create activity. diff --git a/agent/instructions/content/role/scheduled-report.md b/agent/instructions/content/role/scheduled-report.md index 0f27c418..1bd3c8c0 100644 --- a/agent/instructions/content/role/scheduled-report.md +++ b/agent/instructions/content/role/scheduled-report.md @@ -7,6 +7,6 @@ You are OpenInstinct evaluating the completed outcome of a background scheduled - Consider the outcome together with the current conversation and the time for which it was scheduled. - This turn exists only to report the outcome, resume its run with context already present in the conversation, or create a secure setup link for a vault item the run needs. Never invoke another agent, alter a schedule or profile, read or change vault contents, access an account, or perform any other external action. - When the run is waiting for input, answer it with `schedules-answer` if the existing conversation resolves the request clearly, then do not send a message. If it needs a supported vault item, call `request_vault_setup` with only the safe metadata in the request, then call `send_message` exactly once with the returned setup link and ask the user to reply when finished. For any other unresolved request, call `send_message` exactly once with its question. Preserve the internal run ID in context for a later `schedules-answer` call, and never guess or expose it to the user. -- For a completed outcome, call `send_message` exactly once only when it is still useful, actionable, time-sensitive, or materially changes what the user knows. Otherwise finish silently. +- For a completed outcome, call `send_message` exactly once only when it is still useful, actionable, time-sensitive, or materially changes what the user knows. Otherwise finish with exactly `` and do not call `send_message`. - Rewrite useful information as a natural message from OpenInstinct. Never mention the internal worker, handoff, reporting state, or implementation details. - After `send_message`, emit only `DELIVERY_COMPLETE` if the runtime requires terminal assistant text. Never repeat or summarize the delivered message. diff --git a/agent/lib/tests/profile-memory.test.ts b/agent/lib/tests/profile-memory.test.ts index 64fea9fc..06e6199e 100644 --- a/agent/lib/tests/profile-memory.test.ts +++ b/agent/lib/tests/profile-memory.test.ts @@ -209,6 +209,7 @@ function memoryToolsContext( initiator: MemoryToolsContext["session"]["auth"]["initiator"] = null ): MemoryToolsContext { return { + model: null, channel: {}, memory: { scope: { diff --git a/agent/tools/task_update.ts b/agent/tools/task_update.ts deleted file mode 100644 index 6dbdff31..00000000 --- a/agent/tools/task_update.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "eve/tools/task_update"; diff --git a/package.json b/package.json index 6d8a2e10..52d7ef9f 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "cmdk": "1.1.1", "credit-card-type": "^10.3.0", "drizzle-orm": "^0.45.2", - "eve": "https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz", + "eve": "0.55.0", "evlog": "2.28.1", "lucide-react": "1.34.0", "motion": "13.1.1", diff --git a/patches/eve@0.52.2+main.59ec96cc99f65a80.patch b/patches/eve@0.55.0.patch similarity index 100% rename from patches/eve@0.52.2+main.59ec96cc99f65a80.patch rename to patches/eve@0.55.0.patch diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ab4a22b1..c34fb8da 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: '@linqapp/chat-sdk-adapter@0.5.1': 78b56cdd08c4250ad2680c094858b28d6d6935538d8e59e6dd578f106c77b9e7 - eve: c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b + eve@0.55.0: c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b importers: @@ -71,7 +71,7 @@ importers: version: 2.8.0 '@vercel/connect': specifier: ^2.0.0 - version: 2.0.0(ai@7.0.93(zod@4.5.4))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.5)(pg@8.23.0))(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(pg@8.23.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.11(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))))(eve@https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4))) + version: 2.0.0(ai@7.0.93(zod@4.5.4))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.5)(pg@8.23.0))(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(pg@8.23.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.11(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))))(eve@0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4))) '@vercel/oidc': specifier: 3.8.5 version: 3.8.5 @@ -97,11 +97,11 @@ importers: specifier: ^0.45.2 version: 0.45.2(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.5)(pg@8.23.0) eve: - specifier: https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz - version: https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)) + specifier: 0.55.0 + version: 0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)) evlog: specifier: 2.28.1 - version: 2.28.1(ai@7.0.93(zod@4.5.4))(eve@https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)))(express@5.2.1)(hono@4.13.5)(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(ofetch@1.5.1)(react@19.2.8)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) + version: 2.28.1(ai@7.0.93(zod@4.5.4))(eve@0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)))(express@5.2.1)(hono@4.13.5)(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(ofetch@1.5.1)(react@19.2.8)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)) lucide-react: specifier: 1.34.0 version: 1.34.0(react@19.2.8) @@ -3285,7 +3285,6 @@ packages: '@vercel/connect@2.0.0': resolution: {integrity: sha512-CYjPe7ZFzXHjtrwQMIDxA7Ne+tgdVu6NvGa11//3n09y5UOsJjE3LCXwAm2/yZPnvPQTbKocLMFt8tV0doXHeQ==} - version: 2.0.0 peerDependencies: '@ai-sdk/mcp': ^1 || ^2 '@auth/core': '>=0.37.0' @@ -4521,15 +4520,15 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - eve@https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz: - resolution: {integrity: sha512-F/h0gUvr3TwB5jSiUFWN1V+AZ1jfC0SVp5jsHpuhklDGyhNRlD2vFTv+Og+t4sT6fC5MQKUHAkhwyUqH4pJSxA==, tarball: https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz} - version: 0.52.2 + eve@0.55.0: + resolution: {integrity: sha512-G7vzzRPTqpKu8+ZOiY/QjUaY+e2sYk9yLpADa0JIG6AhDxx+QpolWOPTG6d3Nl7uqKsgnZCc4jKdKow2AfhEQQ==} engines: {node: '>=24'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.0.0 - ai: ^7.0.82 + ai: ^7.0.93 braintrust: ^3.0.0 + dd-trace: ^6.13.0 just-bash: ^3.1.0 microsandbox: ^0.5.0 peerDependenciesMeta: @@ -4537,6 +4536,8 @@ packages: optional: true braintrust: optional: true + dd-trace: + optional: true just-bash: optional: true microsandbox: @@ -4558,7 +4559,6 @@ packages: evlog@2.28.1: resolution: {integrity: sha512-RTci0+FRspM0zqyqHmk60LHb0l9CB+1M5criUFrAMfM3/G1Hd7OBT3STtNA93liY5IdK73ph6iWr2UM2Dqe2Sw==} - version: 2.28.1 engines: {node: '>=18.0.0'} peerDependencies: '@nestjs/common': '>=11.1.28' @@ -9796,13 +9796,13 @@ snapshots: dependencies: execa: 5.1.1 - '@vercel/connect@2.0.0(ai@7.0.93(zod@4.5.4))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.5)(pg@8.23.0))(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(pg@8.23.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.11(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))))(eve@https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)))': + '@vercel/connect@2.0.0(ai@7.0.93(zod@4.5.4))(better-auth@1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.5)(pg@8.23.0))(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(pg@8.23.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.11(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))))(eve@0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)))': dependencies: '@vercel/oidc': 3.8.5 optionalDependencies: ai: 7.0.93(zod@4.5.4) better-auth: 1.7.2(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.5.8)(@neondatabase/serverless@1.1.0)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.5)(pg@8.23.0))(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(pg@8.23.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.11(@edge-runtime/vm@3.2.0)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0))) - eve: https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)) + eve: 0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)) '@vercel/container@3.0.0(@vercel/build-utils@14.5.0)': dependencies: @@ -11104,7 +11104,7 @@ snapshots: etag@1.8.1: {} - eve@https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)): + eve@0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)): dependencies: ai: 7.0.93(zod@4.5.4) nitro: 3.0.260903-beta @@ -11126,10 +11126,10 @@ snapshots: dependencies: eventsource-parser: 3.1.1 - evlog@2.28.1(ai@7.0.93(zod@4.5.4))(eve@https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)))(express@5.2.1)(hono@4.13.5)(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(ofetch@1.5.1)(react@19.2.8)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)): + evlog@2.28.1(ai@7.0.93(zod@4.5.4))(eve@0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)))(express@5.2.1)(hono@4.13.5)(next@16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(ofetch@1.5.1)(react@19.2.8)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.27.0)(jiti@2.7.0)(tsx@4.21.0)(yaml@2.9.0)): optionalDependencies: ai: 7.0.93(zod@4.5.4) - eve: https://pkg.eve.dev/59ec96cc99f65a80f7a2daf4ca5e2a0ad95455f2/eve.tgz(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)) + eve: 0.55.0(patch_hash=c9c91db6673be481361a99b505472040d0d7799688b5a4aab02b612b6450773b)(@opentelemetry/api@1.9.1)(ai@7.0.93(zod@4.5.4)) express: 5.2.1 hono: 4.13.5 next: 16.3.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 2999eb97..acaa0561 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -22,5 +22,4 @@ allowBuilds: sharp: true patchedDependencies: "@linqapp/chat-sdk-adapter@0.5.1": patches/@linqapp__chat-sdk-adapter@0.5.1.patch - # URL dependencies are patched by name; package.json pins the immutable source SHA. - eve: patches/eve@0.52.2+main.59ec96cc99f65a80.patch + "eve@0.55.0": patches/eve@0.55.0.patch diff --git a/tests/agent-tool-boundaries.test.ts b/tests/agent-tool-boundaries.test.ts index d8aef859..7238b85f 100644 --- a/tests/agent-tool-boundaries.test.ts +++ b/tests/agent-tool-boundaries.test.ts @@ -28,7 +28,6 @@ describe("root and worker capability boundaries", () => { "messaging.ts", "schedules.ts", "task_cancel.ts", - "task_update.ts", "vault.ts", "web_fetch.ts", "web_search.ts", diff --git a/tests/agent/agent.test.ts b/tests/agent/agent.test.ts index 67e99d3e..b7693d17 100644 --- a/tests/agent/agent.test.ts +++ b/tests/agent/agent.test.ts @@ -60,6 +60,7 @@ describe("root agent model resolution", () => { function scheduledWorkerContext(): DynamicResolveContext { return { + model: null, channel: { kind: "http" }, messages: [], session: { diff --git a/tests/agent/capabilities.test.ts b/tests/agent/capabilities.test.ts index 571fcec6..44a7e942 100644 --- a/tests/agent/capabilities.test.ts +++ b/tests/agent/capabilities.test.ts @@ -118,6 +118,7 @@ async function authoredCapabilities(authenticator: string) { function dynamicContext(authenticator: string) { return { + model: null, channel: { kind: "channel:linq", metadata: {} }, messages: [], session: { diff --git a/tests/agent/channels/channel-compatibility.test.ts b/tests/agent/channels/channel-compatibility.test.ts new file mode 100644 index 00000000..4823fd37 --- /dev/null +++ b/tests/agent/channels/channel-compatibility.test.ts @@ -0,0 +1,47 @@ +import type { AudienceInput } from "eve/channels"; +import type * as CompiledChannel from "../../../node_modules/eve/dist/src/channel/compiled-channel.js"; +import { describe, expect, it, vi } from "vitest"; +import eve from "@agent/channels/eve"; +import scheduledRun from "@agent/channels/scheduled-run"; + +const { isCompiledChannel } = await vi.importActual( + new URL("./channel/compiled-channel.js", import.meta.resolve("eve")).pathname +); + +describe("compiled channel compatibility", () => { + it("preserves HTTP delivery hooks after wrapping its ownership routes", () => { + if (!isCompiledChannel(eve)) + throw new Error("Expected a compiled channel."); + + expect(eve.adapter["action.result"]).toBeTypeOf("function"); + expect(eve.adapter["message.completed"]).toBeTypeOf("function"); + expect(eve.adapter["turn.failed"]).toBeTypeOf("function"); + }); + + it.each([ + { channel: eve, anonymousAudience: "public" }, + { channel: scheduledRun, anonymousAudience: "unknown" }, + ])( + "keeps authenticated conversations private", + ({ channel, anonymousAudience }) => { + if (!isCompiledChannel(channel)) + throw new Error("Expected a compiled channel."); + const audience = channel.adapter.instrumentation?.audience; + if (!audience) throw new Error("Expected a native audience classifier."); + const input = { + channel: { kind: "http" }, + environment: "production", + mode: "conversation", + state: undefined, + auth: { + attributes: {}, + authenticator: "scheduled-worker", + principalType: "user", + }, + } satisfies AudienceInput; + + expect(audience(input)).toBe("private"); + expect(audience({ ...input, auth: null })).toBe(anonymousAudience); + } + ); +}); diff --git a/tests/agent/instructions.test.ts b/tests/agent/instructions.test.ts index 5d14b75c..194ef915 100644 --- a/tests/agent/instructions.test.ts +++ b/tests/agent/instructions.test.ts @@ -128,6 +128,7 @@ function dynamicContext( initiatorAuthenticator?: string ) { return { + model: null, channel: { kind: "channel:linq", metadata: {} }, messages: [], session: { diff --git a/tests/agent/tools/schedules.test.ts b/tests/agent/tools/schedules.test.ts index 2719417f..1093ae03 100644 --- a/tests/agent/tools/schedules.test.ts +++ b/tests/agent/tools/schedules.test.ts @@ -306,6 +306,7 @@ describe("schedule tools", () => { function dynamicContext(authenticator: string, kind = "channel:scheduled-run") { return { + model: null, channel: { kind, metadata: {} }, messages: [], session: { diff --git a/tests/agent/workstreams.test.ts b/tests/agent/workstreams.test.ts index bdcfce95..96e87416 100644 --- a/tests/agent/workstreams.test.ts +++ b/tests/agent/workstreams.test.ts @@ -417,6 +417,7 @@ describe("workstream memory", () => { function context(sessionId: string, authenticator = "authjs") { return { abortSignal: new AbortController().signal, + model: null, channel: {}, getToken() { throw new Error("Token access is outside this test."); diff --git a/tests/worker-input-bubbling.test.ts b/tests/worker-input-bubbling.test.ts index 32874ae5..cdd5230a 100644 --- a/tests/worker-input-bubbling.test.ts +++ b/tests/worker-input-bubbling.test.ts @@ -32,6 +32,7 @@ describe("worker input bubbling", () => { const worker = await browserAgent.events["turn.started"]?.( {}, { + model: null, channel: { kind: "channel:linq", metadata: {} }, messages: [], session: {