dsh-context 0.67.0 → 0.68.1
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 +18 -7
- package/lib/client.js +10 -9
- package/lib/index.d.ts +13 -0
- package/lib/index.js +321 -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,11 @@ interface PluginSettings {
|
|
|
230
232
|
defaultFileSort: DefaultFileSort;
|
|
231
233
|
insightsEntry: InsightsEntry;
|
|
232
234
|
defaultDurationCurve: DefaultDurationCurve;
|
|
235
|
+
fleetTab: FleetTab;
|
|
236
|
+
/** Free text joined ahead of the harness's assembled system prompt; empty disables. */
|
|
237
|
+
promptPrefix: string;
|
|
238
|
+
/** Free text joined behind the harness's assembled system prompt; empty disables. */
|
|
239
|
+
promptSuffix: string;
|
|
233
240
|
}
|
|
234
241
|
interface Snapshot {
|
|
235
242
|
ok: boolean;
|
|
@@ -559,6 +566,9 @@ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
|
559
566
|
defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", "defined">;
|
|
560
567
|
insightsEntry: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
561
568
|
defaultDurationCurve: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
569
|
+
fleetTab: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
570
|
+
promptPrefix: z$1<string, string, "defined">;
|
|
571
|
+
promptSuffix: z$1<string, string, "defined">;
|
|
562
572
|
}>>, Schemastery.ObjectT<NoInfer<{
|
|
563
573
|
maxRequestSteps: z$1<number, number, "defined">;
|
|
564
574
|
maxKeptTurns: z$1<number, number, "defined">;
|
|
@@ -574,6 +584,9 @@ export declare const Config: z$1<Schemastery.ObjectS<NoInfer<{
|
|
|
574
584
|
defaultFileSort: z$1<"count" | "latest" | "path", "count" | "latest" | "path", "defined">;
|
|
575
585
|
insightsEntry: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
576
586
|
defaultDurationCurve: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
587
|
+
fleetTab: z$1<"hide" | "show", "hide" | "show", "defined">;
|
|
588
|
+
promptPrefix: z$1<string, string, "defined">;
|
|
589
|
+
promptSuffix: z$1<string, string, "defined">;
|
|
577
590
|
}>>, "plain">;
|
|
578
591
|
//#endregion
|
|
579
592
|
//#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.1
|
|
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-11T13:11:54+00:00
|
|
8
|
+
* @commit 2c8095c34da3
|
|
9
|
+
* @commit-date 2026-10-11T21:08:45+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,10 @@ 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()),
|
|
1562
|
+
promptPrefix: volatileField(z$1.string().default("").loose()),
|
|
1563
|
+
promptSuffix: volatileField(z$1.string().default("").loose())
|
|
1561
1564
|
});
|
|
1562
1565
|
function resolveBounds(config) {
|
|
1563
1566
|
const resolved = Config(config ?? {});
|
|
@@ -2185,7 +2188,7 @@ function createToolAttribution(ctx) {
|
|
|
2185
2188
|
}
|
|
2186
2189
|
//#endregion
|
|
2187
2190
|
//#region src/host/record.ts
|
|
2188
|
-
function asRecord(value) {
|
|
2191
|
+
function asRecord$1(value) {
|
|
2189
2192
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2190
2193
|
}
|
|
2191
2194
|
//#endregion
|
|
@@ -2226,9 +2229,9 @@ function deepseekSectionOf(ctx) {
|
|
|
2226
2229
|
if (!Array.isArray(rows)) return null;
|
|
2227
2230
|
let shaped = null;
|
|
2228
2231
|
for (const row of rows) try {
|
|
2229
|
-
const record = asRecord(row);
|
|
2232
|
+
const record = asRecord$1(row);
|
|
2230
2233
|
if (record === null) continue;
|
|
2231
|
-
const value = asRecord(record.value);
|
|
2234
|
+
const value = asRecord$1(record.value);
|
|
2232
2235
|
if (value === null || typeof value.apiKeyEnv !== "string" || value.apiKeyEnv === "") continue;
|
|
2233
2236
|
if (record.ns === DEEPSEEK_SETTINGS_NS || record.ns === "llm-deepseek-api-key") return value;
|
|
2234
2237
|
shaped ??= value;
|
|
@@ -2261,12 +2264,12 @@ async function resolveFacts(ctx) {
|
|
|
2261
2264
|
};
|
|
2262
2265
|
}
|
|
2263
2266
|
function balanceOfPayload(value) {
|
|
2264
|
-
const data = asRecord(value);
|
|
2267
|
+
const data = asRecord$1(value);
|
|
2265
2268
|
if (data === null) return null;
|
|
2266
2269
|
const infos = Array.isArray(data.balance_infos) ? data.balance_infos : [];
|
|
2267
2270
|
const balances = [];
|
|
2268
2271
|
for (const info of infos) try {
|
|
2269
|
-
const entry = asRecord(info);
|
|
2272
|
+
const entry = asRecord$1(info);
|
|
2270
2273
|
if (entry === null) continue;
|
|
2271
2274
|
const currency = entry.currency;
|
|
2272
2275
|
const granted = amountOf(entry.granted_balance);
|
|
@@ -2359,7 +2362,7 @@ const BACKFILL_ROUTE = "/api/dsh-context/backfill";
|
|
|
2359
2362
|
const YIELD_MS = 100;
|
|
2360
2363
|
const UNSUPPORTED_FORMAT = "SessionFormatUnsupported";
|
|
2361
2364
|
function headerOf(record) {
|
|
2362
|
-
const header = asRecord(asRecord(record)?.header);
|
|
2365
|
+
const header = asRecord$1(asRecord$1(record)?.header);
|
|
2363
2366
|
if (header === null) return null;
|
|
2364
2367
|
if (typeof header.id !== "string" || header.id === "") return null;
|
|
2365
2368
|
return header;
|
|
@@ -2367,7 +2370,7 @@ function headerOf(record) {
|
|
|
2367
2370
|
const PROBE_KEYS = ["contextActivity", "contextTimeline"];
|
|
2368
2371
|
function servesRows(cache, header) {
|
|
2369
2372
|
try {
|
|
2370
|
-
const values = asRecord(asRecord(cache.cachedSnapshot(header, PROBE_KEYS))?.values);
|
|
2373
|
+
const values = asRecord$1(asRecord$1(cache.cachedSnapshot(header, PROBE_KEYS))?.values);
|
|
2371
2374
|
return values !== null && values.contextActivity !== void 0 && values.contextTimeline !== void 0;
|
|
2372
2375
|
} catch {
|
|
2373
2376
|
return false;
|
|
@@ -2377,7 +2380,7 @@ async function readColdLog(persistence, id, signal) {
|
|
|
2377
2380
|
const handle = await persistence.open(id, "read", { signal });
|
|
2378
2381
|
let events;
|
|
2379
2382
|
try {
|
|
2380
|
-
const result = asRecord(await handle.read(0, void 0, { signal }))?.events;
|
|
2383
|
+
const result = asRecord$1(await handle.read(0, void 0, { signal }))?.events;
|
|
2381
2384
|
events = Array.isArray(result) ? result : [];
|
|
2382
2385
|
} catch (error) {
|
|
2383
2386
|
try {
|
|
@@ -2402,12 +2405,12 @@ function isLive(sessions, id) {
|
|
|
2402
2405
|
}
|
|
2403
2406
|
function isUnsupportedFormat(error) {
|
|
2404
2407
|
try {
|
|
2405
|
-
return String(asRecord(error)?.name).startsWith(UNSUPPORTED_FORMAT);
|
|
2408
|
+
return String(asRecord$1(error)?.name).startsWith(UNSUPPORTED_FORMAT);
|
|
2406
2409
|
} catch {
|
|
2407
2410
|
return false;
|
|
2408
2411
|
}
|
|
2409
2412
|
}
|
|
2410
|
-
function messageOf(error) {
|
|
2413
|
+
function messageOf$1(error) {
|
|
2411
2414
|
try {
|
|
2412
2415
|
return String(error);
|
|
2413
2416
|
} catch {
|
|
@@ -2438,13 +2441,13 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2438
2441
|
"sessions"
|
|
2439
2442
|
], (raw) => {
|
|
2440
2443
|
const injected = raw;
|
|
2441
|
-
const query = asRecord(injected.sessionQuery);
|
|
2442
|
-
const cache = asRecord(injected.sessionProjectionCache);
|
|
2443
|
-
const persistence = asRecord(injected.sessionPersistence);
|
|
2444
|
+
const query = asRecord$1(injected.sessionQuery);
|
|
2445
|
+
const cache = asRecord$1(injected.sessionProjectionCache);
|
|
2446
|
+
const persistence = asRecord$1(injected.sessionPersistence);
|
|
2444
2447
|
if (query === null || typeof query.listSessions !== "function") return;
|
|
2445
2448
|
if (cache === null || typeof cache.cachedSnapshot !== "function" || typeof cache.coldSnapshot !== "function") return;
|
|
2446
2449
|
if (persistence === null || typeof persistence.open !== "function") return;
|
|
2447
|
-
const sessions = asRecord(injected.sessions);
|
|
2450
|
+
const sessions = asRecord$1(injected.sessions);
|
|
2448
2451
|
const abort = new AbortController();
|
|
2449
2452
|
const run = async () => {
|
|
2450
2453
|
const listed = await query.listSessions(abort.signal);
|
|
@@ -2471,8 +2474,8 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2471
2474
|
} catch (error) {
|
|
2472
2475
|
if (isUnsupportedFormat(error)) {
|
|
2473
2476
|
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)})`);
|
|
2477
|
+
ctx.logger.debug(`dsh-context: projection backfill skipped "${header.id}" (${messageOf$1(error)})`);
|
|
2478
|
+
} else ctx.logger.warn(`dsh-context: projection backfill skipped "${header.id}" (${messageOf$1(error)})`);
|
|
2476
2479
|
}
|
|
2477
2480
|
await new Promise((resolve) => setTimeout(resolve, YIELD_MS));
|
|
2478
2481
|
}
|
|
@@ -2482,7 +2485,7 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2482
2485
|
};
|
|
2483
2486
|
launch = () => {
|
|
2484
2487
|
run().catch((error) => {
|
|
2485
|
-
if (!abort.signal.aborted) ctx.logger.warn(`dsh-context: projection backfill stopped early (${messageOf(error)})`);
|
|
2488
|
+
if (!abort.signal.aborted) ctx.logger.warn(`dsh-context: projection backfill stopped early (${messageOf$1(error)})`);
|
|
2486
2489
|
});
|
|
2487
2490
|
};
|
|
2488
2491
|
tryLaunch();
|
|
@@ -2494,11 +2497,11 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2494
2497
|
for (const fiber of [routeFiber, runnerFiber]) fiber?.dispose?.();
|
|
2495
2498
|
};
|
|
2496
2499
|
}
|
|
2497
|
-
function reply(value) {
|
|
2500
|
+
function reply$1(value) {
|
|
2498
2501
|
return Response.json(value, { headers: { "cache-control": "no-store" } });
|
|
2499
2502
|
}
|
|
2500
|
-
function failure(code, message) {
|
|
2501
|
-
return reply({
|
|
2503
|
+
function failure$1(code, message) {
|
|
2504
|
+
return reply$1({
|
|
2502
2505
|
ok: false,
|
|
2503
2506
|
error: {
|
|
2504
2507
|
code,
|
|
@@ -2519,29 +2522,29 @@ function watchDetailChannel(ctx, bounds, coldReads = makeColdReadGate()) {
|
|
|
2519
2522
|
const body = await request.json();
|
|
2520
2523
|
sessionId = body !== null && typeof body === "object" ? body.sessionId : void 0;
|
|
2521
2524
|
} catch {
|
|
2522
|
-
return failure("dsh-context/bad-request", "body is not JSON");
|
|
2525
|
+
return failure$1("dsh-context/bad-request", "body is not JSON");
|
|
2523
2526
|
}
|
|
2524
|
-
if (typeof sessionId !== "string" || sessionId === "") return failure("dsh-context/bad-request", "missing sessionId");
|
|
2527
|
+
if (typeof sessionId !== "string" || sessionId === "") return failure$1("dsh-context/bad-request", "missing sessionId");
|
|
2525
2528
|
try {
|
|
2526
2529
|
const session = getSession(sessionId);
|
|
2527
2530
|
if (session !== void 0 && session !== null) {
|
|
2528
2531
|
const state = projections.stateOf(session, "contextTimeline");
|
|
2529
|
-
if (state === void 0) return reply({
|
|
2532
|
+
if (state === void 0) return reply$1({
|
|
2530
2533
|
ok: true,
|
|
2531
2534
|
value: null
|
|
2532
2535
|
});
|
|
2533
|
-
return reply({
|
|
2536
|
+
return reply$1({
|
|
2534
2537
|
ok: true,
|
|
2535
2538
|
value: buildTimelineDetail(state, bounds)
|
|
2536
2539
|
});
|
|
2537
2540
|
}
|
|
2538
2541
|
const query = ctx.get("sessionQuery");
|
|
2539
2542
|
const observe = typeof query?.observeSession === "function" ? query.observeSession.bind(query) : void 0;
|
|
2540
|
-
if (observe === void 0) return reply({
|
|
2543
|
+
if (observe === void 0) return reply$1({
|
|
2541
2544
|
ok: true,
|
|
2542
2545
|
value: null
|
|
2543
2546
|
});
|
|
2544
|
-
return reply({
|
|
2547
|
+
return reply$1({
|
|
2545
2548
|
ok: true,
|
|
2546
2549
|
value: await coldReads.admit(async () => {
|
|
2547
2550
|
const observation = await observe(sessionId, { projectionMode: "none" });
|
|
@@ -2558,7 +2561,7 @@ function watchDetailChannel(ctx, bounds, coldReads = makeColdReadGate()) {
|
|
|
2558
2561
|
}) ?? null
|
|
2559
2562
|
});
|
|
2560
2563
|
} catch (err) {
|
|
2561
|
-
return failure("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2564
|
+
return failure$1("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2562
2565
|
}
|
|
2563
2566
|
};
|
|
2564
2567
|
if (!registerPostRoute(c, c.get("connection"), "/api/dsh-context/detail", handler, "dsh-context: detail route")) return;
|
|
@@ -2738,6 +2741,275 @@ function createFallbackActivityDefinition() {
|
|
|
2738
2741
|
return fallbackDefinition("contextActivity", contextActivitySchema, { days: {} });
|
|
2739
2742
|
}
|
|
2740
2743
|
//#endregion
|
|
2744
|
+
//#region src/host/fleet.ts
|
|
2745
|
+
const FLEET_ROUTE = "/api/dsh-context/fleet";
|
|
2746
|
+
const MESSAGES_MAX = 40;
|
|
2747
|
+
const MESSAGE_TEXT_MAX = 400;
|
|
2748
|
+
const PROMPT_TEXT_MAX = 1600;
|
|
2749
|
+
const REPLY_TEXT_MAX = 300;
|
|
2750
|
+
function reply(value) {
|
|
2751
|
+
return Response.json(value, { headers: { "cache-control": "no-store" } });
|
|
2752
|
+
}
|
|
2753
|
+
function failure(code, message) {
|
|
2754
|
+
return reply({
|
|
2755
|
+
ok: false,
|
|
2756
|
+
error: {
|
|
2757
|
+
code,
|
|
2758
|
+
message
|
|
2759
|
+
}
|
|
2760
|
+
});
|
|
2761
|
+
}
|
|
2762
|
+
function asRecord(value) {
|
|
2763
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2764
|
+
}
|
|
2765
|
+
function textOfContent(content) {
|
|
2766
|
+
if (!Array.isArray(content)) return "";
|
|
2767
|
+
let out = "";
|
|
2768
|
+
for (const block of content) {
|
|
2769
|
+
const text = asRecord(block)?.text;
|
|
2770
|
+
if (typeof text === "string") out += text;
|
|
2771
|
+
}
|
|
2772
|
+
return out;
|
|
2773
|
+
}
|
|
2774
|
+
const REMINDER_PREFIX = /^\s*<system-reminder>[\s\S]*?<\/system-reminder>\s*/;
|
|
2775
|
+
function clip(text, max) {
|
|
2776
|
+
return text.length > max ? {
|
|
2777
|
+
text: text.slice(0, max) + "…",
|
|
2778
|
+
cut: true
|
|
2779
|
+
} : {
|
|
2780
|
+
text,
|
|
2781
|
+
cut: false
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
function descriptorOf(data) {
|
|
2785
|
+
const mode = data.mode;
|
|
2786
|
+
if (mode !== "one-shot" && mode !== "continuable") return null;
|
|
2787
|
+
const out = { mode };
|
|
2788
|
+
for (const key of [
|
|
2789
|
+
"label",
|
|
2790
|
+
"provider",
|
|
2791
|
+
"agentProvider",
|
|
2792
|
+
"agentModel",
|
|
2793
|
+
"persona"
|
|
2794
|
+
]) {
|
|
2795
|
+
const value = data[key];
|
|
2796
|
+
if (typeof value === "string" && value !== "") out[key] = value;
|
|
2797
|
+
}
|
|
2798
|
+
return out;
|
|
2799
|
+
}
|
|
2800
|
+
const MAILBOX_PREFIX = /^Team message \S+ from [^:]{1,64}:\s*/;
|
|
2801
|
+
const RELAY_PREFIX = /^(?:Agent \S+ sent a message: |Team message from [^:\n]{1,64}:\s*)/;
|
|
2802
|
+
function messageOf(seq, time, data) {
|
|
2803
|
+
const source = asRecord(data.source);
|
|
2804
|
+
const kind = source?.kind;
|
|
2805
|
+
let message = null;
|
|
2806
|
+
if (kind === "agent-message" || kind === "team-message") {
|
|
2807
|
+
let text = textOfContent(data.content);
|
|
2808
|
+
text = text.replace(kind === "team-message" ? MAILBOX_PREFIX : RELAY_PREFIX, "");
|
|
2809
|
+
if (text.trim() === "") return null;
|
|
2810
|
+
message = {
|
|
2811
|
+
seq,
|
|
2812
|
+
time,
|
|
2813
|
+
kind: kind === "agent-message" ? "relay" : "mailbox",
|
|
2814
|
+
text
|
|
2815
|
+
};
|
|
2816
|
+
const from = kind === "agent-message" ? source?.senderSessionId : source?.senderId;
|
|
2817
|
+
if (typeof from === "string" && from !== "") message.from = from;
|
|
2818
|
+
const fromName = source?.senderName;
|
|
2819
|
+
if (typeof fromName === "string" && fromName !== "") message.fromName = fromName;
|
|
2820
|
+
} else if (kind === "subagent-settled") {
|
|
2821
|
+
const summary = source?.summary;
|
|
2822
|
+
const text = typeof summary === "string" && summary.trim() !== "" ? summary : textOfContent(data.content);
|
|
2823
|
+
if (text.trim() === "") return null;
|
|
2824
|
+
message = {
|
|
2825
|
+
seq,
|
|
2826
|
+
time,
|
|
2827
|
+
kind: "settled",
|
|
2828
|
+
text
|
|
2829
|
+
};
|
|
2830
|
+
const from = source?.senderSessionId;
|
|
2831
|
+
if (typeof from === "string" && from !== "") message.from = from;
|
|
2832
|
+
}
|
|
2833
|
+
if (message === null) return null;
|
|
2834
|
+
const cut = clip(message.text, MESSAGE_TEXT_MAX);
|
|
2835
|
+
message.text = cut.text;
|
|
2836
|
+
return message;
|
|
2837
|
+
}
|
|
2838
|
+
function isPlainPrompt(source) {
|
|
2839
|
+
if (source === null) return true;
|
|
2840
|
+
return source.kind === "user";
|
|
2841
|
+
}
|
|
2842
|
+
function rosterMemberOf(data) {
|
|
2843
|
+
const member = asRecord(data.member);
|
|
2844
|
+
if (member === null) return null;
|
|
2845
|
+
if (typeof member.name !== "string" || member.name === "") return null;
|
|
2846
|
+
const out = {
|
|
2847
|
+
name: member.name,
|
|
2848
|
+
description: typeof member.description === "string" ? member.description : ""
|
|
2849
|
+
};
|
|
2850
|
+
if (typeof member.provider === "string" && member.provider !== "") out.provider = member.provider;
|
|
2851
|
+
if (member.context === "fresh" || member.context === "fork") out.context = member.context;
|
|
2852
|
+
return out;
|
|
2853
|
+
}
|
|
2854
|
+
function lastReplyOf(events) {
|
|
2855
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
2856
|
+
const ev = asRecord(events[i]);
|
|
2857
|
+
if (ev === null || ev.type !== "assistant/message") continue;
|
|
2858
|
+
const content = asRecord(asRecord(ev.data)?.message)?.content;
|
|
2859
|
+
if (!Array.isArray(content)) continue;
|
|
2860
|
+
let text = "";
|
|
2861
|
+
for (const block of content) {
|
|
2862
|
+
const b = asRecord(block);
|
|
2863
|
+
if (b?.type === "text" && typeof b.text === "string") text += b.text;
|
|
2864
|
+
}
|
|
2865
|
+
if (text.trim() === "") continue;
|
|
2866
|
+
const time = typeof ev.time === "number" && Number.isFinite(ev.time) ? ev.time : 0;
|
|
2867
|
+
const cut = clip(text, REPLY_TEXT_MAX);
|
|
2868
|
+
return {
|
|
2869
|
+
time,
|
|
2870
|
+
text: cut.text,
|
|
2871
|
+
cut: cut.cut
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
return null;
|
|
2875
|
+
}
|
|
2876
|
+
function fleetDetailOfEvents(events) {
|
|
2877
|
+
let descriptor;
|
|
2878
|
+
let initialPrompt;
|
|
2879
|
+
let truncated = false;
|
|
2880
|
+
const messages = [];
|
|
2881
|
+
const roster = new Map();
|
|
2882
|
+
for (const entry of events) {
|
|
2883
|
+
const ev = asRecord(entry);
|
|
2884
|
+
if (ev === null) continue;
|
|
2885
|
+
const type = ev.type;
|
|
2886
|
+
if (typeof type !== "string") continue;
|
|
2887
|
+
const seq = typeof ev.seq === "number" && Number.isFinite(ev.seq) ? ev.seq : 0;
|
|
2888
|
+
const time = typeof ev.time === "number" && Number.isFinite(ev.time) ? ev.time : 0;
|
|
2889
|
+
const data = asRecord(ev.data);
|
|
2890
|
+
if (data === null) continue;
|
|
2891
|
+
if (type === "subagent/descriptor") {
|
|
2892
|
+
const next = descriptorOf(data);
|
|
2893
|
+
if (next !== null) descriptor = next;
|
|
2894
|
+
continue;
|
|
2895
|
+
}
|
|
2896
|
+
if (type === "team/member") {
|
|
2897
|
+
const member = rosterMemberOf(data);
|
|
2898
|
+
if (member !== null) roster.set(member.name, member);
|
|
2899
|
+
continue;
|
|
2900
|
+
}
|
|
2901
|
+
if (type !== "user/message") continue;
|
|
2902
|
+
const message = messageOf(seq, time, data);
|
|
2903
|
+
if (message !== null) {
|
|
2904
|
+
if (message.text.endsWith("…")) truncated = true;
|
|
2905
|
+
messages.push(message);
|
|
2906
|
+
continue;
|
|
2907
|
+
}
|
|
2908
|
+
if (initialPrompt === void 0 && isPlainPrompt(asRecord(data.source))) {
|
|
2909
|
+
const text = textOfContent(data.content).replace(REMINDER_PREFIX, "");
|
|
2910
|
+
if (text.trim() !== "") {
|
|
2911
|
+
const cut = clip(text, PROMPT_TEXT_MAX);
|
|
2912
|
+
initialPrompt = cut.text;
|
|
2913
|
+
if (cut.cut) truncated = true;
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
messages.sort((a, b) => b.seq - a.seq);
|
|
2918
|
+
if (messages.length > MESSAGES_MAX) {
|
|
2919
|
+
messages.length = MESSAGES_MAX;
|
|
2920
|
+
truncated = true;
|
|
2921
|
+
}
|
|
2922
|
+
const reply = lastReplyOf(events);
|
|
2923
|
+
if (reply !== null && reply.cut) truncated = true;
|
|
2924
|
+
return {
|
|
2925
|
+
...descriptor !== void 0 ? { descriptor } : {},
|
|
2926
|
+
...initialPrompt !== void 0 ? { initialPrompt } : {},
|
|
2927
|
+
...reply !== null ? { lastReply: {
|
|
2928
|
+
time: reply.time,
|
|
2929
|
+
text: reply.text
|
|
2930
|
+
} } : {},
|
|
2931
|
+
...roster.size > 0 ? { roster: [...roster.values()] } : {},
|
|
2932
|
+
messages,
|
|
2933
|
+
truncated
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
function watchFleetChannel(ctx, coldReads = makeColdReadGate()) {
|
|
2937
|
+
ctx.inject(["connection"], (c) => {
|
|
2938
|
+
const handler = async (request) => {
|
|
2939
|
+
let sessionId;
|
|
2940
|
+
try {
|
|
2941
|
+
sessionId = asRecord(await request.json())?.sessionId;
|
|
2942
|
+
} catch {
|
|
2943
|
+
return failure("dsh-context/bad-request", "body is not JSON");
|
|
2944
|
+
}
|
|
2945
|
+
if (typeof sessionId !== "string" || sessionId === "") return failure("dsh-context/bad-request", "missing sessionId");
|
|
2946
|
+
try {
|
|
2947
|
+
const query = ctx.get("sessionQuery");
|
|
2948
|
+
const observe = typeof query?.observeSession === "function" ? query.observeSession.bind(query) : void 0;
|
|
2949
|
+
if (observe === void 0) return reply({
|
|
2950
|
+
ok: true,
|
|
2951
|
+
value: null
|
|
2952
|
+
});
|
|
2953
|
+
return reply({
|
|
2954
|
+
ok: true,
|
|
2955
|
+
value: await coldReads.admit(async () => {
|
|
2956
|
+
const observation = await observe(sessionId, { projectionMode: "none" });
|
|
2957
|
+
const events = observation?.events;
|
|
2958
|
+
if (!Array.isArray(events)) return null;
|
|
2959
|
+
try {
|
|
2960
|
+
return fleetDetailOfEvents(events);
|
|
2961
|
+
} finally {
|
|
2962
|
+
const dispose = observation?.[Symbol.dispose];
|
|
2963
|
+
if (typeof dispose === "function") dispose.call(observation);
|
|
2964
|
+
}
|
|
2965
|
+
}) ?? null
|
|
2966
|
+
});
|
|
2967
|
+
} catch (err) {
|
|
2968
|
+
return failure("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2969
|
+
}
|
|
2970
|
+
};
|
|
2971
|
+
registerPostRoute(c, c.get("connection"), FLEET_ROUTE, handler, "dsh-context: fleet route");
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
//#endregion
|
|
2975
|
+
//#region src/host/promptInjection.ts
|
|
2976
|
+
function liveText(value) {
|
|
2977
|
+
if (value !== null && typeof value === "object" && typeof value.get === "function") {
|
|
2978
|
+
const get = value.get;
|
|
2979
|
+
return () => {
|
|
2980
|
+
const text = get();
|
|
2981
|
+
return typeof text === "string" ? text : "";
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
const text = typeof value === "string" ? value : "";
|
|
2985
|
+
return () => text;
|
|
2986
|
+
}
|
|
2987
|
+
function sectionText(read) {
|
|
2988
|
+
return () => {
|
|
2989
|
+
const text = read();
|
|
2990
|
+
return text.trim().length === 0 ? "" : text;
|
|
2991
|
+
};
|
|
2992
|
+
}
|
|
2993
|
+
const ORDER_CLEARANCE = 1e3;
|
|
2994
|
+
function watchPromptInjection(ctx, config) {
|
|
2995
|
+
ctx.inject(["systemPrompt"], (inner) => {
|
|
2996
|
+
const systemPrompt = inner.systemPrompt;
|
|
2997
|
+
if (systemPrompt === null || systemPrompt === void 0 || typeof systemPrompt.section !== "function" || typeof systemPrompt.getSectionOrder !== "function") return;
|
|
2998
|
+
systemPrompt.section({
|
|
2999
|
+
name: "dsh-context:prompt-prefix",
|
|
3000
|
+
order: systemPrompt.getSectionOrder("HARNESS_IDENTITY") - ORDER_CLEARANCE,
|
|
3001
|
+
text: sectionText(liveText(config.promptPrefix)),
|
|
3002
|
+
interpolate: false
|
|
3003
|
+
});
|
|
3004
|
+
systemPrompt.section({
|
|
3005
|
+
name: "dsh-context:prompt-suffix",
|
|
3006
|
+
order: systemPrompt.getSectionOrder("DEPLOYMENT_PERSONA_SUFFIX") + ORDER_CLEARANCE,
|
|
3007
|
+
text: sectionText(liveText(config.promptSuffix)),
|
|
3008
|
+
interpolate: false
|
|
3009
|
+
});
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
//#endregion
|
|
2741
3013
|
//#region src/host/stepIdentity.ts
|
|
2742
3014
|
const MINTED_ID_PREFIX = "dshctx-";
|
|
2743
3015
|
function lacksId(message) {
|
|
@@ -2795,7 +3067,7 @@ async function disposeOf(resource) {
|
|
|
2795
3067
|
} catch {}
|
|
2796
3068
|
}
|
|
2797
3069
|
function skillInfoOf(value) {
|
|
2798
|
-
const record = asRecord(value);
|
|
3070
|
+
const record = asRecord$1(value);
|
|
2799
3071
|
if (record === null || typeof record.name !== "string" || record.name === "") return null;
|
|
2800
3072
|
return {
|
|
2801
3073
|
name: record.name,
|
|
@@ -2806,7 +3078,7 @@ function skillInfoOf(value) {
|
|
|
2806
3078
|
}
|
|
2807
3079
|
async function sessionViewOf(ctx, sessionId) {
|
|
2808
3080
|
if (sessionId === void 0) return {};
|
|
2809
|
-
const query = asRecord(ctx.get("sessionQuery"));
|
|
3081
|
+
const query = asRecord$1(ctx.get("sessionQuery"));
|
|
2810
3082
|
if (typeof query?.observeSession !== "function") return {};
|
|
2811
3083
|
let observation;
|
|
2812
3084
|
try {
|
|
@@ -2815,9 +3087,9 @@ async function sessionViewOf(ctx, sessionId) {
|
|
|
2815
3087
|
return {};
|
|
2816
3088
|
}
|
|
2817
3089
|
try {
|
|
2818
|
-
const obs = asRecord(observation);
|
|
2819
|
-
const cwd = stringOf(asRecord(obs?.header)?.cwd);
|
|
2820
|
-
const agentPreset = stringOf(asRecord(asRecord(obs?.projections)?.values)?.agentPreset);
|
|
3090
|
+
const obs = asRecord$1(observation);
|
|
3091
|
+
const cwd = stringOf(asRecord$1(obs?.header)?.cwd);
|
|
3092
|
+
const agentPreset = stringOf(asRecord$1(asRecord$1(obs?.projections)?.values)?.agentPreset);
|
|
2821
3093
|
return {
|
|
2822
3094
|
...cwd === void 0 ? {} : { cwd },
|
|
2823
3095
|
...agentPreset === void 0 ? {} : { agentPreset }
|
|
@@ -2827,10 +3099,10 @@ async function sessionViewOf(ctx, sessionId) {
|
|
|
2827
3099
|
}
|
|
2828
3100
|
}
|
|
2829
3101
|
async function resolveRegistry(ctx, sessionId, agentPreset) {
|
|
2830
|
-
const presets = asRecord(ctx.get("agentPresets"));
|
|
3102
|
+
const presets = asRecord$1(ctx.get("agentPresets"));
|
|
2831
3103
|
let live;
|
|
2832
3104
|
if (sessionId !== void 0) {
|
|
2833
|
-
const agents = asRecord(ctx.get("agents"));
|
|
3105
|
+
const agents = asRecord$1(ctx.get("agents"));
|
|
2834
3106
|
if (typeof agents?.get === "function") try {
|
|
2835
3107
|
live = agents.get.call(agents, sessionId);
|
|
2836
3108
|
} catch {
|
|
@@ -2838,20 +3110,20 @@ async function resolveRegistry(ctx, sessionId, agentPreset) {
|
|
|
2838
3110
|
}
|
|
2839
3111
|
}
|
|
2840
3112
|
if (live !== void 0 && live !== null && typeof presets?.serviceFor === "function") {
|
|
2841
|
-
const scoped = asRecord(presets.serviceFor.call(presets, live, "skills"));
|
|
3113
|
+
const scoped = asRecord$1(presets.serviceFor.call(presets, live, "skills"));
|
|
2842
3114
|
if (scoped !== null && typeof scoped.list === "function") return {
|
|
2843
3115
|
registry: scoped,
|
|
2844
3116
|
scope: live,
|
|
2845
3117
|
lease: void 0
|
|
2846
3118
|
};
|
|
2847
3119
|
}
|
|
2848
|
-
const registry = asRecord(ctx.get("skills"));
|
|
3120
|
+
const registry = asRecord$1(ctx.get("skills"));
|
|
2849
3121
|
if (registry === null || typeof registry.list !== "function") return null;
|
|
2850
3122
|
let scope;
|
|
2851
3123
|
let lease;
|
|
2852
3124
|
if (typeof presets?.acquireScope === "function") try {
|
|
2853
3125
|
lease = await presets.acquireScope.call(presets, agentPreset);
|
|
2854
|
-
scope = asRecord(lease)?.key;
|
|
3126
|
+
scope = asRecord$1(lease)?.key;
|
|
2855
3127
|
} catch {
|
|
2856
3128
|
lease = void 0;
|
|
2857
3129
|
}
|
|
@@ -2867,7 +3139,7 @@ function watchSkillCatalog(ctx) {
|
|
|
2867
3139
|
let value = null;
|
|
2868
3140
|
let lease;
|
|
2869
3141
|
try {
|
|
2870
|
-
const body = asRecord(await request.json());
|
|
3142
|
+
const body = asRecord$1(await request.json());
|
|
2871
3143
|
const sessionId = stringOf(body?.sessionId);
|
|
2872
3144
|
const view = await sessionViewOf(ctx, sessionId);
|
|
2873
3145
|
const cwd = view.cwd ?? stringOf(body?.cwd);
|
|
@@ -2991,8 +3263,10 @@ function detectHarnessVersion(ctx, resolveUrl = resolveRunningModule, pluginRoot
|
|
|
2991
3263
|
const name = "dsh-context";
|
|
2992
3264
|
const inject = ["sessionProjections"];
|
|
2993
3265
|
function apply(ctx, config) {
|
|
3266
|
+
const coldReads = makeColdReadGate();
|
|
2994
3267
|
watchBalanceChannel(ctx);
|
|
2995
3268
|
watchSkillCatalog(ctx);
|
|
3269
|
+
watchFleetChannel(ctx, coldReads);
|
|
2996
3270
|
const harnessVersion = detectHarnessVersion(ctx);
|
|
2997
3271
|
if (harnessVersion !== void 0 && !meetsBaseline(harnessVersion)) {
|
|
2998
3272
|
ctx.sessionProjections.register(createFallbackTimelineDefinition(harnessVersion));
|
|
@@ -3002,12 +3276,12 @@ function apply(ctx, config) {
|
|
|
3002
3276
|
}
|
|
3003
3277
|
const attribution = createToolAttribution(ctx);
|
|
3004
3278
|
watchStepIdentity(ctx);
|
|
3005
|
-
const coldReads = makeColdReadGate();
|
|
3006
3279
|
const gate = watchDetailChannel(ctx, resolveBounds(config), coldReads);
|
|
3007
3280
|
ctx.sessionProjections.register(createContextTimelineDefinition(config, () => gate.live));
|
|
3008
3281
|
ctx.sessionProjections.register(createContextHeadersDefinition((name) => attribution.ownerOf(name)));
|
|
3009
3282
|
ctx.sessionProjections.register(createContextActivityDefinition());
|
|
3010
3283
|
watchActivityBackfill(ctx, coldReads);
|
|
3284
|
+
watchPromptInjection(ctx, config);
|
|
3011
3285
|
}
|
|
3012
3286
|
//#endregion
|
|
3013
3287
|
export { Config, apply, inject, name };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.68.1",
|
|
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",
|