@deepseek-ai/dsh-client-file-upload 0.2.0-rc.1 → 0.2.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/lib/index.js +3 -11
- package/lib/typert.host.js +20 -8
- package/lib/typert.remote-client.js +1 -1
- package/lib/types/index.d.ts +3 -4
- package/lib/types/index.js +3 -12
- package/package.json +12 -14
package/README.i18n.yaml
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
en: 9d5bbf52599b0d00
|
|
19
19
|
zh: 7907542ce1e34549
|
|
20
20
|
/deepseek-ai-dsh-client-file-upload/understand-the-implementation:
|
|
21
|
-
en:
|
|
22
|
-
zh:
|
|
21
|
+
en: 77937960a540cf51
|
|
22
|
+
zh: 52c478bd11200975
|
|
23
23
|
/deepseek-ai-dsh-client-file-upload/further-exploration:
|
|
24
24
|
en: ac94eb9da9ecc296
|
|
25
25
|
zh: 25cc3362e2bea330
|
package/README.md
CHANGED
|
@@ -44,11 +44,11 @@ The package has no Cordis configuration fields. A `Blob` uses XMLHttpRequest ins
|
|
|
44
44
|
|
|
45
45
|
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.
|
|
46
46
|
|
|
47
|
-
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`.
|
|
47
|
+
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.
|
|
48
48
|
|
|
49
49
|
| File | Role |
|
|
50
50
|
|---|---|
|
|
51
|
-
| [`src/index.ts`](src/index.ts) | Host streaming route, attachment-service admission, and
|
|
51
|
+
| [`src/index.ts`](src/index.ts) | Host streaming route, attachment-service admission, and Session-owned receipt lifecycle |
|
|
52
52
|
| [`src/types.ts`](src/types.ts) | encoded request, receipt, and durable result types |
|
|
53
53
|
| [`src/client/contract.ts`](src/client/contract.ts) | Client upload, progress, and page-hook types |
|
|
54
54
|
| [`src/client/runtime.ts`](src/client/runtime.ts) | Dedicated Worker and page-owned carrier implementations |
|
|
@@ -56,7 +56,7 @@ The Host plugin provides `ctx.fileUploads`. It owns the authenticated streaming
|
|
|
56
56
|
|
|
57
57
|
</details>
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Each upload receipt belongs to one exact Session, and each request uses one selected carrier. Unsupported stream carriers fail before the body is sent.
|
|
60
60
|
|
|
61
61
|
-----
|
|
62
62
|
|
package/README.zh.md
CHANGED
|
@@ -44,11 +44,11 @@ kind: "package-reference"
|
|
|
44
44
|
|
|
45
45
|
Client 插件提供 `ctx.fileUpload`。其 `upload()` 方法接收所属 Session 标识,组装原始路由请求,并为精确字节调用生成的 Remote。提供方只读取一次可选的 Cordis 启动前 `__DSH_FILE_UPLOAD__` 钩子。没有该钩子时,每个 Blob 或 stream 请求拥有一个短期 Worker,并在完成、失败或取消后释放。存在该钩子时,服务通过页面自己提供的 Fetch 载体发送请求体;Web Worker runtime 会通过请求帧转移 stream 请求体,再以带背压的分片形式交给 Host HTTP bridge。
|
|
46
46
|
|
|
47
|
-
Host 插件提供 `ctx.fileUploads`。它拥有经过认证的流式路由、编码 Remote 兜底、命令凭证解析器与暂存凭证生命周期;编码准入、附件错误识别与字节存储仍由 `ctx.attachments`
|
|
47
|
+
Host 插件提供 `ctx.fileUploads`。它拥有经过认证的流式路由、编码 Remote 兜底、命令凭证解析器与暂存凭证生命周期;编码准入、附件错误识别与字节存储仍由 `ctx.attachments` 提供。Host 调用方传入具有运行时所属上下文的 Agent;凭证表以该 Agent 的准确 Session 对象为键。Session Controller 注册可恢复休眠普通 Agent 的解析器,并在 prompt 准入时消费凭证。Prompt 投递通过可释放事务持有每个凭证绑定。成功投递提交事务前,释放会恢复原绑定;提交后,队列或历史观察会退休该凭证。
|
|
48
48
|
|
|
49
49
|
| 文件 | 职责 |
|
|
50
50
|
|---|---|
|
|
51
|
-
| [`src/index.ts`](src/index.ts) | Host
|
|
51
|
+
| [`src/index.ts`](src/index.ts) | Host 流式路由、附件服务准入与 Session 所属的凭证生命周期 |
|
|
52
52
|
| [`src/types.ts`](src/types.ts) | 编码请求、凭证与持久结果类型 |
|
|
53
53
|
| [`src/client/contract.ts`](src/client/contract.ts) | Client 上传、进度与页面钩子类型 |
|
|
54
54
|
| [`src/client/runtime.ts`](src/client/runtime.ts) | 专用 Worker 与页面自有载体实现 |
|
|
@@ -56,7 +56,7 @@ Host 插件提供 `ctx.fileUploads`。它拥有经过认证的流式路由、编
|
|
|
56
56
|
|
|
57
57
|
</details>
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
每个上传凭证只属于一个准确的 Session,每个请求只使用一个已选定载体。载体不支持的 stream 会在发送请求体前失败。
|
|
60
60
|
|
|
61
61
|
-----
|
|
62
62
|
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { scopeOf } from "@deepseek-ai/dsh-scope";
|
|
3
2
|
import { Remote, RemoteError, TypertRemoteService, remoteErrorOf } from "@deepseek-ai/dsh-typert-protocol";
|
|
4
3
|
import { brandString } from "@deepseek-ai/dsh-brand";
|
|
5
4
|
//#region lib/types/http-route.js
|
|
@@ -74,7 +73,7 @@ const FILE_UPLOAD_PATH = "/api/session/uploadFileBinary";
|
|
|
74
73
|
FILE_UPLOAD_PATH.slice(1);
|
|
75
74
|
//#endregion
|
|
76
75
|
//#region lib/types/index.js
|
|
77
|
-
/** Host file-upload service: streamed intake and
|
|
76
|
+
/** Host file-upload service: streamed intake and Session-owned staged receipts. */
|
|
78
77
|
var __runInitializers = function(thisArg, initializers, value) {
|
|
79
78
|
var useValue = arguments.length > 2;
|
|
80
79
|
for (var i = 0; i < initializers.length; i++) value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
@@ -128,7 +127,7 @@ var PromptFileBindingGuard = class {
|
|
|
128
127
|
this.rollback();
|
|
129
128
|
}
|
|
130
129
|
};
|
|
131
|
-
/** Host service owning upload storage and Agent
|
|
130
|
+
/** Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. */
|
|
132
131
|
let FileUploads = (() => {
|
|
133
132
|
let _classSuper = TypertRemoteService;
|
|
134
133
|
let _instanceExtraInitializers = [];
|
|
@@ -221,13 +220,12 @@ let FileUploads = (() => {
|
|
|
221
220
|
}));
|
|
222
221
|
}
|
|
223
222
|
/**
|
|
224
|
-
* Resolve one staged receipt
|
|
223
|
+
* Resolve one staged receipt for the receiving Agent's exact Session.
|
|
225
224
|
* @param agent - receiving Agent.
|
|
226
225
|
* @param receiptId - opaque receipt minted for one completed upload.
|
|
227
226
|
* @returns durable file reference, or `undefined` for an unknown or foreign receipt.
|
|
228
227
|
*/
|
|
229
228
|
resolve(agent, receiptId) {
|
|
230
|
-
this.assertAgentScope(agent);
|
|
231
229
|
return this.stagedFiles.get(agent.session)?.get(receiptId)?.file;
|
|
232
230
|
}
|
|
233
231
|
/**
|
|
@@ -239,7 +237,6 @@ let FileUploads = (() => {
|
|
|
239
237
|
* @returns binding kept after commit until queue or history observation retires its receipts.
|
|
240
238
|
*/
|
|
241
239
|
bindPrompt(agent, receiptIds, requestId) {
|
|
242
|
-
this.assertAgentScope(agent);
|
|
243
240
|
const staged = this.stagedFiles.get(agent.session);
|
|
244
241
|
const bound = receiptIds.map((receiptId) => {
|
|
245
242
|
const upload = staged?.get(receiptId);
|
|
@@ -261,7 +258,6 @@ let FileUploads = (() => {
|
|
|
261
258
|
* @param requestId - prompt identity carried by the queue occurrence.
|
|
262
259
|
*/
|
|
263
260
|
retirePrompt(agent, requestId) {
|
|
264
|
-
this.assertAgentScope(agent);
|
|
265
261
|
this.retire(agent.session, requestId);
|
|
266
262
|
}
|
|
267
263
|
async commit(agent, save) {
|
|
@@ -293,11 +289,7 @@ let FileUploads = (() => {
|
|
|
293
289
|
if (resolver === void 0) throw new RemoteError("session/not-found", `session "${sessionId}" is not attached`, { sessionId });
|
|
294
290
|
return resolver(sessionId);
|
|
295
291
|
}
|
|
296
|
-
assertAgentScope(agent) {
|
|
297
|
-
if (scopeOf(agent.ctx) !== agent) throw new Error("file-upload: operation requires the Agent's own scope");
|
|
298
|
-
}
|
|
299
292
|
assertOrdinaryAgent(agent) {
|
|
300
|
-
this.assertAgentScope(agent);
|
|
301
293
|
if (agent.session.header.origin === "subagent") throw new RemoteError("subagent/attachment-invalid", "subagent conversations do not accept file uploads", { reason: "SUBAGENT_FILE_UNSUPPORTED" });
|
|
302
294
|
}
|
|
303
295
|
observeSessionEvent(session, event) {
|
package/lib/typert.host.js
CHANGED
|
@@ -63,16 +63,16 @@ export const TYPERT = {
|
|
|
63
63
|
typeSymbol: '@deepseek-ai/dsh-client-file-upload/types#FileUploadValue',
|
|
64
64
|
create: _deepseek_ai_dsh_client_file_upload_fileUploads_upload_result$schema,
|
|
65
65
|
},
|
|
66
|
-
sourceLocation: {"file":"packages/client/file-upload/src/index.ts","line":
|
|
66
|
+
sourceLocation: {"file":"packages/client/file-upload/src/index.ts","line":105,"column":3},
|
|
67
67
|
},
|
|
68
68
|
],
|
|
69
69
|
model: {
|
|
70
70
|
"services": [
|
|
71
71
|
{
|
|
72
|
-
"description": "Host service owning upload storage and Agent
|
|
73
|
-
"summary": "Host service owning upload storage and Agent
|
|
72
|
+
"description": "Host service owning upload storage and receipts keyed by each receiving Agent's exact Session.",
|
|
73
|
+
"summary": "Host service owning upload storage and receipts keyed by each receiving Agent's exact Session.",
|
|
74
74
|
"tags": [],
|
|
75
|
-
"jsDoc": "/** Host service owning upload storage and Agent
|
|
75
|
+
"jsDoc": "/** Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. */",
|
|
76
76
|
"key": "fileUploads",
|
|
77
77
|
"exportName": "FileUploads",
|
|
78
78
|
"members": [
|
|
@@ -101,8 +101,8 @@ export const TYPERT = {
|
|
|
101
101
|
"kind": "method",
|
|
102
102
|
"name": "resolve",
|
|
103
103
|
"signature": "resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined",
|
|
104
|
-
"summary": "Resolve one staged receipt
|
|
105
|
-
"jsDoc": "/**\n * Resolve one staged receipt
|
|
104
|
+
"summary": "Resolve one staged receipt for the receiving Agent's exact Session.",
|
|
105
|
+
"jsDoc": "/**\n * Resolve one staged receipt for the receiving Agent's exact Session.\n * @param agent - receiving Agent.\n * @param receiptId - opaque receipt minted for one completed upload.\n * @returns durable file reference, or `undefined` for an unknown or foreign receipt.\n */"
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
"kind": "method",
|
|
@@ -388,6 +388,14 @@ export const TYPERT = {
|
|
|
388
388
|
"name": "LlmFailure",
|
|
389
389
|
"declaration": "export interface LlmFailure {\n readonly message: string;\n readonly code: string;\n readonly status?: number;\n readonly providerRetryAfterMs?: number;\n readonly requestId?: ProviderRequestId;\n readonly offloadImages?: number;\n}"
|
|
390
390
|
},
|
|
391
|
+
{
|
|
392
|
+
"name": "LlmRetryEventData",
|
|
393
|
+
"declaration": "export type LlmRetryEventData = { retryId: RetryId; turn: number; step: number; provider: string; mode: 'normal'; policyKey: string; retry: number; maxRetries: number; delayMs: number; failure: LlmFailure; } | { retryId: RetryId; turn: number; step: number; provider: string; mode: 'always'; policyKey: string; retry: number; delayMs: number; failure: LlmFailure; };"
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"name": "LlmRetryStartedEventData",
|
|
397
|
+
"declaration": "export interface LlmRetryStartedEventData {\n retryId: RetryId;\n turn: number;\n step: number;\n retry: number;\n}"
|
|
398
|
+
},
|
|
391
399
|
{
|
|
392
400
|
"name": "Message",
|
|
393
401
|
"declaration": "export type Message = MessageRoleMap[keyof MessageRoleMap];"
|
|
@@ -430,7 +438,7 @@ export const TYPERT = {
|
|
|
430
438
|
},
|
|
431
439
|
{
|
|
432
440
|
"name": "MessageSourceMap",
|
|
433
|
-
"declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'system-prompt': SystemPromptMessageSource;\n 'model-selection': { kind: 'model-selection'; } & ContextFormed;\n 'user-approval': { kind: 'user-approval'; } & ContextFormed;\n 'ptc-mode': { kind: 'ptc-mode'; };\n 'tool-registry': { kind: 'tool-registry'; };\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'cordis-host-runner': { kind: 'cordis-host-runner'; };\n goal: GoalMessageSource;\n schedule: { kind: 'schedule'; } & ContextFormed;\n '
|
|
441
|
+
"declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'system-prompt': SystemPromptMessageSource;\n 'model-selection': { kind: 'model-selection'; } & ContextFormed;\n 'user-approval': { kind: 'user-approval'; } & ContextFormed;\n 'ptc-mode': { kind: 'ptc-mode'; };\n 'tool-registry': { kind: 'tool-registry'; };\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'cordis-host-runner': { kind: 'cordis-host-runner'; };\n 'compact-checkpoint': CompactionCheckpointSource;\n 'user-question-reply': { kind: 'user-question-reply'; callId: ToolCallId; outcome: 'answered'; };\n goal: GoalMessageSource;\n schedule: { kind: 'schedule'; } & ContextFormed;\n 'session-reference': SessionReferenceSource;\n}"
|
|
434
442
|
},
|
|
435
443
|
{
|
|
436
444
|
"name": "ModelMessageSource",
|
|
@@ -488,6 +496,10 @@ export const TYPERT = {
|
|
|
488
496
|
"name": "RequestHeaderReason",
|
|
489
497
|
"declaration": "export type RequestHeaderReason = 'initial' | 'resume' | 'change' | 'series';"
|
|
490
498
|
},
|
|
499
|
+
{
|
|
500
|
+
"name": "RetryId",
|
|
501
|
+
"declaration": "export type RetryId = Branded<'RetryId'>;"
|
|
502
|
+
},
|
|
491
503
|
{
|
|
492
504
|
"name": "SandboxMode",
|
|
493
505
|
"declaration": "export type SandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';"
|
|
@@ -522,7 +534,7 @@ export const TYPERT = {
|
|
|
522
534
|
},
|
|
523
535
|
{
|
|
524
536
|
"name": "SessionEventMap",
|
|
525
|
-
"declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'developer/message': { turn: number; step: number; message: DeveloperMessage; headerSeq?: SessionSeq; };\n 'system/message': { turn: number; step: number; message: SystemMessage; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; stream: AssistantStreamRecord[]; usage?: TokenUsage; interrupted?: true; };\n 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[]; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; reason?: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': { inherited?: true; };\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/ptc-dispatch-start': PtcDispatchStartEventData;\n 'tool/ptc-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@deepseek-ai/dsh-session/types').SessionSeq; };\n 'image/offload': { targets: ImageOffloadTarget[]; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'subagent/descriptor': SubagentDescriptorData;\n 'permission/preset': { preset: string; };\n 'subagent/catalog': SubagentCatalogEvent;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; };\n 'feedback/record': FeedbackRecord;\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\n 'schedule/change': ScheduleChange;\n}"
|
|
537
|
+
"declaration": "export interface SessionEventMap {\n 'turn/start': { turn: number; };\n 'turn/end': { turn: number; reason: TurnEndReason; };\n 'step/start': { turn: number; step: number; };\n 'step/end': { turn: number; step: number; };\n 'user/message': UserMessage;\n 'developer/message': { turn: number; step: number; message: DeveloperMessage; headerSeq?: SessionSeq; };\n 'system/message': { turn: number; step: number; message: SystemMessage; };\n 'assistant/message': { turn: number; step: number; message: AssistantMessage; stream: AssistantStreamRecord[]; usage?: TokenUsage; interrupted?: true; };\n 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[]; };\n 'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string; };\n 'tool/result': { turn: number; step: number; message: ToolResultMessage; error?: { name: string; code: string; reason?: string; }; meta?: JsonValue; };\n 'request/header': { header: EpochHeader; reason: RequestHeaderReason; startsSeries?: true; };\n 'request/context': RequestContext;\n 'session/end-seed': { inherited?: true; };\n 'agent/inbox/spliced': { target: InboxTarget; start: number; removedCount?: number; inserted: UserMessage[]; outcome?: 'canceled'; };\n 'sandbox/mode': { mode: SandboxMode; source?: 'delegation'; };\n 'approval/asked': { id: ApprovalRequestId; toolName: string; callId?: ToolCallId; reason?: string; };\n 'approval/decided': { id: ApprovalRequestId; outcome: ApprovalOutcome; };\n 'approval/policy': { policy: ApprovalPolicy; source?: 'delegation'; };\n 'tool/ptc-dispatch-start': PtcDispatchStartEventData;\n 'tool/ptc-dispatch': PtcDispatchEventData;\n 'agent-preset/selected': { agentPreset: string; };\n 'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource; };\n 'command/done': { commandId: CommandId; kind: 'success' | 'error'; text?: string; sourceEventSeq?: import('@deepseek-ai/dsh-session/types').SessionSeq; };\n 'image/offload': { targets: ImageOffloadTarget[]; };\n 'session/title': SessionTitleEventData;\n 'todo/write': { todos: TodoItem[]; };\n 'model/selection': ModelSelection;\n 'subagent/descriptor': SubagentDescriptorData;\n 'permission/preset': { preset: string; };\n 'subagent/catalog': SubagentCatalogEvent;\n 'compaction/start': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; };\n 'compaction/summary': { compactionId: CompactionId; sourceCommandId?: CommandId; summary: ContentBlock[]; shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; provider: string; model: string; maxTokens?: number; usage?: TokenUsage; } & ({ rawOutput: ContentBlock[]; llmStreamCall: true; } | { rawOutput?: ContentBlock[]; llmStreamCall?: never; });\n 'compaction/end': { compactionId: CompactionId; sourceCommandId?: CommandId; turn: number | null; error?: string; };\n 'compaction/prune': { shadowedRange: { start: SessionSeq; end: SessionSeq; }; shadowedSeqs: SessionSeq[]; shadowedTokenCount: number; };\n 'feedback/record': FeedbackRecord;\n 'llm/retry': LlmRetryEventData;\n 'llm/retry-started': LlmRetryStartedEventData;\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\n 'schedule/change': ScheduleChange;\n}"
|
|
526
538
|
},
|
|
527
539
|
{
|
|
528
540
|
"name": "SessionEventType",
|
|
@@ -60,7 +60,7 @@ export const TYPERT_REMOTE = {
|
|
|
60
60
|
typeSymbol: '@deepseek-ai/dsh-client-file-upload/types#FileUploadValue',
|
|
61
61
|
create: _deepseek_ai_dsh_client_file_upload_fileUploads_upload_result$schema,
|
|
62
62
|
},
|
|
63
|
-
sourceLocation: {"file":"packages/client/file-upload/src/index.ts","line":
|
|
63
|
+
sourceLocation: {"file":"packages/client/file-upload/src/index.ts","line":105,"column":3},
|
|
64
64
|
},
|
|
65
65
|
],
|
|
66
66
|
}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Host file-upload service: streamed intake and
|
|
1
|
+
/** Host file-upload service: streamed intake and Session-owned staged receipts. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
3
|
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
4
4
|
import type { FileAttachmentRef } from '@deepseek-ai/dsh-attachment';
|
|
@@ -19,7 +19,7 @@ export interface PromptFileBinding extends Disposable {
|
|
|
19
19
|
/** Keep the receipt bindings until queue or history observation retires them. */
|
|
20
20
|
commit(): void;
|
|
21
21
|
}
|
|
22
|
-
/** Host service owning upload storage and Agent
|
|
22
|
+
/** Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. */
|
|
23
23
|
export declare class FileUploads extends TypertRemoteService {
|
|
24
24
|
static inject: string[];
|
|
25
25
|
private readonly stagedFiles;
|
|
@@ -52,7 +52,7 @@ export declare class FileUploads extends TypertRemoteService {
|
|
|
52
52
|
readonly name?: string;
|
|
53
53
|
}): Promise<FileUploadValue>;
|
|
54
54
|
/**
|
|
55
|
-
* Resolve one staged receipt
|
|
55
|
+
* Resolve one staged receipt for the receiving Agent's exact Session.
|
|
56
56
|
* @param agent - receiving Agent.
|
|
57
57
|
* @param receiptId - opaque receipt minted for one completed upload.
|
|
58
58
|
* @returns durable file reference, or `undefined` for an unknown or foreign receipt.
|
|
@@ -75,7 +75,6 @@ export declare class FileUploads extends TypertRemoteService {
|
|
|
75
75
|
retirePrompt(agent: Agent, requestId: string): void;
|
|
76
76
|
private commit;
|
|
77
77
|
private resolveAgent;
|
|
78
|
-
private assertAgentScope;
|
|
79
78
|
private assertOrdinaryAgent;
|
|
80
79
|
private observeSessionEvent;
|
|
81
80
|
private retire;
|
package/lib/types/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Host file-upload service: streamed intake and
|
|
1
|
+
/** Host file-upload service: streamed intake and Session-owned staged receipts. */
|
|
2
2
|
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
3
3
|
var useValue = arguments.length > 2;
|
|
4
4
|
for (var i = 0; i < initializers.length; i++) {
|
|
@@ -34,7 +34,6 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
|
|
|
34
34
|
done = true;
|
|
35
35
|
};
|
|
36
36
|
import { randomUUID } from 'node:crypto';
|
|
37
|
-
import { scopeOf } from '@deepseek-ai/dsh-scope';
|
|
38
37
|
import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
39
38
|
import { handleFileUploadHttp } from "./http-route.js";
|
|
40
39
|
import { FILE_UPLOAD_PATH } from "./protocol.js";
|
|
@@ -54,7 +53,7 @@ class PromptFileBindingGuard {
|
|
|
54
53
|
this.rollback();
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
|
-
/** Host service owning upload storage and Agent
|
|
56
|
+
/** Host service owning upload storage and receipts keyed by each receiving Agent's exact Session. */
|
|
58
57
|
let FileUploads = (() => {
|
|
59
58
|
let _classSuper = TypertRemoteService;
|
|
60
59
|
let _instanceExtraInitializers = [];
|
|
@@ -125,13 +124,12 @@ let FileUploads = (() => {
|
|
|
125
124
|
}));
|
|
126
125
|
}
|
|
127
126
|
/**
|
|
128
|
-
* Resolve one staged receipt
|
|
127
|
+
* Resolve one staged receipt for the receiving Agent's exact Session.
|
|
129
128
|
* @param agent - receiving Agent.
|
|
130
129
|
* @param receiptId - opaque receipt minted for one completed upload.
|
|
131
130
|
* @returns durable file reference, or `undefined` for an unknown or foreign receipt.
|
|
132
131
|
*/
|
|
133
132
|
resolve(agent, receiptId) {
|
|
134
|
-
this.assertAgentScope(agent);
|
|
135
133
|
return this.stagedFiles.get(agent.session)?.get(receiptId)?.file;
|
|
136
134
|
}
|
|
137
135
|
/**
|
|
@@ -143,7 +141,6 @@ let FileUploads = (() => {
|
|
|
143
141
|
* @returns binding kept after commit until queue or history observation retires its receipts.
|
|
144
142
|
*/
|
|
145
143
|
bindPrompt(agent, receiptIds, requestId) {
|
|
146
|
-
this.assertAgentScope(agent);
|
|
147
144
|
const staged = this.stagedFiles.get(agent.session);
|
|
148
145
|
const bound = receiptIds.map((receiptId) => {
|
|
149
146
|
const upload = staged?.get(receiptId);
|
|
@@ -168,7 +165,6 @@ let FileUploads = (() => {
|
|
|
168
165
|
* @param requestId - prompt identity carried by the queue occurrence.
|
|
169
166
|
*/
|
|
170
167
|
retirePrompt(agent, requestId) {
|
|
171
|
-
this.assertAgentScope(agent);
|
|
172
168
|
this.retire(agent.session, requestId);
|
|
173
169
|
}
|
|
174
170
|
async commit(agent, save) {
|
|
@@ -205,12 +201,7 @@ let FileUploads = (() => {
|
|
|
205
201
|
}
|
|
206
202
|
return resolver(sessionId);
|
|
207
203
|
}
|
|
208
|
-
assertAgentScope(agent) {
|
|
209
|
-
if (scopeOf(agent.ctx) !== agent)
|
|
210
|
-
throw new Error('file-upload: operation requires the Agent\'s own scope');
|
|
211
|
-
}
|
|
212
204
|
assertOrdinaryAgent(agent) {
|
|
213
|
-
this.assertAgentScope(agent);
|
|
214
205
|
if (agent.session.header.origin === 'subagent') {
|
|
215
206
|
throw new RemoteError('subagent/attachment-invalid', 'subagent conversations do not accept file uploads', { reason: 'SUBAGENT_FILE_UNSUPPORTED' });
|
|
216
207
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-file-upload",
|
|
3
3
|
"description": "Agent-scoped browser file upload, streaming intake, and staged receipt service",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.1-alpha.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -59,23 +59,21 @@
|
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"zod": "^4.4.3",
|
|
62
|
-
"@deepseek-ai/dsh-typert-protocol": "0.2.
|
|
63
|
-
"@deepseek-ai/dsh-brand": "0.2.
|
|
62
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.1-alpha.1",
|
|
63
|
+
"@deepseek-ai/dsh-brand": "0.2.1-alpha.1"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
67
|
-
"@deepseek-ai/dsh-scope": "0.2.0-rc.1"
|
|
66
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1"
|
|
68
67
|
},
|
|
69
68
|
"devDependencies": {
|
|
70
|
-
"@deepseek-ai/cordis": "~4.0.
|
|
71
|
-
"@deepseek-ai/dsh-agent": "0.2.
|
|
72
|
-
"@deepseek-ai/dsh-client-connection": "0.2.
|
|
73
|
-
"@deepseek-ai/dsh-commands": "0.2.
|
|
74
|
-
"@deepseek-ai/dsh-
|
|
75
|
-
"@deepseek-ai/dsh-
|
|
76
|
-
"@deepseek-ai/dsh-
|
|
77
|
-
"@deepseek-ai/dsh-
|
|
78
|
-
"@deepseek-ai/dsh-attachment": "0.2.0-rc.1"
|
|
69
|
+
"@deepseek-ai/cordis": "~4.0.5-alpha.1",
|
|
70
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.1",
|
|
71
|
+
"@deepseek-ai/dsh-client-connection": "0.2.1-alpha.1",
|
|
72
|
+
"@deepseek-ai/dsh-commands": "0.2.1-alpha.1",
|
|
73
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.1-alpha.1",
|
|
74
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.1",
|
|
75
|
+
"@deepseek-ai/dsh-attachment": "0.2.1-alpha.1",
|
|
76
|
+
"@deepseek-ai/dsh-util-crypto": "0.2.1-alpha.1"
|
|
79
77
|
},
|
|
80
78
|
"scripts": {
|
|
81
79
|
"bundle": "tsdown",
|