dsh-context 0.35.0 → 0.37.0

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/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { ZodType, z } from "zod";
2
- import { Session, SessionEvent } from "@deepseek-ai/dsh-session";
3
- import { Context, Service } from "@deepseek-ai/cordis";
1
+ import { z } from "zod";
2
+ import "@deepseek-ai/dsh-session";
3
+ import { Context } from "@deepseek-ai/cordis";
4
4
  //#region src/host/config.d.ts
5
5
  interface Config {
6
6
  /** Cap on kept per-step request records (the hard step backstop). */
@@ -29,13 +29,90 @@ declare const Config: z.ZodPreprocess<z.ZodObject<{
29
29
  maxArchiveNodes: z.ZodDefault<z.ZodNumber>;
30
30
  }, z.core.$strict>>;
31
31
  //#endregion
32
- //#region src/shared/types.d.ts
32
+ //#region src/host/headers.d.ts
33
+ interface HeadersState {
34
+ headers: HeaderRecord[];
35
+ }
36
+ //#endregion
37
+ //#region src/host/fold.d.ts
33
38
  /**
34
- * Shared wire contract the snapshot model exchanged between the Host and Client halves. Delivered as the `view()` payload of the
35
- * `contextTimeline`/`contextHeaders` session projections (registered on `ctx.sessionProjections`; the registry pushes finished views as
36
- * `session/projection` frames see host/timeline.ts). TYPE-ONLY host-side module: both halves import these as `import type`, so nothing
37
- * from here ever reaches the runtime bundles.
39
+ * History retention bounds (configurable since 0.11 see config.ts; these
40
+ * are the defaults' values). The fold keeps per-STEP request records; once the
41
+ * newest run count exceeds `maxKeptTurns`, the timeline is trimmed to the
42
+ * most recent whole TURN runs (never cutting a turn in half), so turn
43
+ * granularity can always show the full recent turn range instead of a
44
+ * step-count fragment. The turn-run trim runs whenever the cap is crossed
45
+ * (not only when the raw step bound is), so the bounded state stays at the
46
+ * newest ~`maxKeptTurns` turns deterministically as a live log grows.
38
47
  */
48
+ interface TimelineState {
49
+ /** Model-visible surface, newest last. */
50
+ surface: SurfaceNode[];
51
+ sums: Record<Category, number>;
52
+ systemTokens: number;
53
+ toolsTokens: number;
54
+ /**
55
+ * The projection-cache precondition is plain JSON: a property whose value
56
+ * is `undefined` makes the whole checkpoint unserializable
57
+ * (`snapshotJsonValue` rejects it), which fails EVERY cache write for the
58
+ * session — including the `title` projection row that powers the session
59
+ * list after a restart. Optional fields therefore use absent properties
60
+ * (`model`/`provider`/`lastModel`/`contextWindow` are simply not set until
61
+ * a value is known) instead of `undefined`-valued ones. Reads via
62
+ * `state.model` are identical for both shapes (`undefined` on miss).
63
+ */
64
+ model?: string;
65
+ provider?: string;
66
+ lastModel?: string;
67
+ contextWindow?: number;
68
+ requests: RequestRecord[];
69
+ events: ContextEventRecord[];
70
+ /**
71
+ * Recently removed surface nodes (stamped COPIES carrying `gone`), in
72
+ * removal order. Feeds the Context browser's per-step reconstruction.
73
+ * Bounded two ways in trimState: capped to `maxArchiveNodes`, and pruned
74
+ * to removals after the oldest retained request (older removals can only
75
+ * serve steps the requests trim already forgot).
76
+ */
77
+ archived: SurfaceNode[];
78
+ /**
79
+ * Session-cost raw material: cumulative billed-token totals per DeepSeek
80
+ * V4 model family and pricing period (see SessionCostUsage). Running
81
+ * totals — never trimmed, so the estimate always covers the COMPLETE
82
+ * session log even after the request/event retention bounds cut in.
83
+ * Absent until a v4-flash / v4-pro request reports usage.
84
+ */
85
+ cost?: SessionCostUsage;
86
+ archiveFloor?: number;
87
+ /**
88
+ * Tool callId → name, armed by `tool/call` and DELETED when its
89
+ * `tool/result` folds in (one result per call, in log order) — the map
90
+ * stays at pending-call size instead of growing for the session's whole
91
+ * lifetime (it is persisted state, shallow-copied by every fold step).
92
+ */
93
+ callNames: Record<string, string>;
94
+ /**
95
+ * Seq list of the surface nodes the next replacement will shadow, armed by
96
+ * the metering event (`compaction/summary` | `compaction/prune`) and
97
+ * consumed by the replacement that must follow it synchronously. The
98
+ * producer's shadow price covers exactly these seqs — which can differ
99
+ * from the replacement's declared range (pruned replacement nodes keep
100
+ * their own seqs, beyond the range end) — so removal must follow the seqs.
101
+ * Absent until armed, and REMOVED (not set to `undefined`) when consumed,
102
+ * to keep the state plain JSON for the projection cache.
103
+ */
104
+ pendingShadowedSeqs?: number[];
105
+ /**
106
+ * The seq of the compaction/prune event that armed `pendingShadowedSeqs` —
107
+ * the shadowed path rewrites that event's `tokens` from the gross shadow
108
+ * price to the NET freed amount (removed nodes minus the synchronous
109
+ * replacement), so the row matches the drop the trend chart shows. Same
110
+ * arm/remove lifecycle as `pendingShadowedSeqs`.
111
+ */
112
+ pendingShadowEventSeq?: number;
113
+ }
114
+ //#endregion
115
+ //#region src/shared/types.d.ts
39
116
  declare module '@deepseek-ai/dsh-session-projection/types' {
40
117
  interface SessionProjectionMap {
41
118
  /**
@@ -55,6 +132,10 @@ declare module '@deepseek-ai/dsh-session-projection/types' {
55
132
  */
56
133
  contextHeaders: ContextHeaders;
57
134
  }
135
+ interface SessionProjectionStateMap {
136
+ contextTimeline: TimelineState;
137
+ contextHeaders: HeadersState;
138
+ }
58
139
  }
59
140
  type Category = 'user' | 'inject' | 'assistant' | 'tool';
60
141
  interface Snapshot {
@@ -247,6 +328,15 @@ interface HeaderTool {
247
328
  tokens: number;
248
329
  /** Producer-declared description (may be long; the browser truncates). */
249
330
  description?: string;
331
+ /**
332
+ * The registering plugin's label, when attribution is known: either a
333
+ * `plugin` field carried by the raw header entry (harness-provided) or the
334
+ * host's best-effort attribution (`mcp:<server>` for MCP tools, or the
335
+ * pinned first-party package map). `UNKNOWN_TOOL_SOURCE` marks a tool whose
336
+ * provider predates the attribution hook; absent means nothing is known and
337
+ * the browser shows no tag.
338
+ */
339
+ plugin?: string;
250
340
  /** The raw JSON schema object the model received (plain JSON). */
251
341
  schema?: unknown;
252
342
  }
@@ -264,315 +354,6 @@ interface ContextHeaders {
264
354
  headers: HeaderRecord[];
265
355
  }
266
356
  //#endregion
267
- //#region src/host/fold.d.ts
268
- /**
269
- * History retention bounds (configurable since 0.11 — see config.ts; these
270
- * are the defaults' values). The fold keeps per-STEP request records; once the
271
- * newest run count exceeds `maxKeptTurns`, the timeline is trimmed to the
272
- * most recent whole TURN runs (never cutting a turn in half), so turn
273
- * granularity can always show the full recent turn range instead of a
274
- * step-count fragment. The turn-run trim runs whenever the cap is crossed
275
- * (not only when the raw step bound is), so the bounded state stays at the
276
- * newest ~`maxKeptTurns` turns deterministically as a live log grows.
277
- */
278
- interface TimelineState {
279
- /** Model-visible surface, newest last. */
280
- surface: SurfaceNode[];
281
- sums: Record<Category, number>;
282
- systemTokens: number;
283
- toolsTokens: number;
284
- /**
285
- * The projection-cache precondition is plain JSON: a property whose value
286
- * is `undefined` makes the whole checkpoint unserializable
287
- * (`snapshotJsonValue` rejects it), which fails EVERY cache write for the
288
- * session — including the `title` projection row that powers the session
289
- * list after a restart. Optional fields therefore use absent properties
290
- * (`model`/`provider`/`lastModel`/`contextWindow` are simply not set until
291
- * a value is known) instead of `undefined`-valued ones. Reads via
292
- * `state.model` are identical for both shapes (`undefined` on miss).
293
- */
294
- model?: string;
295
- provider?: string;
296
- lastModel?: string;
297
- contextWindow?: number;
298
- requests: RequestRecord[];
299
- events: ContextEventRecord[];
300
- /**
301
- * Recently removed surface nodes (stamped COPIES carrying `gone`), in
302
- * removal order. Feeds the Context browser's per-step reconstruction.
303
- * Bounded two ways in trimState: capped to `maxArchiveNodes`, and pruned
304
- * to removals after the oldest retained request (older removals can only
305
- * serve steps the requests trim already forgot).
306
- */
307
- archived: SurfaceNode[];
308
- /**
309
- * Session-cost raw material: cumulative billed-token totals per DeepSeek
310
- * V4 model family and pricing period (see SessionCostUsage). Running
311
- * totals — never trimmed, so the estimate always covers the COMPLETE
312
- * session log even after the request/event retention bounds cut in.
313
- * Absent until a v4-flash / v4-pro request reports usage.
314
- */
315
- cost?: SessionCostUsage;
316
- archiveFloor?: number;
317
- /**
318
- * Tool callId → name, armed by `tool/call` and DELETED when its
319
- * `tool/result` folds in (one result per call, in log order) — the map
320
- * stays at pending-call size instead of growing for the session's whole
321
- * lifetime (it is persisted state, shallow-copied by every fold step).
322
- */
323
- callNames: Record<string, string>;
324
- /**
325
- * Seq list of the surface nodes the next replacement will shadow, armed by
326
- * the metering event (`compaction/summary` | `compaction/prune`) and
327
- * consumed by the replacement that must follow it synchronously. The
328
- * producer's shadow price covers exactly these seqs — which can differ
329
- * from the replacement's declared range (pruned replacement nodes keep
330
- * their own seqs, beyond the range end) — so removal must follow the seqs.
331
- * Absent until armed, and REMOVED (not set to `undefined`) when consumed,
332
- * to keep the state plain JSON for the projection cache.
333
- */
334
- pendingShadowedSeqs?: number[];
335
- /**
336
- * The seq of the compaction/prune event that armed `pendingShadowedSeqs` —
337
- * the shadowed path rewrites that event's `tokens` from the gross shadow
338
- * price to the NET freed amount (removed nodes minus the synchronous
339
- * replacement), so the row matches the drop the trend chart shows. Same
340
- * arm/remove lifecycle as `pendingShadowedSeqs`.
341
- */
342
- pendingShadowEventSeq?: number;
343
- }
344
- //#endregion
345
- //#region node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.8_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_c0ffab70d18276fadfe75ed916313ea3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/types.d.ts
346
- /**
347
- * Pure-type outlet of the session-projection Service Definition: the one projection type
348
- * table, importable from client aggregates without dragging the host-side
349
- * cordis Context merges of the package root (dsh-agent → dsh-session). Domain
350
- * packages may declare-merge through either the package root or this outlet —
351
- * re-export preserves symbol identity, so both land on the same table.
352
- *
353
- * @module @deepseek-ai/dsh-session-projection/types
354
- */
355
- /**
356
- * The single projection type table for the whole chain (host provider, wire
357
- * block, client cell, React hook). Domain packages merge their key here via
358
- * declaration merging; values are wire-JSON whole values. How a value is
359
- * rendered is the slot system's business, never this layer's.
360
- */
361
- interface SessionProjectionMap {}
362
- //#endregion
363
- //#region node_modules/.pnpm/@deepseek-ai+dsh-session-projection@0.1.0-rc.8_@deepseek-ai+cordis@4.0.1_@deepseek-ai+d_c0ffab70d18276fadfe75ed916313ea3/node_modules/@deepseek-ai/dsh-session-projection/lib/types/index.d.ts
364
- declare module '@deepseek-ai/cordis' {
365
- interface Context {
366
- sessionProjections: SessionProjectionRegistry;
367
- }
368
- }
369
- /**
370
- * One domain's state-driven computation unit: three pure synchronous
371
- * functions plus declarations — never an opaque getter. The framework drives
372
- * `apply` on every committed session event; the domain holds no
373
- * subscriptions and owns only the mathematics. All three functions MUST be
374
- * synchronous (an async unit would tear the carriers' consistency cut) and
375
- * `state` MUST be plain JSON (the persisted-cache precondition).
376
- */
377
- interface ProjectionDefinition<K extends keyof SessionProjectionMap, S> {
378
- /** The projection key this unit owns (its `SessionProjectionMap` entry). */
379
- key: K;
380
- /** Validates the wire payload (`view` output) before it leaves the host. */
381
- schema: ZodType<SessionProjectionMap[K]>;
382
- /**
383
- * State for the empty log.
384
- * @returns the initial state.
385
- */
386
- init(): S;
387
- /**
388
- * Pure transition: previous state + one committed event → next state. A
389
- * unit uninterested in an event MUST return the same state reference — an
390
- * unchanged reference (`Object.is`) produces zero downstream work.
391
- * @param state - the state covering all prior events.
392
- * @param event - the next committed session event.
393
- * @returns the next state (same reference when the event is not the unit's).
394
- */
395
- apply(state: S, event: SessionEvent): S;
396
- /**
397
- * State → wire payload (the read-side projection).
398
- * @param state - the current state.
399
- * @returns the whole current value for this unit's key.
400
- */
401
- view(state: S): SessionProjectionMap[K];
402
- /**
403
- * Persisted-cache invalidation version: bump whenever the serialized state fields or the
404
- * fold semantics change, so persisted `(sessionId, key, ver, seq, val)`
405
- * rows from an older unit are discarded instead of being forward-applied
406
- * into garbage. Non-negative integer.
407
- */
408
- stateVersion: number;
409
- }
410
- /**
411
- * Change-feed listener: one unit's value changed for one session. `value` is
412
- * the schema-validated `view` output; `seq` is the unit's watermark at
413
- * emission (the seq of the event that caused the change).
414
- */
415
- type ProjectionChangeListener = (session: Session, key: Extract<keyof SessionProjectionMap, string>, value: unknown, seq: number) => void;
416
- /**
417
- * One consistent read cut over every registered unit for one session.
418
- * `asOfSeq` is the shared watermark — the seq of the last event every value
419
- * reflects (`-1` for an empty log, mirroring `session/subscribed.lastSeq`).
420
- */
421
- interface ProjectionSnapshot {
422
- /** Seq of the last event the values reflect; -1 for an empty log. */
423
- asOfSeq: number;
424
- /** Whole current value per registered key. */
425
- values: Partial<SessionProjectionMap>;
426
- }
427
- /**
428
- * One unit's checkpoint: its internal state (plain JSON by the unit
429
- * contract), the seq of the last event folded into it, and the unit
430
- * `stateVersion` that produced it — the persisted projection-cache row
431
- * `(sessionId, key, ver, seq, val)` minus the two outer keys. A row is
432
- * never authoritative, only a fold shortcut: `restore` discards it on a
433
- * version mismatch or when it claims events past the stored log end.
434
- */
435
- interface ProjectionCheckpointRow {
436
- /** The registering unit's `stateVersion` at fold time. */
437
- ver: number;
438
- /** Seq of the last event folded into `val`; -1 for the empty log. */
439
- seq: number;
440
- /** The unit's internal state — plain JSON per the unit contract. */
441
- val: unknown;
442
- }
443
- /** Checkpoint rows keyed by projection key (one session's persisted cache value). */
444
- type ProjectionCheckpoint = Record<string, ProjectionCheckpointRow>;
445
- /**
446
- * `ctx.sessionProjections`: the projection unit table and its drive. The
447
- * service subscribes to `session/event` once; every committed event passes
448
- * every registered unit's `apply` (eager drive), and a changed state
449
- * reference notifies the change feed with the schema-validated view.
450
- * Cells build lazily — a unit registered after events flowed, or a session
451
- * older than the registry, folds `init` over the in-memory log on first
452
- * touch (event or read). Registration is an effect (disposer rides the
453
- * calling fiber): an unloaded domain plugin's key disappears from snapshots
454
- * and clients read it as capability absence. Domain
455
- * plugins register under `ctx.inject(['sessionProjections'], …)` so headless
456
- * assemblies without the registry stay unaffected. Registrants sharing a key
457
- * share one unit and are counted: the same tool package mounted in N agent
458
- * presets registers N times, and the key survives until the last one
459
- * unloads.
460
- */
461
- declare class SessionProjectionRegistry extends Service {
462
- private readonly registrations;
463
- private readonly listeners;
464
- /**
465
- * Create and install the registry as `ctx.sessionProjections`.
466
- * @param ctx - Cordis context that owns the service.
467
- */
468
- constructor(ctx: Context);
469
- /**
470
- * Register one domain's unit. The registration is an effect on the calling
471
- * context's fiber: disposing the fiber (or calling the returned disposer)
472
- * removes the key — and the unit's cached cells — from subsequent drives
473
- * and snapshots.
474
- * @param definition - key, state schema, pure unit functions, and stateVersion.
475
- * @returns the exact disposer that unregisters this unit.
476
- */
477
- register<K extends keyof SessionProjectionMap, S>(definition: ProjectionDefinition<K, S>): () => void;
478
- /**
479
- * Subscribe to the change feed. The registration is an effect on the
480
- * calling context's fiber.
481
- * @param listener - called once per unit whose state reference changed, per committed event.
482
- * @returns the exact disposer that unsubscribes.
483
- */
484
- onChanged(listener: ProjectionChangeListener): () => void;
485
- /**
486
- * One consistent cut over every registered unit for one session, read from
487
- * the watermark cache (missing cells fold lazily over the in-memory log).
488
- * Fully synchronous — every value and `asOfSeq` reflect the same log
489
- * position. Each value passes its unit's schema before leaving.
490
- * @param session - the session whose projection values are read.
491
- * @returns the snapshot; `values` is empty when no unit is registered.
492
- */
493
- snapshot(session: Session): ProjectionSnapshot;
494
- /**
495
- * State-level checkpoint of every registered unit for one session, read
496
- * from the watermark cache (missing cells fold lazily over the in-memory
497
- * log). This is the write side of the persisted projection cache: the
498
- * returned rows are the `(key → {ver, seq, val})` part of the durable
499
- * `(sessionId, key, ver, seq, val)`
500
- * rows. Every `val` is a DETACHED structured clone — never the live
501
- * cell reference: the watermark cache is this registry's authoritative
502
- * mutable state, and a caller reaching the live reference could corrupt
503
- * every subsequent snapshot and frame through it (plain JSON by the unit
504
- * contract, so the clone is total).
505
- * @param session - the session whose unit states are checkpointed.
506
- * @returns one row per registered key; empty when no unit is registered.
507
- */
508
- checkpoint(session: Session): ProjectionCheckpoint;
509
- /**
510
- * The stored seq a {@link restore} tail read over `checkpoint` must start
511
- * at: one event BELOW the lowest usable watermark (a row is usable when
512
- * its `ver` matches the live unit's `stateVersion`; an absent or mismatched row
513
- * pulls the floor to `0` — that key must refold the full log). The
514
- * one-below anchor is load-bearing: the tail then proves how far the
515
- * stored log still extends, so {@link restore} can detect a log that
516
- * shrank below a row's watermark (crash-repair truncation) instead of
517
- * serving the stale row as current — an empty tail read from the anchor
518
- * yields an end below every watermark and the restore rejects for a full
519
- * re-read.
520
- * @param checkpoint - persisted rows for one session (possibly stale or empty).
521
- * @returns the seq to hand the persistence `readFrom`, or `undefined`
522
- * when no unit is registered (no read needed — {@link restore} would
523
- * serve empty values regardless).
524
- */
525
- restoreFloor(checkpoint: ProjectionCheckpoint): number | undefined;
526
- /**
527
- * View a checkpoint's rows without any log read: for every registered
528
- * unit whose row's `ver` matches, serve the schema-validated
529
- * `view` of the stored state; mismatched or absent rows leave their key
530
- * absent (a cold or listing consumer treats it as not-yet-available and a
531
- * fuller read path refolds it). The zero-I/O rung of the read ladder —
532
- * values are as stale as their rows, never wrong.
533
- * @param checkpoint - persisted rows for one session (possibly stale or empty).
534
- * @returns whole values per key with a usable row; empty when none.
535
- */
536
- viewCheckpoint(checkpoint: ProjectionCheckpoint): Partial<SessionProjectionMap>;
537
- /**
538
- * Cold read: fold every registered unit over a stored log suffix, seeding
539
- * each from its checkpoint row when usable — the one read recipe (cached
540
- * state + forward tail replay + `view`) applied without a live `Session`.
541
- * Call with the events returned by a persistence
542
- * `readFrom(id, restoreFloor(checkpoint))` and that same floor as
543
- * `baseSeq`; the floor's one-below anchor makes the supplied end honest,
544
- * so a shrunk log is detected here. A row is usable iff its
545
- * `ver` matches the live unit's `stateVersion`, it does not predate `baseSeq`
546
- * (`seq >= baseSeq - 1`), and it does not claim events past the
547
- * supplied end (`seq <= endSeq`); an unusable row is discarded
548
- * and its key refolds from `init` — which is only sound over the full
549
- * log, so a discarded row with `baseSeq > 0` throws (the caller re-reads
550
- * from seq 0, e.g. after a crash-repair truncation shrank the log below
551
- * a row's watermark).
552
- * @param checkpoint - persisted rows for one session (possibly stale or empty).
553
- * @param events - the stored events with `seq >= baseSeq`, in seq order.
554
- * @param baseSeq - the seq `events` starts at (its first event's seq when non-empty).
555
- * @returns the snapshot cut at the supplied log end (`asOfSeq` is the last
556
- * supplied event's seq, `baseSeq - 1` for an empty tail) plus the
557
- * refreshed checkpoint rows at that cut, ready for a durable write-back.
558
- */
559
- restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseSeq: number): {
560
- snapshot: ProjectionSnapshot;
561
- checkpoint: ProjectionCheckpoint;
562
- };
563
- /** Fold one unit from init over `events`, producing a cell watermarked at the last folded event. */
564
- private buildCell;
565
- /** Read (or lazily build, folding the full in-memory log) one unit's cell. */
566
- private cellFor;
567
- /** Eager drive: pass one committed event through every registered unit; notify on changed references. */
568
- private drive;
569
- }
570
- //#endregion
571
- //#region src/host/headers.d.ts
572
- interface HeadersState {
573
- headers: HeaderRecord[];
574
- }
575
- //#endregion
576
357
  //#region src/host/index.d.ts
577
358
  declare const name = "dsh-context";
578
359
  declare const inject: string[];