diff --git a/docs/module-graph.md b/docs/module-graph.md index 5147fbcba0..6a8565fb86 100644 --- a/docs/module-graph.md +++ b/docs/module-graph.md @@ -475,7 +475,6 @@ flowchart TD pkg_attachment_local --> pkg_attachment pkg_attachment_local --> pkg_home_paths pkg_client_connection --> pkg_scope - pkg_client_file_upload --> pkg_scope pkg_authorization --> pkg_credentials pkg_authorization --> pkg_invariants pkg_authorization --> pkg_llm @@ -1405,6 +1404,7 @@ flowchart TD | [`base`](../packages/bundle/base) | `bundle` | — | | [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | — | | [`sdk-minimal`](../packages/bundle/sdk-minimal) | `bundle` | — | +| [`client-file-upload`](../packages/client/file-upload) | `client` | — | | [`client-hmr`](../packages/client/hmr) | `client` | — | | [`client-locale`](../packages/client/locale) | `client` | — | | [`client-modules`](../packages/client/modules) | `client` | — | @@ -1516,7 +1516,6 @@ flowchart TD | [`api-terminal-controller`](../packages/api/terminal-controller) | `api` | [`subprocess`](../packages/subprocess/subprocess) | | [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths) | | [`client-connection`](../packages/client/connection) | `client` | [`scope`](../packages/core/scope) | -| [`client-file-upload`](../packages/client/file-upload) | `client` | [`scope`](../packages/core/scope) | | [`authorization`](../packages/credentials/authorization) | `credentials` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) | | [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`launch-environment`](../packages/util/launch-environment) | | [`experimental-computer-use-cua-driver-mcp`](../packages/experimental/computer-use-cua-driver-mcp) | `experimental` | [`computer-use`](../packages/computer-use/computer-use) | diff --git a/docs/module-graph.zh.md b/docs/module-graph.zh.md index a1a4c081d1..09dff80e20 100644 --- a/docs/module-graph.zh.md +++ b/docs/module-graph.zh.md @@ -477,7 +477,6 @@ flowchart TD pkg_attachment_local --> pkg_attachment pkg_attachment_local --> pkg_home_paths pkg_client_connection --> pkg_scope - pkg_client_file_upload --> pkg_scope pkg_authorization --> pkg_credentials pkg_authorization --> pkg_invariants pkg_authorization --> pkg_llm @@ -1407,6 +1406,7 @@ flowchart TD | [`base`](../packages/bundle/base) | `bundle` | — | | [`sdk-app`](../packages/bundle/sdk-app) | `bundle` | — | | [`sdk-minimal`](../packages/bundle/sdk-minimal) | `bundle` | — | +| [`client-file-upload`](../packages/client/file-upload) | `client` | — | | [`client-hmr`](../packages/client/hmr) | `client` | — | | [`client-locale`](../packages/client/locale) | `client` | — | | [`client-modules`](../packages/client/modules) | `client` | — | @@ -1518,7 +1518,6 @@ flowchart TD | [`api-terminal-controller`](../packages/api/terminal-controller) | `api` | [`subprocess`](../packages/subprocess/subprocess) | | [`attachment-local`](../packages/attachment/attachment-local) | `attachment` | [`attachment`](../packages/attachment/attachment), [`home-paths`](../packages/util/home-paths) | | [`client-connection`](../packages/client/connection) | `client` | [`scope`](../packages/core/scope) | -| [`client-file-upload`](../packages/client/file-upload) | `client` | [`scope`](../packages/core/scope) | | [`authorization`](../packages/credentials/authorization) | `credentials` | [`credentials`](../packages/credentials/credentials), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm) | | [`credentials-local`](../packages/credentials/credentials-local) | `credentials` | [`atomic-write`](../packages/util/atomic-write), [`credentials`](../packages/credentials/credentials), [`home-paths`](../packages/util/home-paths), [`launch-environment`](../packages/util/launch-environment) | | [`experimental-computer-use-cua-driver-mcp`](../packages/experimental/computer-use-cua-driver-mcp) | `experimental` | [`computer-use`](../packages/computer-use/computer-use) | diff --git a/docs/subsystems/attachment.md b/docs/subsystems/attachment.md index db1c1cfa15..12ae675e3c 100644 --- a/docs/subsystems/attachment.md +++ b/docs/subsystems/attachment.md @@ -303,7 +303,7 @@ Source: [`packages/attachment/attachment/src/index.ts`](../../packages/attachmen ### `ctx.fileUploads` — `FileUploads` -Host service owning upload storage and Agent-scoped staged receipts. +Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. ```ts cordis-catalog /** @@ -330,7 +330,7 @@ registerAgentResolver(resolve: AgentResolver): () => void async uploadStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable readonly signal?: AbortSignal readonly name?: string }): Promise /** - * Resolve one staged receipt inside its receiving Agent scope. + * Resolve one staged receipt for the receiving Agent's exact Session. * @param agent - receiving Agent. * @param receiptId - opaque receipt minted for one completed upload. * @returns durable file reference, or `undefined` for an unknown or foreign receipt. diff --git a/docs/subsystems/attachment.zh.md b/docs/subsystems/attachment.zh.md index 82379de504..06ea726f19 100644 --- a/docs/subsystems/attachment.zh.md +++ b/docs/subsystems/attachment.zh.md @@ -303,7 +303,7 @@ Source: [`packages/attachment/attachment/src/index.ts`](../../packages/attachmen ### `ctx.fileUploads` — `FileUploads` -Host service owning upload storage and Agent-scoped staged receipts. +Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. ```ts cordis-catalog /** @@ -330,7 +330,7 @@ registerAgentResolver(resolve: AgentResolver): () => void async uploadStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable readonly signal?: AbortSignal readonly name?: string }): Promise /** - * Resolve one staged receipt inside its receiving Agent scope. + * Resolve one staged receipt for the receiving Agent's exact Session. * @param agent - receiving Agent. * @param receiptId - opaque receipt minted for one completed upload. * @returns durable file reference, or `undefined` for an unknown or foreign receipt. diff --git a/packages/api/session-controller/tests/commands-upload-file.host.spec.ts b/packages/api/session-controller/tests/commands-upload-file.host.spec.ts index 14527cccec..53d1137628 100644 --- a/packages/api/session-controller/tests/commands-upload-file.host.spec.ts +++ b/packages/api/session-controller/tests/commands-upload-file.host.spec.ts @@ -13,7 +13,7 @@ import CommandRuntime from '@deepseek-ai/dsh-commands' import { createScope } from '@deepseek-ai/dsh-scope' import FileUploads from '@deepseek-ai/dsh-client-file-upload' import type { FileUploadReceiptId } from '@deepseek-ai/dsh-client-file-upload/types' -import { describe, expect, it, vi } from 'vitest' +import { describe, expect, it, onTestFinished, vi } from 'vitest' import type { ApiSessionAgentController } from '../src/agent.ts' import { SessionCommandController } from '../src/commands.ts' import type { SessionRequestId } from '../src/types.ts' @@ -33,6 +33,7 @@ async function uploadHarness(origin?: 'subagent'): Promise<{ uploadRoute: (request: Request) => Promise }> { const ctx = new Context() + onTestFinished(() => ctx.fiber.dispose()) await ctx.plugin(SessionStore) await ctx.plugin(AgentRegistry) await ctx.plugin(CommandRuntime) @@ -266,7 +267,7 @@ describe('Session file uploads', () => { })).rejects.toMatchObject({ code: 'session/not-found' }) }) - it('rejects subagent uploads and access outside the receiving Agent scope', async () => { + it('rejects subagent uploads before storing bytes', async () => { const child = await uploadHarness('subagent') await expect(child.uploads.upload( child.agent, @@ -277,16 +278,24 @@ describe('Session file uploads', () => { details: { reason: 'SUBAGENT_FILE_UNSUPPORTED' }, }) expect(child.saveFile).not.toHaveBeenCalled() + }) - const ordinary = await uploadHarness() - const receipt = await ordinary.uploads.upload( - ordinary.agent, - { data: 'AAAA' }, - new AbortController().signal, - ) - const foreignScope = { ...ordinary.agent, ctx: ordinary.ctx } as Agent - expect(() => ordinary.uploads.resolve(foreignScope, receipt.receiptId)) - .toThrow('operation requires the Agent\'s own scope') + it('isolates receipts by Session object even when Session ids match', async () => { + const owner = await uploadHarness() + const other = await uploadHarness() + expect(other.agent.session.id).toBe(owner.agent.session.id) + expect(other.agent.session).not.toBe(owner.agent.session) + const receipt = await owner.uploads.upload(owner.agent, { data: 'AAAA' }, new AbortController().signal) + const binding = owner.uploads.bindPrompt(owner.agent, [receipt.receiptId], 'owner-prompt') + binding.commit() + + expect(owner.uploads.resolve(other.agent, receipt.receiptId)).toBeUndefined() + expect(() => owner.uploads.bindPrompt(other.agent, [receipt.receiptId], 'other-prompt')) + .toThrow(expect.objectContaining({ code: 'session/attachment-invalid', details: { reason: 'FILE_NOT_STAGED' } })) + owner.uploads.retirePrompt(other.agent, 'owner-prompt') + expect(owner.uploads.resolve(owner.agent, receipt.receiptId)).toEqual(receipt.file) + owner.uploads.retirePrompt(owner.agent, 'owner-prompt') + expect(owner.uploads.resolve(owner.agent, receipt.receiptId)).toBeUndefined() }) it('retires accepted receipts after their rpcId becomes observable', async () => { diff --git a/packages/client/file-upload/README.i18n.yaml b/packages/client/file-upload/README.i18n.yaml index 2867fd1467..13bc92c5c9 100644 --- a/packages/client/file-upload/README.i18n.yaml +++ b/packages/client/file-upload/README.i18n.yaml @@ -18,8 +18,8 @@ en: 9d5bbf52599b0d00 zh: 7907542ce1e34549 /deepseek-ai-dsh-client-file-upload/understand-the-implementation: - en: da896ccc5ecbe207 - zh: f434a7572085ee1e + en: f4927d1dd1428534 + zh: 5d0db8b297a8f1b2 /deepseek-ai-dsh-client-file-upload/further-exploration: en: ac94eb9da9ecc296 zh: 25cc3362e2bea330 diff --git a/packages/client/file-upload/README.md b/packages/client/file-upload/README.md index e0c0d7637d..948a69c72b 100644 --- a/packages/client/file-upload/README.md +++ b/packages/client/file-upload/README.md @@ -44,11 +44,11 @@ The package has no Cordis configuration fields. A `Blob` uses XMLHttpRequest ins The Client plugin provides `ctx.fileUpload`. Its `upload()` method receives the owning Session identity, assembles the raw route request, and invokes the generated Remote for exact bytes. The provider reads the optional pre-Cordis `__DSH_FILE_UPLOAD__` hook once. Without a hook, each Blob or stream request owns a short-lived Worker and releases it after completion, failure, or cancellation. With the hook, the service sends the body through the page-owned Fetch carrier; the Web Worker runtime transfers stream bodies through its request frame and exposes them to the Host HTTP bridge as backpressured chunks. -The Host plugin provides `ctx.fileUploads`. It owns the authenticated streaming route, encoded Remote fallback, command receipt resolver, and staged-receipt lifecycle; encoded admission, attachment-error recognition, and byte storage stay behind `ctx.attachments`. Receipt tables use the receiving Agent's Session object as their key. The Session Controller registers the resolver that can resume a cold ordinary Agent and consumes receipts during prompt admission. Prompt delivery holds each receipt binding in a disposable transaction: disposal restores the previous binding until successful delivery commits it, and queue or history observation then retires the committed receipt. +The Host plugin provides `ctx.fileUploads`. It owns the authenticated streaming route, encoded Remote fallback, command receipt resolver, and staged-receipt lifecycle; encoded admission, attachment-error recognition, and byte storage stay behind `ctx.attachments`. Host callers supply an Agent with its runtime-owned context; receipt tables use that Agent's exact Session object as their key. The Session Controller registers the resolver that can resume a cold ordinary Agent and consumes receipts during prompt admission. Prompt delivery holds each receipt binding in a disposable transaction: disposal restores the previous binding until successful delivery commits it, and queue or history observation then retires the committed receipt. | File | Role | |---|---| -| [`src/index.ts`](src/index.ts) | Host streaming route, attachment-service admission, and Agent-scoped receipt lifecycle | +| [`src/index.ts`](src/index.ts) | Host streaming route, attachment-service admission, and Session-owned receipt lifecycle | | [`src/types.ts`](src/types.ts) | encoded request, receipt, and durable result types | | [`src/client/contract.ts`](src/client/contract.ts) | Client upload, progress, and page-hook types | | [`src/client/runtime.ts`](src/client/runtime.ts) | Dedicated Worker and page-owned carrier implementations | diff --git a/packages/client/file-upload/README.zh.md b/packages/client/file-upload/README.zh.md index abdf965694..52e605dfb9 100644 --- a/packages/client/file-upload/README.zh.md +++ b/packages/client/file-upload/README.zh.md @@ -44,11 +44,11 @@ kind: "package-reference" Client 插件提供 `ctx.fileUpload`。其 `upload()` 方法接收所属 Session 标识,组装原始路由请求,并为精确字节调用生成的 Remote。提供方只读取一次可选的 Cordis 启动前 `__DSH_FILE_UPLOAD__` 钩子。没有该钩子时,每个 Blob 或 stream 请求拥有一个短期 Worker,并在完成、失败或取消后释放。存在该钩子时,服务通过页面自己提供的 Fetch 载体发送请求体;Web Worker runtime 会通过请求帧转移 stream 请求体,再以带背压的分片形式交给 Host HTTP bridge。 -Host 插件提供 `ctx.fileUploads`。它拥有经过认证的流式路由、编码 Remote 兜底、命令凭证解析器与暂存凭证生命周期;编码准入、附件错误识别与字节存储仍由 `ctx.attachments` 提供。凭证表以接收方 Agent 的 Session 对象为键。Session Controller 注册可恢复休眠普通 Agent 的解析器,并在 prompt 准入时消费凭证。Prompt 投递通过可释放事务持有每个凭证绑定。成功投递提交事务前,释放会恢复原绑定;提交后,队列或历史观察会退休该凭证。 +Host 插件提供 `ctx.fileUploads`。它拥有经过认证的流式路由、编码 Remote 兜底、命令凭证解析器与暂存凭证生命周期;编码准入、附件错误识别与字节存储仍由 `ctx.attachments` 提供。Host 调用方传入具有运行时所属上下文的 Agent;凭证表以该 Agent 的准确 Session 对象为键。Session Controller 注册可恢复休眠普通 Agent 的解析器,并在 prompt 准入时消费凭证。Prompt 投递通过可释放事务持有每个凭证绑定。成功投递提交事务前,释放会恢复原绑定;提交后,队列或历史观察会退休该凭证。 | 文件 | 职责 | |---|---| -| [`src/index.ts`](src/index.ts) | Host 流式路由、附件服务准入与按 Agent scope 管理的凭证生命周期 | +| [`src/index.ts`](src/index.ts) | Host 流式路由、附件服务准入与 Session 所属的凭证生命周期 | | [`src/types.ts`](src/types.ts) | 编码请求、凭证与持久结果类型 | | [`src/client/contract.ts`](src/client/contract.ts) | Client 上传、进度与页面钩子类型 | | [`src/client/runtime.ts`](src/client/runtime.ts) | 专用 Worker 与页面自有载体实现 | diff --git a/packages/client/file-upload/package.json b/packages/client/file-upload/package.json index cc924e4e34..858ff12775 100644 --- a/packages/client/file-upload/package.json +++ b/packages/client/file-upload/package.json @@ -67,15 +67,13 @@ "@deepseek-ai/dsh-brand": "workspace:*" }, "peerDependencies": { - "@deepseek-ai/cordis": "workspace:~", - "@deepseek-ai/dsh-scope": "workspace:*" + "@deepseek-ai/cordis": "workspace:~" }, "devDependencies": { "@deepseek-ai/cordis": "workspace:~", "@deepseek-ai/dsh-agent": "workspace:*", "@deepseek-ai/dsh-client-connection": "workspace:*", "@deepseek-ai/dsh-commands": "workspace:*", - "@deepseek-ai/dsh-scope": "workspace:*", "@deepseek-ai/dsh-util-crypto": "workspace:*", "@deepseek-ai/dsh-api-remotes": "workspace:*", "@deepseek-ai/dsh-session": "workspace:*", diff --git a/packages/client/file-upload/src/index.ts b/packages/client/file-upload/src/index.ts index 2520ba1225..a784096461 100644 --- a/packages/client/file-upload/src/index.ts +++ b/packages/client/file-upload/src/index.ts @@ -1,4 +1,4 @@ -/** Host file-upload service: streamed intake and Agent-scoped staged receipts. */ +/** Host file-upload service: streamed intake and Session-owned staged receipts. */ import { randomUUID } from 'node:crypto' import type { Context } from '@deepseek-ai/cordis' @@ -6,7 +6,6 @@ import type { Agent } from '@deepseek-ai/dsh-agent' import type { FileAttachmentRef } from '@deepseek-ai/dsh-attachment' import type {} from '@deepseek-ai/dsh-client-connection' import type { CommandFileReceiptResolver } from '@deepseek-ai/dsh-commands' -import { scopeOf } from '@deepseek-ai/dsh-scope' import type { Session, SessionEvent, SessionId } from '@deepseek-ai/dsh-session' import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol' import { handleFileUploadHttp } from './http-route.ts' @@ -53,7 +52,7 @@ class PromptFileBindingGuard implements PromptFileBinding { } } -/** Host service owning upload storage and Agent-scoped staged receipts. */ +/** Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. */ export class FileUploads extends TypertRemoteService { static inject = ['agents', 'attachments', 'commands', 'connection'] @@ -131,13 +130,12 @@ export class FileUploads extends TypertRemoteService { } /** - * Resolve one staged receipt inside its receiving Agent scope. + * Resolve one staged receipt for the receiving Agent's exact Session. * @param agent - receiving Agent. * @param receiptId - opaque receipt minted for one completed upload. * @returns durable file reference, or `undefined` for an unknown or foreign receipt. */ resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined { - this.assertAgentScope(agent) return this.stagedFiles.get(agent.session)?.get(receiptId)?.file } @@ -154,7 +152,6 @@ export class FileUploads extends TypertRemoteService { receiptIds: readonly FileUploadReceiptId[], requestId: string, ): PromptFileBinding { - this.assertAgentScope(agent) const staged = this.stagedFiles.get(agent.session) const bound = receiptIds.map((receiptId) => { const upload = staged?.get(receiptId) @@ -176,7 +173,6 @@ export class FileUploads extends TypertRemoteService { * @param requestId - prompt identity carried by the queue occurrence. */ retirePrompt(agent: Agent, requestId: string): void { - this.assertAgentScope(agent) this.retire(agent.session, requestId) } @@ -223,12 +219,7 @@ export class FileUploads extends TypertRemoteService { return resolver(sessionId) } - private assertAgentScope(agent: Agent): void { - if (scopeOf(agent.ctx) !== agent) throw new Error('file-upload: operation requires the Agent\'s own scope') - } - private assertOrdinaryAgent(agent: Agent): void { - this.assertAgentScope(agent) if (agent.session.header.origin === 'subagent') { throw new RemoteError( 'subagent/attachment-invalid' as never, diff --git a/packages/client/file-upload/tsconfig.host.json b/packages/client/file-upload/tsconfig.host.json index 6c8c29bc15..9a719da31d 100644 --- a/packages/client/file-upload/tsconfig.host.json +++ b/packages/client/file-upload/tsconfig.host.json @@ -10,7 +10,6 @@ { "path": "../../../vendor/cordis" }, { "path": "../../util/brand" }, { "path": "../../core/agent" }, - { "path": "../../core/scope" }, { "path": "../../core/session" }, { "path": "../../attachment/attachment" }, { "path": "../../interaction/commands" }, diff --git a/packages/extensions/tool-cordis/src/api-catalog.ts b/packages/extensions/tool-cordis/src/api-catalog.ts index a7043c75ef..8753c5d0c6 100644 --- a/packages/extensions/tool-cordis/src/api-catalog.ts +++ b/packages/extensions/tool-cordis/src/api-catalog.ts @@ -999,8 +999,8 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ }, { key: 'fileUploads', - summary: 'Host service owning upload storage and Agent-scoped staged receipts.', - description: 'Host service owning upload storage and Agent-scoped staged receipts.', + summary: 'Host service owning upload storage and receipts keyed by each receiving Agent\'s exact Session.', + description: 'Host service owning upload storage and receipts keyed by each receiving Agent\'s exact Session.', methods: [ { signature: 'registerAgentResolver(resolve: AgentResolver): () => void', @@ -1022,7 +1022,7 @@ export const SERVICE_API: readonly ServiceApiEntry[] = [ }, { signature: 'resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined', - description: 'Resolve one staged receipt inside its receiving Agent scope.', + description: 'Resolve one staged receipt for the receiving Agent\'s exact Session.', parameters: [{ name: 'agent', description: 'receiving Agent.' }, { name: 'receiptId', description: 'opaque receipt minted for one completed upload.' }], returns: 'durable file reference, or `undefined` for an unknown or foreign receipt.', }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6c7ce04c19..ee724fea59 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1159,9 +1159,6 @@ importers: '@deepseek-ai/dsh-deque': specifier: workspace:* version: link:../../util/deque - '@deepseek-ai/dsh-session': - specifier: workspace:* - version: link:../../core/session '@deepseek-ai/dsh-util-values': specifier: workspace:* version: link:../../util/values @@ -2852,9 +2849,6 @@ importers: '@deepseek-ai/dsh-commands': specifier: workspace:* version: link:../../interaction/commands - '@deepseek-ai/dsh-scope': - specifier: workspace:* - version: link:../../core/scope '@deepseek-ai/dsh-session': specifier: workspace:* version: link:../../core/session @@ -9693,7 +9687,7 @@ importers: version: link:../../../vendor/schemastery '@earendil-works/pi-ai': specifier: ^0.87.1 - version: 0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3) + version: 0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(supports-color@9.4.0)(ws@8.21.0)(zod@4.4.3) devDependencies: '@deepseek-ai/cordis': specifier: workspace:~ @@ -22668,15 +22662,15 @@ snapshots: transitivePeerDependencies: - '@algolia/client-search' - '@earendil-works/pi-ai@0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.21.0)(zod@4.4.3)': + '@earendil-works/pi-ai@0.87.1(patch_hash=b9bcce474fb2ac44633dff0fa722816a5bff5451b4575d5874035ea14ba70a4f)(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(supports-color@9.4.0)(ws@8.21.0)(zod@4.4.3)': dependencies: '@anthropic-ai/sdk': 0.124.0(zod@4.4.3) '@aws-sdk/client-bedrock-runtime': 3.1127.0 '@earendil-works/pi-telemetry': 0.87.1 '@google/genai': 2.21.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)) '@smithy/node-http-handler': 4.12.1 - http-proxy-agent: 9.1.0 - https-proxy-agent: 9.1.0 + http-proxy-agent: 9.1.0(supports-color@9.4.0) + https-proxy-agent: 9.1.0(supports-color@9.4.0) openai: 6.40.0(ws@8.21.0)(zod@4.4.3) partial-json: 0.1.7 typebox: 1.3.27 @@ -26859,7 +26853,7 @@ snapshots: transitivePeerDependencies: - supports-color - http-proxy-agent@9.1.0: + http-proxy-agent@9.1.0(supports-color@9.4.0): dependencies: agent-base: 9.0.0 debug: 4.4.3(supports-color@9.4.0) @@ -26918,7 +26912,7 @@ snapshots: transitivePeerDependencies: - supports-color - https-proxy-agent@9.1.0: + https-proxy-agent@9.1.0(supports-color@9.4.0): dependencies: agent-base: 9.0.0 debug: 4.4.3(supports-color@9.4.0)