dsh-plugin-guide 0.3.3 → 0.3.5

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.
Files changed (102) hide show
  1. package/README.es.md +5 -1
  2. package/README.hi.md +5 -1
  3. package/README.md +5 -1
  4. package/README.pt.md +5 -1
  5. package/README.zh.md +5 -1
  6. package/dist/dsh-plugin-dev.js +3 -3
  7. package/guide/plugin-dev-guide.md +2 -2
  8. package/guide/quick-reference.es.md +2 -2
  9. package/guide/quick-reference.hi.md +1 -1
  10. package/guide/quick-reference.md +2 -2
  11. package/guide/quick-reference.pt.md +2 -2
  12. package/guide/quick-reference.zh-CN.md +2 -2
  13. package/package.json +5 -4
  14. package/references/official-docs/AGENTS.md +2 -2
  15. package/references/official-docs/SNAPSHOT.md +3 -3
  16. package/references/official-docs/THIRD_PARTY_NOTICES.md +4 -6
  17. package/references/official-docs/docs/agent-lifecycle.i18n.yaml +2 -2
  18. package/references/official-docs/docs/agent-lifecycle.md +5 -3
  19. package/references/official-docs/docs/agent-lifecycle.zh.md +5 -3
  20. package/references/official-docs/docs/architecture.i18n.yaml +2 -2
  21. package/references/official-docs/docs/architecture.md +7 -3
  22. package/references/official-docs/docs/architecture.zh.md +7 -3
  23. package/references/official-docs/docs/capability-seams.i18n.yaml +2 -2
  24. package/references/official-docs/docs/capability-seams.md +5 -0
  25. package/references/official-docs/docs/capability-seams.zh.md +5 -0
  26. package/references/official-docs/docs/config-catalog.i18n.yaml +2 -2
  27. package/references/official-docs/docs/config-catalog.md +15 -21
  28. package/references/official-docs/docs/config-catalog.zh.md +15 -21
  29. package/references/official-docs/docs/cookbook/extension-cookbook.i18n.yaml +2 -2
  30. package/references/official-docs/docs/cookbook/extension-cookbook.md +12 -10
  31. package/references/official-docs/docs/cookbook/extension-cookbook.zh.md +12 -10
  32. package/references/official-docs/docs/deepseek-llm-api-wire-extensions.i18n.yaml +2 -2
  33. package/references/official-docs/docs/deepseek-llm-api-wire-extensions.md +16 -12
  34. package/references/official-docs/docs/deepseek-llm-api-wire-extensions.zh.md +16 -12
  35. package/references/official-docs/docs/event-producer-consumer.i18n.yaml +2 -2
  36. package/references/official-docs/docs/event-producer-consumer.md +28 -27
  37. package/references/official-docs/docs/event-producer-consumer.zh.md +32 -31
  38. package/references/official-docs/docs/module-graph.i18n.yaml +2 -2
  39. package/references/official-docs/docs/module-graph.md +36 -14
  40. package/references/official-docs/docs/module-graph.zh.md +36 -14
  41. package/references/official-docs/docs/persistence-catalog.i18n.yaml +2 -2
  42. package/references/official-docs/docs/persistence-catalog.md +49 -39
  43. package/references/official-docs/docs/persistence-catalog.zh.md +39 -29
  44. package/references/official-docs/docs/subsystems/attachment.i18n.yaml +2 -2
  45. package/references/official-docs/docs/subsystems/attachment.md +157 -4
  46. package/references/official-docs/docs/subsystems/attachment.zh.md +157 -4
  47. package/references/official-docs/docs/subsystems/commands.i18n.yaml +2 -2
  48. package/references/official-docs/docs/subsystems/commands.md +24 -15
  49. package/references/official-docs/docs/subsystems/commands.zh.md +24 -15
  50. package/references/official-docs/docs/subsystems/conversation.i18n.yaml +2 -2
  51. package/references/official-docs/docs/subsystems/conversation.md +4 -4
  52. package/references/official-docs/docs/subsystems/conversation.zh.md +4 -4
  53. package/references/official-docs/docs/subsystems/core.i18n.yaml +2 -2
  54. package/references/official-docs/docs/subsystems/core.md +62 -1
  55. package/references/official-docs/docs/subsystems/core.zh.md +62 -1
  56. package/references/official-docs/docs/subsystems/llm-streaming.i18n.yaml +2 -2
  57. package/references/official-docs/docs/subsystems/llm-streaming.md +23 -2
  58. package/references/official-docs/docs/subsystems/llm-streaming.zh.md +23 -2
  59. package/references/official-docs/docs/subsystems/persistence.i18n.yaml +2 -2
  60. package/references/official-docs/docs/subsystems/persistence.md +10 -10
  61. package/references/official-docs/docs/subsystems/persistence.zh.md +10 -10
  62. package/references/official-docs/docs/subsystems/session-projection.i18n.yaml +2 -2
  63. package/references/official-docs/docs/subsystems/session-projection.md +19 -0
  64. package/references/official-docs/docs/subsystems/session-projection.zh.md +19 -0
  65. package/references/official-docs/docs/subsystems/session-reference.i18n.yaml +2 -2
  66. package/references/official-docs/docs/subsystems/session-reference.md +25 -1
  67. package/references/official-docs/docs/subsystems/session-reference.zh.md +25 -1
  68. package/references/official-docs/docs/subsystems/session-telemetry.i18n.yaml +2 -2
  69. package/references/official-docs/docs/subsystems/session-telemetry.md +6 -5
  70. package/references/official-docs/docs/subsystems/session-telemetry.zh.md +6 -5
  71. package/references/official-docs/docs/subsystems/session.i18n.yaml +2 -2
  72. package/references/official-docs/docs/subsystems/session.md +52 -40
  73. package/references/official-docs/docs/subsystems/session.zh.md +52 -40
  74. package/references/official-docs/docs/subsystems/web-client.i18n.yaml +2 -2
  75. package/references/official-docs/docs/subsystems/web-client.md +1 -1
  76. package/references/official-docs/docs/subsystems/web-client.zh.md +1 -1
  77. package/references/official-docs/docs/subsystems/workspace.i18n.yaml +2 -2
  78. package/references/official-docs/docs/subsystems/workspace.md +8 -8
  79. package/references/official-docs/docs/subsystems/workspace.zh.md +8 -8
  80. package/references/official-docs/docs/testing.i18n.yaml +2 -2
  81. package/references/official-docs/docs/testing.md +2 -2
  82. package/references/official-docs/docs/testing.zh.md +2 -2
  83. package/references/official-docs/docs/user/guide/network-proxy.i18n.yaml +6 -0
  84. package/references/official-docs/docs/user/guide/network-proxy.md +85 -0
  85. package/references/official-docs/docs/user/guide/network-proxy.zh.md +85 -0
  86. package/references/official-docs/docs/user/guide/providers.i18n.yaml +2 -2
  87. package/references/official-docs/docs/user/guide/providers.md +70 -17
  88. package/references/official-docs/docs/user/guide/providers.zh.md +70 -17
  89. package/references/official-docs/docs/web-styling.i18n.yaml +2 -2
  90. package/references/official-docs/docs/web-styling.md +1 -0
  91. package/references/official-docs/docs/web-styling.zh.md +1 -0
  92. package/references/official-docs/website-docs.ts +8 -0
  93. package/templates/js/README.es.md +1 -1
  94. package/templates/js/README.hi.md +1 -1
  95. package/templates/js/README.md +1 -1
  96. package/templates/js/README.pt.md +1 -1
  97. package/templates/js/README.zh.md +1 -1
  98. package/templates/ts/README.es.md +1 -1
  99. package/templates/ts/README.hi.md +1 -1
  100. package/templates/ts/README.md +1 -1
  101. package/templates/ts/README.pt.md +1 -1
  102. package/templates/ts/README.zh.md +1 -1
@@ -9,7 +9,7 @@
9
9
 
10
10
  英文源文件根据源码生成(`scripts/gen-persistence-catalog.ts`),并由 `pnpm run verify-persistence-catalog`(`doc-sync`(文档同步门禁)的一部分)验证新鲜度;本中文文件作为经评审对侧通过双语配对维护。声明块保留源码声明和嵌套属性的 JSDoc,只移除其所在接口/模块带来的缩进,并使用 `ts persistence-catalog` 围栏(doc-typecheck 会跳过这些围栏,因为声明引用了其所属模块中的类型)。payload 中的类型名称会链接到记录该类型的页面。参见 [persistence-log-catalog Agent Note](../.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md)。
11
11
 
12
- 以下信封声明组合了每个事件的 `type`、单调递增的 `seq`、以 epoch 毫秒表示的 `time`、`data`、可选的未知类型跳过标记 `ignorable`,以及条件字段 `surfaceOp`/`sourceEventSeqs`。**surface** 表示 `SurfaceEventType` 成员:它会生成一条 LLM(大语言模型)消息,并声明该事件如何加入 surface 列表。**log-only** 表示其他所有事件:这类记录可持久化、可回放,但不参与派生历史。每个 payload 均可进行 JSON 序列化(在 `Session.append` 处强制执行),整个格式固定为 `SESSION_FORMAT_VERSION = 0`:这是预发布格式,不暗示任何兼容性(参见[版本立场](subsystems/persistence.zh.md))。范围仅限本仓库中的包;下游插件可以继续合并其他事件类型,而这些类型按设计不属于本目录。
12
+ 以下信封声明组合了每个事件的 `type`、单调递增的 `seq`、以 epoch 毫秒表示的 `time`、`data`、可选的未知类型跳过标记 `ignorable`,以及条件字段 `surfaceOp`/`sourceEventSeqs`。**surface** 表示 `SurfaceEventType` 成员:它会生成一条 LLM(大语言模型)消息,并声明该事件如何加入 surface 列表。**log-only** 表示其他所有事件:这类记录可持久化、可回放,但不参与派生历史。每个 payload 均可进行 JSON 序列化(在 `Session.append` 处强制执行)。当前 writer 会写入 `SESSION_FORMAT_VERSION`;受支持的历史产物通过构建期静态相邻迁移目录进入这套当前词汇(参见[版本生命周期](subsystems/persistence.zh.md))。范围仅限本仓库中的包;下游插件可以继续合并其他当前版本事件类型,这些类型按设计不属于本目录,并且在后续格式迁移边中需要显式 disposition。
13
13
 
14
14
  ## 事件信封
15
15
 
@@ -20,7 +20,8 @@ export type SessionEventType = keyof SessionEventMap
20
20
  /**
21
21
  * The subset of {@link SessionEventType} values whose events produce LLM
22
22
  * messages and are eligible to appear on the ordered surface. Only these
23
- * event types may carry {@link SurfaceOp} and {@link SessionEvent.sourceEventSeqs}.
23
+ * event types may carry {@link SurfaceOp}; user and tool events may also cite
24
+ * earlier sources through {@link SessionEvent.sourceEventSeqs}.
24
25
  */
25
26
  export type SurfaceEventType =
26
27
  | 'user/message'
@@ -53,7 +54,7 @@ export type SurfaceOp =
53
54
  * The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional:
54
55
  * they only exist on {@link SurfaceEventType} variants (`user/message`,
55
56
  * `assistant/message`, `tool/result`).
56
- * Non-surface events (boundary markers, chunks, usage, errors) never carry
57
+ * Non-surface events (boundary markers, attempts, errors) never carry
57
58
  * surface metadata — the compiler enforces this at `Session.append()`
58
59
  * call sites.
59
60
  */
@@ -78,12 +79,9 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
78
79
  ignorable?: true
79
80
  } & (K extends SurfaceEventType ? {
80
81
  /**
81
- * Seq numbers of earlier events that this event cites as sources
82
- * (e.g. the `assistant/chunk` seqs that built an `assistant/message`,
83
- * or the surface nodes shadowed by a compaction replace node). An
84
- * `assistant/message` may carry a present empty array for a known empty
85
- * provider stream; when the field is absent, the event does not record which
86
- * earlier events produced the message.
82
+ * Seq numbers of earlier events that this event cites as sources, such as
83
+ * the surface nodes shadowed by a compaction replacement. A v2
84
+ * `assistant/message` embeds its provider stream and cannot carry this field.
87
85
  */
88
86
  sourceEventSeqs?: SessionSeq[]
89
87
  /** How this event entered the surface; absent for non-surface events. */
@@ -92,7 +90,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
92
90
  }[T]
93
91
  ```
94
92
 
95
- 来源:[`packages/core/session/src/types.ts:368`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:375`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:404`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:436`](../packages/core/session/src/types.ts)
93
+ 来源:[`packages/core/session/src/types.ts:379`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:387`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:416`](../packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:447`](../packages/core/session/src/types.ts)
96
94
 
97
95
  ## 事件
98
96
 
@@ -206,18 +204,20 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
206
204
 
207
205
  ### `assistant/*`
208
206
 
209
- <a id="assistantchunk--log-only"></a>
207
+ <a id="assistantattempt--log-only"></a>
210
208
 
211
- #### `assistant/chunk` — log-only
209
+ #### `assistant/attempt` — log-only
212
210
 
213
211
  ```ts persistence-catalog
214
- /** Raw stream chunk — token-level replay fidelity. */
215
- 'assistant/chunk': { turn: number; step: number; chunk: StreamChunk }
212
+ /**
213
+ * One model attempt that committed no surface message. The embedded stream
214
+ * preserves a failed, retried, cancelled, or stream-error attempt that
215
+ * reached settlement without fabricating model-visible history.
216
+ */
217
+ 'assistant/attempt': { turn: number; step: number; stream: AssistantStreamRecord[] }
216
218
  ```
217
219
 
218
- 类型:[StreamChunk](subsystems/llm-streaming.zh.md)
219
-
220
- 来源:[`packages/core/session/src/types.ts:291`](../packages/core/session/src/types.ts)
220
+ 来源:[`packages/core/session/src/types.ts:313`](../packages/core/session/src/types.ts)
221
221
 
222
222
  <a id="assistantmessage--surface"></a>
223
223
 
@@ -234,12 +234,20 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
234
234
  * marker distinguishes that prefix without re-deriving interruption from turn
235
235
  * boundaries. An aborted turn with no such event streamed no visible content.
236
236
  */
237
- 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true }
237
+ 'assistant/message': {
238
+ turn: number
239
+ step: number
240
+ message: AssistantMessage
241
+ /** Exact timed model stream, compacted without joining delta boundaries. */
242
+ stream: AssistantStreamRecord[]
243
+ usage?: TokenUsage
244
+ interrupted?: true
245
+ }
238
246
  ```
239
247
 
240
248
  类型:[TokenUsage](subsystems/llm-streaming.zh.md)
241
249
 
242
- 来源:[`packages/core/session/src/types.ts:302`](../packages/core/session/src/types.ts)
250
+ 来源:[`packages/core/session/src/types.ts:299`](../packages/core/session/src/types.ts)
243
251
 
244
252
  ### `command/*`
245
253
 
@@ -262,7 +270,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
262
270
  }
263
271
  ```
264
272
 
265
- 来源:[`packages/interaction/commands/src/types.ts:104`](../packages/interaction/commands/src/types.ts)
273
+ 来源:[`packages/interaction/commands/src/types.ts:110`](../packages/interaction/commands/src/types.ts)
266
274
 
267
275
  <a id="commandrun--log-only"></a>
268
276
 
@@ -282,7 +290,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
282
290
  'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource }
283
291
  ```
284
292
 
285
- 来源:[`packages/interaction/commands/src/types.ts:97`](../packages/interaction/commands/src/types.ts)
293
+ 来源:[`packages/interaction/commands/src/types.ts:103`](../packages/interaction/commands/src/types.ts)
286
294
 
287
295
  ### `compaction/*`
288
296
 
@@ -638,12 +646,12 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
638
646
  * Marks the end of a constructor seed. Events before it have smaller seq
639
647
  * values and came from the seed (resume, fork, or replay); this lifecycle
640
648
  * produced none of them. This log-only event is the durable projection of
641
- * {@link Session.firstLiveSeq}. Its payload is empty — position and `time`
642
- * carry the meaning.
649
+ * {@link Session.firstLiveSeq}.
643
650
  *
644
- * Locate the LAST one in stored history. A seed already ending in one is not
645
- * re-marked, so reopening an untouched session does not grow its log per
646
- * pickup and the event need not be at the current `firstLiveSeq`.
651
+ * A fresh fork child owns one `{ inherited: true }` marker at its exact
652
+ * inherited-prefix cut, even when that prefix ends in an ancestor marker.
653
+ * The last tagged marker is the current Session's cut; untagged markers keep
654
+ * ordinary restore and replay lifecycle boundaries.
647
655
  *
648
656
  * `Session`'s constructor is the only legitimate writer. The invariant
649
657
  * companion deliberately constrains nothing here, so a plugin appending one
@@ -656,10 +664,10 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
656
664
  * writers — a concurrently live session holds its own boundary elsewhere,
657
665
  * so tolerating concurrent writers needs a signal beyond the log.
658
666
  */
659
- 'session/end-seed': Record<string, never>
667
+ 'session/end-seed': { inherited?: true }
660
668
  ```
661
669
 
662
- 来源:[`packages/core/session/src/types.ts:364`](../packages/core/session/src/types.ts)
670
+ 来源:[`packages/core/session/src/types.ts:375`](../packages/core/session/src/types.ts)
663
671
 
664
672
  <a id="sessiontitle--log-only"></a>
665
673
 
@@ -701,12 +709,14 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
701
709
  'session-log-deepseek/delivery-accepted': {
702
710
  /** Session identity the accepted delivery carried; inherited fork markers retain the parent's id. */
703
711
  sessionId: import('@deepseek-ai/dsh-session/types').SessionId
712
+ /** Accepted Session format generation; absence identifies version 0. */
713
+ sessionFormatVersion?: number
704
714
  /** Last canonical event included in the accepted request. */
705
715
  throughSeq: import('@deepseek-ai/dsh-session/types').SessionSeq
706
716
  }
707
717
  ```
708
718
 
709
- 来源:[`packages/session/session-log-deepseek/src/types.ts:57`](../packages/session/session-log-deepseek/src/types.ts)
719
+ 来源:[`packages/session/session-log-deepseek/src/types.ts:59`](../packages/session/session-log-deepseek/src/types.ts)
710
720
 
711
721
  ### `step/*`
712
722
 
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write docs/subsystems/attachment.md
5
- attachment.md: 15daa2b8d541ba847d48f5c43a06c1c537df6d11
6
- attachment.zh.md: c74a18f6bec63e117afcdb141512be04f8d75f9a
5
+ attachment.md: 53b3e51e5b1c87625256178287061386342bc055
6
+ attachment.zh.md: 549c06cc5abe542e5d6feeba10b24ebf6ba8dfd1
@@ -1,10 +1,10 @@
1
- # Durable Image Attachments
1
+ # Durable Attachments
2
2
 
3
3
  English | [中文](attachment.zh.md)
4
4
 
5
- The attachment seam separates binary image ownership from the session log. A producer gives validated encoded bytes to [`ctx.attachments`](#ctxattachments--attachmentstore-abstract-seam); the service publishes an immutable content-addressed reference only after the object is durable. Session events and model-visible `ImageBlock`s contain that reference and metadata, never a browser object URL, host temporary path, provider URL, or base64 payload.
5
+ The attachment seam separates binary image and generic-file ownership from the session log. A producer gives bytes to [`ctx.attachments`](#ctxattachments--attachmentstore-abstract-seam); the service publishes an immutable content-addressed reference only after the object is durable. Session events and model-visible attachment blocks contain that reference and metadata, never a browser object URL, host temporary path, provider URL, or base64 payload. The independent [`ctx.fileUploads`](#ctxfileuploads--fileuploads) service binds browser file transfers and staged receipts to the receiving Agent.
6
6
 
7
- Unsent browser drafts may stay in memory and native clients may stage them in operating-system temporary storage. Once the host accepts a user message, its images move below `<DSH_HOME>/attachments/v1` before the user event is appended. Structured model image output follows the same persist-before-event rule.
7
+ Unsent browser drafts may stay in memory and native clients may stage them in operating-system temporary storage. Browser generic files become durable before they receive a staged prompt receipt. Once the host accepts a user message, its images move below `<DSH_HOME>/attachments/v1` before the user event is appended. Structured model image output follows the same persist-before-event rule.
8
8
 
9
9
  Source: [`packages/attachment/attachment/src/types.ts`](../../packages/attachment/attachment/src/types.ts)
10
10
 
@@ -62,6 +62,38 @@ The reference records intrinsic dimensions and encoded length so clients can lay
62
62
 
63
63
  ## Commit and verified-read payloads
64
64
 
65
+ ```ts type-equiv
66
+ /**
67
+ * Browser-submitted prompt content accepted by Host prompt endpoints; the
68
+ * accepting Host promotes image parts to durable references through
69
+ * `ctx.attachments.admitPromptContent()` before any message is created, so a wire caller can
70
+ * never cite an attachment it did not upload.
71
+ */
72
+ type PromptContentPart =
73
+ | { readonly type: 'text'; readonly text: string }
74
+ | {
75
+ readonly type: 'image'
76
+ readonly mediaType: ImageMediaType
77
+ readonly data: string
78
+ readonly name?: string
79
+ }
80
+ ```
81
+
82
+ ```ts type-equiv
83
+ /** Host prompt content whose file receipts are resolved and whose image bytes await admission. */
84
+ type AttachmentAdmissionPart =
85
+ | PromptContentPart
86
+ | { readonly type: 'file'; readonly attachment: FileAttachmentRef }
87
+ ```
88
+
89
+ ```ts type-equiv
90
+ /** Host-admitted prompt content with every attachment represented by its durable reference. */
91
+ type AdmittedPromptContentPart =
92
+ | { readonly type: 'text'; readonly text: string }
93
+ | { readonly type: 'image'; readonly attachment: ImageAttachmentRef }
94
+ | { readonly type: 'file'; readonly attachment: FileAttachmentRef }
95
+ ```
96
+
65
97
  ```ts type-equiv
66
98
  /** Base64-encoded image upload accompanying one wire request. */
67
99
  interface EncodedImageAttachment {
@@ -125,7 +157,7 @@ interface RequestImageAttachment {
125
157
  }
126
158
  ```
127
159
 
128
- `saveImage()` prepares and atomically commits a provider-independent normalized attachment before returning its `ImageAttachmentRef`. `saveImages()` prepares every validated attachment once before publishing the batch, so validation rejection leaves no partial objects and publication does not repeat decoding or quality selection. `admitEncodedImages()` is the wire entry for base64 uploads and delegates count, aggregate-byte, and ordered batch admission to `saveImages()`. `readImage()` verifies a normalized attachment from an authorized session path. `imageHostPath()` exposes only the provider-owned host object location; it does not decide whether the current tool execution world can read it. `readImageRequest()` derives and caches one deterministic request version under an exact route pixel and byte budget. That version contains encoded bytes and metadata but no execution-world path. New entries are fully decoded before publication, while cache hits use a bounded metadata probe. Callers use `Promise.all` over the singular method when they need an ordered batch. The local implementation lazily encodes preferred candidates, singleflights equal request identities, lets each waiter cancel independently, stops shared work when no waiter remains, and bounds all transforms with its instance-level limiter, which defaults to two simultaneous transformations. The service is retention-neutral: resumed and forked sessions may share objects, so reference-aware garbage collection is deferred rather than tied to one session's deletion.
160
+ `saveImage()` prepares and atomically commits a provider-independent normalized attachment before returning its `ImageAttachmentRef`. `saveImages()` prepares every validated attachment once before publishing the batch, so validation rejection leaves no partial objects and publication does not repeat decoding or quality selection. `admitPromptContent()` accepts the complete ordered Host prompt after file receipt resolution, replaces base64 image uploads with durable references, and passes durable file references unchanged. `admitEncodedImages()` supports other wire entries and delegates count, aggregate-byte, and ordered batch admission to `saveImages()`. `admitEncodedFile()` gives encoded protocol adapters the same service-owned canonical-base64 admission, and `isAttachmentError()` lets those adapters recognize stable attachment failures without importing implementation helpers. `readImage()` verifies a normalized attachment from an authorized session path. `imageHostPath()` exposes only the provider-owned host object location; it does not decide whether the current tool execution world can read it. `readImageRequest()` derives and caches one deterministic request version under an exact route pixel and byte budget. That version contains encoded bytes and metadata but no execution-world path. New entries are fully decoded before publication, while cache hits use a bounded metadata probe. Callers use `Promise.all` over the singular method when they need an ordered batch. The local implementation lazily encodes preferred candidates, singleflights equal request identities, lets each waiter cancel independently, stops shared work when no waiter remains, and bounds all transforms with its instance-level limiter, which defaults to two simultaneous transformations. The service is retention-neutral: resumed and forked sessions may share objects, so reference-aware garbage collection is deferred rather than tied to one session's deletion.
129
161
 
130
162
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
131
163
 
@@ -157,6 +189,30 @@ abstract validateImage(input: SaveImageAttachment): Promise<void>
157
189
  */
158
190
  async saveImages(inputs: readonly SaveImageAttachment[]): Promise<readonly ImageAttachmentRef[]>
159
191
 
192
+ /**
193
+ * Admit one Host prompt and replace each uploaded image with its durable reference.
194
+ * Text and durable file references pass through unchanged. A prompt without image parts performs no storage operation.
195
+ * @param content - prompt parts in message order after file receipt resolution.
196
+ * @returns admitted prompt parts in the same order as `content`.
197
+ * @throws AttachmentError when the image batch is refused.
198
+ */
199
+ async admitPromptContent( content: readonly AttachmentAdmissionPart[], ): Promise<AdmittedPromptContentPart[]>
200
+
201
+ /**
202
+ * Decode and durably commit one canonical base64 file upload.
203
+ * @param input - canonical base64 bytes and optional display name.
204
+ * @returns the durable content-addressed file reference.
205
+ * @throws AttachmentError when the encoding or storage operation is refused.
206
+ */
207
+ admitEncodedFile(input: EncodedFileAttachment): Promise<FileAttachmentRef>
208
+
209
+ /**
210
+ * Identify a failure emitted by this attachment capability by its stable code.
211
+ * @param error - value caught from an attachment operation.
212
+ * @returns whether the value is an attachment failure.
213
+ */
214
+ isAttachmentError(error: unknown): error is AttachmentError
215
+
160
216
  /**
161
217
  * Validate and durably commit one image before its owning session event is appended.
162
218
  * The returned reference describes the persisted normalized image. When
@@ -184,6 +240,43 @@ abstract readImage(ref: ImageAttachmentRef, signal?: AbortSignal): Promise<Store
184
240
  */
185
241
  imageHostPath(ref: ImageAttachmentRef): string | undefined
186
242
 
243
+ /**
244
+ * Durably commit one file byte-for-byte before its owning session event is
245
+ * appended. Files carry no admission limits: any byte content and length is
246
+ * accepted, and the stored object is the exact submitted bytes. Backends
247
+ * without verbatim file storage keep this default rejection.
248
+ * @param input - exact bytes and optional display name.
249
+ * @returns the durable content-addressed file reference.
250
+ */
251
+ saveFile(input: SaveFileAttachment): Promise<FileAttachmentRef>
252
+
253
+ /**
254
+ * Durably commit one file byte-for-byte from bounded chunks. Providers must
255
+ * apply backpressure and must not collect the complete file in memory.
256
+ * Backends without streamed verbatim storage keep this default rejection.
257
+ * @param input - ordered exact bytes, optional cancellation, and display name.
258
+ * @returns the durable content-addressed file reference.
259
+ */
260
+ saveFileStream(input: SaveFileStreamAttachment): Promise<FileAttachmentRef>
261
+
262
+ /**
263
+ * Read and verify one verbatim stored file as bounded chunks. Providers must
264
+ * not collect the complete file in memory. Backends without verbatim file
265
+ * reads keep this default rejection.
266
+ * @param ref - durable reference from the session log.
267
+ * @param signal - optional cancellation for backend reads and verification work.
268
+ * @returns exact file bytes in order; integrity failures reject the iteration.
269
+ */
270
+ async *readFileStream( ref: FileAttachmentRef, signal?: AbortSignal, ): AsyncIterable<Uint8Array>
271
+
272
+ /**
273
+ * Locate the verbatim stored file object in the harness host filesystem.
274
+ * @param ref - durable file reference.
275
+ * @returns an absolute host path, or undefined when this backend is not host-file-backed.
276
+ * @throws an AttachmentError when the durable reference is invalid.
277
+ */
278
+ fileHostPath(ref: FileAttachmentRef): string | undefined
279
+
187
280
  /**
188
281
  * Generate or read one deterministic model-request version from the stored normalized image.
189
282
  * @param ref - durable provider-independent normalized attachment reference.
@@ -195,4 +288,64 @@ readImageRequest( ref: ImageAttachmentRef, policy: ImageRequestPolicy, signal?:
195
288
  ```
196
289
 
197
290
  Source: [`packages/attachment/attachment/src/index.ts`](../../packages/attachment/attachment/src/index.ts)
291
+
292
+ <a id="ctxfileuploads--fileuploads"></a>
293
+
294
+ ### `ctx.fileUploads` — `FileUploads`
295
+
296
+ Host service owning upload storage and Agent-scoped staged receipts.
297
+
298
+ ```ts cordis-catalog
299
+ /**
300
+ * Register the ordinary-Session resolver used when a raw upload addresses a cold Session.
301
+ * @param resolve - resolver that returns the exact live Agent or throws a Remote error.
302
+ * @returns disposer removing this resolver.
303
+ */
304
+ registerAgentResolver(resolve: AgentResolver): () => void
305
+
306
+ /**
307
+ * Persist one encoded upload and stage it under the Agent receiver selected by Typert.
308
+ * @param agent - receiving Agent resolved from the Remote Agent scope.
309
+ * @param request - canonical base64 bytes and optional display name.
310
+ * @param signal - caller cancellation before storage begins.
311
+ * @returns the staged receipt and durable file reference.
312
+ */
313
+ @Remote('upload') upload(agent: Agent, request: EncodedFileUploadRequest, signal: AbortSignal): Promise<FileUploadValue>
314
+
315
+ /**
316
+ * Persist raw chunks for one Session without aggregating the upload.
317
+ * @param request - Session identity, ordered bytes, cancellation, and optional display name.
318
+ * @returns the staged receipt and durable file reference.
319
+ */
320
+ async uploadStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable<Uint8Array> readonly signal?: AbortSignal readonly name?: string }): Promise<FileUploadValue>
321
+
322
+ /**
323
+ * Resolve one staged receipt inside its receiving Agent scope.
324
+ * @param agent - receiving Agent.
325
+ * @param receiptId - opaque receipt minted for one completed upload.
326
+ * @returns durable file reference, or `undefined` for an unknown or foreign receipt.
327
+ */
328
+ resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined
329
+
330
+ /**
331
+ * Bind receipts while one prompt enters an Agent inbox.
332
+ * Disposal restores every prior binding unless the caller commits successful delivery.
333
+ * @param agent - receiving Agent.
334
+ * @param receiptIds - distinct staged receipts referenced by the prompt.
335
+ * @param requestId - prompt identity later observed in queue or history.
336
+ * @returns binding kept after commit until queue or history observation retires its receipts.
337
+ */
338
+ bindPrompt( agent: Agent, receiptIds: readonly FileUploadReceiptId[], requestId: string, ): PromptFileBinding
339
+
340
+ /**
341
+ * Retire every receipt accepted by one removed queue occurrence.
342
+ * @param agent - receiving Agent.
343
+ * @param requestId - prompt identity carried by the queue occurrence.
344
+ */
345
+ retirePrompt(agent: Agent, requestId: string): void
346
+ ```
347
+
348
+ Types: [Agent](core.md) · [SessionId](core.md)
349
+
350
+ Source: [`packages/client/file-upload/src/index.ts`](../../packages/client/file-upload/src/index.ts)
198
351
  <!-- END GENERATED cordis-surface -->
@@ -1,10 +1,10 @@
1
- # 持久图片附件
1
+ # 持久附件
2
2
 
3
3
  [English](attachment.md) | 中文
4
4
 
5
- 附件 seam 将二进制图片的所有权与会话日志分离。生产方把经过校验的编码字节交给 [`ctx.attachments`](#ctxattachments--attachmentstore-abstract-seam);只有对象完成持久化后,该服务才会发布不可变的内容寻址引用。会话事件和模型可见的 `ImageBlock` 包含该引用及其元数据,绝不包含浏览器对象 URL、宿主临时路径、提供方 URL 或 base64 数据。
5
+ 附件 seam 将二进制图片和通用文件的所有权与会话日志分离。生产方把字节交给 [`ctx.attachments`](#ctxattachments--attachmentstore-abstract-seam);只有对象完成持久化后,该服务才会发布不可变的内容寻址引用。会话事件和模型可见的附件块包含该引用及其元数据,绝不包含浏览器对象 URL、宿主临时路径、提供方 URL 或 base64 数据。独立的 [`ctx.fileUploads`](#ctxfileuploads--fileuploads) 服务把浏览器文件传输与暂存凭证绑定到接收方 Agent。
6
6
 
7
- 未发送的浏览器草稿可以保留在内存中,原生客户端也可以将其暂存于操作系统临时存储。宿主接受用户消息后,会先把消息中的图片移到 `<DSH_HOME>/attachments/v1` 下,再追加用户事件。结构化模型图片输出遵循同样的先持久化、后追加事件规则。
7
+ 未发送的浏览器草稿可以保留在内存中,原生客户端也可以将其暂存于操作系统临时存储。浏览器通用文件取得暂存 prompt 凭证前会完成持久化。宿主接受用户消息后,会先把消息中的图片移到 `<DSH_HOME>/attachments/v1` 下,再追加用户事件。结构化模型图片输出遵循同样的先持久化、后追加事件规则。
8
8
 
9
9
  来源:[`packages/attachment/attachment/src/types.ts`](../../packages/attachment/attachment/src/types.ts)
10
10
 
@@ -62,6 +62,38 @@ interface ImageAttachmentLimits {
62
62
 
63
63
  ## 提交与经校验读取的数据
64
64
 
65
+ ```ts type-equiv
66
+ /**
67
+ * Browser-submitted prompt content accepted by Host prompt endpoints; the
68
+ * accepting Host promotes image parts to durable references through
69
+ * `ctx.attachments.admitPromptContent()` before any message is created, so a wire caller can
70
+ * never cite an attachment it did not upload.
71
+ */
72
+ type PromptContentPart =
73
+ | { readonly type: 'text'; readonly text: string }
74
+ | {
75
+ readonly type: 'image'
76
+ readonly mediaType: ImageMediaType
77
+ readonly data: string
78
+ readonly name?: string
79
+ }
80
+ ```
81
+
82
+ ```ts type-equiv
83
+ /** Host prompt content whose file receipts are resolved and whose image bytes await admission. */
84
+ type AttachmentAdmissionPart =
85
+ | PromptContentPart
86
+ | { readonly type: 'file'; readonly attachment: FileAttachmentRef }
87
+ ```
88
+
89
+ ```ts type-equiv
90
+ /** Host-admitted prompt content with every attachment represented by its durable reference. */
91
+ type AdmittedPromptContentPart =
92
+ | { readonly type: 'text'; readonly text: string }
93
+ | { readonly type: 'image'; readonly attachment: ImageAttachmentRef }
94
+ | { readonly type: 'file'; readonly attachment: FileAttachmentRef }
95
+ ```
96
+
65
97
  ```ts type-equiv
66
98
  /** Base64-encoded image upload accompanying one wire request. */
67
99
  interface EncodedImageAttachment {
@@ -125,7 +157,7 @@ interface RequestImageAttachment {
125
157
  }
126
158
  ```
127
159
 
128
- `saveImage()` 准备并原子提交提供方无关的规范化附件,然后直接返回 `ImageAttachmentRef`。`saveImages()` 在发布批次前为每个成员各准备一次经过验证的附件,因此校验拒绝不会留下部分对象,发布也不会重复解码或选择质量。`admitEncodedImages()` 是面向 base64 上传的 wire 入口,把张数、聚合字节和有序批量准入交给 `saveImages()`。`readImage()` 校验来自已授权会话路径的规范化附件。`imageHostPath()` 只公开提供方所持对象的宿主位置,不判断当前工具执行环境能否读取它。`readImageRequest()` 按确切路由的像素和字节预算派生并缓存确定性请求版本。该版本包含编码字节和元数据,不包含执行环境路径。新条目在发布前完整解码,缓存命中只做有界元数据探测。调用方需要有序批次时,对单数方法使用 `Promise.all`。本地实现按需编码首选候选、合并相同请求身份的并发任务、允许每个等待方单独取消、没有等待方时停止共享任务,并通过实例级限流器限制全部变换,默认同时执行两项。该服务不规定保留策略:恢复和 fork 后的会话可能共享对象,因此基于引用的垃圾回收会延期实现,不与单个会话的删除绑定。
160
+ `saveImage()` 准备并原子提交提供方无关的规范化附件,然后直接返回 `ImageAttachmentRef`。`saveImages()` 在发布批次前为每个成员各准备一次经过验证的附件,因此校验拒绝不会留下部分对象,发布也不会重复解码或选择质量。`admitPromptContent()` 在文件凭证解析后接收完整且有序的 Host prompt,把 base64 图片上传替换为持久引用,并让持久文件引用原样通过。`admitEncodedImages()` 支持其他 wire 入口,把张数、聚合字节和有序批量准入交给 `saveImages()`。`admitEncodedFile()` 让编码协议适配器使用服务拥有的规范 base64 准入,`isAttachmentError()` 让这些适配器无需导入实现辅助函数即可识别稳定的附件错误。`readImage()` 校验来自已授权会话路径的规范化附件。`imageHostPath()` 只公开提供方所持对象的宿主位置,不判断当前工具执行环境能否读取它。`readImageRequest()` 按确切路由的像素和字节预算派生并缓存确定性请求版本。该版本包含编码字节和元数据,不包含执行环境路径。新条目在发布前完整解码,缓存命中只做有界元数据探测。调用方需要有序批次时,对单数方法使用 `Promise.all`。本地实现按需编码首选候选、合并相同请求身份的并发任务、允许每个等待方单独取消、没有等待方时停止共享任务,并通过实例级限流器限制全部变换,默认同时执行两项。该服务不规定保留策略:恢复和 fork 后的会话可能共享对象,因此基于引用的垃圾回收会延期实现,不与单个会话的删除绑定。
129
161
 
130
162
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
131
163
 
@@ -157,6 +189,30 @@ abstract validateImage(input: SaveImageAttachment): Promise<void>
157
189
  */
158
190
  async saveImages(inputs: readonly SaveImageAttachment[]): Promise<readonly ImageAttachmentRef[]>
159
191
 
192
+ /**
193
+ * Admit one Host prompt and replace each uploaded image with its durable reference.
194
+ * Text and durable file references pass through unchanged. A prompt without image parts performs no storage operation.
195
+ * @param content - prompt parts in message order after file receipt resolution.
196
+ * @returns admitted prompt parts in the same order as `content`.
197
+ * @throws AttachmentError when the image batch is refused.
198
+ */
199
+ async admitPromptContent( content: readonly AttachmentAdmissionPart[], ): Promise<AdmittedPromptContentPart[]>
200
+
201
+ /**
202
+ * Decode and durably commit one canonical base64 file upload.
203
+ * @param input - canonical base64 bytes and optional display name.
204
+ * @returns the durable content-addressed file reference.
205
+ * @throws AttachmentError when the encoding or storage operation is refused.
206
+ */
207
+ admitEncodedFile(input: EncodedFileAttachment): Promise<FileAttachmentRef>
208
+
209
+ /**
210
+ * Identify a failure emitted by this attachment capability by its stable code.
211
+ * @param error - value caught from an attachment operation.
212
+ * @returns whether the value is an attachment failure.
213
+ */
214
+ isAttachmentError(error: unknown): error is AttachmentError
215
+
160
216
  /**
161
217
  * Validate and durably commit one image before its owning session event is appended.
162
218
  * The returned reference describes the persisted normalized image. When
@@ -184,6 +240,43 @@ abstract readImage(ref: ImageAttachmentRef, signal?: AbortSignal): Promise<Store
184
240
  */
185
241
  imageHostPath(ref: ImageAttachmentRef): string | undefined
186
242
 
243
+ /**
244
+ * Durably commit one file byte-for-byte before its owning session event is
245
+ * appended. Files carry no admission limits: any byte content and length is
246
+ * accepted, and the stored object is the exact submitted bytes. Backends
247
+ * without verbatim file storage keep this default rejection.
248
+ * @param input - exact bytes and optional display name.
249
+ * @returns the durable content-addressed file reference.
250
+ */
251
+ saveFile(input: SaveFileAttachment): Promise<FileAttachmentRef>
252
+
253
+ /**
254
+ * Durably commit one file byte-for-byte from bounded chunks. Providers must
255
+ * apply backpressure and must not collect the complete file in memory.
256
+ * Backends without streamed verbatim storage keep this default rejection.
257
+ * @param input - ordered exact bytes, optional cancellation, and display name.
258
+ * @returns the durable content-addressed file reference.
259
+ */
260
+ saveFileStream(input: SaveFileStreamAttachment): Promise<FileAttachmentRef>
261
+
262
+ /**
263
+ * Read and verify one verbatim stored file as bounded chunks. Providers must
264
+ * not collect the complete file in memory. Backends without verbatim file
265
+ * reads keep this default rejection.
266
+ * @param ref - durable reference from the session log.
267
+ * @param signal - optional cancellation for backend reads and verification work.
268
+ * @returns exact file bytes in order; integrity failures reject the iteration.
269
+ */
270
+ async *readFileStream( ref: FileAttachmentRef, signal?: AbortSignal, ): AsyncIterable<Uint8Array>
271
+
272
+ /**
273
+ * Locate the verbatim stored file object in the harness host filesystem.
274
+ * @param ref - durable file reference.
275
+ * @returns an absolute host path, or undefined when this backend is not host-file-backed.
276
+ * @throws an AttachmentError when the durable reference is invalid.
277
+ */
278
+ fileHostPath(ref: FileAttachmentRef): string | undefined
279
+
187
280
  /**
188
281
  * Generate or read one deterministic model-request version from the stored normalized image.
189
282
  * @param ref - durable provider-independent normalized attachment reference.
@@ -195,4 +288,64 @@ readImageRequest( ref: ImageAttachmentRef, policy: ImageRequestPolicy, signal?:
195
288
  ```
196
289
 
197
290
  Source: [`packages/attachment/attachment/src/index.ts`](../../packages/attachment/attachment/src/index.ts)
291
+
292
+ <a id="ctxfileuploads--fileuploads"></a>
293
+
294
+ ### `ctx.fileUploads` — `FileUploads`
295
+
296
+ Host service owning upload storage and Agent-scoped staged receipts.
297
+
298
+ ```ts cordis-catalog
299
+ /**
300
+ * Register the ordinary-Session resolver used when a raw upload addresses a cold Session.
301
+ * @param resolve - resolver that returns the exact live Agent or throws a Remote error.
302
+ * @returns disposer removing this resolver.
303
+ */
304
+ registerAgentResolver(resolve: AgentResolver): () => void
305
+
306
+ /**
307
+ * Persist one encoded upload and stage it under the Agent receiver selected by Typert.
308
+ * @param agent - receiving Agent resolved from the Remote Agent scope.
309
+ * @param request - canonical base64 bytes and optional display name.
310
+ * @param signal - caller cancellation before storage begins.
311
+ * @returns the staged receipt and durable file reference.
312
+ */
313
+ @Remote('upload') upload(agent: Agent, request: EncodedFileUploadRequest, signal: AbortSignal): Promise<FileUploadValue>
314
+
315
+ /**
316
+ * Persist raw chunks for one Session without aggregating the upload.
317
+ * @param request - Session identity, ordered bytes, cancellation, and optional display name.
318
+ * @returns the staged receipt and durable file reference.
319
+ */
320
+ async uploadStream(request: { readonly sessionId: SessionId readonly data: AsyncIterable<Uint8Array> readonly signal?: AbortSignal readonly name?: string }): Promise<FileUploadValue>
321
+
322
+ /**
323
+ * Resolve one staged receipt inside its receiving Agent scope.
324
+ * @param agent - receiving Agent.
325
+ * @param receiptId - opaque receipt minted for one completed upload.
326
+ * @returns durable file reference, or `undefined` for an unknown or foreign receipt.
327
+ */
328
+ resolve(agent: Agent, receiptId: FileUploadReceiptId): FileAttachmentRef | undefined
329
+
330
+ /**
331
+ * Bind receipts while one prompt enters an Agent inbox.
332
+ * Disposal restores every prior binding unless the caller commits successful delivery.
333
+ * @param agent - receiving Agent.
334
+ * @param receiptIds - distinct staged receipts referenced by the prompt.
335
+ * @param requestId - prompt identity later observed in queue or history.
336
+ * @returns binding kept after commit until queue or history observation retires its receipts.
337
+ */
338
+ bindPrompt( agent: Agent, receiptIds: readonly FileUploadReceiptId[], requestId: string, ): PromptFileBinding
339
+
340
+ /**
341
+ * Retire every receipt accepted by one removed queue occurrence.
342
+ * @param agent - receiving Agent.
343
+ * @param requestId - prompt identity carried by the queue occurrence.
344
+ */
345
+ retirePrompt(agent: Agent, requestId: string): void
346
+ ```
347
+
348
+ Types: [Agent](core.zh.md) · [SessionId](core.zh.md)
349
+
350
+ Source: [`packages/client/file-upload/src/index.ts`](../../packages/client/file-upload/src/index.ts)
198
351
  <!-- END GENERATED cordis-surface -->
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write docs/subsystems/commands.md
5
- commands.md: 46d3b736afd3a72d1119c9744cd592a86b9cbc29
6
- commands.zh.md: db8d6e722e3a1742887aaa4023ab67b9ed914552
5
+ commands.md: 4705048e06796792d8e013450b72035b1f87315b
6
+ commands.zh.md: f3af9f6e81745514efd1e073868292a02f90dca8