dsh-context 0.67.0 → 0.68.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 +15 -6
- package/lib/client.js +9 -9
- package/lib/index.d.ts +5 -0
- package/lib/index.js +280 -47
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -221,6 +221,8 @@ type DefaultToolSort = 'size' | 'count' | 'name';
|
|
|
221
221
|
type DefaultPlacement = 'all' | 'tab' | 'sidebar';
|
|
222
222
|
type InsightsEntry = 'show' | 'hide';
|
|
223
223
|
type DefaultDurationCurve = 'show' | 'hide';
|
|
224
|
+
/** Whether the Fleet conversation tab is served. */
|
|
225
|
+
type FleetTab = 'show' | 'hide';
|
|
224
226
|
interface PluginSettings {
|
|
225
227
|
defaultPlacement: DefaultPlacement;
|
|
226
228
|
defaultGranularity: DefaultGranularity;
|
|
@@ -230,6 +232,7 @@ interface PluginSettings {
|
|
|
230
232
|
defaultFileSort: DefaultFileSort;
|
|
231
233
|
insightsEntry: InsightsEntry;
|
|
232
234
|
defaultDurationCurve: DefaultDurationCurve;
|
|
235
|
+
fleetTab: FleetTab;
|
|
233
236
|
}
|
|
234
237
|
interface Snapshot {
|
|
235
238
|
ok: boolean;
|
|
@@ -559,6 +562,7 @@ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
|
559
562
|
defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", "defined">;
|
|
560
563
|
insightsEntry: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
561
564
|
defaultDurationCurve: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
565
|
+
fleetTab: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
562
566
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
563
567
|
maxRequestSteps: z$1<number, number, "defined">;
|
|
564
568
|
maxKeptTurns: z$1<number, number, "defined">;
|
|
@@ -574,6 +578,7 @@ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
|
574
578
|
defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", "defined">;
|
|
575
579
|
insightsEntry: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
576
580
|
defaultDurationCurve: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
581
|
+
fleetTab: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
577
582
|
}>>, "plain">;
|
|
578
583
|
//#endregion
|
|
579
584
|
//#region src/host/index.d.ts
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-context v0.
|
|
2
|
+
* dsh-context v0.68.0
|
|
3
3
|
* 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.
|
|
4
4
|
* @author bowenliang123
|
|
5
5
|
* @license Apache-2.0
|
|
6
6
|
* @homepage https://github.com/bowenliang123/dsh-context
|
|
7
|
-
* @built 2026-10-
|
|
8
|
-
* @commit
|
|
9
|
-
* @commit-date 2026-10-
|
|
7
|
+
* @built 2026-10-11T02:40:54+00:00
|
|
8
|
+
* @commit 425fd2e7b82e
|
|
9
|
+
* @commit-date 2026-10-11T10:37:14+08:00
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createRequire } from "node:module";
|
|
@@ -946,7 +946,7 @@ function removeSurfaceSeqs(st, claimed, goneSeq) {
|
|
|
946
946
|
st.surface = kept;
|
|
947
947
|
return removed;
|
|
948
948
|
}
|
|
949
|
-
function messageOf$
|
|
949
|
+
function messageOf$2(data) {
|
|
950
950
|
const message = data?.message;
|
|
951
951
|
return message !== null && typeof message === "object" ? message : null;
|
|
952
952
|
}
|
|
@@ -1127,7 +1127,7 @@ function applyTimeline(state, event, bounds) {
|
|
|
1127
1127
|
pushSystem(s, {
|
|
1128
1128
|
seq: event.seq,
|
|
1129
1129
|
time: event.time,
|
|
1130
|
-
tokens: estimateSystemContent(messageOf$
|
|
1130
|
+
tokens: estimateSystemContent(messageOf$2(data)?.content)
|
|
1131
1131
|
});
|
|
1132
1132
|
break;
|
|
1133
1133
|
}
|
|
@@ -1284,7 +1284,7 @@ function applyTimeline(state, event, bounds) {
|
|
|
1284
1284
|
case "user/message":
|
|
1285
1285
|
case "developer/message": {
|
|
1286
1286
|
const developer = event.type === "developer/message";
|
|
1287
|
-
const msg = developer ? messageOf$
|
|
1287
|
+
const msg = developer ? messageOf$2(data) : deriveEventMessage(event);
|
|
1288
1288
|
if (developer && (msg === null || !Array.isArray(msg.content))) return state;
|
|
1289
1289
|
const s = ensure([
|
|
1290
1290
|
"surface",
|
|
@@ -1557,7 +1557,8 @@ const Config = z$1.object({
|
|
|
1557
1557
|
"path"
|
|
1558
1558
|
]).default("count").loose()),
|
|
1559
1559
|
insightsEntry: volatileField(z$1.union(["show", "hide"]).default("show").loose()),
|
|
1560
|
-
defaultDurationCurve: volatileField(z$1.union(["show", "hide"]).default("show").loose())
|
|
1560
|
+
defaultDurationCurve: volatileField(z$1.union(["show", "hide"]).default("show").loose()),
|
|
1561
|
+
fleetTab: volatileField(z$1.union(["show", "hide"]).default("show").loose())
|
|
1561
1562
|
});
|
|
1562
1563
|
function resolveBounds(config) {
|
|
1563
1564
|
const resolved = Config(config ?? {});
|
|
@@ -2185,7 +2186,7 @@ function createToolAttribution(ctx) {
|
|
|
2185
2186
|
}
|
|
2186
2187
|
//#endregion
|
|
2187
2188
|
//#region src/host/record.ts
|
|
2188
|
-
function asRecord(value) {
|
|
2189
|
+
function asRecord$1(value) {
|
|
2189
2190
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2190
2191
|
}
|
|
2191
2192
|
//#endregion
|
|
@@ -2226,9 +2227,9 @@ function deepseekSectionOf(ctx) {
|
|
|
2226
2227
|
if (!Array.isArray(rows)) return null;
|
|
2227
2228
|
let shaped = null;
|
|
2228
2229
|
for (const row of rows) try {
|
|
2229
|
-
const record = asRecord(row);
|
|
2230
|
+
const record = asRecord$1(row);
|
|
2230
2231
|
if (record === null) continue;
|
|
2231
|
-
const value = asRecord(record.value);
|
|
2232
|
+
const value = asRecord$1(record.value);
|
|
2232
2233
|
if (value === null || typeof value.apiKeyEnv !== "string" || value.apiKeyEnv === "") continue;
|
|
2233
2234
|
if (record.ns === DEEPSEEK_SETTINGS_NS || record.ns === "llm-deepseek-api-key") return value;
|
|
2234
2235
|
shaped ??= value;
|
|
@@ -2261,12 +2262,12 @@ async function resolveFacts(ctx) {
|
|
|
2261
2262
|
};
|
|
2262
2263
|
}
|
|
2263
2264
|
function balanceOfPayload(value) {
|
|
2264
|
-
const data = asRecord(value);
|
|
2265
|
+
const data = asRecord$1(value);
|
|
2265
2266
|
if (data === null) return null;
|
|
2266
2267
|
const infos = Array.isArray(data.balance_infos) ? data.balance_infos : [];
|
|
2267
2268
|
const balances = [];
|
|
2268
2269
|
for (const info of infos) try {
|
|
2269
|
-
const entry = asRecord(info);
|
|
2270
|
+
const entry = asRecord$1(info);
|
|
2270
2271
|
if (entry === null) continue;
|
|
2271
2272
|
const currency = entry.currency;
|
|
2272
2273
|
const granted = amountOf(entry.granted_balance);
|
|
@@ -2359,7 +2360,7 @@ const BACKFILL_ROUTE = "/api/dsh-context/backfill";
|
|
|
2359
2360
|
const YIELD_MS = 100;
|
|
2360
2361
|
const UNSUPPORTED_FORMAT = "SessionFormatUnsupported";
|
|
2361
2362
|
function headerOf(record) {
|
|
2362
|
-
const header = asRecord(asRecord(record)?.header);
|
|
2363
|
+
const header = asRecord$1(asRecord$1(record)?.header);
|
|
2363
2364
|
if (header === null) return null;
|
|
2364
2365
|
if (typeof header.id !== "string" || header.id === "") return null;
|
|
2365
2366
|
return header;
|
|
@@ -2367,7 +2368,7 @@ function headerOf(record) {
|
|
|
2367
2368
|
const PROBE_KEYS = ["contextActivity", "contextTimeline"];
|
|
2368
2369
|
function servesRows(cache, header) {
|
|
2369
2370
|
try {
|
|
2370
|
-
const values = asRecord(asRecord(cache.cachedSnapshot(header, PROBE_KEYS))?.values);
|
|
2371
|
+
const values = asRecord$1(asRecord$1(cache.cachedSnapshot(header, PROBE_KEYS))?.values);
|
|
2371
2372
|
return values !== null && values.contextActivity !== void 0 && values.contextTimeline !== void 0;
|
|
2372
2373
|
} catch {
|
|
2373
2374
|
return false;
|
|
@@ -2377,7 +2378,7 @@ async function readColdLog(persistence, id, signal) {
|
|
|
2377
2378
|
const handle = await persistence.open(id, "read", { signal });
|
|
2378
2379
|
let events;
|
|
2379
2380
|
try {
|
|
2380
|
-
const result = asRecord(await handle.read(0, void 0, { signal }))?.events;
|
|
2381
|
+
const result = asRecord$1(await handle.read(0, void 0, { signal }))?.events;
|
|
2381
2382
|
events = Array.isArray(result) ? result : [];
|
|
2382
2383
|
} catch (error) {
|
|
2383
2384
|
try {
|
|
@@ -2402,12 +2403,12 @@ function isLive(sessions, id) {
|
|
|
2402
2403
|
}
|
|
2403
2404
|
function isUnsupportedFormat(error) {
|
|
2404
2405
|
try {
|
|
2405
|
-
return String(asRecord(error)?.name).startsWith(UNSUPPORTED_FORMAT);
|
|
2406
|
+
return String(asRecord$1(error)?.name).startsWith(UNSUPPORTED_FORMAT);
|
|
2406
2407
|
} catch {
|
|
2407
2408
|
return false;
|
|
2408
2409
|
}
|
|
2409
2410
|
}
|
|
2410
|
-
function messageOf(error) {
|
|
2411
|
+
function messageOf$1(error) {
|
|
2411
2412
|
try {
|
|
2412
2413
|
return String(error);
|
|
2413
2414
|
} catch {
|
|
@@ -2438,13 +2439,13 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2438
2439
|
"sessions"
|
|
2439
2440
|
], (raw) => {
|
|
2440
2441
|
const injected = raw;
|
|
2441
|
-
const query = asRecord(injected.sessionQuery);
|
|
2442
|
-
const cache = asRecord(injected.sessionProjectionCache);
|
|
2443
|
-
const persistence = asRecord(injected.sessionPersistence);
|
|
2442
|
+
const query = asRecord$1(injected.sessionQuery);
|
|
2443
|
+
const cache = asRecord$1(injected.sessionProjectionCache);
|
|
2444
|
+
const persistence = asRecord$1(injected.sessionPersistence);
|
|
2444
2445
|
if (query === null || typeof query.listSessions !== "function") return;
|
|
2445
2446
|
if (cache === null || typeof cache.cachedSnapshot !== "function" || typeof cache.coldSnapshot !== "function") return;
|
|
2446
2447
|
if (persistence === null || typeof persistence.open !== "function") return;
|
|
2447
|
-
const sessions = asRecord(injected.sessions);
|
|
2448
|
+
const sessions = asRecord$1(injected.sessions);
|
|
2448
2449
|
const abort = new AbortController();
|
|
2449
2450
|
const run = async () => {
|
|
2450
2451
|
const listed = await query.listSessions(abort.signal);
|
|
@@ -2471,8 +2472,8 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2471
2472
|
} catch (error) {
|
|
2472
2473
|
if (isUnsupportedFormat(error)) {
|
|
2473
2474
|
refused++;
|
|
2474
|
-
ctx.logger.debug(`dsh-context: projection backfill skipped "${header.id}" (${messageOf(error)})`);
|
|
2475
|
-
} else ctx.logger.warn(`dsh-context: projection backfill skipped "${header.id}" (${messageOf(error)})`);
|
|
2475
|
+
ctx.logger.debug(`dsh-context: projection backfill skipped "${header.id}" (${messageOf$1(error)})`);
|
|
2476
|
+
} else ctx.logger.warn(`dsh-context: projection backfill skipped "${header.id}" (${messageOf$1(error)})`);
|
|
2476
2477
|
}
|
|
2477
2478
|
await new Promise((resolve) => setTimeout(resolve, YIELD_MS));
|
|
2478
2479
|
}
|
|
@@ -2482,7 +2483,7 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2482
2483
|
};
|
|
2483
2484
|
launch = () => {
|
|
2484
2485
|
run().catch((error) => {
|
|
2485
|
-
if (!abort.signal.aborted) ctx.logger.warn(`dsh-context: projection backfill stopped early (${messageOf(error)})`);
|
|
2486
|
+
if (!abort.signal.aborted) ctx.logger.warn(`dsh-context: projection backfill stopped early (${messageOf$1(error)})`);
|
|
2486
2487
|
});
|
|
2487
2488
|
};
|
|
2488
2489
|
tryLaunch();
|
|
@@ -2494,11 +2495,11 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2494
2495
|
for (const fiber of [routeFiber, runnerFiber]) fiber?.dispose?.();
|
|
2495
2496
|
};
|
|
2496
2497
|
}
|
|
2497
|
-
function reply(value) {
|
|
2498
|
+
function reply$1(value) {
|
|
2498
2499
|
return Response.json(value, { headers: { "cache-control": "no-store" } });
|
|
2499
2500
|
}
|
|
2500
|
-
function failure(code, message) {
|
|
2501
|
-
return reply({
|
|
2501
|
+
function failure$1(code, message) {
|
|
2502
|
+
return reply$1({
|
|
2502
2503
|
ok: false,
|
|
2503
2504
|
error: {
|
|
2504
2505
|
code,
|
|
@@ -2519,29 +2520,29 @@ function watchDetailChannel(ctx, bounds, coldReads = makeColdReadGate()) {
|
|
|
2519
2520
|
const body = await request.json();
|
|
2520
2521
|
sessionId = body !== null && typeof body === "object" ? body.sessionId : void 0;
|
|
2521
2522
|
} catch {
|
|
2522
|
-
return failure("dsh-context/bad-request", "body is not JSON");
|
|
2523
|
+
return failure$1("dsh-context/bad-request", "body is not JSON");
|
|
2523
2524
|
}
|
|
2524
|
-
if (typeof sessionId !== "string" || sessionId === "") return failure("dsh-context/bad-request", "missing sessionId");
|
|
2525
|
+
if (typeof sessionId !== "string" || sessionId === "") return failure$1("dsh-context/bad-request", "missing sessionId");
|
|
2525
2526
|
try {
|
|
2526
2527
|
const session = getSession(sessionId);
|
|
2527
2528
|
if (session !== void 0 && session !== null) {
|
|
2528
2529
|
const state = projections.stateOf(session, "contextTimeline");
|
|
2529
|
-
if (state === void 0) return reply({
|
|
2530
|
+
if (state === void 0) return reply$1({
|
|
2530
2531
|
ok: true,
|
|
2531
2532
|
value: null
|
|
2532
2533
|
});
|
|
2533
|
-
return reply({
|
|
2534
|
+
return reply$1({
|
|
2534
2535
|
ok: true,
|
|
2535
2536
|
value: buildTimelineDetail(state, bounds)
|
|
2536
2537
|
});
|
|
2537
2538
|
}
|
|
2538
2539
|
const query = ctx.get("sessionQuery");
|
|
2539
2540
|
const observe = typeof query?.observeSession === "function" ? query.observeSession.bind(query) : void 0;
|
|
2540
|
-
if (observe === void 0) return reply({
|
|
2541
|
+
if (observe === void 0) return reply$1({
|
|
2541
2542
|
ok: true,
|
|
2542
2543
|
value: null
|
|
2543
2544
|
});
|
|
2544
|
-
return reply({
|
|
2545
|
+
return reply$1({
|
|
2545
2546
|
ok: true,
|
|
2546
2547
|
value: await coldReads.admit(async () => {
|
|
2547
2548
|
const observation = await observe(sessionId, { projectionMode: "none" });
|
|
@@ -2558,7 +2559,7 @@ function watchDetailChannel(ctx, bounds, coldReads = makeColdReadGate()) {
|
|
|
2558
2559
|
}) ?? null
|
|
2559
2560
|
});
|
|
2560
2561
|
} catch (err) {
|
|
2561
|
-
return failure("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2562
|
+
return failure$1("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2562
2563
|
}
|
|
2563
2564
|
};
|
|
2564
2565
|
if (!registerPostRoute(c, c.get("connection"), "/api/dsh-context/detail", handler, "dsh-context: detail route")) return;
|
|
@@ -2738,6 +2739,237 @@ function createFallbackActivityDefinition() {
|
|
|
2738
2739
|
return fallbackDefinition("contextActivity", contextActivitySchema, { days: {} });
|
|
2739
2740
|
}
|
|
2740
2741
|
//#endregion
|
|
2742
|
+
//#region src/host/fleet.ts
|
|
2743
|
+
const FLEET_ROUTE = "/api/dsh-context/fleet";
|
|
2744
|
+
const MESSAGES_MAX = 40;
|
|
2745
|
+
const MESSAGE_TEXT_MAX = 400;
|
|
2746
|
+
const PROMPT_TEXT_MAX = 1600;
|
|
2747
|
+
const REPLY_TEXT_MAX = 300;
|
|
2748
|
+
function reply(value) {
|
|
2749
|
+
return Response.json(value, { headers: { "cache-control": "no-store" } });
|
|
2750
|
+
}
|
|
2751
|
+
function failure(code, message) {
|
|
2752
|
+
return reply({
|
|
2753
|
+
ok: false,
|
|
2754
|
+
error: {
|
|
2755
|
+
code,
|
|
2756
|
+
message
|
|
2757
|
+
}
|
|
2758
|
+
});
|
|
2759
|
+
}
|
|
2760
|
+
function asRecord(value) {
|
|
2761
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2762
|
+
}
|
|
2763
|
+
function textOfContent(content) {
|
|
2764
|
+
if (!Array.isArray(content)) return "";
|
|
2765
|
+
let out = "";
|
|
2766
|
+
for (const block of content) {
|
|
2767
|
+
const text = asRecord(block)?.text;
|
|
2768
|
+
if (typeof text === "string") out += text;
|
|
2769
|
+
}
|
|
2770
|
+
return out;
|
|
2771
|
+
}
|
|
2772
|
+
const REMINDER_PREFIX = /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*/;
|
|
2773
|
+
function clip(text, max) {
|
|
2774
|
+
return text.length > max ? {
|
|
2775
|
+
text: text.slice(0, max) + "…",
|
|
2776
|
+
cut: true
|
|
2777
|
+
} : {
|
|
2778
|
+
text,
|
|
2779
|
+
cut: false
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
function descriptorOf(data) {
|
|
2783
|
+
const mode = data.mode;
|
|
2784
|
+
if (mode !== "one-shot" && mode !== "continuable") return null;
|
|
2785
|
+
const out = { mode };
|
|
2786
|
+
for (const key of [
|
|
2787
|
+
"label",
|
|
2788
|
+
"provider",
|
|
2789
|
+
"agentProvider",
|
|
2790
|
+
"agentModel",
|
|
2791
|
+
"persona"
|
|
2792
|
+
]) {
|
|
2793
|
+
const value = data[key];
|
|
2794
|
+
if (typeof value === "string" && value !== "") out[key] = value;
|
|
2795
|
+
}
|
|
2796
|
+
return out;
|
|
2797
|
+
}
|
|
2798
|
+
const MAILBOX_PREFIX = /^Team message \S+ from [^:]{1,64}:\s*/;
|
|
2799
|
+
const RELAY_PREFIX = /^(?:Agent \S+ sent a message: |Team message from [^:\n]{1,64}:\s*)/;
|
|
2800
|
+
function messageOf(seq, time, data) {
|
|
2801
|
+
const source = asRecord(data.source);
|
|
2802
|
+
const kind = source?.kind;
|
|
2803
|
+
let message = null;
|
|
2804
|
+
if (kind === "agent-message" || kind === "team-message") {
|
|
2805
|
+
let text = textOfContent(data.content);
|
|
2806
|
+
text = text.replace(kind === "team-message" ? MAILBOX_PREFIX : RELAY_PREFIX, "");
|
|
2807
|
+
if (text.trim() === "") return null;
|
|
2808
|
+
message = {
|
|
2809
|
+
seq,
|
|
2810
|
+
time,
|
|
2811
|
+
kind: kind === "agent-message" ? "relay" : "mailbox",
|
|
2812
|
+
text
|
|
2813
|
+
};
|
|
2814
|
+
const from = kind === "agent-message" ? source?.senderSessionId : source?.senderId;
|
|
2815
|
+
if (typeof from === "string" && from !== "") message.from = from;
|
|
2816
|
+
const fromName = source?.senderName;
|
|
2817
|
+
if (typeof fromName === "string" && fromName !== "") message.fromName = fromName;
|
|
2818
|
+
} else if (kind === "subagent-settled") {
|
|
2819
|
+
const summary = source?.summary;
|
|
2820
|
+
const text = typeof summary === "string" && summary.trim() !== "" ? summary : textOfContent(data.content);
|
|
2821
|
+
if (text.trim() === "") return null;
|
|
2822
|
+
message = {
|
|
2823
|
+
seq,
|
|
2824
|
+
time,
|
|
2825
|
+
kind: "settled",
|
|
2826
|
+
text
|
|
2827
|
+
};
|
|
2828
|
+
const from = source?.senderSessionId;
|
|
2829
|
+
if (typeof from === "string" && from !== "") message.from = from;
|
|
2830
|
+
}
|
|
2831
|
+
if (message === null) return null;
|
|
2832
|
+
const cut = clip(message.text, MESSAGE_TEXT_MAX);
|
|
2833
|
+
message.text = cut.text;
|
|
2834
|
+
return message;
|
|
2835
|
+
}
|
|
2836
|
+
function isPlainPrompt(source) {
|
|
2837
|
+
if (source === null) return true;
|
|
2838
|
+
return source.kind === "user";
|
|
2839
|
+
}
|
|
2840
|
+
function rosterMemberOf(data) {
|
|
2841
|
+
const member = asRecord(data.member);
|
|
2842
|
+
if (member === null) return null;
|
|
2843
|
+
if (typeof member.name !== "string" || member.name === "") return null;
|
|
2844
|
+
const out = {
|
|
2845
|
+
name: member.name,
|
|
2846
|
+
description: typeof member.description === "string" ? member.description : ""
|
|
2847
|
+
};
|
|
2848
|
+
if (typeof member.provider === "string" && member.provider !== "") out.provider = member.provider;
|
|
2849
|
+
if (member.context === "fresh" || member.context === "fork") out.context = member.context;
|
|
2850
|
+
return out;
|
|
2851
|
+
}
|
|
2852
|
+
function lastReplyOf(events) {
|
|
2853
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
2854
|
+
const ev = asRecord(events[i]);
|
|
2855
|
+
if (ev === null || ev.type !== "assistant/message") continue;
|
|
2856
|
+
const content = asRecord(asRecord(ev.data)?.message)?.content;
|
|
2857
|
+
if (!Array.isArray(content)) continue;
|
|
2858
|
+
let text = "";
|
|
2859
|
+
for (const block of content) {
|
|
2860
|
+
const b = asRecord(block);
|
|
2861
|
+
if (b?.type === "text" && typeof b.text === "string") text += b.text;
|
|
2862
|
+
}
|
|
2863
|
+
if (text.trim() === "") continue;
|
|
2864
|
+
const time = typeof ev.time === "number" && Number.isFinite(ev.time) ? ev.time : 0;
|
|
2865
|
+
const cut = clip(text, REPLY_TEXT_MAX);
|
|
2866
|
+
return {
|
|
2867
|
+
time,
|
|
2868
|
+
text: cut.text,
|
|
2869
|
+
cut: cut.cut
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2872
|
+
return null;
|
|
2873
|
+
}
|
|
2874
|
+
function fleetDetailOfEvents(events) {
|
|
2875
|
+
let descriptor;
|
|
2876
|
+
let initialPrompt;
|
|
2877
|
+
let truncated = false;
|
|
2878
|
+
const messages = [];
|
|
2879
|
+
const roster = new Map();
|
|
2880
|
+
for (const entry of events) {
|
|
2881
|
+
const ev = asRecord(entry);
|
|
2882
|
+
if (ev === null) continue;
|
|
2883
|
+
const type = ev.type;
|
|
2884
|
+
if (typeof type !== "string") continue;
|
|
2885
|
+
const seq = typeof ev.seq === "number" && Number.isFinite(ev.seq) ? ev.seq : 0;
|
|
2886
|
+
const time = typeof ev.time === "number" && Number.isFinite(ev.time) ? ev.time : 0;
|
|
2887
|
+
const data = asRecord(ev.data);
|
|
2888
|
+
if (data === null) continue;
|
|
2889
|
+
if (type === "subagent/descriptor") {
|
|
2890
|
+
const next = descriptorOf(data);
|
|
2891
|
+
if (next !== null) descriptor = next;
|
|
2892
|
+
continue;
|
|
2893
|
+
}
|
|
2894
|
+
if (type === "team/member") {
|
|
2895
|
+
const member = rosterMemberOf(data);
|
|
2896
|
+
if (member !== null) roster.set(member.name, member);
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
if (type !== "user/message") continue;
|
|
2900
|
+
const message = messageOf(seq, time, data);
|
|
2901
|
+
if (message !== null) {
|
|
2902
|
+
if (message.text.endsWith("…")) truncated = true;
|
|
2903
|
+
messages.push(message);
|
|
2904
|
+
continue;
|
|
2905
|
+
}
|
|
2906
|
+
if (initialPrompt === void 0 && isPlainPrompt(asRecord(data.source))) {
|
|
2907
|
+
const text = textOfContent(data.content).replace(REMINDER_PREFIX, "");
|
|
2908
|
+
if (text.trim() !== "") {
|
|
2909
|
+
const cut = clip(text, PROMPT_TEXT_MAX);
|
|
2910
|
+
initialPrompt = cut.text;
|
|
2911
|
+
if (cut.cut) truncated = true;
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
}
|
|
2915
|
+
messages.sort((a, b) => b.seq - a.seq);
|
|
2916
|
+
if (messages.length > MESSAGES_MAX) {
|
|
2917
|
+
messages.length = MESSAGES_MAX;
|
|
2918
|
+
truncated = true;
|
|
2919
|
+
}
|
|
2920
|
+
const reply = lastReplyOf(events);
|
|
2921
|
+
if (reply !== null && reply.cut) truncated = true;
|
|
2922
|
+
return {
|
|
2923
|
+
...descriptor !== void 0 ? { descriptor } : {},
|
|
2924
|
+
...initialPrompt !== void 0 ? { initialPrompt } : {},
|
|
2925
|
+
...reply !== null ? { lastReply: {
|
|
2926
|
+
time: reply.time,
|
|
2927
|
+
text: reply.text
|
|
2928
|
+
} } : {},
|
|
2929
|
+
...roster.size > 0 ? { roster: [...roster.values()] } : {},
|
|
2930
|
+
messages,
|
|
2931
|
+
truncated
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
function watchFleetChannel(ctx, coldReads = makeColdReadGate()) {
|
|
2935
|
+
ctx.inject(["connection"], (c) => {
|
|
2936
|
+
const handler = async (request) => {
|
|
2937
|
+
let sessionId;
|
|
2938
|
+
try {
|
|
2939
|
+
sessionId = asRecord(await request.json())?.sessionId;
|
|
2940
|
+
} catch {
|
|
2941
|
+
return failure("dsh-context/bad-request", "body is not JSON");
|
|
2942
|
+
}
|
|
2943
|
+
if (typeof sessionId !== "string" || sessionId === "") return failure("dsh-context/bad-request", "missing sessionId");
|
|
2944
|
+
try {
|
|
2945
|
+
const query = ctx.get("sessionQuery");
|
|
2946
|
+
const observe = typeof query?.observeSession === "function" ? query.observeSession.bind(query) : void 0;
|
|
2947
|
+
if (observe === void 0) return reply({
|
|
2948
|
+
ok: true,
|
|
2949
|
+
value: null
|
|
2950
|
+
});
|
|
2951
|
+
return reply({
|
|
2952
|
+
ok: true,
|
|
2953
|
+
value: await coldReads.admit(async () => {
|
|
2954
|
+
const observation = await observe(sessionId, { projectionMode: "none" });
|
|
2955
|
+
const events = observation?.events;
|
|
2956
|
+
if (!Array.isArray(events)) return null;
|
|
2957
|
+
try {
|
|
2958
|
+
return fleetDetailOfEvents(events);
|
|
2959
|
+
} finally {
|
|
2960
|
+
const dispose = observation?.[Symbol.dispose];
|
|
2961
|
+
if (typeof dispose === "function") dispose.call(observation);
|
|
2962
|
+
}
|
|
2963
|
+
}) ?? null
|
|
2964
|
+
});
|
|
2965
|
+
} catch (err) {
|
|
2966
|
+
return failure("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2967
|
+
}
|
|
2968
|
+
};
|
|
2969
|
+
registerPostRoute(c, c.get("connection"), FLEET_ROUTE, handler, "dsh-context: fleet route");
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
//#endregion
|
|
2741
2973
|
//#region src/host/stepIdentity.ts
|
|
2742
2974
|
const MINTED_ID_PREFIX = "dshctx-";
|
|
2743
2975
|
function lacksId(message) {
|
|
@@ -2795,7 +3027,7 @@ async function disposeOf(resource) {
|
|
|
2795
3027
|
} catch {}
|
|
2796
3028
|
}
|
|
2797
3029
|
function skillInfoOf(value) {
|
|
2798
|
-
const record = asRecord(value);
|
|
3030
|
+
const record = asRecord$1(value);
|
|
2799
3031
|
if (record === null || typeof record.name !== "string" || record.name === "") return null;
|
|
2800
3032
|
return {
|
|
2801
3033
|
name: record.name,
|
|
@@ -2806,7 +3038,7 @@ function skillInfoOf(value) {
|
|
|
2806
3038
|
}
|
|
2807
3039
|
async function sessionViewOf(ctx, sessionId) {
|
|
2808
3040
|
if (sessionId === void 0) return {};
|
|
2809
|
-
const query = asRecord(ctx.get("sessionQuery"));
|
|
3041
|
+
const query = asRecord$1(ctx.get("sessionQuery"));
|
|
2810
3042
|
if (typeof query?.observeSession !== "function") return {};
|
|
2811
3043
|
let observation;
|
|
2812
3044
|
try {
|
|
@@ -2815,9 +3047,9 @@ async function sessionViewOf(ctx, sessionId) {
|
|
|
2815
3047
|
return {};
|
|
2816
3048
|
}
|
|
2817
3049
|
try {
|
|
2818
|
-
const obs = asRecord(observation);
|
|
2819
|
-
const cwd = stringOf(asRecord(obs?.header)?.cwd);
|
|
2820
|
-
const agentPreset = stringOf(asRecord(asRecord(obs?.projections)?.values)?.agentPreset);
|
|
3050
|
+
const obs = asRecord$1(observation);
|
|
3051
|
+
const cwd = stringOf(asRecord$1(obs?.header)?.cwd);
|
|
3052
|
+
const agentPreset = stringOf(asRecord$1(asRecord$1(obs?.projections)?.values)?.agentPreset);
|
|
2821
3053
|
return {
|
|
2822
3054
|
...cwd === void 0 ? {} : { cwd },
|
|
2823
3055
|
...agentPreset === void 0 ? {} : { agentPreset }
|
|
@@ -2827,10 +3059,10 @@ async function sessionViewOf(ctx, sessionId) {
|
|
|
2827
3059
|
}
|
|
2828
3060
|
}
|
|
2829
3061
|
async function resolveRegistry(ctx, sessionId, agentPreset) {
|
|
2830
|
-
const presets = asRecord(ctx.get("agentPresets"));
|
|
3062
|
+
const presets = asRecord$1(ctx.get("agentPresets"));
|
|
2831
3063
|
let live;
|
|
2832
3064
|
if (sessionId !== void 0) {
|
|
2833
|
-
const agents = asRecord(ctx.get("agents"));
|
|
3065
|
+
const agents = asRecord$1(ctx.get("agents"));
|
|
2834
3066
|
if (typeof agents?.get === "function") try {
|
|
2835
3067
|
live = agents.get.call(agents, sessionId);
|
|
2836
3068
|
} catch {
|
|
@@ -2838,20 +3070,20 @@ async function resolveRegistry(ctx, sessionId, agentPreset) {
|
|
|
2838
3070
|
}
|
|
2839
3071
|
}
|
|
2840
3072
|
if (live !== void 0 && live !== null && typeof presets?.serviceFor === "function") {
|
|
2841
|
-
const scoped = asRecord(presets.serviceFor.call(presets, live, "skills"));
|
|
3073
|
+
const scoped = asRecord$1(presets.serviceFor.call(presets, live, "skills"));
|
|
2842
3074
|
if (scoped !== null && typeof scoped.list === "function") return {
|
|
2843
3075
|
registry: scoped,
|
|
2844
3076
|
scope: live,
|
|
2845
3077
|
lease: void 0
|
|
2846
3078
|
};
|
|
2847
3079
|
}
|
|
2848
|
-
const registry = asRecord(ctx.get("skills"));
|
|
3080
|
+
const registry = asRecord$1(ctx.get("skills"));
|
|
2849
3081
|
if (registry === null || typeof registry.list !== "function") return null;
|
|
2850
3082
|
let scope;
|
|
2851
3083
|
let lease;
|
|
2852
3084
|
if (typeof presets?.acquireScope === "function") try {
|
|
2853
3085
|
lease = await presets.acquireScope.call(presets, agentPreset);
|
|
2854
|
-
scope = asRecord(lease)?.key;
|
|
3086
|
+
scope = asRecord$1(lease)?.key;
|
|
2855
3087
|
} catch {
|
|
2856
3088
|
lease = void 0;
|
|
2857
3089
|
}
|
|
@@ -2867,7 +3099,7 @@ function watchSkillCatalog(ctx) {
|
|
|
2867
3099
|
let value = null;
|
|
2868
3100
|
let lease;
|
|
2869
3101
|
try {
|
|
2870
|
-
const body = asRecord(await request.json());
|
|
3102
|
+
const body = asRecord$1(await request.json());
|
|
2871
3103
|
const sessionId = stringOf(body?.sessionId);
|
|
2872
3104
|
const view = await sessionViewOf(ctx, sessionId);
|
|
2873
3105
|
const cwd = view.cwd ?? stringOf(body?.cwd);
|
|
@@ -2991,8 +3223,10 @@ function detectHarnessVersion(ctx, resolveUrl = resolveRunningModule, pluginRoot
|
|
|
2991
3223
|
const name = "dsh-context";
|
|
2992
3224
|
const inject = ["sessionProjections"];
|
|
2993
3225
|
function apply(ctx, config) {
|
|
3226
|
+
const coldReads = makeColdReadGate();
|
|
2994
3227
|
watchBalanceChannel(ctx);
|
|
2995
3228
|
watchSkillCatalog(ctx);
|
|
3229
|
+
watchFleetChannel(ctx, coldReads);
|
|
2996
3230
|
const harnessVersion = detectHarnessVersion(ctx);
|
|
2997
3231
|
if (harnessVersion !== void 0 && !meetsBaseline(harnessVersion)) {
|
|
2998
3232
|
ctx.sessionProjections.register(createFallbackTimelineDefinition(harnessVersion));
|
|
@@ -3002,7 +3236,6 @@ function apply(ctx, config) {
|
|
|
3002
3236
|
}
|
|
3003
3237
|
const attribution = createToolAttribution(ctx);
|
|
3004
3238
|
watchStepIdentity(ctx);
|
|
3005
|
-
const coldReads = makeColdReadGate();
|
|
3006
3239
|
const gate = watchDetailChannel(ctx, resolveBounds(config), coldReads);
|
|
3007
3240
|
ctx.sessionProjections.register(createContextTimelineDefinition(config, () => gate.live));
|
|
3008
3241
|
ctx.sessionProjections.register(createContextHeadersDefinition((name) => attribution.ownerOf(name)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.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",
|