dsh-context 0.8.0 → 0.9.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/client.js +226 -439
- package/lib/index.js +269 -210
- package/package.json +9 -2
package/lib/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/host/timeline.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
1
4
|
// src/host/pricing.ts
|
|
2
5
|
var CHARS_PER_TOKEN = 4;
|
|
3
6
|
var BLOCK_OVERHEAD = 4;
|
|
@@ -64,6 +67,8 @@ function isInjection(source) {
|
|
|
64
67
|
// src/host/fold.ts
|
|
65
68
|
var MAX_REQUEST_STEPS = 1500;
|
|
66
69
|
var MAX_KEPT_TURNS = 300;
|
|
70
|
+
var MAX_EVENTS = 400;
|
|
71
|
+
var MAX_NODES = 200;
|
|
67
72
|
function trimToLastTurns(requests, maxTurns) {
|
|
68
73
|
let runs = 0;
|
|
69
74
|
let start = requests.length;
|
|
@@ -79,17 +84,33 @@ function trimToLastTurns(requests, maxTurns) {
|
|
|
79
84
|
}
|
|
80
85
|
return requests.slice(start);
|
|
81
86
|
}
|
|
82
|
-
function
|
|
87
|
+
function countTurnRuns(requests) {
|
|
88
|
+
let runs = 0;
|
|
89
|
+
let prevTurn;
|
|
90
|
+
for (const r of requests) {
|
|
91
|
+
if (r.turn !== prevTurn) {
|
|
92
|
+
runs++;
|
|
93
|
+
prevTurn = r.turn;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return runs;
|
|
97
|
+
}
|
|
98
|
+
function trimState(st) {
|
|
99
|
+
if (countTurnRuns(st.requests) > MAX_KEPT_TURNS) {
|
|
100
|
+
st.requests = trimToLastTurns(st.requests, MAX_KEPT_TURNS);
|
|
101
|
+
}
|
|
102
|
+
if (st.requests.length > MAX_REQUEST_STEPS) {
|
|
103
|
+
st.requests = st.requests.slice(-MAX_REQUEST_STEPS);
|
|
104
|
+
}
|
|
105
|
+
if (st.events.length > MAX_EVENTS) st.events = st.events.slice(-MAX_EVENTS);
|
|
106
|
+
}
|
|
107
|
+
function createTimelineState() {
|
|
83
108
|
return {
|
|
84
|
-
n: 0,
|
|
85
|
-
// number of log events already folded
|
|
86
109
|
surface: [],
|
|
87
|
-
// { seq, cat, tokens, form?, text?, tool?, err?, skill?, calls? }
|
|
88
110
|
sums: { user: 0, inject: 0, assistant: 0, tool: 0 },
|
|
89
111
|
systemTokens: 0,
|
|
90
112
|
toolsTokens: 0,
|
|
91
113
|
toolList: [],
|
|
92
|
-
// { name, tokens }
|
|
93
114
|
model: void 0,
|
|
94
115
|
provider: void 0,
|
|
95
116
|
lastModel: void 0,
|
|
@@ -98,11 +119,8 @@ function createFold() {
|
|
|
98
119
|
sampledSurfaceTokens: void 0,
|
|
99
120
|
occupancyWindow: void 0,
|
|
100
121
|
requests: [],
|
|
101
|
-
// one entry per answered model call
|
|
102
122
|
events: [],
|
|
103
|
-
// notable context events (structured; the Client labels them)
|
|
104
123
|
callNames: {}
|
|
105
|
-
// callId -> tool name
|
|
106
124
|
};
|
|
107
125
|
}
|
|
108
126
|
function categoryOf(type, message) {
|
|
@@ -132,9 +150,12 @@ function applySurface(st, ev, type, data, message) {
|
|
|
132
150
|
if (names.length > 0) node.calls = names.slice(0, 3);
|
|
133
151
|
}
|
|
134
152
|
} else if (type === "tool/result") {
|
|
153
|
+
const srcId = source?.callId;
|
|
154
|
+
const srcName = typeof srcId === "string" ? st.callNames[srcId] : void 0;
|
|
135
155
|
const block = message?.content?.[0];
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
156
|
+
const blockId = block?.toolCallId;
|
|
157
|
+
if (srcName) node.tool = srcName;
|
|
158
|
+
else if (typeof blockId === "string") node.tool = st.callNames[blockId];
|
|
138
159
|
if (data?.error) node.err = true;
|
|
139
160
|
} else if (source?.kind === "skill-invocation") {
|
|
140
161
|
node.skill = typeof source.name === "string" ? source.name : "?";
|
|
@@ -196,170 +217,179 @@ function sampleUsage(st, usage) {
|
|
|
196
217
|
st.pressureTokens = pressureTokens;
|
|
197
218
|
st.sampledSurfaceTokens = st.sums.user + st.sums.inject + st.sums.assistant + st.sums.tool;
|
|
198
219
|
}
|
|
199
|
-
function
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
function applyTimeline(state, event) {
|
|
221
|
+
let st;
|
|
222
|
+
const ensure = () => st ??= {
|
|
223
|
+
...state,
|
|
224
|
+
surface: [...state.surface],
|
|
225
|
+
sums: { ...state.sums },
|
|
226
|
+
toolList: [...state.toolList],
|
|
227
|
+
requests: [...state.requests],
|
|
228
|
+
events: [...state.events],
|
|
229
|
+
callNames: { ...state.callNames }
|
|
230
|
+
};
|
|
231
|
+
const data = event.data;
|
|
232
|
+
switch (event.type) {
|
|
233
|
+
case "request/header": {
|
|
234
|
+
const header = data?.header ?? {};
|
|
235
|
+
const tools = Array.isArray(header.tools) ? header.tools : [];
|
|
236
|
+
const s = ensure();
|
|
237
|
+
s.toolList = tools.map((t) => ({
|
|
238
|
+
name: typeof t.name === "string" ? t.name : "?",
|
|
239
|
+
tokens: estimateToolSchema(t)
|
|
240
|
+
}));
|
|
241
|
+
s.toolsTokens = estimateToolsTotal(tools);
|
|
242
|
+
s.systemTokens = estimateSystem(header.system);
|
|
243
|
+
if (header.config && typeof header.config.model === "string") s.model = header.config.model;
|
|
244
|
+
if (header.config && typeof header.config.provider === "string") s.provider = header.config.provider;
|
|
245
|
+
if (data?.reason === "change" && s.model && s.lastModel && s.model !== s.lastModel) {
|
|
246
|
+
s.events.push({ seq: event.seq, time: event.time, kind: "model", from: s.lastModel, to: s.model });
|
|
221
247
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
248
|
+
if (s.model) s.lastModel = s.model;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
case "request/context": {
|
|
252
|
+
const s = ensure();
|
|
253
|
+
if (data && typeof data.contextWindow === "number") s.contextWindow = data.contextWindow;
|
|
254
|
+
if (data && typeof data.model === "string") s.model = data.model;
|
|
255
|
+
if (data && typeof data.provider === "string") s.provider = data.provider;
|
|
256
|
+
s.occupancyWindow = data && typeof data.contextWindow === "number" ? data.contextWindow : void 0;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
case "tool/call": {
|
|
260
|
+
if (data && data.callId !== void 0 && typeof data.name === "string") {
|
|
261
|
+
const s = ensure();
|
|
262
|
+
s.callNames[String(data.callId)] = data.name;
|
|
263
|
+
}
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
case "user/message": {
|
|
267
|
+
const msg = data;
|
|
268
|
+
const s = ensure();
|
|
269
|
+
const node = applySurface(s, event, event.type, data, msg);
|
|
270
|
+
const source = msg?.source;
|
|
271
|
+
if (isInjection(source)) {
|
|
272
|
+
const rec = {
|
|
273
|
+
seq: event.seq,
|
|
274
|
+
time: event.time,
|
|
275
|
+
kind: "inject",
|
|
276
|
+
form: source.form || "context",
|
|
277
|
+
tokens: node.tokens
|
|
278
|
+
};
|
|
279
|
+
if (source.kind === "skill-invocation") {
|
|
280
|
+
rec.sub = "skill";
|
|
281
|
+
rec.name = typeof source.name === "string" ? source.name : "?";
|
|
282
|
+
} else if (typeof source.plugin === "string" && source.plugin !== "") {
|
|
283
|
+
rec.name = source.plugin;
|
|
250
284
|
}
|
|
251
|
-
|
|
285
|
+
s.events.push(rec);
|
|
252
286
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "tool/result": {
|
|
290
|
+
const toolMsg = data?.message ?? null;
|
|
291
|
+
const s = ensure();
|
|
292
|
+
applySurface(s, event, event.type, data, toolMsg);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
case "assistant/chunk": {
|
|
296
|
+
const chunk = data?.chunk;
|
|
297
|
+
if (chunk !== void 0 && chunk.type === "usage") {
|
|
298
|
+
const s = ensure();
|
|
299
|
+
sampleUsage(s, chunk.usage);
|
|
257
300
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
case "assistant/message": {
|
|
304
|
+
const usage = data?.usage;
|
|
305
|
+
const s = ensure();
|
|
306
|
+
sampleUsage(s, usage);
|
|
307
|
+
const total = s.systemTokens + s.toolsTokens + s.sums.user + s.sums.inject + s.sums.assistant + s.sums.tool;
|
|
308
|
+
const record = {
|
|
309
|
+
turn: data && typeof data.turn === "number" ? data.turn : void 0,
|
|
310
|
+
step: data && typeof data.step === "number" ? data.step : void 0,
|
|
311
|
+
time: event.time,
|
|
312
|
+
seq: event.seq,
|
|
313
|
+
system: s.systemTokens,
|
|
314
|
+
tools: s.toolsTokens,
|
|
315
|
+
user: s.sums.user,
|
|
316
|
+
inject: s.sums.inject,
|
|
317
|
+
assistant: s.sums.assistant,
|
|
318
|
+
tool: s.sums.tool,
|
|
319
|
+
total
|
|
320
|
+
};
|
|
321
|
+
if (usage && typeof usage.inputTokens === "number") {
|
|
322
|
+
record.prompt = usage.inputTokens + (usage.cacheReadTokens || 0) + (usage.cacheWriteTokens || 0);
|
|
323
|
+
if (typeof usage.outputTokens === "number") record.output = usage.outputTokens;
|
|
262
324
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
tools: st.toolsTokens,
|
|
274
|
-
user: st.sums.user,
|
|
275
|
-
inject: st.sums.inject,
|
|
276
|
-
assistant: st.sums.assistant,
|
|
277
|
-
tool: st.sums.tool,
|
|
278
|
-
total
|
|
279
|
-
};
|
|
280
|
-
if (usage && typeof usage.inputTokens === "number") {
|
|
281
|
-
record.prompt = usage.inputTokens + (usage.cacheReadTokens || 0) + (usage.cacheWriteTokens || 0);
|
|
282
|
-
if (typeof usage.outputTokens === "number") record.output = usage.outputTokens;
|
|
283
|
-
}
|
|
284
|
-
st.requests.push(record);
|
|
285
|
-
const asstMsg = data?.message ?? null;
|
|
286
|
-
applySurface(st, ev, ev.type, data, asstMsg);
|
|
287
|
-
break;
|
|
325
|
+
s.requests.push(record);
|
|
326
|
+
const asstMsg = data?.message ?? null;
|
|
327
|
+
applySurface(s, event, event.type, data, asstMsg);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
case "compaction/summary":
|
|
331
|
+
case "compaction/prune": {
|
|
332
|
+
const s = ensure();
|
|
333
|
+
if (data && Array.isArray(data.shadowedSeqs)) {
|
|
334
|
+
s.pendingShadowedSeqs = data.shadowedSeqs.filter((x) => typeof x === "number");
|
|
288
335
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
tokens: data && typeof data.shadowedTokenCount === "number" ? data.shadowedTokenCount : 0,
|
|
298
|
-
count: data && Array.isArray(data.shadowedSeqs) ? data.shadowedSeqs.length : 0
|
|
299
|
-
});
|
|
300
|
-
break;
|
|
301
|
-
case "compaction/prune":
|
|
302
|
-
if (data && Array.isArray(data.shadowedSeqs)) {
|
|
303
|
-
st.pendingShadowedSeqs = data.shadowedSeqs.filter((s) => typeof s === "number");
|
|
304
|
-
}
|
|
305
|
-
st.events.push({
|
|
306
|
-
seq: ev.seq,
|
|
307
|
-
time: ev.time,
|
|
308
|
-
kind: "prune",
|
|
309
|
-
tokens: data && typeof data.shadowedTokenCount === "number" ? data.shadowedTokenCount : 0
|
|
310
|
-
});
|
|
311
|
-
break;
|
|
312
|
-
default:
|
|
313
|
-
break;
|
|
336
|
+
s.events.push({
|
|
337
|
+
seq: event.seq,
|
|
338
|
+
time: event.time,
|
|
339
|
+
kind: event.type === "compaction/summary" ? "compaction" : "prune",
|
|
340
|
+
tokens: data && typeof data.shadowedTokenCount === "number" ? data.shadowedTokenCount : 0,
|
|
341
|
+
...event.type === "compaction/summary" && data && Array.isArray(data.shadowedSeqs) ? { count: data.shadowedSeqs.length } : {}
|
|
342
|
+
});
|
|
343
|
+
break;
|
|
314
344
|
}
|
|
345
|
+
default:
|
|
346
|
+
return state;
|
|
315
347
|
}
|
|
316
|
-
st
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (st.requests.length > MAX_REQUEST_STEPS) st.requests = st.requests.slice(-MAX_REQUEST_STEPS);
|
|
348
|
+
if (st !== void 0) {
|
|
349
|
+
trimState(st);
|
|
350
|
+
return st;
|
|
320
351
|
}
|
|
321
|
-
|
|
352
|
+
return state;
|
|
322
353
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const surfaceTotal = st.sums.user + st.sums.inject + st.sums.assistant + st.sums.tool;
|
|
327
|
-
const projectedTokens = st.pressureTokens !== void 0 && st.sampledSurfaceTokens !== void 0 ? Math.max(0, st.pressureTokens + surfaceTotal - st.sampledSurfaceTokens) : void 0;
|
|
354
|
+
function buildTimelineView(state) {
|
|
355
|
+
const surfaceTotal = state.sums.user + state.sums.inject + state.sums.assistant + state.sums.tool;
|
|
356
|
+
const projectedTokens = state.pressureTokens !== void 0 && state.sampledSurfaceTokens !== void 0 ? Math.max(0, state.pressureTokens + surfaceTotal - state.sampledSurfaceTokens) : void 0;
|
|
328
357
|
const result = {
|
|
329
358
|
ok: true,
|
|
330
|
-
model:
|
|
331
|
-
provider:
|
|
332
|
-
contextWindow:
|
|
359
|
+
model: state.model,
|
|
360
|
+
provider: state.provider,
|
|
361
|
+
contextWindow: state.contextWindow,
|
|
333
362
|
current: {
|
|
334
|
-
system:
|
|
335
|
-
tools:
|
|
336
|
-
user:
|
|
337
|
-
inject:
|
|
338
|
-
assistant:
|
|
339
|
-
tool:
|
|
340
|
-
total: surfaceTotal +
|
|
363
|
+
system: state.systemTokens,
|
|
364
|
+
tools: state.toolsTokens,
|
|
365
|
+
user: state.sums.user,
|
|
366
|
+
inject: state.sums.inject,
|
|
367
|
+
assistant: state.sums.assistant,
|
|
368
|
+
tool: state.sums.tool,
|
|
369
|
+
total: surfaceTotal + state.systemTokens + state.toolsTokens
|
|
341
370
|
},
|
|
342
371
|
occupancy: {
|
|
343
|
-
...
|
|
372
|
+
...state.pressureTokens === void 0 ? {} : { pressureTokens: state.pressureTokens },
|
|
344
373
|
surfaceTokens: surfaceTotal,
|
|
345
|
-
...
|
|
374
|
+
...state.sampledSurfaceTokens === void 0 ? {} : { sampledSurfaceTokens: state.sampledSurfaceTokens },
|
|
346
375
|
...projectedTokens === void 0 ? {} : { projectedTokens },
|
|
347
|
-
...
|
|
376
|
+
...state.occupancyWindow === void 0 ? {} : { contextWindow: state.occupancyWindow }
|
|
348
377
|
},
|
|
349
|
-
toolList:
|
|
350
|
-
requests:
|
|
351
|
-
events:
|
|
378
|
+
toolList: state.toolList,
|
|
379
|
+
requests: state.requests.map((r) => ({ ...r })),
|
|
380
|
+
events: state.events.map((e) => ({ ...e })),
|
|
352
381
|
nodes: [],
|
|
353
382
|
droppedNodes: 0
|
|
354
383
|
};
|
|
355
|
-
|
|
356
|
-
result.
|
|
357
|
-
|
|
384
|
+
result.droppedNodes = Math.max(0, state.surface.length - MAX_NODES);
|
|
385
|
+
result.nodes = state.surface.slice(-MAX_NODES);
|
|
386
|
+
const requests = result.requests;
|
|
387
|
+
const events = result.events;
|
|
358
388
|
let ri = 0;
|
|
359
|
-
for (const ev of
|
|
360
|
-
while (ri <
|
|
361
|
-
const next =
|
|
362
|
-
const prev = ri > 0 ?
|
|
389
|
+
for (const ev of events) {
|
|
390
|
+
while (ri < requests.length && requests[ri].seq <= ev.seq) ri++;
|
|
391
|
+
const next = requests[ri];
|
|
392
|
+
const prev = ri > 0 ? requests[ri - 1] : void 0;
|
|
363
393
|
if (next !== void 0 && typeof next.turn === "number" && typeof next.step === "number") {
|
|
364
394
|
ev.turn = next.turn;
|
|
365
395
|
ev.step = next.step;
|
|
@@ -371,68 +401,97 @@ function buildResult(st) {
|
|
|
371
401
|
}
|
|
372
402
|
return result;
|
|
373
403
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
404
|
+
|
|
405
|
+
// src/host/timeline.ts
|
|
406
|
+
var surfaceNodeSchema = z.object({
|
|
407
|
+
seq: z.number().int().nonnegative(),
|
|
408
|
+
time: z.number().optional(),
|
|
409
|
+
cat: z.enum(["user", "inject", "assistant", "tool"]),
|
|
410
|
+
tokens: z.number().int().nonnegative(),
|
|
411
|
+
form: z.string().optional(),
|
|
412
|
+
text: z.string().optional(),
|
|
413
|
+
tool: z.string().optional(),
|
|
414
|
+
err: z.boolean().optional(),
|
|
415
|
+
skill: z.string().optional(),
|
|
416
|
+
calls: z.array(z.string()).optional()
|
|
417
|
+
}).strict();
|
|
418
|
+
var requestRecordSchema = z.object({
|
|
419
|
+
turn: z.number().optional(),
|
|
420
|
+
step: z.number().optional(),
|
|
421
|
+
time: z.number(),
|
|
422
|
+
seq: z.number(),
|
|
423
|
+
system: z.number().int().nonnegative(),
|
|
424
|
+
tools: z.number().int().nonnegative(),
|
|
425
|
+
user: z.number().int().nonnegative(),
|
|
426
|
+
inject: z.number().int().nonnegative(),
|
|
427
|
+
assistant: z.number().int().nonnegative(),
|
|
428
|
+
tool: z.number().int().nonnegative(),
|
|
429
|
+
total: z.number().int().nonnegative(),
|
|
430
|
+
prompt: z.number().int().nonnegative().optional(),
|
|
431
|
+
output: z.number().int().nonnegative().optional(),
|
|
432
|
+
stepCount: z.number().int().positive().optional()
|
|
433
|
+
}).strict();
|
|
434
|
+
var contextEventSchema = z.object({
|
|
435
|
+
seq: z.number(),
|
|
436
|
+
time: z.number(),
|
|
437
|
+
kind: z.enum(["compaction", "prune", "inject", "model"]),
|
|
438
|
+
form: z.string().optional(),
|
|
439
|
+
tokens: z.number().optional(),
|
|
440
|
+
count: z.number().optional(),
|
|
441
|
+
sub: z.string().optional(),
|
|
442
|
+
name: z.string().optional(),
|
|
443
|
+
from: z.string().optional(),
|
|
444
|
+
to: z.string().optional(),
|
|
445
|
+
fromTurn: z.number().optional(),
|
|
446
|
+
fromStep: z.number().optional(),
|
|
447
|
+
turn: z.number().optional(),
|
|
448
|
+
step: z.number().optional()
|
|
449
|
+
}).strict();
|
|
450
|
+
var currentSchema = z.object({
|
|
451
|
+
system: z.number().int().nonnegative(),
|
|
452
|
+
tools: z.number().int().nonnegative(),
|
|
453
|
+
user: z.number().int().nonnegative(),
|
|
454
|
+
inject: z.number().int().nonnegative(),
|
|
455
|
+
assistant: z.number().int().nonnegative(),
|
|
456
|
+
tool: z.number().int().nonnegative(),
|
|
457
|
+
total: z.number().int().nonnegative()
|
|
458
|
+
}).strict();
|
|
459
|
+
var occupancySchema = z.object({
|
|
460
|
+
pressureTokens: z.number().int().nonnegative().optional(),
|
|
461
|
+
surfaceTokens: z.number().int().nonnegative(),
|
|
462
|
+
sampledSurfaceTokens: z.number().int().nonnegative().optional(),
|
|
463
|
+
projectedTokens: z.number().int().nonnegative().optional(),
|
|
464
|
+
contextWindow: z.number().int().positive().optional()
|
|
465
|
+
}).strict();
|
|
466
|
+
var contextTimelineSchema = z.object({
|
|
467
|
+
ok: z.literal(true),
|
|
468
|
+
model: z.string().optional(),
|
|
469
|
+
provider: z.string().optional(),
|
|
470
|
+
contextWindow: z.number().optional(),
|
|
471
|
+
current: currentSchema,
|
|
472
|
+
occupancy: occupancySchema.optional(),
|
|
473
|
+
toolList: z.array(z.object({ name: z.string(), tokens: z.number().int().nonnegative() }).strict()),
|
|
474
|
+
requests: z.array(requestRecordSchema),
|
|
475
|
+
events: z.array(contextEventSchema),
|
|
476
|
+
nodes: z.array(surfaceNodeSchema),
|
|
477
|
+
droppedNodes: z.number().int().nonnegative()
|
|
478
|
+
}).strict();
|
|
479
|
+
var contextTimelineDefinition = {
|
|
480
|
+
key: "contextTimeline",
|
|
481
|
+
schema: contextTimelineSchema,
|
|
482
|
+
init: () => createTimelineState(),
|
|
483
|
+
apply: (state, event) => applyTimeline(state, event),
|
|
484
|
+
view: (state) => buildTimelineView(state),
|
|
485
|
+
stateVersion: 1
|
|
486
|
+
};
|
|
402
487
|
|
|
403
488
|
// src/host/index.ts
|
|
404
489
|
var name = "dsh-context";
|
|
405
|
-
var inject = ["
|
|
490
|
+
var inject = ["sessionProjections"];
|
|
406
491
|
function apply(ctx) {
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
"/dsh-context",
|
|
411
|
-
async (endpoint, payload) => {
|
|
412
|
-
try {
|
|
413
|
-
if (endpoint !== "snapshot") {
|
|
414
|
-
return { ok: false, error: { code: "internal", message: `unknown endpoint: ${endpoint}`, details: {} } };
|
|
415
|
-
}
|
|
416
|
-
const sessionId = payload !== null && typeof payload === "object" ? payload.sessionId : void 0;
|
|
417
|
-
if (typeof sessionId !== "string" || sessionId === "") {
|
|
418
|
-
return { ok: false, error: { code: "internal", message: "missing sessionId", details: {} } };
|
|
419
|
-
}
|
|
420
|
-
const value = await computeSnapshot(ctx, states, sessionId);
|
|
421
|
-
return { ok: true, value };
|
|
422
|
-
} catch (err) {
|
|
423
|
-
return {
|
|
424
|
-
ok: false,
|
|
425
|
-
error: {
|
|
426
|
-
code: "internal",
|
|
427
|
-
message: err instanceof Error ? err.message : String(err),
|
|
428
|
-
details: {}
|
|
429
|
-
}
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
},
|
|
433
|
-
{ authority: "trusted-host" }
|
|
434
|
-
);
|
|
435
|
-
}, "dsh-context: rpc channel");
|
|
492
|
+
ctx.inject(["sessionProjections"], (projectionCtx) => {
|
|
493
|
+
projectionCtx.sessionProjections.register(contextTimelineDefinition);
|
|
494
|
+
});
|
|
436
495
|
}
|
|
437
496
|
export {
|
|
438
497
|
apply,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Context insight panel for DeepSeek Harness: see what the model's context window is made of and how it evolves — composition, per-request history, compactions, injections, and model switches.",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Context insight panel for DeepSeek Harness: see what the model's context window is made of and how it evolves — composition, per-request history, compactions, injections, and model switches. Streamed through the harness's session-projection pipeline.",
|
|
5
5
|
"author": "bowenliang123",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -56,8 +56,15 @@
|
|
|
56
56
|
"ui"
|
|
57
57
|
],
|
|
58
58
|
"license": "Apache-2.0",
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"zod": "^4.4.3"
|
|
61
|
+
},
|
|
59
62
|
"devDependencies": {
|
|
60
63
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
64
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.6",
|
|
65
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.6",
|
|
66
|
+
"@deepseek-ai/dsh-session-projection": "0.1.0-rc.6",
|
|
67
|
+
"@deepseek-ai/dsh-token-meter": "0.1.0-rc.6",
|
|
61
68
|
"@types/react": "^18.3.31",
|
|
62
69
|
"esbuild": "^0.28.2",
|
|
63
70
|
"husky": "^9.1.7",
|