dsh-plugin-guide 0.3.2 → 0.3.3
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.es.md +1 -1
- package/README.hi.md +1 -1
- package/README.md +1 -1
- package/README.pt.md +1 -1
- package/README.zh.md +1 -1
- package/dist/dsh-plugin-dev.js +3 -3
- package/guide/plugin-dev-guide.md +1 -1
- package/guide/quick-reference.es.md +1 -1
- package/guide/quick-reference.md +1 -1
- package/guide/quick-reference.pt.md +1 -1
- package/guide/quick-reference.zh-CN.md +1 -1
- package/package.json +3 -3
- package/references/official-docs/AGENTS.md +1 -1
- package/references/official-docs/SNAPSHOT.md +3 -3
- package/references/official-docs/docs/architecture.i18n.yaml +2 -2
- package/references/official-docs/docs/architecture.md +2 -1
- package/references/official-docs/docs/architecture.zh.md +2 -1
- package/references/official-docs/docs/capability-seams.i18n.yaml +2 -2
- package/references/official-docs/docs/capability-seams.md +3 -1
- package/references/official-docs/docs/capability-seams.zh.md +3 -1
- package/references/official-docs/docs/config-catalog.i18n.yaml +2 -2
- package/references/official-docs/docs/config-catalog.md +96 -54
- package/references/official-docs/docs/config-catalog.zh.md +93 -51
- package/references/official-docs/docs/cookbook/adding-a-package.i18n.yaml +2 -2
- package/references/official-docs/docs/cookbook/adding-a-package.md +1 -1
- package/references/official-docs/docs/cookbook/adding-a-package.zh.md +1 -1
- package/references/official-docs/docs/event-producer-consumer.i18n.yaml +2 -2
- package/references/official-docs/docs/event-producer-consumer.md +17 -17
- package/references/official-docs/docs/event-producer-consumer.zh.md +17 -17
- package/references/official-docs/docs/module-graph.i18n.yaml +2 -2
- package/references/official-docs/docs/module-graph.md +193 -361
- package/references/official-docs/docs/module-graph.zh.md +193 -361
- package/references/official-docs/docs/persistence-catalog.i18n.yaml +2 -2
- package/references/official-docs/docs/persistence-catalog.md +41 -41
- package/references/official-docs/docs/persistence-catalog.zh.md +40 -40
- package/references/official-docs/docs/subsystems/agent-team.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/agent-team.md +4 -3
- package/references/official-docs/docs/subsystems/agent-team.zh.md +4 -3
- package/references/official-docs/docs/subsystems/code-runtime.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/code-runtime.md +7 -3
- package/references/official-docs/docs/subsystems/code-runtime.zh.md +7 -3
- package/references/official-docs/docs/subsystems/commands.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/commands.md +1 -1
- package/references/official-docs/docs/subsystems/commands.zh.md +1 -1
- package/references/official-docs/docs/subsystems/compaction.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/compaction.md +9 -9
- package/references/official-docs/docs/subsystems/compaction.zh.md +9 -9
- package/references/official-docs/docs/subsystems/core.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/core.md +4 -3
- package/references/official-docs/docs/subsystems/core.zh.md +4 -3
- package/references/official-docs/docs/subsystems/feedback.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/feedback.md +2 -2
- package/references/official-docs/docs/subsystems/feedback.zh.md +2 -2
- package/references/official-docs/docs/subsystems/persistence.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/persistence.md +179 -187
- package/references/official-docs/docs/subsystems/persistence.zh.md +179 -187
- package/references/official-docs/docs/subsystems/schedule.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/schedule.md +1 -1
- package/references/official-docs/docs/subsystems/schedule.zh.md +1 -1
- package/references/official-docs/docs/subsystems/session-projection.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-projection.md +21 -17
- package/references/official-docs/docs/subsystems/session-projection.zh.md +21 -17
- package/references/official-docs/docs/subsystems/session-query.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-query.md +19 -13
- package/references/official-docs/docs/subsystems/session-query.zh.md +19 -13
- package/references/official-docs/docs/subsystems/session-title.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session-title.md +5 -5
- package/references/official-docs/docs/subsystems/session-title.zh.md +5 -5
- package/references/official-docs/docs/subsystems/session.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/session.md +94 -34
- package/references/official-docs/docs/subsystems/session.zh.md +94 -34
- package/references/official-docs/docs/subsystems/slots.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/slots.md +1 -0
- package/references/official-docs/docs/subsystems/slots.zh.md +1 -0
- package/references/official-docs/docs/subsystems/storage.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/storage.md +28 -5
- package/references/official-docs/docs/subsystems/storage.zh.md +28 -5
- package/references/official-docs/docs/subsystems/subagent.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/subagent.md +32 -88
- package/references/official-docs/docs/subsystems/subagent.zh.md +31 -87
- package/references/official-docs/docs/subsystems/token-meter.i18n.yaml +2 -2
- package/references/official-docs/docs/subsystems/token-meter.md +2 -2
- package/references/official-docs/docs/subsystems/token-meter.zh.md +2 -2
- package/references/official-docs/docs/tool-catalog.i18n.yaml +2 -2
- package/references/official-docs/docs/tool-catalog.md +9 -63
- package/references/official-docs/docs/tool-catalog.zh.md +8 -62
- package/references/official-docs/docs/web-styling.i18n.yaml +2 -2
- package/references/official-docs/docs/web-styling.md +3 -0
- package/references/official-docs/docs/web-styling.zh.md +3 -0
- package/references/official-docs/packages/AGENTS.md +2 -2
- package/templates/js/README.es.md +1 -1
- package/templates/js/README.hi.md +1 -1
- package/templates/js/README.md +1 -1
- package/templates/js/README.pt.md +1 -1
- package/templates/js/README.zh.md +1 -1
- package/templates/ts/README.es.md +1 -1
- package/templates/ts/README.hi.md +1 -1
- package/templates/ts/README.md +1 -1
- package/templates/ts/README.pt.md +1 -1
- package/templates/ts/README.zh.md +1 -1
|
@@ -179,6 +179,28 @@ interface RequestContext {
|
|
|
179
179
|
|
|
180
180
|
A proper discriminated union over `type` (not independent `type`/`data` unions), so `switch (event.type)` narrows `event.data` without casts. `seq` is the monotonic position in the log (`seq = log.length`); `time` is epoch ms.
|
|
181
181
|
|
|
182
|
+
```ts type-equiv
|
|
183
|
+
/** Sequence number of one existing event in a Session log. */
|
|
184
|
+
type SessionSeq = BrandedNumber<'SessionSeq'>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```ts type-equiv
|
|
188
|
+
/** A Session log gap, prefix length, or read offset, which may equal the event count. */
|
|
189
|
+
type SessionLogOffset = BrandedNumber<'SessionLogOffset'>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```ts type-equiv
|
|
193
|
+
/** Inclusive Session event watermark, or `-1` before any event exists. */
|
|
194
|
+
type SessionSeqCursor = SessionSeq | -1
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```ts type-equiv
|
|
198
|
+
/** One existing Session event position, or explicit absence. */
|
|
199
|
+
type OptionalSessionSeq = SessionSeq | null
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`SessionSeq(value)` and `SessionLogOffset(value)` admit only non-negative safe integers and reject negative zero. They add compile-time brands without changing the serialized number; arithmetic returns an ordinary `number` that callers must admit again through the constructor for its intended role.
|
|
203
|
+
|
|
182
204
|
```ts type-equiv
|
|
183
205
|
/**
|
|
184
206
|
* One immutable entry in the session log.
|
|
@@ -197,7 +219,7 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
197
219
|
[K in SessionEventType]: {
|
|
198
220
|
type: K
|
|
199
221
|
/** Monotonic sequence number within the session. */
|
|
200
|
-
seq:
|
|
222
|
+
seq: SessionSeq
|
|
201
223
|
/** Unix epoch milliseconds. */
|
|
202
224
|
time: number
|
|
203
225
|
data: SessionEventMap[K]
|
|
@@ -221,7 +243,7 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
221
243
|
* provider stream; when the field is absent, the event does not record which
|
|
222
244
|
* earlier events produced the message.
|
|
223
245
|
*/
|
|
224
|
-
sourceEventSeqs?:
|
|
246
|
+
sourceEventSeqs?: SessionSeq[]
|
|
225
247
|
/** How this event entered the surface; absent for non-surface events. */
|
|
226
248
|
surfaceOp?: SurfaceOp
|
|
227
249
|
} : object)
|
|
@@ -268,7 +290,7 @@ type SurfaceEventType =
|
|
|
268
290
|
*/
|
|
269
291
|
type SurfaceOp =
|
|
270
292
|
| 'append'
|
|
271
|
-
| { op: 'replace'; start:
|
|
293
|
+
| { op: 'replace'; start: SessionSeq; end: SessionSeq }
|
|
272
294
|
```
|
|
273
295
|
|
|
274
296
|
`'append'` is the normal tail-append path. `replace` shadows surface entries from `start` through `end` inclusive (both must be valid surface seqs; `start === end` replaces a single entry) and inserts the new event in their place.
|
|
@@ -288,7 +310,7 @@ interface SurfaceIntent {
|
|
|
288
310
|
* absent, the event does not record which earlier events produced the message.
|
|
289
311
|
* Other surface events require a non-empty set when this field is present.
|
|
290
312
|
*/
|
|
291
|
-
sourceEventSeqs?:
|
|
313
|
+
sourceEventSeqs?: SessionSeq[]
|
|
292
314
|
}
|
|
293
315
|
```
|
|
294
316
|
|
|
@@ -306,7 +328,7 @@ Only `assistant/message` may carry a present empty `sourceEventSeqs`; when the f
|
|
|
306
328
|
/** Readonly live projection of the message-producing session events. */
|
|
307
329
|
interface SessionSurface {
|
|
308
330
|
/** Current surface event sequences in model-visible order. */
|
|
309
|
-
readonly nodes: readonly
|
|
331
|
+
readonly nodes: readonly SessionSeq[]
|
|
310
332
|
/** Monotonic count of committed positional replacements. */
|
|
311
333
|
readonly replaceGeneration: number
|
|
312
334
|
}
|
|
@@ -320,13 +342,13 @@ interface SessionSurface {
|
|
|
320
342
|
/** One replacement operation observed while folding a session surface. */
|
|
321
343
|
interface SurfaceFoldReplacement {
|
|
322
344
|
/** Seq of the event that replaced the prior surface range. */
|
|
323
|
-
seq:
|
|
345
|
+
seq: SessionSeq
|
|
324
346
|
/** Declared inclusive start seq of the replaced surface range. */
|
|
325
|
-
start:
|
|
347
|
+
start: SessionSeq
|
|
326
348
|
/** Declared inclusive end seq of the replaced surface range. */
|
|
327
|
-
end:
|
|
349
|
+
end: SessionSeq
|
|
328
350
|
/** Actual surface entries removed by the operation, in surface order. */
|
|
329
|
-
shadowedSeqs:
|
|
351
|
+
shadowedSeqs: SessionSeq[]
|
|
330
352
|
}
|
|
331
353
|
```
|
|
332
354
|
|
|
@@ -334,7 +356,7 @@ interface SurfaceFoldReplacement {
|
|
|
334
356
|
/** Complete result of replaying the surface operations in a session log. */
|
|
335
357
|
interface SurfaceFoldResult {
|
|
336
358
|
/** Current surface event sequences in model-visible order. */
|
|
337
|
-
nodes:
|
|
359
|
+
nodes: SessionSeq[]
|
|
338
360
|
/** Replacement operations in event order. */
|
|
339
361
|
replacements: SurfaceFoldReplacement[]
|
|
340
362
|
}
|
|
@@ -358,13 +380,15 @@ declare class Session {
|
|
|
358
380
|
get surface(): SessionSurface;
|
|
359
381
|
/**
|
|
360
382
|
* Detached, deep-frozen creation metadata (format version, cwd, lineage,
|
|
361
|
-
*
|
|
383
|
+
* and whether fork history exists). Supplied by the store via `ctx.sessions.create()`. When a
|
|
362
384
|
* `Session` is created without a store-owned header, a minimal header is
|
|
363
385
|
* synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
|
|
364
386
|
* `session.header` is always present. Kept out of the event log — it is a
|
|
365
387
|
* storage concern, not replayable conversation state.
|
|
366
388
|
*/
|
|
367
389
|
readonly header: SessionHeader;
|
|
390
|
+
/** Number of leading events inherited from this Session's fork parent. */
|
|
391
|
+
readonly inheritedEventCount: SessionLogOffset;
|
|
368
392
|
/** The session identity, derived from its durable header's single copy. */
|
|
369
393
|
get id(): SessionId;
|
|
370
394
|
/**
|
|
@@ -373,9 +397,9 @@ declare class Session {
|
|
|
373
397
|
* construction — replay, fork, or resume — and were never published on the
|
|
374
398
|
* `session/event` firehose (constructor seeds do not emit), so consumers
|
|
375
399
|
* that replay the log as a publication substitute (telemetry adoption)
|
|
376
|
-
* start here. Distinct from
|
|
377
|
-
*
|
|
378
|
-
* while
|
|
400
|
+
* start here. Distinct from {@link inheritedEventCount}, the DURABLE
|
|
401
|
+
* fork-lineage cut: a resumed session's constructor seed is its full stored
|
|
402
|
+
* log, while the inherited count keeps the original fork value — this field is the
|
|
379
403
|
* in-process construction fact.
|
|
380
404
|
*
|
|
381
405
|
* Not persisted itself: a seeded session projects it into the log as the
|
|
@@ -388,17 +412,23 @@ declare class Session {
|
|
|
388
412
|
* When this lifecycle appends the marker, it occupies this seq before the
|
|
389
413
|
* store attaches and therefore does not publish either. Otherwise this seq
|
|
390
414
|
* holds an ordinary published write.
|
|
391
|
-
|
|
392
|
-
readonly firstLiveSeq:
|
|
415
|
+
*/
|
|
416
|
+
readonly firstLiveSeq: SessionLogOffset;
|
|
393
417
|
/**
|
|
394
418
|
* Create a detached session by validating and snapshotting borrowed seed
|
|
395
419
|
* events and storage metadata.
|
|
396
420
|
* @param id - session identity.
|
|
397
421
|
* @param seed - optional borrowed replay or fork events.
|
|
398
422
|
* @param header - optional borrowed storage metadata.
|
|
423
|
+
* @param inheritedEventCount - exact fork-inherited prefix length for a seeded header.
|
|
399
424
|
* @returns a detached session.
|
|
400
425
|
*/
|
|
401
|
-
static create(
|
|
426
|
+
static create(
|
|
427
|
+
id: SessionId,
|
|
428
|
+
seed?: readonly SessionEvent[],
|
|
429
|
+
header?: SessionHeader,
|
|
430
|
+
inheritedEventCount?: SessionLogOffset,
|
|
431
|
+
): Session;
|
|
402
432
|
/**
|
|
403
433
|
* Restore a detached session by taking ownership of fresh persistence values.
|
|
404
434
|
* The storage format, event envelopes, sequence continuity, surface transitions,
|
|
@@ -406,18 +436,46 @@ declare class Session {
|
|
|
406
436
|
* @param id - restored session identity.
|
|
407
437
|
* @param seed - fresh detached events whose ownership is transferred.
|
|
408
438
|
* @param header - fresh detached metadata whose ownership is transferred.
|
|
439
|
+
* @param inheritedEventCount - exact fork-inherited prefix length decoded from storage.
|
|
409
440
|
* @returns a restored detached session.
|
|
410
441
|
*/
|
|
411
|
-
static fromRestore(
|
|
442
|
+
static fromRestore(
|
|
443
|
+
id: SessionId,
|
|
444
|
+
seed: readonly SessionEvent[],
|
|
445
|
+
header: SessionHeader,
|
|
446
|
+
inheritedEventCount: SessionLogOffset,
|
|
447
|
+
): Session;
|
|
448
|
+
/**
|
|
449
|
+
* Return the immutable event stored at one exact sequence number.
|
|
450
|
+
* @param seq - event sequence number.
|
|
451
|
+
* @returns the accepted event, or undefined when the log does not contain it.
|
|
452
|
+
*/
|
|
453
|
+
eventAt(seq: SessionSeq): SessionEvent | undefined;
|
|
454
|
+
/**
|
|
455
|
+
* Materialize an immutable snapshot of a half-open event sequence range.
|
|
456
|
+
* A full current snapshot is reused until the next append; every previously
|
|
457
|
+
* returned snapshot remains stable after later appends.
|
|
458
|
+
* @param fromSeq - non-negative inclusive sequence number; defaults to the log start.
|
|
459
|
+
* @param toSeqExclusive - non-negative exclusive sequence number; defaults to the current end.
|
|
460
|
+
* @returns a frozen array of the selected deeply frozen events.
|
|
461
|
+
*/
|
|
462
|
+
snapshotEvents(
|
|
463
|
+
fromSeq: SessionLogOffset = SessionLogOffset(0),
|
|
464
|
+
toSeqExclusive: SessionLogOffset = this.seq,
|
|
465
|
+
): readonly SessionEvent[];
|
|
466
|
+
/**
|
|
467
|
+
* Return this Session's events after its fork-inherited prefix.
|
|
468
|
+
* @returns a fresh array containing child-owned events in log order.
|
|
469
|
+
*/
|
|
470
|
+
ownEvents(): readonly SessionEvent[];
|
|
412
471
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
* cast nor ordinary JavaScript can rewrite durable history.
|
|
472
|
+
* Whether one existing event position is outside the fork-inherited prefix.
|
|
473
|
+
* @param seq - event position in this Session.
|
|
474
|
+
* @returns true when the event belongs to this Session rather than its parent.
|
|
417
475
|
*/
|
|
418
|
-
|
|
476
|
+
isOwnSeq(seq: SessionSeq): boolean;
|
|
419
477
|
/** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
|
|
420
|
-
get seq():
|
|
478
|
+
get seq(): SessionLogOffset;
|
|
421
479
|
/**
|
|
422
480
|
* Append one typed event to the log and synchronously notify observers via
|
|
423
481
|
* the store-owned, module-private publication hooks. The hot path never blocks
|
|
@@ -462,7 +520,7 @@ declare class Session {
|
|
|
462
520
|
* The {@link EpochHeader} in force after the log's last header event — the
|
|
463
521
|
* header the NEXT request will be compared against — or undefined before
|
|
464
522
|
* the first `request/header` snapshot. The live, incrementally-maintained
|
|
465
|
-
* form of `foldRequestHeader(session.
|
|
523
|
+
* form of `foldRequestHeader(session.snapshotEvents())`: each header event is folded
|
|
466
524
|
* once, when first seen, so a per-step read costs O(new events).
|
|
467
525
|
* @returns the folded header, or undefined when no header event exists yet.
|
|
468
526
|
*/
|
|
@@ -517,7 +575,7 @@ Everything else (`turn/*`, `step/*`, plugin-owned `llm/retry`) is structural and
|
|
|
517
575
|
|
|
518
576
|
`ctx.sessions.create(id, { seed, meta })` is the low-level replay/fork primitive. For ordinary live-session forks, `SessionStore` exposes one policy API:
|
|
519
577
|
|
|
520
|
-
- `fork(source, boundary?, childSessionId?)` accepts a live `Session` object or live `SessionId`, selects source events through the inclusive `
|
|
578
|
+
- `fork(source, boundary?, childSessionId?)` accepts a live `Session` object or live `SessionId`, selects source events through the inclusive `SessionSeq` boundary (default: current last event), requires the selected prefix to end outside an open turn, then creates a live child session with deep-cloned seed events, `parentSession`, `isSeeded: true`, the exact `inheritedEventCount`, and inherited `cwd`.
|
|
521
579
|
|
|
522
580
|
An explicit `boundary` lets callers fork from any stable between-turn position, including a previous `turn/end` or a later standalone log-only event, even if the source has newer events or an open current turn. The API rejects a prefix that ends inside an open turn instead of clipping silently. Broader execution-relation sanity stays in the existing `dsh-invariants` plugin and persistence repair path rather than being duplicated in `fork()`. `dsh-subagent-fork-in-process` keeps its completed-prefix clipping because tool-time delegation usually starts while the parent turn is open; ordinary session branching should make the requested boundary explicit.
|
|
523
581
|
|
|
@@ -549,8 +607,10 @@ interface TurnEndReasonMap {
|
|
|
549
607
|
/** At least one step reached its output-token ceiling, even if a plugin continued the turn. */
|
|
550
608
|
'max-tokens': { kind: 'max-tokens' }
|
|
551
609
|
/**
|
|
552
|
-
* A
|
|
553
|
-
*
|
|
610
|
+
* A crash-orphaned turn was closed after the fact: agent-loop resume appends
|
|
611
|
+
* this closer for a stored log whose last turn never ended, and session-query
|
|
612
|
+
* synthesizes it on cold reads. The loop never emits this marker live, and
|
|
613
|
+
* the events recorded before the crash remain intact.
|
|
554
614
|
*/
|
|
555
615
|
interrupted: { kind: 'interrupted' }
|
|
556
616
|
}
|
|
@@ -566,7 +626,7 @@ The optional `dsh-session/invariant` companion enforces the relations owned by c
|
|
|
566
626
|
|
|
567
627
|
## The end-seed boundary: `session/end-seed`
|
|
568
628
|
|
|
569
|
-
A
|
|
629
|
+
A Session constructed with an explicit seed — restore, fork, or replay — appends this log-only event immediately after that constructor seed, as its first live write. Events before it have smaller seq values and came through construction. It is the durable projection of `firstLiveSeq`: that field answers where this lifecycle's writes start for a consumer holding the object, while the event answers the same question for one holding only stored bytes. It does not define fork ownership; `isSeeded` plus `inheritedEventCount` do. The payload is empty, so position and `time` carry the whole meaning, and it produces no message. `Session`'s constructor is the only legitimate writer.
|
|
570
630
|
|
|
571
631
|
An explicitly supplied empty seed writes `session/end-seed` at seq 0, which distinguishes an empty resumed session from a fresh one. A seed already ending in `session/end-seed` is not re-marked, so reopening an untouched session does not grow its log per pickup. Locate the LAST `session/end-seed` in stored history rather than assuming one exists at `firstLiveSeq`: after a pickup with no work, the event has a smaller seq than the next lifecycle's `firstLiveSeq`.
|
|
572
632
|
|
|
@@ -584,7 +644,7 @@ The hook bridges' `hook/invoked` / `hook/result` pairs (from `@deepseek-ai/dsh-h
|
|
|
584
644
|
|
|
585
645
|
## Durability contract
|
|
586
646
|
|
|
587
|
-
What a persistence backend relies on: the durable log persists every event losslessly, **including** `assistant/chunk` — `seq` must stay contiguous, so chunks cannot be filtered out of the canonical log. A backend may choose its own storage encoding for an event batch as long as `
|
|
647
|
+
What a persistence backend relies on: the durable log persists every event losslessly, **including** `assistant/chunk` — `seq` must stay contiguous, so chunks cannot be filtered out of the canonical log. A backend may choose its own storage encoding for an event batch as long as a handle's `read()` returns the exact appended events (the JSONL backend's default packed chunk rows are such an encoding — see [persistence.md](persistence.md)). All `event.data` must be JSON-serializable; `Session.append` enforces this at the source (throwing on non-serializable data), so a bad event never enters the log and `session.snapshotEvents()` always equals what a backend can persist. Adding an event type that carries non-serializable data, corrupts core execution nesting, or violates its owner's declared relation is a breaking change to the on-disk format.
|
|
588
648
|
|
|
589
649
|
The backends that consume this contract are on [persistence.md](persistence.md).
|
|
590
650
|
|
|
@@ -622,7 +682,7 @@ resolveAgent(sessionId: SessionId): Promise<ApiSessionAgentResult>
|
|
|
622
682
|
* @param signal - optional caller cancellation for persistence reads.
|
|
623
683
|
* @returns the current attached state or persisted header and event prefix.
|
|
624
684
|
*/
|
|
625
|
-
inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<
|
|
685
|
+
inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<SessionInspection>
|
|
626
686
|
|
|
627
687
|
/**
|
|
628
688
|
* Read all visible Session rows without resuming an Agent.
|
|
@@ -742,7 +802,7 @@ inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<{ meta: SessionH
|
|
|
742
802
|
@Remote({ mode: 'stream' }) control(signal: AbortSignal): AsyncIterable<SessionControlFrame>
|
|
743
803
|
```
|
|
744
804
|
|
|
745
|
-
Types: [
|
|
805
|
+
Types: [SessionId](core.md) · [SessionInspection](persistence.md) · [SessionSearchRequest](session-query.md)
|
|
746
806
|
|
|
747
807
|
Source: [`packages/api/session-controller/src/index.ts`](../../packages/api/session-controller/src/index.ts)
|
|
748
808
|
|
|
@@ -752,7 +812,7 @@ Source: [`packages/api/session-controller/src/index.ts`](../../packages/api/sess
|
|
|
752
812
|
|
|
753
813
|
In-memory session store (`ctx.sessions`).
|
|
754
814
|
|
|
755
|
-
Persistence is intentionally not implemented here —
|
|
815
|
+
Persistence is intentionally not implemented here — the agent lifecycle attaches a session-log writer to each published session's write handle; a session published outside that lifecycle persists nothing.
|
|
756
816
|
|
|
757
817
|
```ts cordis-catalog
|
|
758
818
|
/**
|
|
@@ -875,7 +935,7 @@ list(): Session[]
|
|
|
875
935
|
* `SessionStore`'s id policy.
|
|
876
936
|
* @returns The created live child session.
|
|
877
937
|
*/
|
|
878
|
-
fork(source: SessionForkSource, boundary?:
|
|
938
|
+
fork(source: SessionForkSource, boundary?: SessionSeq, childSessionId?: SessionId): Session
|
|
879
939
|
```
|
|
880
940
|
|
|
881
941
|
Types: [CreateSessionOptions](persistence.md) · [PrepareSessionOptions](persistence.md) · [SessionId](core.md)
|
|
@@ -179,6 +179,28 @@ interface RequestContext {
|
|
|
179
179
|
|
|
180
180
|
基于 `type` 的真正可辨识联合(而非独立的 `type`/`data` 联合),因此 `switch (event.type)` 能直接收窄 `event.data`,无需类型断言。`seq` 是日志中的单调递增位置(`seq = log.length`);`time` 为 epoch 毫秒。
|
|
181
181
|
|
|
182
|
+
```ts type-equiv
|
|
183
|
+
/** Sequence number of one existing event in a Session log. */
|
|
184
|
+
type SessionSeq = BrandedNumber<'SessionSeq'>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```ts type-equiv
|
|
188
|
+
/** A Session log gap, prefix length, or read offset, which may equal the event count. */
|
|
189
|
+
type SessionLogOffset = BrandedNumber<'SessionLogOffset'>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```ts type-equiv
|
|
193
|
+
/** Inclusive Session event watermark, or `-1` before any event exists. */
|
|
194
|
+
type SessionSeqCursor = SessionSeq | -1
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```ts type-equiv
|
|
198
|
+
/** One existing Session event position, or explicit absence. */
|
|
199
|
+
type OptionalSessionSeq = SessionSeq | null
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`SessionSeq(value)` 与 `SessionLogOffset(value)` 只接纳非负安全整数,并拒绝负零。它们仅添加编译期品牌,不改变序列化后的数值;算术会返回普通 `number`,调用方必须按结果的预期角色通过对应构造器重新接纳。
|
|
203
|
+
|
|
182
204
|
```ts type-equiv
|
|
183
205
|
/**
|
|
184
206
|
* One immutable entry in the session log.
|
|
@@ -197,7 +219,7 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
197
219
|
[K in SessionEventType]: {
|
|
198
220
|
type: K
|
|
199
221
|
/** Monotonic sequence number within the session. */
|
|
200
|
-
seq:
|
|
222
|
+
seq: SessionSeq
|
|
201
223
|
/** Unix epoch milliseconds. */
|
|
202
224
|
time: number
|
|
203
225
|
data: SessionEventMap[K]
|
|
@@ -221,7 +243,7 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
221
243
|
* provider stream; when the field is absent, the event does not record which
|
|
222
244
|
* earlier events produced the message.
|
|
223
245
|
*/
|
|
224
|
-
sourceEventSeqs?:
|
|
246
|
+
sourceEventSeqs?: SessionSeq[]
|
|
225
247
|
/** How this event entered the surface; absent for non-surface events. */
|
|
226
248
|
surfaceOp?: SurfaceOp
|
|
227
249
|
} : object)
|
|
@@ -270,7 +292,7 @@ type SurfaceEventType =
|
|
|
270
292
|
*/
|
|
271
293
|
type SurfaceOp =
|
|
272
294
|
| 'append'
|
|
273
|
-
| { op: 'replace'; start:
|
|
295
|
+
| { op: 'replace'; start: SessionSeq; end: SessionSeq }
|
|
274
296
|
```
|
|
275
297
|
|
|
276
298
|
`'append'` 是常规的尾部追加路径。`replace` 会遮蔽从 `start` 到 `end`(含两端)的 surface 条目(两者都必须是有效的 surface seq;`start === end` 时仅替换单个条目),并在原位置插入新事件。
|
|
@@ -290,7 +312,7 @@ interface SurfaceIntent {
|
|
|
290
312
|
* absent, the event does not record which earlier events produced the message.
|
|
291
313
|
* Other surface events require a non-empty set when this field is present.
|
|
292
314
|
*/
|
|
293
|
-
sourceEventSeqs?:
|
|
315
|
+
sourceEventSeqs?: SessionSeq[]
|
|
294
316
|
}
|
|
295
317
|
```
|
|
296
318
|
|
|
@@ -308,7 +330,7 @@ interface SurfaceIntent {
|
|
|
308
330
|
/** Readonly live projection of the message-producing session events. */
|
|
309
331
|
interface SessionSurface {
|
|
310
332
|
/** Current surface event sequences in model-visible order. */
|
|
311
|
-
readonly nodes: readonly
|
|
333
|
+
readonly nodes: readonly SessionSeq[]
|
|
312
334
|
/** Monotonic count of committed positional replacements. */
|
|
313
335
|
readonly replaceGeneration: number
|
|
314
336
|
}
|
|
@@ -322,13 +344,13 @@ interface SessionSurface {
|
|
|
322
344
|
/** One replacement operation observed while folding a session surface. */
|
|
323
345
|
interface SurfaceFoldReplacement {
|
|
324
346
|
/** Seq of the event that replaced the prior surface range. */
|
|
325
|
-
seq:
|
|
347
|
+
seq: SessionSeq
|
|
326
348
|
/** Declared inclusive start seq of the replaced surface range. */
|
|
327
|
-
start:
|
|
349
|
+
start: SessionSeq
|
|
328
350
|
/** Declared inclusive end seq of the replaced surface range. */
|
|
329
|
-
end:
|
|
351
|
+
end: SessionSeq
|
|
330
352
|
/** Actual surface entries removed by the operation, in surface order. */
|
|
331
|
-
shadowedSeqs:
|
|
353
|
+
shadowedSeqs: SessionSeq[]
|
|
332
354
|
}
|
|
333
355
|
```
|
|
334
356
|
|
|
@@ -336,7 +358,7 @@ interface SurfaceFoldReplacement {
|
|
|
336
358
|
/** Complete result of replaying the surface operations in a session log. */
|
|
337
359
|
interface SurfaceFoldResult {
|
|
338
360
|
/** Current surface event sequences in model-visible order. */
|
|
339
|
-
nodes:
|
|
361
|
+
nodes: SessionSeq[]
|
|
340
362
|
/** Replacement operations in event order. */
|
|
341
363
|
replacements: SurfaceFoldReplacement[]
|
|
342
364
|
}
|
|
@@ -360,13 +382,15 @@ declare class Session {
|
|
|
360
382
|
get surface(): SessionSurface;
|
|
361
383
|
/**
|
|
362
384
|
* Detached, deep-frozen creation metadata (format version, cwd, lineage,
|
|
363
|
-
*
|
|
385
|
+
* and whether fork history exists). Supplied by the store via `ctx.sessions.create()`. When a
|
|
364
386
|
* `Session` is created without a store-owned header, a minimal header is
|
|
365
387
|
* synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
|
|
366
388
|
* `session.header` is always present. Kept out of the event log — it is a
|
|
367
389
|
* storage concern, not replayable conversation state.
|
|
368
390
|
*/
|
|
369
391
|
readonly header: SessionHeader;
|
|
392
|
+
/** Number of leading events inherited from this Session's fork parent. */
|
|
393
|
+
readonly inheritedEventCount: SessionLogOffset;
|
|
370
394
|
/** The session identity, derived from its durable header's single copy. */
|
|
371
395
|
get id(): SessionId;
|
|
372
396
|
/**
|
|
@@ -375,9 +399,9 @@ declare class Session {
|
|
|
375
399
|
* construction — replay, fork, or resume — and were never published on the
|
|
376
400
|
* `session/event` firehose (constructor seeds do not emit), so consumers
|
|
377
401
|
* that replay the log as a publication substitute (telemetry adoption)
|
|
378
|
-
* start here. Distinct from
|
|
379
|
-
*
|
|
380
|
-
* while
|
|
402
|
+
* start here. Distinct from {@link inheritedEventCount}, the DURABLE
|
|
403
|
+
* fork-lineage cut: a resumed session's constructor seed is its full stored
|
|
404
|
+
* log, while the inherited count keeps the original fork value — this field is the
|
|
381
405
|
* in-process construction fact.
|
|
382
406
|
*
|
|
383
407
|
* Not persisted itself: a seeded session projects it into the log as the
|
|
@@ -390,17 +414,23 @@ declare class Session {
|
|
|
390
414
|
* When this lifecycle appends the marker, it occupies this seq before the
|
|
391
415
|
* store attaches and therefore does not publish either. Otherwise this seq
|
|
392
416
|
* holds an ordinary published write.
|
|
393
|
-
|
|
394
|
-
readonly firstLiveSeq:
|
|
417
|
+
*/
|
|
418
|
+
readonly firstLiveSeq: SessionLogOffset;
|
|
395
419
|
/**
|
|
396
420
|
* Create a detached session by validating and snapshotting borrowed seed
|
|
397
421
|
* events and storage metadata.
|
|
398
422
|
* @param id - session identity.
|
|
399
423
|
* @param seed - optional borrowed replay or fork events.
|
|
400
424
|
* @param header - optional borrowed storage metadata.
|
|
425
|
+
* @param inheritedEventCount - exact fork-inherited prefix length for a seeded header.
|
|
401
426
|
* @returns a detached session.
|
|
402
427
|
*/
|
|
403
|
-
static create(
|
|
428
|
+
static create(
|
|
429
|
+
id: SessionId,
|
|
430
|
+
seed?: readonly SessionEvent[],
|
|
431
|
+
header?: SessionHeader,
|
|
432
|
+
inheritedEventCount?: SessionLogOffset,
|
|
433
|
+
): Session;
|
|
404
434
|
/**
|
|
405
435
|
* Restore a detached session by taking ownership of fresh persistence values.
|
|
406
436
|
* The storage format, event envelopes, sequence continuity, surface transitions,
|
|
@@ -408,18 +438,46 @@ declare class Session {
|
|
|
408
438
|
* @param id - restored session identity.
|
|
409
439
|
* @param seed - fresh detached events whose ownership is transferred.
|
|
410
440
|
* @param header - fresh detached metadata whose ownership is transferred.
|
|
441
|
+
* @param inheritedEventCount - exact fork-inherited prefix length decoded from storage.
|
|
411
442
|
* @returns a restored detached session.
|
|
412
443
|
*/
|
|
413
|
-
static fromRestore(
|
|
444
|
+
static fromRestore(
|
|
445
|
+
id: SessionId,
|
|
446
|
+
seed: readonly SessionEvent[],
|
|
447
|
+
header: SessionHeader,
|
|
448
|
+
inheritedEventCount: SessionLogOffset,
|
|
449
|
+
): Session;
|
|
450
|
+
/**
|
|
451
|
+
* Return the immutable event stored at one exact sequence number.
|
|
452
|
+
* @param seq - event sequence number.
|
|
453
|
+
* @returns the accepted event, or undefined when the log does not contain it.
|
|
454
|
+
*/
|
|
455
|
+
eventAt(seq: SessionSeq): SessionEvent | undefined;
|
|
456
|
+
/**
|
|
457
|
+
* Materialize an immutable snapshot of a half-open event sequence range.
|
|
458
|
+
* A full current snapshot is reused until the next append; every previously
|
|
459
|
+
* returned snapshot remains stable after later appends.
|
|
460
|
+
* @param fromSeq - non-negative inclusive sequence number; defaults to the log start.
|
|
461
|
+
* @param toSeqExclusive - non-negative exclusive sequence number; defaults to the current end.
|
|
462
|
+
* @returns a frozen array of the selected deeply frozen events.
|
|
463
|
+
*/
|
|
464
|
+
snapshotEvents(
|
|
465
|
+
fromSeq: SessionLogOffset = SessionLogOffset(0),
|
|
466
|
+
toSeqExclusive: SessionLogOffset = this.seq,
|
|
467
|
+
): readonly SessionEvent[];
|
|
468
|
+
/**
|
|
469
|
+
* Return this Session's events after its fork-inherited prefix.
|
|
470
|
+
* @returns a fresh array containing child-owned events in log order.
|
|
471
|
+
*/
|
|
472
|
+
ownEvents(): readonly SessionEvent[];
|
|
414
473
|
/**
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* cast nor ordinary JavaScript can rewrite durable history.
|
|
474
|
+
* Whether one existing event position is outside the fork-inherited prefix.
|
|
475
|
+
* @param seq - event position in this Session.
|
|
476
|
+
* @returns true when the event belongs to this Session rather than its parent.
|
|
419
477
|
*/
|
|
420
|
-
|
|
478
|
+
isOwnSeq(seq: SessionSeq): boolean;
|
|
421
479
|
/** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
|
|
422
|
-
get seq():
|
|
480
|
+
get seq(): SessionLogOffset;
|
|
423
481
|
/**
|
|
424
482
|
* Append one typed event to the log and synchronously notify observers via
|
|
425
483
|
* the store-owned, module-private publication hooks. The hot path never blocks
|
|
@@ -464,7 +522,7 @@ declare class Session {
|
|
|
464
522
|
* The {@link EpochHeader} in force after the log's last header event — the
|
|
465
523
|
* header the NEXT request will be compared against — or undefined before
|
|
466
524
|
* the first `request/header` snapshot. The live, incrementally-maintained
|
|
467
|
-
* form of `foldRequestHeader(session.
|
|
525
|
+
* form of `foldRequestHeader(session.snapshotEvents())`: each header event is folded
|
|
468
526
|
* once, when first seen, so a per-step read costs O(new events).
|
|
469
527
|
* @returns the folded header, or undefined when no header event exists yet.
|
|
470
528
|
*/
|
|
@@ -519,7 +577,7 @@ declare class Session {
|
|
|
519
577
|
|
|
520
578
|
`ctx.sessions.create(id, { seed, meta })` 是底层的回放/fork 原语。对于普通的活跃会话 fork,`SessionStore` 暴露一个策略 API:
|
|
521
579
|
|
|
522
|
-
- `fork(source, boundary?, childSessionId?)` 接受一个活跃的 `Session` 对象或活跃的 `SessionId`,选取到 `
|
|
580
|
+
- `fork(source, boundary?, childSessionId?)` 接受一个活跃的 `Session` 对象或活跃的 `SessionId`,选取到 `SessionSeq` boundary(含)为止的源事件(默认为当前最后一个事件),要求所选前缀结束时没有开放轮次,然后创建一个活跃的子会话,包含深克隆的 seed event、`parentSession`、`isSeeded: true`、精确 `inheritedEventCount` 及继承的 `cwd`。
|
|
523
581
|
|
|
524
582
|
显式 `boundary` 允许调用者从任意稳定的轮次间位置 fork,包括之前的 `turn/end` 或更晚的独立纯日志事件,即使源会话有更新的事件或正在进行的轮次。API 拒绝结束于开放轮次内的前缀,而不是静默截断。更广泛的执行关系健全性检查留在既有的 `dsh-invariants` 插件和持久化修复路径中,不在 `fork()` 中重复。`dsh-subagent-fork-in-process` 保留其已完成前缀截断逻辑,因为工具调用时的委托通常在父轮次仍然打开时启动;普通的会话分支应显式指定请求的 boundary。
|
|
525
583
|
|
|
@@ -553,8 +611,10 @@ interface TurnEndReasonMap {
|
|
|
553
611
|
/** At least one step reached its output-token ceiling, even if a plugin continued the turn. */
|
|
554
612
|
'max-tokens': { kind: 'max-tokens' }
|
|
555
613
|
/**
|
|
556
|
-
* A
|
|
557
|
-
*
|
|
614
|
+
* A crash-orphaned turn was closed after the fact: agent-loop resume appends
|
|
615
|
+
* this closer for a stored log whose last turn never ended, and session-query
|
|
616
|
+
* synthesizes it on cold reads. The loop never emits this marker live, and
|
|
617
|
+
* the events recorded before the crash remain intact.
|
|
558
618
|
*/
|
|
559
619
|
interrupted: { kind: 'interrupted' }
|
|
560
620
|
}
|
|
@@ -570,7 +630,7 @@ interface TurnEndReasonMap {
|
|
|
570
630
|
|
|
571
631
|
## 种子结束边界:`session/end-seed`
|
|
572
632
|
|
|
573
|
-
|
|
633
|
+
用显式 seed 构造的 Session(restore、fork 或 replay)会紧接该 constructor seed 之后追加这个仅日志事件,作为自己的第一次实时写入。在它之前的事件具有更小的 seq,且经由构造进入。它是 `firstLiveSeq` 的持久投影:该字段为持有对象的 consumer 回答本 lifecycle 的写入从哪里开始,该事件则为只持有存储字节的 consumer 回答同一问题。它不定义 fork ownership;`isSeeded` 与 `inheritedEventCount` 才定义。payload 为空,因此位置与 `time` 承载全部含义,且不产生任何消息。`Session` 的构造函数是唯一合法的写入方。
|
|
574
634
|
|
|
575
635
|
显式传入的空种子会在 seq 0 写入 `session/end-seed`,从而把从空日志恢复的会话与全新会话区分开来。种子本身已以 `session/end-seed` 结尾时不会重复标记,因此重新打开一个未被改动的会话不会每次拾起都增长日志。应定位存储历史中的最后一条 `session/end-seed`,而不是假定 `firstLiveSeq` 处一定有一条:在一次没有产生工作的拾起之后,该事件的 seq 会小于下一个生命周期的 `firstLiveSeq`。
|
|
576
636
|
|
|
@@ -588,7 +648,7 @@ interface TurnEndReasonMap {
|
|
|
588
648
|
|
|
589
649
|
## 持久性约定
|
|
590
650
|
|
|
591
|
-
持久化后端依赖的约定如下:持久日志无损保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。后端可以为事件批次选择自己的存储编码,只要 `
|
|
651
|
+
持久化后端依赖的约定如下:持久日志无损保存每个事件,**包括** `assistant/chunk`;`seq` 必须连续,因此不能从规范日志中过滤分片。后端可以为事件批次选择自己的存储编码,只要 handle 的 `read()` 返回与追加时完全一致的事件即可(JSONL 后端默认启用的打包分片行就是此类编码;见 [persistence.md](persistence.zh.md))。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.snapshotEvents()` 始终与后端可持久化的内容一致。新增会携带不可序列化数据、破坏核心执行嵌套或违反事件所有方声明关系的事件类型,都会构成磁盘格式的破坏性变更。
|
|
592
652
|
|
|
593
653
|
消费此约定的后端见 [persistence.md](persistence.zh.md)。
|
|
594
654
|
|
|
@@ -626,7 +686,7 @@ resolveAgent(sessionId: SessionId): Promise<ApiSessionAgentResult>
|
|
|
626
686
|
* @param signal - optional caller cancellation for persistence reads.
|
|
627
687
|
* @returns the current attached state or persisted header and event prefix.
|
|
628
688
|
*/
|
|
629
|
-
inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<
|
|
689
|
+
inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<SessionInspection>
|
|
630
690
|
|
|
631
691
|
/**
|
|
632
692
|
* Read all visible Session rows without resuming an Agent.
|
|
@@ -746,7 +806,7 @@ inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<{ meta: SessionH
|
|
|
746
806
|
@Remote({ mode: 'stream' }) control(signal: AbortSignal): AsyncIterable<SessionControlFrame>
|
|
747
807
|
```
|
|
748
808
|
|
|
749
|
-
Types: [
|
|
809
|
+
Types: [SessionId](core.zh.md) · [SessionInspection](persistence.zh.md) · [SessionSearchRequest](session-query.zh.md)
|
|
750
810
|
|
|
751
811
|
Source: [`packages/api/session-controller/src/index.ts`](../../packages/api/session-controller/src/index.ts)
|
|
752
812
|
|
|
@@ -756,7 +816,7 @@ Source: [`packages/api/session-controller/src/index.ts`](../../packages/api/sess
|
|
|
756
816
|
|
|
757
817
|
In-memory session store (`ctx.sessions`).
|
|
758
818
|
|
|
759
|
-
Persistence is intentionally not implemented here —
|
|
819
|
+
Persistence is intentionally not implemented here — the agent lifecycle attaches a session-log writer to each published session's write handle; a session published outside that lifecycle persists nothing.
|
|
760
820
|
|
|
761
821
|
```ts cordis-catalog
|
|
762
822
|
/**
|
|
@@ -879,7 +939,7 @@ list(): Session[]
|
|
|
879
939
|
* `SessionStore`'s id policy.
|
|
880
940
|
* @returns The created live child session.
|
|
881
941
|
*/
|
|
882
|
-
fork(source: SessionForkSource, boundary?:
|
|
942
|
+
fork(source: SessionForkSource, boundary?: SessionSeq, childSessionId?: SessionId): Session
|
|
883
943
|
```
|
|
884
944
|
|
|
885
945
|
Types: [CreateSessionOptions](persistence.zh.md) · [PrepareSessionOptions](persistence.zh.md) · [SessionId](core.zh.md)
|
|
@@ -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/slots.md
|
|
5
|
-
slots.md:
|
|
6
|
-
slots.zh.md:
|
|
5
|
+
slots.md: a37374ff11f9d460a2566a7a30f8318e69cbfa0b
|
|
6
|
+
slots.zh.md: 09329b1f299f4912490f888efa3146ec0ce11e28
|
|
@@ -135,6 +135,7 @@ root
|
|
|
135
135
|
│ │ │ ├─ conversation.chat.commandview
|
|
136
136
|
│ │ │ ├─ conversation.chat.turnTail
|
|
137
137
|
│ │ │ └─ tool.call.toolview
|
|
138
|
+
│ │ │ ├─ tool.call.images
|
|
138
139
|
│ │ │ └─ tool.view.cordis
|
|
139
140
|
│ │ ├─ conversation.message.images
|
|
140
141
|
│ │ └─ conversation.trajectory.images
|
|
@@ -135,6 +135,7 @@ root
|
|
|
135
135
|
│ │ │ ├─ conversation.chat.commandview
|
|
136
136
|
│ │ │ ├─ conversation.chat.turnTail
|
|
137
137
|
│ │ │ └─ tool.call.toolview
|
|
138
|
+
│ │ │ ├─ tool.call.images
|
|
138
139
|
│ │ │ └─ tool.view.cordis
|
|
139
140
|
│ │ ├─ conversation.message.images
|
|
140
141
|
│ │ └─ conversation.trajectory.images
|
|
@@ -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/storage.md
|
|
5
|
-
storage.md:
|
|
6
|
-
storage.zh.md:
|
|
5
|
+
storage.md: 03b0fa1c674064994039d37c4fec906dc45794b3
|
|
6
|
+
storage.zh.md: ded8783fbfe7f0d7d8a846c7a66d780b48de1445
|