@deepseek-ai/dsh-client-file-upload 0.1.6-alpha.2 → 0.1.7-alpha.2

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/lib/client.js CHANGED
@@ -55,10 +55,11 @@ window.__ModuleLoader__.load({
55
55
  this.name = "RemoteError";
56
56
  }
57
57
  };
58
- //#endregion
59
- //#region lib/types/protocol.js
60
- /** Authenticated raw-byte route owned by the file-upload service. */
61
- const FILE_UPLOAD_PATH = "/api/session/uploadFileBinary";
58
+ /**
59
+ * Browser-relative form of {@link FILE_UPLOAD_PATH}; see
60
+ * .agents/notes/implemented/architecture/2026-09-14-web-document-relative-app-routes.md.
61
+ */
62
+ const FILE_UPLOAD_ROUTE = "/api/session/uploadFileBinary".slice(1);
62
63
  //#endregion
63
64
  //#region lib/types/client/runtime.js
64
65
  /** Background browser upload implementation for Blob and byte-stream bodies. */
@@ -180,7 +181,7 @@ window.__ModuleLoader__.load({
180
181
  const query = new URLSearchParams({ sessionId });
181
182
  if (name !== void 0) query.set("name", name);
182
183
  const response = await this.post({
183
- path: `${FILE_UPLOAD_PATH}?${query.toString()}`,
184
+ path: `${FILE_UPLOAD_ROUTE}?${query.toString()}`,
184
185
  body: data,
185
186
  headers: { "content-type": "application/octet-stream" },
186
187
  ...signal === void 0 ? {} : { signal },
@@ -204,7 +205,7 @@ window.__ModuleLoader__.load({
204
205
  ...request.body instanceof ReadableStream ? { duplex: "half" } : {},
205
206
  ...request.signal === void 0 ? {} : { signal: request.signal }
206
207
  };
207
- const response = await customFetch(resolveUrl(request.path), init);
208
+ const response = await customFetch(request.path, init);
208
209
  return {
209
210
  status: response.status,
210
211
  body: await response.text()
@@ -259,7 +260,7 @@ window.__ModuleLoader__.load({
259
260
  }
260
261
  request.signal?.addEventListener("abort", abort, { once: true });
261
262
  const message = {
262
- url: resolveUrl(request.path).href,
263
+ url: new URL(request.path, document.baseURI).href,
263
264
  body: request.body,
264
265
  headers: request.headers ?? {}
265
266
  };
@@ -268,11 +269,6 @@ window.__ModuleLoader__.load({
268
269
  });
269
270
  } };
270
271
  }
271
- function resolveUrl(path) {
272
- const pageLocation = Reflect.get(globalThis, "location");
273
- const origin = typeof pageLocation === "object" && pageLocation !== null && "origin" in pageLocation && typeof pageLocation.origin === "string" ? pageLocation.origin : void 0;
274
- return new URL(path, origin === void 0 || origin === "null" ? "http://dsh.internal" : origin);
275
- }
276
272
  function parseFileUploadResult(body) {
277
273
  const value = JSON.parse(body);
278
274
  if (!isRecord(value) || typeof value.ok !== "boolean") throw new TypeError("file upload transport returned an invalid result");
package/lib/index.js CHANGED
@@ -71,6 +71,7 @@ async function* requestBodyChunks(body) {
71
71
  //#region lib/types/protocol.js
72
72
  /** Authenticated raw-byte route owned by the file-upload service. */
73
73
  const FILE_UPLOAD_PATH = "/api/session/uploadFileBinary";
74
+ FILE_UPLOAD_PATH.slice(1);
74
75
  //#endregion
75
76
  //#region lib/types/index.js
76
77
  /** Host file-upload service: streamed intake and Agent-scoped staged receipts. */
@@ -158,7 +158,7 @@ export const TYPERT = {
158
158
  },
159
159
  {
160
160
  "name": "AssistantMessage",
161
- "declaration": "export interface AssistantMessage extends Message {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}"
161
+ "declaration": "export interface AssistantMessage extends MessageBase {\n readonly role: 'assistant';\n readonly source: ModelMessageSource;\n}"
162
162
  },
163
163
  {
164
164
  "name": "AssistantProviderMetadata",
@@ -196,6 +196,10 @@ export const TYPERT = {
196
196
  "name": "CommandSourceMap",
197
197
  "declaration": "export interface CommandSourceMap {\n user: { kind: 'user'; };\n}"
198
198
  },
199
+ {
200
+ "name": "CompactionCheckpointSource",
201
+ "declaration": "export type CompactionCheckpointSource = typeof COMPACT_CHECKPOINT_MARKER & { readonly compactionId: CompactionId; readonly sourceCommandId?: CommandId; };"
202
+ },
199
203
  {
200
204
  "name": "CompactionId",
201
205
  "declaration": "export type CompactionId = Branded<'CompactionId'>;"
@@ -206,7 +210,7 @@ export const TYPERT = {
206
210
  },
207
211
  {
208
212
  "name": "ContentBlockMap",
209
- "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n file: FileBlock;\n 'tool-call': ToolCallBlock;\n 'tool-result': ToolResultBlock;\n}"
213
+ "declaration": "export interface ContentBlockMap {\n text: TextBlock;\n reasoning: ReasoningBlock;\n image: ImageBlock;\n file: FileBlock;\n 'tool-call': ToolCallBlock;\n 'tool-addition': ToolAdditionBlock;\n 'tool-removal': ToolRemovalBlock;\n}"
210
214
  },
211
215
  {
212
216
  "name": "ContentBlockType",
@@ -224,13 +228,17 @@ export const TYPERT = {
224
228
  "name": "ContinuableSubagentDescriptorData",
225
229
  "declaration": "export interface ContinuableSubagentDescriptorData extends SubagentDescriptorBase {\n readonly mode: 'continuable';\n readonly label: string;\n readonly agentProvider?: string;\n readonly agentModel?: string;\n readonly agentReasoningEffort?: ReasoningEffortId;\n readonly persona?: string;\n readonly toolFilter?: ToolRestriction;\n}"
226
230
  },
231
+ {
232
+ "name": "DeveloperMessage",
233
+ "declaration": "export interface DeveloperMessage extends MessageBase {\n readonly role: 'developer';\n}"
234
+ },
227
235
  {
228
236
  "name": "EncodedFileUploadRequest",
229
237
  "declaration": "export interface EncodedFileUploadRequest {\n readonly data: string;\n readonly name?: string;\n}"
230
238
  },
231
239
  {
232
240
  "name": "EpochHeader",
233
- "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n tools?: ToolSchema[];\n}"
241
+ "declaration": "export interface EpochHeader {\n config: LlmCallConfig;\n adapterDefaults?: LlmCallConfigAdapterDefaults;\n tools?: ToolSchema[];\n system?: never;\n}"
234
242
  },
235
243
  {
236
244
  "name": "FeedbackCategory",
@@ -332,6 +340,10 @@ export const TYPERT = {
332
340
  "name": "JsonValue",
333
341
  "declaration": "export type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue; };"
334
342
  },
343
+ {
344
+ "name": "KnownCatalogMode",
345
+ "declaration": "export type KnownCatalogMode = { readonly mode: 'one-shot'; readonly label?: string; } | { readonly mode: 'continuable'; readonly label: string; };"
346
+ },
335
347
  {
336
348
  "name": "LlmCallConfig",
337
349
  "declaration": "export interface LlmCallConfig {\n provider: string;\n model: string;\n reasoningEffort?: ReasoningEffortId;\n temperature?: number;\n maxTokens?: number;\n stop?: string[];\n}"
@@ -346,7 +358,11 @@ export const TYPERT = {
346
358
  },
347
359
  {
348
360
  "name": "Message",
349
- "declaration": "export interface Message {\n readonly id: MessageId;\n readonly role: 'system' | 'user' | 'assistant';\n readonly content: ContentBlock[];\n readonly source: MessageSource;\n}"
361
+ "declaration": "export type Message = MessageRoleMap[keyof MessageRoleMap];"
362
+ },
363
+ {
364
+ "name": "MessageBase",
365
+ "declaration": "export interface MessageBase {\n readonly id: MessageId;\n readonly content: readonly ContentBlock[];\n readonly source: MessageSource;\n}"
350
366
  },
351
367
  {
352
368
  "name": "MessageFeedbackDelete",
@@ -372,13 +388,17 @@ export const TYPERT = {
372
388
  "name": "MessageId",
373
389
  "declaration": "export type MessageId = Branded<'MessageId'>;"
374
390
  },
391
+ {
392
+ "name": "MessageRoleMap",
393
+ "declaration": "export interface MessageRoleMap {\n system: SystemMessage;\n developer: DeveloperMessage;\n user: UserMessage;\n assistant: AssistantMessage;\n tool: ToolResultMessage;\n}"
394
+ },
375
395
  {
376
396
  "name": "MessageSource",
377
397
  "declaration": "export type MessageSource = MessageSourceMap[keyof MessageSourceMap];"
378
398
  },
379
399
  {
380
400
  "name": "MessageSourceMap",
381
- "declaration": "export interface MessageSourceMap {\n user: { kind: 'user'; };\n plugin: { kind: 'plugin'; plugin: string; } & ContextFormed;\n model: ModelMessageSource;\n tool: ToolMessageSource;\n 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; };\n 'agent-message': AgentMessageSource;\n 'subagent-settled': SubagentSettledMessageSource;\n 'skill-invocation': SkillInvocationSource;\n 'team-message': TeamMessageSource;\n goal: GoalMessageSource;\n 'session-reference': SessionReferenceSource;\n}"
401
+ "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 'team-message': TeamMessageSource;\n goal: GoalMessageSource;\n 'compact-checkpoint': CompactionCheckpointSource;\n 'session-reference': SessionReferenceSource;\n}"
382
402
  },
383
403
  {
384
404
  "name": "ModelMessageSource",
@@ -438,7 +458,7 @@ export const TYPERT = {
438
458
  },
439
459
  {
440
460
  "name": "Session",
441
- "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n readonly inheritedEventCount: SessionLogOffset;\n get id(): SessionId;\n readonly firstLiveSeq: SessionLogOffset;\n eventAt(seq: SessionSeq): SessionEvent | undefined;\n snapshotEvents(fromSeq: SessionLogOffset = SessionLogOffset(0), toSeqExclusive: SessionLogOffset = this.seq): readonly SessionEvent[];\n ownEvents(): readonly SessionEvent[];\n isOwnSeq(seq: SessionSeq): boolean;\n get seq(): SessionLogOffset;\n append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent<T>] : []): SessionEvent<T>;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}"
461
+ "declaration": "export class Session {\n get surface(): SessionSurface;\n readonly header: SessionHeader;\n readonly inheritedEventCount: SessionLogOffset;\n get id(): SessionId;\n readonly firstLiveSeq: SessionLogOffset;\n readonly firstLifecycleSeq: SessionLogOffset;\n eventAt(seq: SessionSeq): SessionEvent | undefined;\n snapshotEvents(fromSeq: SessionLogOffset = SessionLogOffset(0), toSeqExclusive: SessionLogOffset = this.seq): readonly SessionEvent[];\n ownEvents(): readonly SessionEvent[];\n isOwnSeq(seq: SessionSeq): boolean;\n get seq(): SessionLogOffset;\n append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent<T>] : []): SessionEvent<T>;\n requestHeader(): EpochHeader | undefined;\n requestContext(): RequestContext | undefined;\n deriveMessages(): Message[];\n deriveEventMessage(event: SessionEvent): Message | null;\n}"
442
462
  },
443
463
  {
444
464
  "name": "SessionEvent",
@@ -446,7 +466,7 @@ export const TYPERT = {
446
466
  },
447
467
  {
448
468
  "name": "SessionEventMap",
449
- "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 '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 'feedback/record': FeedbackRecord;\n 'team/member': { version: 2; teamId: TeamId; member: TeamMemberSnapshot; };\n 'team/task': { version: 2; teamId: TeamId; task: TeamTaskSnapshot; };\n 'team/message/queued': { version: 2; teamId: TeamId; message: TeamMessageSnapshot; };\n 'team/message/delivered': { version: 2; teamId: TeamId; messageId: TeamMessageId; targetId: SessionId; };\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\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}"
469
+ "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 'feedback/record': FeedbackRecord;\n 'team/member': { version: 2; teamId: TeamId; member: TeamMemberSnapshot; };\n 'team/task': { version: 2; teamId: TeamId; task: TeamTaskSnapshot; };\n 'team/message/queued': { version: 2; teamId: TeamId; message: TeamMessageSnapshot; };\n 'team/message/delivered': { version: 2; teamId: TeamId; messageId: TeamMessageId; targetId: SessionId; };\n 'goal/change': GoalChangeMeta;\n 'feedback/message-put': MessageFeedbackPut;\n 'feedback/message-delete': MessageFeedbackDelete;\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}"
450
470
  },
451
471
  {
452
472
  "name": "SessionEventType",
@@ -506,7 +526,7 @@ export const TYPERT = {
506
526
  },
507
527
  {
508
528
  "name": "SubagentCatalogEvent",
509
- "declaration": "export type SubagentCatalogEvent = { readonly version: 0; readonly childId: SessionId; readonly childCreatedAt: number; } & ({ readonly mode: 'one-shot'; readonly label?: string; } | { readonly mode: 'continuable'; readonly label: string; });"
529
+ "declaration": "export type SubagentCatalogEvent = { readonly childId: SessionId; readonly childCreatedAt: number; } & (({ readonly version: 0; } & KnownCatalogMode) | ({ readonly version: 1; } & (KnownCatalogMode | { readonly mode: 'unknown'; readonly label?: string; })));"
510
530
  },
511
531
  {
512
532
  "name": "SubagentDescriptorBase",
@@ -522,7 +542,7 @@ export const TYPERT = {
522
542
  },
523
543
  {
524
544
  "name": "SurfaceEventType",
525
- "declaration": "export type SurfaceEventType = 'system/message' | 'user/message' | 'assistant/message' | 'tool/result';"
545
+ "declaration": "export type SurfaceEventType = 'system/message' | 'developer/message' | 'user/message' | 'assistant/message' | 'tool/result';"
526
546
  },
527
547
  {
528
548
  "name": "SurfaceIntent",
@@ -534,7 +554,11 @@ export const TYPERT = {
534
554
  },
535
555
  {
536
556
  "name": "SystemMessage",
537
- "declaration": "export interface SystemMessage extends Message {\n readonly role: 'system';\n readonly source: MessageSourceMap['plugin'];\n}"
557
+ "declaration": "export interface SystemMessage extends MessageBase {\n readonly role: 'system';\n readonly source: MessageSourceMap['system-prompt'];\n}"
558
+ },
559
+ {
560
+ "name": "SystemPromptMessageSource",
561
+ "declaration": "export interface SystemPromptMessageSource {\n kind: 'system-prompt';\n}"
538
562
  },
539
563
  {
540
564
  "name": "SystemPromptUpdate",
@@ -588,6 +612,10 @@ export const TYPERT = {
588
612
  "name": "TokenUsage",
589
613
  "declaration": "export interface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n totalTokens?: number;\n cacheReadTokens?: number;\n cacheWriteTokens?: number;\n reasoningTokens?: number;\n}"
590
614
  },
615
+ {
616
+ "name": "ToolAdditionBlock",
617
+ "declaration": "export interface ToolAdditionBlock {\n type: 'tool-addition';\n toolName: string;\n tool?: never;\n}"
618
+ },
591
619
  {
592
620
  "name": "ToolCallBlock",
593
621
  "declaration": "export interface ToolCallBlock {\n type: 'tool-call';\n id: ToolCallId;\n name: string;\n arguments: string;\n}"
@@ -601,20 +629,20 @@ export const TYPERT = {
601
629
  "declaration": "export interface ToolMessageSource {\n kind: 'tool';\n callId: ToolCallId;\n}"
602
630
  },
603
631
  {
604
- "name": "ToolRestriction",
605
- "declaration": "export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n}"
632
+ "name": "ToolRemovalBlock",
633
+ "declaration": "export interface ToolRemovalBlock {\n type: 'tool-removal';\n toolName: string;\n}"
606
634
  },
607
635
  {
608
- "name": "ToolResultBlock",
609
- "declaration": "export interface ToolResultBlock {\n type: 'tool-result';\n toolCallId: ToolCallId;\n content: ContentBlock[];\n isError?: boolean;\n}"
636
+ "name": "ToolRestriction",
637
+ "declaration": "export interface ToolRestriction {\n readonly allow?: readonly string[];\n readonly deny?: readonly string[];\n}"
610
638
  },
611
639
  {
612
640
  "name": "ToolResultMessage",
613
- "declaration": "export interface ToolResultMessage extends Message {\n readonly role: 'user';\n readonly content: [ToolResultBlock];\n readonly source: ToolMessageSource;\n}"
641
+ "declaration": "export interface ToolResultMessage extends MessageBase {\n readonly role: 'tool';\n readonly source: ToolMessageSource;\n readonly toolCallId: ToolCallId;\n readonly isError?: boolean;\n}"
614
642
  },
615
643
  {
616
644
  "name": "ToolSchema",
617
- "declaration": "export interface ToolSchema {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n}"
645
+ "declaration": "export interface ToolSchema {\n deferLoading?: true;\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n}"
618
646
  },
619
647
  {
620
648
  "name": "TurnEndCancelCause",
@@ -626,11 +654,11 @@ export const TYPERT = {
626
654
  },
627
655
  {
628
656
  "name": "TurnEndReasonMap",
629
- "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n}"
657
+ "declaration": "export interface TurnEndReasonMap {\n completed: { kind: 'completed'; };\n aborted: { kind: 'aborted'; reason: TurnEndCancelCause; };\n blocked: { kind: 'blocked'; };\n error: { kind: 'error'; error: LlmFailure; };\n 'max-tokens': { kind: 'max-tokens'; };\n interrupted: { kind: 'interrupted'; };\n forked: { kind: 'forked'; };\n}"
630
658
  },
631
659
  {
632
660
  "name": "UserMessage",
633
- "declaration": "export interface UserMessage extends Message {\n readonly role: 'user';\n}"
661
+ "declaration": "export interface UserMessage extends MessageBase {\n readonly role: 'user';\n}"
634
662
  }
635
663
  ]
636
664
  }
@@ -5,6 +5,7 @@ import type { SessionId } from '@deepseek-ai/dsh-session/types';
5
5
  import type { FileUploadValue } from '../types.ts';
6
6
  import type { FileUploadBody, FileUploadService } from './contract.ts';
7
7
  interface FileUploadRequest {
8
+ /** Document-relative app-owned upload route, query string included. */
8
9
  readonly path: string;
9
10
  readonly body: FileUploadBody;
10
11
  readonly headers?: Readonly<Record<string, string>>;
@@ -2,7 +2,7 @@
2
2
  import { Service } from '@deepseek-ai/cordis';
3
3
  import { bytesToBase64 } from '@deepseek-ai/dsh-util-crypto';
4
4
  import { RemoteError } from '@deepseek-ai/dsh-typert-protocol';
5
- import { FILE_UPLOAD_PATH } from "../protocol.js";
5
+ import { FILE_UPLOAD_ROUTE } from "../protocol.js";
6
6
  /**
7
7
  * Self-contained Worker body; its string form becomes the Blob Worker source.
8
8
  * @param scope - Worker global used for requests and progress messages.
@@ -112,7 +112,7 @@ export class FileUploadRuntime extends Service {
112
112
  if (name !== undefined)
113
113
  query.set('name', name);
114
114
  const response = await this.post({
115
- path: `${FILE_UPLOAD_PATH}?${query.toString()}`,
115
+ path: `${FILE_UPLOAD_ROUTE}?${query.toString()}`,
116
116
  body: data,
117
117
  headers: { 'content-type': 'application/octet-stream' },
118
118
  ...(signal === undefined ? {} : { signal }),
@@ -139,7 +139,7 @@ function customTransport(customFetch) {
139
139
  ...(request.body instanceof ReadableStream ? { duplex: 'half' } : {}),
140
140
  ...(request.signal === undefined ? {} : { signal: request.signal }),
141
141
  };
142
- const response = await customFetch(resolveUrl(request.path), init);
142
+ const response = await customFetch(request.path, init);
143
143
  return { status: response.status, body: await response.text() };
144
144
  },
145
145
  };
@@ -195,7 +195,8 @@ function workerTransport() {
195
195
  }
196
196
  request.signal?.addEventListener('abort', abort, { once: true });
197
197
  const message = {
198
- url: resolveUrl(request.path).href,
198
+ // The Worker's own base is `blob:`, so its request URL must be absolute.
199
+ url: new URL(request.path, document.baseURI).href,
199
200
  body: request.body,
200
201
  headers: request.headers ?? {},
201
202
  };
@@ -207,14 +208,6 @@ function workerTransport() {
207
208
  },
208
209
  };
209
210
  }
210
- function resolveUrl(path) {
211
- const pageLocation = Reflect.get(globalThis, 'location');
212
- const origin = typeof pageLocation === 'object' && pageLocation !== null
213
- && 'origin' in pageLocation && typeof pageLocation.origin === 'string'
214
- ? pageLocation.origin
215
- : undefined;
216
- return new URL(path, origin === undefined || origin === 'null' ? 'http://dsh.internal' : origin);
217
- }
218
211
  function parseFileUploadResult(body) {
219
212
  const value = JSON.parse(body);
220
213
  if (!isRecord(value) || typeof value.ok !== 'boolean') {
@@ -1,3 +1,8 @@
1
1
  /** Authenticated raw-byte route owned by the file-upload service. */
2
2
  export declare const FILE_UPLOAD_PATH = "/api/session/uploadFileBinary";
3
+ /**
4
+ * Browser-relative form of {@link FILE_UPLOAD_PATH}; see
5
+ * .agents/notes/implemented/architecture/2026-09-14-web-document-relative-app-routes.md.
6
+ */
7
+ export declare const FILE_UPLOAD_ROUTE: string;
3
8
  //# sourceMappingURL=protocol.d.ts.map
@@ -1,3 +1,8 @@
1
1
  /** Authenticated raw-byte route owned by the file-upload service. */
2
2
  export const FILE_UPLOAD_PATH = '/api/session/uploadFileBinary';
3
+ /**
4
+ * Browser-relative form of {@link FILE_UPLOAD_PATH}; see
5
+ * .agents/notes/implemented/architecture/2026-09-14-web-document-relative-app-routes.md.
6
+ */
7
+ export const FILE_UPLOAD_ROUTE = FILE_UPLOAD_PATH.slice(1);
3
8
  //# sourceMappingURL=protocol.js.map
@@ -18,11 +18,12 @@ export interface FileUploadValue {
18
18
  export type FileUploadReceiptId = Branded<'file-upload-receipt-id'>;
19
19
  /**
20
20
  * Fetch-shaped carrier installed by a page that owns its Host transport.
21
- * @param input - absolute same-origin upload URL.
21
+ * @param input - document-relative upload route; a carrier that needs an
22
+ * absolute URL resolves it against its own base.
22
23
  * @param init - raw request body, headers, and cancellation signal.
23
24
  * @returns the Host response.
24
25
  */
25
- export type FileUploadFetch = (input: URL, init: RequestInit) => Promise<Response>;
26
+ export type FileUploadFetch = (input: string | URL, init: RequestInit) => Promise<Response>;
26
27
  /** Pre-Cordis hook supplied by a page whose Host runs in another execution context. */
27
28
  export interface ClientFileUploadHooks {
28
29
  readonly fetch: FileUploadFetch;
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.1.6-alpha.2",
4
+ "version": "0.1.7-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -59,23 +59,23 @@
59
59
  ],
60
60
  "dependencies": {
61
61
  "zod": "^4.4.3",
62
- "@deepseek-ai/dsh-typert-protocol": "^0.1.6-alpha.2",
63
- "@deepseek-ai/dsh-brand": "^0.1.6-alpha.2"
62
+ "@deepseek-ai/dsh-typert-protocol": "0.1.7-alpha.2",
63
+ "@deepseek-ai/dsh-brand": "0.1.7-alpha.2"
64
64
  },
65
65
  "peerDependencies": {
66
- "@deepseek-ai/cordis": "^4.0.2",
67
- "@deepseek-ai/dsh-scope": "^0.1.6-alpha.2"
66
+ "@deepseek-ai/cordis": "~4.0.4",
67
+ "@deepseek-ai/dsh-scope": "0.1.7-alpha.2"
68
68
  },
69
69
  "devDependencies": {
70
- "@deepseek-ai/cordis": "^4.0.2",
71
- "@deepseek-ai/dsh-client-connection": "^0.1.6-alpha.2",
72
- "@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
73
- "@deepseek-ai/dsh-commands": "^0.1.6-alpha.2",
74
- "@deepseek-ai/dsh-util-crypto": "^0.1.6-alpha.2",
75
- "@deepseek-ai/dsh-scope": "^0.1.6-alpha.2",
76
- "@deepseek-ai/dsh-api-remotes": "^0.1.6-alpha.2",
77
- "@deepseek-ai/dsh-attachment": "^0.1.6-alpha.2",
78
- "@deepseek-ai/dsh-session": "^0.1.6-alpha.2"
70
+ "@deepseek-ai/cordis": "~4.0.4",
71
+ "@deepseek-ai/dsh-client-connection": "0.1.7-alpha.2",
72
+ "@deepseek-ai/dsh-agent": "0.1.7-alpha.2",
73
+ "@deepseek-ai/dsh-commands": "0.1.7-alpha.2",
74
+ "@deepseek-ai/dsh-scope": "0.1.7-alpha.2",
75
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-alpha.2",
76
+ "@deepseek-ai/dsh-session": "0.1.7-alpha.2",
77
+ "@deepseek-ai/dsh-attachment": "0.1.7-alpha.2",
78
+ "@deepseek-ai/dsh-util-crypto": "0.1.7-alpha.2"
79
79
  },
80
80
  "scripts": {
81
81
  "bundle": "tsdown",