dsh-context 0.62.3 → 0.64.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/README.md +6 -6
- package/lib/client.js +689 -437
- package/lib/index.d.ts +48 -0
- package/lib/index.js +92 -19
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -157,6 +157,39 @@ interface TimelineState {
|
|
|
157
157
|
time: number;
|
|
158
158
|
firstToken?: number;
|
|
159
159
|
};
|
|
160
|
+
/**
|
|
161
|
+
* The open step's CLOSED user-wait intervals (real log instants), pushed
|
|
162
|
+
* replace-style as each wait settles: an approval decision (its asked →
|
|
163
|
+
* decided pair closes via `stepApprovals`) and an `ask_user_question`
|
|
164
|
+
* call's whole tool window (its body is the answer wait itself, in both
|
|
165
|
+
* the blocking and the timed schema's foreground phase). `step/end`
|
|
166
|
+
* subtracts their clamped union from the step window to price the
|
|
167
|
+
* request's `activeMs`, then DELETES the slot. Same arm/remove lifecycle
|
|
168
|
+
* as `stepStart` — never written in place, so no CloneKey covers it.
|
|
169
|
+
*/
|
|
170
|
+
stepWaits?: {
|
|
171
|
+
start: number;
|
|
172
|
+
end: number;
|
|
173
|
+
}[];
|
|
174
|
+
/**
|
|
175
|
+
* The open step's PENDING approval waits (request id → its `approval/asked`
|
|
176
|
+
* instant), armed only while a step is open and disarmed by the matching
|
|
177
|
+
* `approval/decided`. A crash mid-decision leaves the pair dangling —
|
|
178
|
+
* resume repair appends no synthetic decision — so `step/end` closes the
|
|
179
|
+
* survivors at its own instant. One record, not a map: pending approvals
|
|
180
|
+
* are a handful at most, and the rebuild-on-change copy stays trivial.
|
|
181
|
+
* Deleted at `step/start` (a superseded step's leftovers) and `step/end`.
|
|
182
|
+
*/
|
|
183
|
+
stepApprovals?: Record<string, number>;
|
|
184
|
+
/**
|
|
185
|
+
* The seq of the request record committed by the open step's
|
|
186
|
+
* `assistant/message` — the back-pointer `step/end` stamps `activeMs`
|
|
187
|
+
* onto. It stays the requests TAIL until then (nothing pushes between a
|
|
188
|
+
* step's message and its end, and the turn trim only drops the oldest),
|
|
189
|
+
* so the stamp is an O(1) tail write guarded by the seq. Same arm/remove
|
|
190
|
+
* lifecycle as `stepStart`.
|
|
191
|
+
*/
|
|
192
|
+
stepRequestSeq?: number;
|
|
160
193
|
/**
|
|
161
194
|
* The timing strip's painted spans (shared/types.ts TimingSpan): every
|
|
162
195
|
* completed step's time slices in log order, stamped with their REAL
|
|
@@ -364,6 +397,8 @@ type DefaultToolSort = 'size' | 'count' | 'name';
|
|
|
364
397
|
type DefaultPlacement = 'all' | 'tab' | 'sidebar';
|
|
365
398
|
/** Whether the Context Insights panel's sidebar entry is offered at all. */
|
|
366
399
|
type InsightsEntry = 'show' | 'hide';
|
|
400
|
+
/** Whether the trend chart mounts with the per-request duration curve overlaid. */
|
|
401
|
+
type DefaultDurationCurve = 'show' | 'hide';
|
|
367
402
|
interface Snapshot {
|
|
368
403
|
ok: boolean;
|
|
369
404
|
/**
|
|
@@ -790,6 +825,15 @@ interface RequestRecord {
|
|
|
790
825
|
*/
|
|
791
826
|
cacheRead?: number;
|
|
792
827
|
output?: number;
|
|
828
|
+
/**
|
|
829
|
+
* The request's step ACTIVE milliseconds (`step/start` → `step/end`: the
|
|
830
|
+
* model call plus its tool runs) minus the in-step user waits — approval
|
|
831
|
+
* decisions and `ask_user_question` answer windows — the trend chart's
|
|
832
|
+
* duration overlay. Stamped at `step/end` onto the step's committed record;
|
|
833
|
+
* absent while that step is still open (the live tail) or when the step
|
|
834
|
+
* closed without one (an unpaired/hostile log).
|
|
835
|
+
*/
|
|
836
|
+
activeMs?: number;
|
|
793
837
|
/**
|
|
794
838
|
* Turn-mode aggregate marker, set by the Client's aggregateByTurn (one bar
|
|
795
839
|
* per turn shows its LAST step's record). The Host never sets it.
|
|
@@ -913,6 +957,8 @@ export interface Config {
|
|
|
913
957
|
defaultFileSort?: DefaultFileSort;
|
|
914
958
|
/** Whether the Context Insights panel's sidebar entry is offered. */
|
|
915
959
|
insightsEntry?: InsightsEntry;
|
|
960
|
+
/** Whether the trend chart mounts with the duration curve overlaid. */
|
|
961
|
+
defaultDurationCurve?: DefaultDurationCurve;
|
|
916
962
|
}
|
|
917
963
|
/** The cordis `Config` validator and the Config-form generation's served schema. */
|
|
918
964
|
export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
@@ -929,6 +975,7 @@ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
|
929
975
|
defaultToolSort: z$1<"count" | "name" | "size", "count" | "name" | "size", Mode>;
|
|
930
976
|
defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", Mode>;
|
|
931
977
|
insightsEntry: z$1<"hide" | "show", "hide" | "show", Mode>;
|
|
978
|
+
defaultDurationCurve: z$1<"hide" | "show", "hide" | "show", Mode>;
|
|
932
979
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
933
980
|
maxRequestSteps: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
|
|
934
981
|
maxKeptTurns: z$1<number, number, Mode extends "volatile" | "volatile-defined" ? "volatile-defined" : "defined">;
|
|
@@ -943,6 +990,7 @@ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
|
943
990
|
defaultToolSort: z$1<"count" | "name" | "size", "count" | "name" | "size", Mode>;
|
|
944
991
|
defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", Mode>;
|
|
945
992
|
insightsEntry: z$1<"hide" | "show", "hide" | "show", Mode>;
|
|
993
|
+
defaultDurationCurve: z$1<"hide" | "show", "hide" | "show", Mode>;
|
|
946
994
|
}>>, "plain">;
|
|
947
995
|
//#endregion
|
|
948
996
|
//#region src/host/index.d.ts
|
package/lib/index.js
CHANGED
|
@@ -259,8 +259,8 @@ function estimateBlocks(blocks) {
|
|
|
259
259
|
}
|
|
260
260
|
/**
|
|
261
261
|
* Price one surface message exactly like dsh's token-meter estimate:
|
|
262
|
-
* an empty-content assistant/
|
|
263
|
-
*
|
|
262
|
+
* an empty-content assistant/developer event projects to NO message, so it
|
|
263
|
+
* prices 0; every other message pays content + role framing.
|
|
264
264
|
*/
|
|
265
265
|
function estimateMessage(message, emptyIsZero = false) {
|
|
266
266
|
if (emptyIsZero && (message === null || message === void 0 || !Array.isArray(message.content) || message.content.length === 0)) return 0;
|
|
@@ -844,6 +844,7 @@ function createTimelineState() {
|
|
|
844
844
|
function categoryOf(type, message) {
|
|
845
845
|
if (type === "assistant/message") return "assistant";
|
|
846
846
|
if (type === "tool/result") return "tool";
|
|
847
|
+
if (type === "developer/message") return "inject";
|
|
847
848
|
const kind = message?.source?.kind;
|
|
848
849
|
if (kind === "skill-invocation" || kind === "skill-catalog") return "skill";
|
|
849
850
|
if (isInjection(message?.source)) return "inject";
|
|
@@ -943,12 +944,9 @@ function removeSurfaceSeqs(st, claimed, goneSeq) {
|
|
|
943
944
|
return removed;
|
|
944
945
|
}
|
|
945
946
|
/**
|
|
946
|
-
*
|
|
947
|
-
*
|
|
948
|
-
*
|
|
949
|
-
* message reads null here, never throws or guesses a shape. Purely a type
|
|
950
|
-
* cast: `deriveEventMessage` returns `event.data` for a user/message (no
|
|
951
|
-
* `data.message` indirection), so its result feeds every other case.
|
|
947
|
+
* A message nested under data.message. A structural read keeps malformed
|
|
948
|
+
* payloads total and handles developer messages absent from the V3
|
|
949
|
+
* dependency's deriveEventMessage. User messages instead live in data itself.
|
|
952
950
|
*/
|
|
953
951
|
function messageOf$1(data) {
|
|
954
952
|
const message = data?.message;
|
|
@@ -988,7 +986,7 @@ function applySurface(st, ev, type, data, message) {
|
|
|
988
986
|
seq: ev.seq,
|
|
989
987
|
time: ev.time,
|
|
990
988
|
cat,
|
|
991
|
-
tokens: estimateMessage(message, type === "assistant/message")
|
|
989
|
+
tokens: estimateMessage(message, type === "assistant/message" || type === "developer/message")
|
|
992
990
|
};
|
|
993
991
|
const imgs = imageCountOf(message?.content);
|
|
994
992
|
if (imgs > 0) node.imgs = imgs;
|
|
@@ -1397,13 +1395,38 @@ function applyTimeline(state, event, bounds) {
|
|
|
1397
1395
|
const s = ensure([]);
|
|
1398
1396
|
s.stepStart = { time: event.time };
|
|
1399
1397
|
delete s.stepSpans;
|
|
1398
|
+
delete s.stepWaits;
|
|
1399
|
+
delete s.stepApprovals;
|
|
1400
|
+
delete s.stepRequestSeq;
|
|
1400
1401
|
break;
|
|
1401
1402
|
}
|
|
1402
1403
|
case "step/end": {
|
|
1403
1404
|
const start = state.stepStart;
|
|
1404
1405
|
if (start === void 0) return state;
|
|
1405
|
-
const s = ensure(["timing"]);
|
|
1406
|
+
const s = ensure(state.stepRequestSeq !== void 0 ? ["timing", "requests"] : ["timing"]);
|
|
1406
1407
|
ensureTiming(s).wallMs += durOf(start.time, event.time);
|
|
1408
|
+
const waits = [...state.stepWaits ?? []];
|
|
1409
|
+
for (const id in state.stepApprovals) waits.push({
|
|
1410
|
+
start: state.stepApprovals[id],
|
|
1411
|
+
end: event.time
|
|
1412
|
+
});
|
|
1413
|
+
waits.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
1414
|
+
let waitMs = 0;
|
|
1415
|
+
let waitCursor = start.time;
|
|
1416
|
+
for (const wait of waits) {
|
|
1417
|
+
const from = Math.max(waitCursor, wait.start);
|
|
1418
|
+
const to = Math.min(wait.end, event.time);
|
|
1419
|
+
if (to > from) {
|
|
1420
|
+
waitMs += to - from;
|
|
1421
|
+
waitCursor = to;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
const activeMs = durOf(start.time, event.time) - waitMs;
|
|
1425
|
+
const last = state.requests.at(-1);
|
|
1426
|
+
if (last !== void 0 && last.seq === state.stepRequestSeq) s.requests[s.requests.length - 1] = {
|
|
1427
|
+
...last,
|
|
1428
|
+
activeMs
|
|
1429
|
+
};
|
|
1407
1430
|
const painted = [];
|
|
1408
1431
|
for (const span of state.stepSpans ?? []) {
|
|
1409
1432
|
const from = Math.max(start.time, span.start);
|
|
@@ -1440,11 +1463,43 @@ function applyTimeline(state, event, bounds) {
|
|
|
1440
1463
|
s.spans = [...state.spans, ...flushed];
|
|
1441
1464
|
delete s.stepStart;
|
|
1442
1465
|
delete s.stepSpans;
|
|
1466
|
+
delete s.stepWaits;
|
|
1467
|
+
delete s.stepApprovals;
|
|
1468
|
+
delete s.stepRequestSeq;
|
|
1443
1469
|
bumpDetailRev(s);
|
|
1444
1470
|
break;
|
|
1445
1471
|
}
|
|
1446
|
-
case "
|
|
1447
|
-
const
|
|
1472
|
+
case "approval/asked": {
|
|
1473
|
+
const id = data?.id;
|
|
1474
|
+
if (state.stepStart === void 0 || typeof id !== "string") return state;
|
|
1475
|
+
const s = ensure([]);
|
|
1476
|
+
s.stepApprovals = {
|
|
1477
|
+
...state.stepApprovals,
|
|
1478
|
+
[id]: event.time
|
|
1479
|
+
};
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1482
|
+
case "approval/decided": {
|
|
1483
|
+
const id = data?.id;
|
|
1484
|
+
const open = state.stepApprovals;
|
|
1485
|
+
const askedAt = typeof id === "string" ? open?.[id] : void 0;
|
|
1486
|
+
if (open === void 0 || askedAt === void 0) return state;
|
|
1487
|
+
const s = ensure([]);
|
|
1488
|
+
s.stepWaits = [...state.stepWaits ?? [], {
|
|
1489
|
+
start: askedAt,
|
|
1490
|
+
end: event.time
|
|
1491
|
+
}];
|
|
1492
|
+
const kept = {};
|
|
1493
|
+
for (const k in open) if (k !== id) kept[k] = open[k];
|
|
1494
|
+
if (Object.keys(kept).length > 0) s.stepApprovals = kept;
|
|
1495
|
+
else delete s.stepApprovals;
|
|
1496
|
+
break;
|
|
1497
|
+
}
|
|
1498
|
+
case "user/message":
|
|
1499
|
+
case "developer/message": {
|
|
1500
|
+
const developer = event.type === "developer/message";
|
|
1501
|
+
const msg = developer ? messageOf$1(data) : deriveEventMessage(event);
|
|
1502
|
+
if (developer && (msg === null || !Array.isArray(msg.content))) return state;
|
|
1448
1503
|
const s = ensure([
|
|
1449
1504
|
"surface",
|
|
1450
1505
|
"sums",
|
|
@@ -1454,15 +1509,15 @@ function applyTimeline(state, event, bounds) {
|
|
|
1454
1509
|
bumpDetailRev(s);
|
|
1455
1510
|
const node = applySurface(s, event, event.type, data, msg);
|
|
1456
1511
|
const source = msg?.source;
|
|
1457
|
-
if (isInjection(source)) {
|
|
1512
|
+
if (developer || isInjection(source)) {
|
|
1458
1513
|
const rec = {
|
|
1459
1514
|
seq: event.seq,
|
|
1460
1515
|
time: event.time,
|
|
1461
1516
|
kind: "inject",
|
|
1462
|
-
form: typeof source
|
|
1517
|
+
form: typeof source?.form === "string" && source.form !== "" ? source.form : "context",
|
|
1463
1518
|
tokens: node.tokens
|
|
1464
1519
|
};
|
|
1465
|
-
if (source
|
|
1520
|
+
if (source?.kind === "skill-invocation") {
|
|
1466
1521
|
rec.sub = "skill";
|
|
1467
1522
|
rec.name = typeof source.name === "string" ? source.name : "?";
|
|
1468
1523
|
} else {
|
|
@@ -1471,7 +1526,7 @@ function applyTimeline(state, event, bounds) {
|
|
|
1471
1526
|
rec.name = label;
|
|
1472
1527
|
node.name = label;
|
|
1473
1528
|
}
|
|
1474
|
-
if (source
|
|
1529
|
+
if (source?.form === "notice" && typeof source.summary === "string" && source.summary !== "") rec.detail = source.summary;
|
|
1475
1530
|
}
|
|
1476
1531
|
s.events.push(rec);
|
|
1477
1532
|
} else {
|
|
@@ -1498,6 +1553,10 @@ function applyTimeline(state, event, bounds) {
|
|
|
1498
1553
|
bumpDetailRev(s);
|
|
1499
1554
|
const node = applySurface(s, event, event.type, data, toolMsg);
|
|
1500
1555
|
if (node.tool === ASK_USER_TOOL) s.humanInputs = (s.humanInputs ?? 0) + 1;
|
|
1556
|
+
if (pendingEntry !== void 0 && pendingEntry.name === ASK_USER_TOOL && state.stepStart !== void 0) s.stepWaits = [...state.stepWaits ?? [], {
|
|
1557
|
+
start: pendingEntry.start,
|
|
1558
|
+
end: event.time
|
|
1559
|
+
}];
|
|
1501
1560
|
if (pendingEntry !== void 0) pushFileOps(s, opsOfCall({
|
|
1502
1561
|
seq: event.seq,
|
|
1503
1562
|
time: event.time,
|
|
@@ -1565,6 +1624,7 @@ function applyTimeline(state, event, bounds) {
|
|
|
1565
1624
|
};
|
|
1566
1625
|
if (data && typeof data.turn === "number") record.turn = data.turn;
|
|
1567
1626
|
if (data && typeof data.step === "number") record.step = data.step;
|
|
1627
|
+
if (state.stepStart !== void 0) s.stepRequestSeq = record.seq;
|
|
1568
1628
|
let output = null;
|
|
1569
1629
|
if (usage !== null && typeof usage === "object") {
|
|
1570
1630
|
const input = tokenCountOf(usage.inputTokens);
|
|
@@ -2794,7 +2854,8 @@ const Config = z$1.object({
|
|
|
2794
2854
|
"latest",
|
|
2795
2855
|
"path"
|
|
2796
2856
|
]).default("count").loose()),
|
|
2797
|
-
insightsEntry: volatileField(z$1.union(["show", "hide"]).default("show").loose())
|
|
2857
|
+
insightsEntry: volatileField(z$1.union(["show", "hide"]).default("show").loose()),
|
|
2858
|
+
defaultDurationCurve: volatileField(z$1.union(["show", "hide"]).default("show").loose())
|
|
2798
2859
|
});
|
|
2799
2860
|
/** Resolve the fold's retention bounds (the schema fills every default). */
|
|
2800
2861
|
function resolveBounds(config) {
|
|
@@ -3174,6 +3235,11 @@ const requestRecordSchema = z.object({
|
|
|
3174
3235
|
skill: z.number().int().nonnegative().optional(),
|
|
3175
3236
|
cacheRead: z.number().int().nonnegative().optional(),
|
|
3176
3237
|
output: z.number().int().nonnegative().optional(),
|
|
3238
|
+
/**
|
|
3239
|
+
* The request's step active milliseconds (see RequestRecord.activeMs).
|
|
3240
|
+
* Optional so a record whose step never closed (the live tail) still parses.
|
|
3241
|
+
*/
|
|
3242
|
+
activeMs: z.number().nonnegative().optional(),
|
|
3177
3243
|
stepCount: z.number().int().positive().optional()
|
|
3178
3244
|
}).strict();
|
|
3179
3245
|
const contextEventSchema = z.object({
|
|
@@ -3373,6 +3439,12 @@ const timelineStateSchema = z.object({
|
|
|
3373
3439
|
time: z.number(),
|
|
3374
3440
|
firstToken: z.number().optional()
|
|
3375
3441
|
}).strict().optional(),
|
|
3442
|
+
stepWaits: z.array(z.object({
|
|
3443
|
+
start: z.number(),
|
|
3444
|
+
end: z.number()
|
|
3445
|
+
}).strict()).optional(),
|
|
3446
|
+
stepApprovals: z.record(z.string(), z.number()).optional(),
|
|
3447
|
+
stepRequestSeq: z.number().optional(),
|
|
3376
3448
|
callNames: z.record(z.string(), z.object({
|
|
3377
3449
|
name: z.string(),
|
|
3378
3450
|
start: z.number(),
|
|
@@ -3432,7 +3504,7 @@ function createContextTimelineDefinition(config, slim) {
|
|
|
3432
3504
|
},
|
|
3433
3505
|
init: () => createTimelineState(),
|
|
3434
3506
|
apply: (state, event) => applyTimeline(state, event, bounds),
|
|
3435
|
-
stateVersion:
|
|
3507
|
+
stateVersion: 26
|
|
3436
3508
|
};
|
|
3437
3509
|
}
|
|
3438
3510
|
//#endregion
|
|
@@ -3555,7 +3627,8 @@ const SettingsSchema = z$1.object({
|
|
|
3555
3627
|
"latest",
|
|
3556
3628
|
"path"
|
|
3557
3629
|
]).default("count").loose(),
|
|
3558
|
-
insightsEntry: z$1.union(["show", "hide"]).default("show").loose()
|
|
3630
|
+
insightsEntry: z$1.union(["show", "hide"]).default("show").loose(),
|
|
3631
|
+
defaultDurationCurve: z$1.union(["show", "hide"]).default("show").loose()
|
|
3559
3632
|
});
|
|
3560
3633
|
/** Serve the namespace while a settings provider with the register face is composed; inert otherwise. */
|
|
3561
3634
|
function installSettings(ctx) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
|
|
5
5
|
"icon": "icon.svg",
|
|
6
6
|
"author": "bowenliang123",
|