dsh-context 0.66.1 → 0.67.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 +2 -2
- package/lib/client.js +10 -10
- package/lib/index.d.ts +181 -661
- package/lib/index.js +397 -419
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-context v0.
|
|
2
|
+
* dsh-context v0.67.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-10T10:12:42+00:00
|
|
8
|
+
* @commit df136da57dac
|
|
9
|
+
* @commit-date 2026-10-10T18:10:23+08:00
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createRequire } from "node:module";
|
|
@@ -18,21 +18,6 @@ import { dirname, isAbsolute, join, normalize, relative } from "node:path";
|
|
|
18
18
|
import { fileURLToPath } from "node:url";
|
|
19
19
|
import { getHeapStatistics } from "node:v8";
|
|
20
20
|
import { randomUUID } from "node:crypto";
|
|
21
|
-
//#region src/shared/providers.ts
|
|
22
|
-
const MODELS_DEV_PROVIDER_IDS = {
|
|
23
|
-
"deepseek-official": "deepseek",
|
|
24
|
-
"deepseek-account": "deepseek",
|
|
25
|
-
"kimi-coding": "moonshotai",
|
|
26
|
-
"minimax-cn": "minimax",
|
|
27
|
-
"zai-coding-cn": "zhipuai"
|
|
28
|
-
};
|
|
29
|
-
function modelsDevProviderOf(dshProviderId) {
|
|
30
|
-
return MODELS_DEV_PROVIDER_IDS[dshProviderId] ?? dshProviderId;
|
|
31
|
-
}
|
|
32
|
-
function isDeepSeekProvider(dshProviderId) {
|
|
33
|
-
return modelsDevProviderOf(dshProviderId) === "deepseek";
|
|
34
|
-
}
|
|
35
|
-
//#endregion
|
|
36
21
|
//#region src/shared/estimate.ts
|
|
37
22
|
const CHARS_PER_TOKEN$1 = 4;
|
|
38
23
|
const ROLE_OVERHEAD$1 = 4;
|
|
@@ -548,7 +533,7 @@ function opsOfCall(input) {
|
|
|
548
533
|
}];
|
|
549
534
|
}
|
|
550
535
|
//#endregion
|
|
551
|
-
//#region src/host/
|
|
536
|
+
//#region src/host/foldState.ts
|
|
552
537
|
function trimToLastTurns(requests, maxTurns) {
|
|
553
538
|
let runs = 0;
|
|
554
539
|
let start = requests.length;
|
|
@@ -624,6 +609,280 @@ function createTimelineState() {
|
|
|
624
609
|
spans: []
|
|
625
610
|
};
|
|
626
611
|
}
|
|
612
|
+
//#endregion
|
|
613
|
+
//#region src/shared/providers.ts
|
|
614
|
+
const MODELS_DEV_PROVIDER_IDS = {
|
|
615
|
+
"deepseek-official": "deepseek",
|
|
616
|
+
"deepseek-account": "deepseek",
|
|
617
|
+
"kimi-coding": "moonshotai",
|
|
618
|
+
"minimax-cn": "minimax",
|
|
619
|
+
"zai-coding-cn": "zhipuai"
|
|
620
|
+
};
|
|
621
|
+
function modelsDevProviderOf(dshProviderId) {
|
|
622
|
+
return MODELS_DEV_PROVIDER_IDS[dshProviderId] ?? dshProviderId;
|
|
623
|
+
}
|
|
624
|
+
function isDeepSeekProvider(dshProviderId) {
|
|
625
|
+
return modelsDevProviderOf(dshProviderId) === "deepseek";
|
|
626
|
+
}
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/host/foldMetering.ts
|
|
629
|
+
function tokenCountOf(value) {
|
|
630
|
+
if (typeof value === "number") return Number.isFinite(value) ? Math.max(0, Math.round(value)) : null;
|
|
631
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
632
|
+
const parsed = Number(value);
|
|
633
|
+
return Number.isFinite(parsed) ? Math.max(0, Math.round(parsed)) : null;
|
|
634
|
+
}
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
function isPeakUtc(time) {
|
|
638
|
+
const at = new Date(time);
|
|
639
|
+
const day = at.getUTCDay();
|
|
640
|
+
if (day === 0 || day === 6) return false;
|
|
641
|
+
const h = at.getUTCHours();
|
|
642
|
+
return h >= 1 && h < 4 || h >= 6 && h < 10;
|
|
643
|
+
}
|
|
644
|
+
function addBilledUsage(prev, provider, model, time, usage) {
|
|
645
|
+
const period = isDeepSeekProvider(provider) && !isPeakUtc(time) ? "off" : "peak";
|
|
646
|
+
const models = prev?.[provider] ?? {};
|
|
647
|
+
const periods = models[model] ?? {};
|
|
648
|
+
const b = periods[period] ?? {
|
|
649
|
+
uncached: 0,
|
|
650
|
+
cacheRead: 0,
|
|
651
|
+
cacheWrite: 0,
|
|
652
|
+
output: 0
|
|
653
|
+
};
|
|
654
|
+
const nextPeriods = { ...periods };
|
|
655
|
+
nextPeriods[period] = {
|
|
656
|
+
uncached: b.uncached + usage.uncached,
|
|
657
|
+
cacheRead: b.cacheRead + usage.cacheRead,
|
|
658
|
+
cacheWrite: b.cacheWrite + usage.cacheWrite,
|
|
659
|
+
output: b.output + usage.output
|
|
660
|
+
};
|
|
661
|
+
const nextModels = {
|
|
662
|
+
...models,
|
|
663
|
+
[model]: nextPeriods
|
|
664
|
+
};
|
|
665
|
+
return {
|
|
666
|
+
...prev ?? {},
|
|
667
|
+
[provider]: nextModels
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function copyCostUsage(cost) {
|
|
671
|
+
const copy = {};
|
|
672
|
+
for (const provider in cost) {
|
|
673
|
+
const models = {};
|
|
674
|
+
for (const model in cost[provider]) {
|
|
675
|
+
const periods = cost[provider][model];
|
|
676
|
+
const modelCopy = {};
|
|
677
|
+
if (periods.peak !== void 0) modelCopy.peak = { ...periods.peak };
|
|
678
|
+
if (periods.off !== void 0) modelCopy.off = { ...periods.off };
|
|
679
|
+
models[model] = modelCopy;
|
|
680
|
+
}
|
|
681
|
+
copy[provider] = models;
|
|
682
|
+
}
|
|
683
|
+
return copy;
|
|
684
|
+
}
|
|
685
|
+
function accumulateCost(st, time, usage) {
|
|
686
|
+
const model = st.model;
|
|
687
|
+
if (model === void 0) return;
|
|
688
|
+
st.cost = addBilledUsage(st.cost, st.provider ?? "", model, time, usage);
|
|
689
|
+
}
|
|
690
|
+
const TOOL_TIMING_CAP = 16;
|
|
691
|
+
const DECODE_KINDS = [
|
|
692
|
+
"reasoning",
|
|
693
|
+
"text",
|
|
694
|
+
"toolarg"
|
|
695
|
+
];
|
|
696
|
+
function durOf(from, to) {
|
|
697
|
+
if (!Number.isFinite(from) || !Number.isFinite(to)) return 0;
|
|
698
|
+
return Math.max(0, to - from);
|
|
699
|
+
}
|
|
700
|
+
function ensureTiming(st) {
|
|
701
|
+
if (st.timing === void 0) st.timing = {
|
|
702
|
+
wallMs: 0,
|
|
703
|
+
ttftMs: 0,
|
|
704
|
+
genMs: 0,
|
|
705
|
+
calls: 0,
|
|
706
|
+
toolsMs: 0,
|
|
707
|
+
toolCalls: 0,
|
|
708
|
+
tools: {}
|
|
709
|
+
};
|
|
710
|
+
return st.timing;
|
|
711
|
+
}
|
|
712
|
+
const DECODE_FIELDS = {
|
|
713
|
+
reasoning: {
|
|
714
|
+
ms: "reasoningMs",
|
|
715
|
+
n: "reasoningBlocks"
|
|
716
|
+
},
|
|
717
|
+
text: {
|
|
718
|
+
ms: "textMs",
|
|
719
|
+
n: "textBlocks"
|
|
720
|
+
},
|
|
721
|
+
toolarg: {
|
|
722
|
+
ms: "toolArgMs",
|
|
723
|
+
n: "toolArgBlocks"
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
function addDecode(timing, kind, ms, blocks) {
|
|
727
|
+
const field = DECODE_FIELDS[kind];
|
|
728
|
+
if (ms > 0) timing[field.ms] = (timing[field.ms] ?? 0) + ms;
|
|
729
|
+
if (blocks > 0) timing[field.n] = (timing[field.n] ?? 0) + blocks;
|
|
730
|
+
}
|
|
731
|
+
function bumpToolTotals(timing, name, ms) {
|
|
732
|
+
if (name === "__proto__") return;
|
|
733
|
+
if (!Object.hasOwn(timing.tools, name)) {
|
|
734
|
+
if (Object.keys(timing.tools).length >= TOOL_TIMING_CAP) {
|
|
735
|
+
let minKey = "";
|
|
736
|
+
let minMs = Infinity;
|
|
737
|
+
for (const k in timing.tools) if (timing.tools[k].ms < minMs) {
|
|
738
|
+
minMs = timing.tools[k].ms;
|
|
739
|
+
minKey = k;
|
|
740
|
+
}
|
|
741
|
+
const kept = {};
|
|
742
|
+
for (const k in timing.tools) if (k !== minKey) kept[k] = timing.tools[k];
|
|
743
|
+
timing.tools = kept;
|
|
744
|
+
}
|
|
745
|
+
timing.tools[name] = {
|
|
746
|
+
calls: 1,
|
|
747
|
+
ms
|
|
748
|
+
};
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
const cur = timing.tools[name];
|
|
752
|
+
timing.tools[name] = {
|
|
753
|
+
calls: cur.calls + 1,
|
|
754
|
+
ms: cur.ms + ms
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
//#endregion
|
|
758
|
+
//#region src/host/foldWire.ts
|
|
759
|
+
function headFieldsOf(state) {
|
|
760
|
+
const surfaceTotal = state.sums.user + state.sums.inject + state.sums.skill + state.sums.assistant + state.sums.tool;
|
|
761
|
+
const result = {
|
|
762
|
+
ok: true,
|
|
763
|
+
...state.model !== void 0 ? { model: state.model } : {},
|
|
764
|
+
...state.provider !== void 0 ? { provider: state.provider } : {},
|
|
765
|
+
...state.contextWindow !== void 0 ? { contextWindow: state.contextWindow } : {},
|
|
766
|
+
current: {
|
|
767
|
+
system: state.systemTokens,
|
|
768
|
+
tools: state.toolsTokens,
|
|
769
|
+
user: state.sums.user,
|
|
770
|
+
inject: state.sums.inject,
|
|
771
|
+
skill: state.sums.skill,
|
|
772
|
+
assistant: state.sums.assistant,
|
|
773
|
+
tool: state.sums.tool,
|
|
774
|
+
total: surfaceTotal + state.systemTokens + state.toolsTokens
|
|
775
|
+
},
|
|
776
|
+
images: state.surface.reduce((n, node) => n + (node.imgs ?? 0), 0),
|
|
777
|
+
toolCalls: state.surface.reduce((n, node) => node.cat === "tool" || node.cat === "skill" && node.tool !== void 0 ? n + 1 : n, 0),
|
|
778
|
+
humanInputs: state.humanInputs ?? 0,
|
|
779
|
+
answers: state.answers ?? 0,
|
|
780
|
+
...state.lastUser !== void 0 ? { lastUser: state.lastUser } : {},
|
|
781
|
+
requests: [],
|
|
782
|
+
events: [],
|
|
783
|
+
nodes: [],
|
|
784
|
+
droppedNodes: 0,
|
|
785
|
+
archive: []
|
|
786
|
+
};
|
|
787
|
+
if (state.cost !== void 0) result.cost = copyCostUsage(state.cost);
|
|
788
|
+
if (state.timing !== void 0) {
|
|
789
|
+
const tools = {};
|
|
790
|
+
for (const k in state.timing.tools) tools[k] = { ...state.timing.tools[k] };
|
|
791
|
+
result.timing = {
|
|
792
|
+
...state.timing,
|
|
793
|
+
tools
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
if (state.systems !== void 0 && state.systems.length > 0) result.systems = state.systems.map((n) => ({ ...n }));
|
|
797
|
+
return result;
|
|
798
|
+
}
|
|
799
|
+
function detailCollectionsOf(state, bounds) {
|
|
800
|
+
const result = {
|
|
801
|
+
requests: state.requests.map((r) => ({ ...r })),
|
|
802
|
+
events: state.events.map((e) => ({ ...e })),
|
|
803
|
+
nodes: [],
|
|
804
|
+
droppedNodes: 0,
|
|
805
|
+
archive: state.archived.map((n) => ({ ...n })),
|
|
806
|
+
fileOps: state.fileOps.map((o) => ({ ...o })),
|
|
807
|
+
...state.fileOpsFloor !== void 0 ? { fileOpsFloor: state.fileOpsFloor } : {},
|
|
808
|
+
spans: state.spans.map((s) => ({ ...s }))
|
|
809
|
+
};
|
|
810
|
+
const overflowCount = Math.max(0, state.surface.length - bounds.maxNodes);
|
|
811
|
+
const overflow = state.surface.slice(0, overflowCount);
|
|
812
|
+
const tail = state.surface.slice(overflowCount);
|
|
813
|
+
const pinned = overflow.filter((n) => n.cat === "inject" || n.cat === "skill");
|
|
814
|
+
result.nodes = pinned.length > 0 ? [...pinned, ...tail] : tail;
|
|
815
|
+
result.droppedNodes = overflowCount - pinned.length;
|
|
816
|
+
if (result.droppedNodes > 0) {
|
|
817
|
+
let floor = 0;
|
|
818
|
+
for (const n of overflow) if (n.cat !== "inject" && n.cat !== "skill") floor = Math.max(floor, n.seq);
|
|
819
|
+
result.surfaceFloor = floor;
|
|
820
|
+
}
|
|
821
|
+
if (state.archiveFloor !== void 0) result.archiveFloor = state.archiveFloor;
|
|
822
|
+
const requests = result.requests;
|
|
823
|
+
const events = result.events;
|
|
824
|
+
let ri = 0;
|
|
825
|
+
for (const ev of events) {
|
|
826
|
+
while (ri < requests.length && requests[ri].seq <= ev.seq) ri++;
|
|
827
|
+
const next = requests.at(ri);
|
|
828
|
+
const prev = ri > 0 ? requests.at(ri - 1) : void 0;
|
|
829
|
+
if (next !== void 0 && typeof next.turn === "number" && typeof next.step === "number") {
|
|
830
|
+
ev.turn = next.turn;
|
|
831
|
+
ev.step = next.step;
|
|
832
|
+
}
|
|
833
|
+
if (prev !== void 0 && typeof prev.turn === "number" && typeof prev.step === "number") {
|
|
834
|
+
ev.fromTurn = prev.turn;
|
|
835
|
+
ev.fromStep = prev.step;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return result;
|
|
839
|
+
}
|
|
840
|
+
function buildTimelineHead(state) {
|
|
841
|
+
const result = headFieldsOf(state);
|
|
842
|
+
const turns = new Set();
|
|
843
|
+
for (const r of state.requests) turns.add(r.turn ?? 0);
|
|
844
|
+
let injects = 0;
|
|
845
|
+
let compactions = 0;
|
|
846
|
+
let prunes = 0;
|
|
847
|
+
const skills = new Set();
|
|
848
|
+
for (const e of state.events) {
|
|
849
|
+
if (e.kind === "inject") injects++;
|
|
850
|
+
else if (e.kind === "compaction") compactions++;
|
|
851
|
+
else if (e.kind === "prune") prunes++;
|
|
852
|
+
if (e.sub === "skill" && typeof e.name === "string" && e.name !== "") skills.add(e.name);
|
|
853
|
+
}
|
|
854
|
+
result.counts = {
|
|
855
|
+
turns: turns.size,
|
|
856
|
+
steps: state.requests.length,
|
|
857
|
+
injects,
|
|
858
|
+
compactions,
|
|
859
|
+
prunes,
|
|
860
|
+
skills: skills.size
|
|
861
|
+
};
|
|
862
|
+
const last = state.requests.at(-1);
|
|
863
|
+
if (last !== void 0) result.last = {
|
|
864
|
+
seq: last.seq,
|
|
865
|
+
total: last.total,
|
|
866
|
+
...typeof last.prompt === "number" ? { prompt: last.prompt } : {}
|
|
867
|
+
};
|
|
868
|
+
result.detailRev = state.detailRev ?? 0;
|
|
869
|
+
return result;
|
|
870
|
+
}
|
|
871
|
+
function buildTimelineDetail(state, bounds) {
|
|
872
|
+
return {
|
|
873
|
+
rev: state.detailRev ?? 0,
|
|
874
|
+
head: buildTimelineHead(state),
|
|
875
|
+
...detailCollectionsOf(state, bounds)
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
function buildTimelineView(state, bounds) {
|
|
879
|
+
return {
|
|
880
|
+
...headFieldsOf(state),
|
|
881
|
+
...detailCollectionsOf(state, bounds)
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
//#endregion
|
|
885
|
+
//#region src/host/fold.ts
|
|
627
886
|
function categoryOf(type, message) {
|
|
628
887
|
if (type === "assistant/message") return "assistant";
|
|
629
888
|
if (type === "tool/result") return "tool";
|
|
@@ -727,191 +986,79 @@ function applySurface(st, ev, type, message) {
|
|
|
727
986
|
} else if (type === "tool/result") {
|
|
728
987
|
const srcId = source?.callId;
|
|
729
988
|
const toolEntry = typeof srcId === "string" ? st.callNames[srcId] : void 0;
|
|
730
|
-
if (toolEntry !== void 0) {
|
|
731
|
-
node.tool = toolEntry.name;
|
|
732
|
-
const timing = ensureTiming(st);
|
|
733
|
-
const dur = durOf(toolEntry.start, ev.time);
|
|
734
|
-
timing.toolsMs += dur;
|
|
735
|
-
timing.toolCalls += 1;
|
|
736
|
-
bumpToolTotals(timing, toolEntry.name, dur);
|
|
737
|
-
if (st.stepStart !== void 0) st.stepSpans = [...st.stepSpans ?? [], {
|
|
738
|
-
kind: "tools",
|
|
739
|
-
start: toolEntry.start,
|
|
740
|
-
end: ev.time
|
|
741
|
-
}];
|
|
742
|
-
}
|
|
743
|
-
if (typeof srcId === "string") {
|
|
744
|
-
const kept = {};
|
|
745
|
-
for (const k in st.callNames) if (k !== srcId) kept[k] = st.callNames[k];
|
|
746
|
-
st.callNames = kept;
|
|
747
|
-
}
|
|
748
|
-
if (message?.isError === true) node.err = true;
|
|
749
|
-
} else if (source?.kind === "skill-invocation") node.skill = typeof source.name === "string" ? source.name : "?";
|
|
750
|
-
else if (source?.kind === "plugin") {
|
|
751
|
-
if (source.form === "notice" && typeof source.summary === "string") node.text = source.summary;
|
|
752
|
-
else if (source.form === "snapshot" && Array.isArray(source.sections)) node.text = source.sections.map((s) => s?.name).filter(Boolean).join(", ").slice(0, 80);
|
|
753
|
-
else {
|
|
754
|
-
const ptext = firstText(message?.content);
|
|
755
|
-
if (ptext !== "") node.text = ptext;
|
|
756
|
-
}
|
|
757
|
-
} else {
|
|
758
|
-
const utext = firstText(message?.content);
|
|
759
|
-
if (utext !== "") node.text = utext;
|
|
760
|
-
}
|
|
761
|
-
const shadowedSeqs = st.pendingShadowedSeqs;
|
|
762
|
-
const shadowEventSeq = st.pendingShadowEventSeq;
|
|
763
|
-
delete st.pendingShadowedSeqs;
|
|
764
|
-
delete st.pendingShadowEventSeq;
|
|
765
|
-
const op = replaceRangeOf(ev.surfaceOp);
|
|
766
|
-
if (op !== null) {
|
|
767
|
-
if (Array.isArray(shadowedSeqs) && shadowedSeqs.length > 0) {
|
|
768
|
-
const removed = removeSurfaceSeqs(st, new Set(shadowedSeqs), ev.seq);
|
|
769
|
-
st.sums[cat] += node.tokens;
|
|
770
|
-
st.surface.push(node);
|
|
771
|
-
if (shadowEventSeq !== void 0) {
|
|
772
|
-
const removedSum = removed.reduce((sum, n) => sum + n.tokens, 0);
|
|
773
|
-
const i = st.events.findIndex((e) => e.seq === shadowEventSeq);
|
|
774
|
-
if (i >= 0) st.events[i] = {
|
|
775
|
-
...st.events[i],
|
|
776
|
-
tokens: Math.max(0, removedSum - node.tokens)
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
return node;
|
|
780
|
-
}
|
|
781
|
-
let si = -1;
|
|
782
|
-
let ei = -1;
|
|
783
|
-
for (let i = 0; i < st.surface.length; i++) {
|
|
784
|
-
if (si < 0 && st.surface[i].seq === op.start) si = i;
|
|
785
|
-
if (st.surface[i].seq === op.end) {
|
|
786
|
-
ei = i;
|
|
787
|
-
break;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
if (si >= 0 && ei >= si) {
|
|
791
|
-
const removed = st.surface.splice(si, ei - si + 1, node);
|
|
792
|
-
archiveRemoved(st, removed, ev.seq);
|
|
793
|
-
for (const r of removed) st.sums[r.cat] -= r.tokens;
|
|
794
|
-
st.sums[cat] += node.tokens;
|
|
795
|
-
return node;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
st.surface.push(node);
|
|
799
|
-
st.sums[cat] += node.tokens;
|
|
800
|
-
return node;
|
|
801
|
-
}
|
|
802
|
-
function tokenCountOf(value) {
|
|
803
|
-
if (typeof value === "number") return Number.isFinite(value) ? Math.max(0, Math.round(value)) : null;
|
|
804
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
805
|
-
const parsed = Number(value);
|
|
806
|
-
return Number.isFinite(parsed) ? Math.max(0, Math.round(parsed)) : null;
|
|
807
|
-
}
|
|
808
|
-
return null;
|
|
809
|
-
}
|
|
810
|
-
function isPeakUtc(time) {
|
|
811
|
-
const at = new Date(time);
|
|
812
|
-
const day = at.getUTCDay();
|
|
813
|
-
if (day === 0 || day === 6) return false;
|
|
814
|
-
const h = at.getUTCHours();
|
|
815
|
-
return h >= 1 && h < 4 || h >= 6 && h < 10;
|
|
816
|
-
}
|
|
817
|
-
function addBilledUsage(prev, provider, model, time, usage) {
|
|
818
|
-
const period = isDeepSeekProvider(provider) && !isPeakUtc(time) ? "off" : "peak";
|
|
819
|
-
const models = prev?.[provider] ?? {};
|
|
820
|
-
const periods = models[model] ?? {};
|
|
821
|
-
const b = periods[period] ?? {
|
|
822
|
-
uncached: 0,
|
|
823
|
-
cacheRead: 0,
|
|
824
|
-
cacheWrite: 0,
|
|
825
|
-
output: 0
|
|
826
|
-
};
|
|
827
|
-
const nextPeriods = { ...periods };
|
|
828
|
-
nextPeriods[period] = {
|
|
829
|
-
uncached: b.uncached + usage.input,
|
|
830
|
-
cacheRead: b.cacheRead + usage.cacheRead,
|
|
831
|
-
cacheWrite: b.cacheWrite + usage.cacheWrite,
|
|
832
|
-
output: b.output + usage.output
|
|
833
|
-
};
|
|
834
|
-
const nextModels = {
|
|
835
|
-
...models,
|
|
836
|
-
[model]: nextPeriods
|
|
837
|
-
};
|
|
838
|
-
return {
|
|
839
|
-
...prev ?? {},
|
|
840
|
-
[provider]: nextModels
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
function accumulateCost(st, time, usage) {
|
|
844
|
-
const model = st.model;
|
|
845
|
-
if (model === void 0) return;
|
|
846
|
-
st.cost = addBilledUsage(st.cost, st.provider ?? "", model, time, usage);
|
|
847
|
-
}
|
|
848
|
-
const TOOL_TIMING_CAP = 16;
|
|
849
|
-
const ASK_USER_TOOL = "ask_user_question";
|
|
850
|
-
const DECODE_KINDS = [
|
|
851
|
-
"reasoning",
|
|
852
|
-
"text",
|
|
853
|
-
"toolarg"
|
|
854
|
-
];
|
|
855
|
-
function durOf(from, to) {
|
|
856
|
-
if (!Number.isFinite(from) || !Number.isFinite(to)) return 0;
|
|
857
|
-
return Math.max(0, to - from);
|
|
858
|
-
}
|
|
859
|
-
function ensureTiming(st) {
|
|
860
|
-
if (st.timing === void 0) st.timing = {
|
|
861
|
-
wallMs: 0,
|
|
862
|
-
ttftMs: 0,
|
|
863
|
-
genMs: 0,
|
|
864
|
-
calls: 0,
|
|
865
|
-
toolsMs: 0,
|
|
866
|
-
toolCalls: 0,
|
|
867
|
-
tools: {}
|
|
868
|
-
};
|
|
869
|
-
return st.timing;
|
|
870
|
-
}
|
|
871
|
-
const DECODE_FIELDS = {
|
|
872
|
-
reasoning: {
|
|
873
|
-
ms: "reasoningMs",
|
|
874
|
-
n: "reasoningBlocks"
|
|
875
|
-
},
|
|
876
|
-
text: {
|
|
877
|
-
ms: "textMs",
|
|
878
|
-
n: "textBlocks"
|
|
879
|
-
},
|
|
880
|
-
toolarg: {
|
|
881
|
-
ms: "toolArgMs",
|
|
882
|
-
n: "toolArgBlocks"
|
|
989
|
+
if (toolEntry !== void 0) {
|
|
990
|
+
node.tool = toolEntry.name;
|
|
991
|
+
const timing = ensureTiming(st);
|
|
992
|
+
const dur = durOf(toolEntry.start, ev.time);
|
|
993
|
+
timing.toolsMs += dur;
|
|
994
|
+
timing.toolCalls += 1;
|
|
995
|
+
bumpToolTotals(timing, toolEntry.name, dur);
|
|
996
|
+
if (st.stepStart !== void 0) st.stepSpans = [...st.stepSpans ?? [], {
|
|
997
|
+
kind: "tools",
|
|
998
|
+
start: toolEntry.start,
|
|
999
|
+
end: ev.time
|
|
1000
|
+
}];
|
|
1001
|
+
}
|
|
1002
|
+
if (typeof srcId === "string") {
|
|
1003
|
+
const kept = {};
|
|
1004
|
+
for (const k in st.callNames) if (k !== srcId) kept[k] = st.callNames[k];
|
|
1005
|
+
st.callNames = kept;
|
|
1006
|
+
}
|
|
1007
|
+
if (message?.isError === true) node.err = true;
|
|
1008
|
+
} else if (source?.kind === "skill-invocation") node.skill = typeof source.name === "string" ? source.name : "?";
|
|
1009
|
+
else if (source?.kind === "plugin") {
|
|
1010
|
+
if (source.form === "notice" && typeof source.summary === "string") node.text = source.summary;
|
|
1011
|
+
else if (source.form === "snapshot" && Array.isArray(source.sections)) node.text = source.sections.map((s) => s?.name).filter(Boolean).join(", ").slice(0, 80);
|
|
1012
|
+
else {
|
|
1013
|
+
const ptext = firstText(message?.content);
|
|
1014
|
+
if (ptext !== "") node.text = ptext;
|
|
1015
|
+
}
|
|
1016
|
+
} else {
|
|
1017
|
+
const utext = firstText(message?.content);
|
|
1018
|
+
if (utext !== "") node.text = utext;
|
|
883
1019
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
1020
|
+
const shadowedSeqs = st.pendingShadowedSeqs;
|
|
1021
|
+
const shadowEventSeq = st.pendingShadowEventSeq;
|
|
1022
|
+
delete st.pendingShadowedSeqs;
|
|
1023
|
+
delete st.pendingShadowEventSeq;
|
|
1024
|
+
const op = replaceRangeOf(ev.surfaceOp);
|
|
1025
|
+
if (op !== null) {
|
|
1026
|
+
if (Array.isArray(shadowedSeqs) && shadowedSeqs.length > 0) {
|
|
1027
|
+
const removed = removeSurfaceSeqs(st, new Set(shadowedSeqs), ev.seq);
|
|
1028
|
+
st.sums[cat] += node.tokens;
|
|
1029
|
+
st.surface.push(node);
|
|
1030
|
+
if (shadowEventSeq !== void 0) {
|
|
1031
|
+
const removedSum = removed.reduce((sum, n) => sum + n.tokens, 0);
|
|
1032
|
+
const i = st.events.findIndex((e) => e.seq === shadowEventSeq);
|
|
1033
|
+
if (i >= 0) st.events[i] = {
|
|
1034
|
+
...st.events[i],
|
|
1035
|
+
tokens: Math.max(0, removedSum - node.tokens)
|
|
1036
|
+
};
|
|
898
1037
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1038
|
+
return node;
|
|
1039
|
+
}
|
|
1040
|
+
let si = -1;
|
|
1041
|
+
let ei = -1;
|
|
1042
|
+
for (let i = 0; i < st.surface.length; i++) {
|
|
1043
|
+
if (si < 0 && st.surface[i].seq === op.start) si = i;
|
|
1044
|
+
if (st.surface[i].seq === op.end) {
|
|
1045
|
+
ei = i;
|
|
1046
|
+
break;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
if (si >= 0 && ei >= si) {
|
|
1050
|
+
const removed = st.surface.splice(si, ei - si + 1, node);
|
|
1051
|
+
archiveRemoved(st, removed, ev.seq);
|
|
1052
|
+
for (const r of removed) st.sums[r.cat] -= r.tokens;
|
|
1053
|
+
st.sums[cat] += node.tokens;
|
|
1054
|
+
return node;
|
|
902
1055
|
}
|
|
903
|
-
timing.tools[name] = {
|
|
904
|
-
calls: 1,
|
|
905
|
-
ms
|
|
906
|
-
};
|
|
907
|
-
return;
|
|
908
1056
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
ms: cur.ms + ms
|
|
913
|
-
};
|
|
1057
|
+
st.surface.push(node);
|
|
1058
|
+
st.sums[cat] += node.tokens;
|
|
1059
|
+
return node;
|
|
914
1060
|
}
|
|
1061
|
+
const ASK_USER_TOOL = "ask_user_question";
|
|
915
1062
|
const CLONE_ALL = [
|
|
916
1063
|
"surface",
|
|
917
1064
|
"sums",
|
|
@@ -1273,7 +1420,7 @@ function applyTimeline(state, event, bounds) {
|
|
|
1273
1420
|
if (cacheRead !== null) record.cacheRead = cacheRead;
|
|
1274
1421
|
if (output !== null) record.output = output;
|
|
1275
1422
|
accumulateCost(s, event.time, {
|
|
1276
|
-
|
|
1423
|
+
uncached: input ?? 0,
|
|
1277
1424
|
cacheRead: cacheRead ?? 0,
|
|
1278
1425
|
cacheWrite: cacheWrite ?? 0,
|
|
1279
1426
|
output: output ?? 0
|
|
@@ -1367,145 +1514,6 @@ function applyTimeline(state, event, bounds) {
|
|
|
1367
1514
|
}
|
|
1368
1515
|
return state;
|
|
1369
1516
|
}
|
|
1370
|
-
function headFieldsOf(state) {
|
|
1371
|
-
const surfaceTotal = state.sums.user + state.sums.inject + state.sums.skill + state.sums.assistant + state.sums.tool;
|
|
1372
|
-
const result = {
|
|
1373
|
-
ok: true,
|
|
1374
|
-
...state.model !== void 0 ? { model: state.model } : {},
|
|
1375
|
-
...state.provider !== void 0 ? { provider: state.provider } : {},
|
|
1376
|
-
...state.contextWindow !== void 0 ? { contextWindow: state.contextWindow } : {},
|
|
1377
|
-
current: {
|
|
1378
|
-
system: state.systemTokens,
|
|
1379
|
-
tools: state.toolsTokens,
|
|
1380
|
-
user: state.sums.user,
|
|
1381
|
-
inject: state.sums.inject,
|
|
1382
|
-
skill: state.sums.skill,
|
|
1383
|
-
assistant: state.sums.assistant,
|
|
1384
|
-
tool: state.sums.tool,
|
|
1385
|
-
total: surfaceTotal + state.systemTokens + state.toolsTokens
|
|
1386
|
-
},
|
|
1387
|
-
images: state.surface.reduce((n, node) => n + (node.imgs ?? 0), 0),
|
|
1388
|
-
toolCalls: state.surface.reduce((n, node) => node.cat === "tool" || node.cat === "skill" && node.tool !== void 0 ? n + 1 : n, 0),
|
|
1389
|
-
humanInputs: state.humanInputs ?? 0,
|
|
1390
|
-
answers: state.answers ?? 0,
|
|
1391
|
-
...state.lastUser !== void 0 ? { lastUser: state.lastUser } : {},
|
|
1392
|
-
requests: [],
|
|
1393
|
-
events: [],
|
|
1394
|
-
nodes: [],
|
|
1395
|
-
droppedNodes: 0,
|
|
1396
|
-
archive: []
|
|
1397
|
-
};
|
|
1398
|
-
if (state.cost !== void 0) {
|
|
1399
|
-
const cost = {};
|
|
1400
|
-
for (const provider in state.cost) {
|
|
1401
|
-
const models = {};
|
|
1402
|
-
for (const model in state.cost[provider]) {
|
|
1403
|
-
const periods = state.cost[provider][model];
|
|
1404
|
-
const copy = {};
|
|
1405
|
-
if (periods.peak !== void 0) copy.peak = { ...periods.peak };
|
|
1406
|
-
if (periods.off !== void 0) copy.off = { ...periods.off };
|
|
1407
|
-
models[model] = copy;
|
|
1408
|
-
}
|
|
1409
|
-
cost[provider] = models;
|
|
1410
|
-
}
|
|
1411
|
-
result.cost = cost;
|
|
1412
|
-
}
|
|
1413
|
-
if (state.timing !== void 0) {
|
|
1414
|
-
const tools = {};
|
|
1415
|
-
for (const k in state.timing.tools) tools[k] = { ...state.timing.tools[k] };
|
|
1416
|
-
result.timing = {
|
|
1417
|
-
...state.timing,
|
|
1418
|
-
tools
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
if (state.systems !== void 0 && state.systems.length > 0) result.systems = state.systems.map((n) => ({ ...n }));
|
|
1422
|
-
return result;
|
|
1423
|
-
}
|
|
1424
|
-
function detailCollectionsOf(state, bounds) {
|
|
1425
|
-
const result = {
|
|
1426
|
-
requests: state.requests.map((r) => ({ ...r })),
|
|
1427
|
-
events: state.events.map((e) => ({ ...e })),
|
|
1428
|
-
nodes: [],
|
|
1429
|
-
droppedNodes: 0,
|
|
1430
|
-
archive: state.archived.map((n) => ({ ...n })),
|
|
1431
|
-
fileOps: state.fileOps.map((o) => ({ ...o })),
|
|
1432
|
-
...state.fileOpsFloor !== void 0 ? { fileOpsFloor: state.fileOpsFloor } : {},
|
|
1433
|
-
spans: state.spans.map((s) => ({ ...s }))
|
|
1434
|
-
};
|
|
1435
|
-
const overflowCount = Math.max(0, state.surface.length - bounds.maxNodes);
|
|
1436
|
-
const overflow = state.surface.slice(0, overflowCount);
|
|
1437
|
-
const tail = state.surface.slice(overflowCount);
|
|
1438
|
-
const pinned = overflow.filter((n) => n.cat === "inject" || n.cat === "skill");
|
|
1439
|
-
result.nodes = pinned.length > 0 ? [...pinned, ...tail] : tail;
|
|
1440
|
-
result.droppedNodes = overflowCount - pinned.length;
|
|
1441
|
-
if (result.droppedNodes > 0) {
|
|
1442
|
-
let floor = 0;
|
|
1443
|
-
for (const n of overflow) if (n.cat !== "inject" && n.cat !== "skill") floor = Math.max(floor, n.seq);
|
|
1444
|
-
result.surfaceFloor = floor;
|
|
1445
|
-
}
|
|
1446
|
-
if (state.archiveFloor !== void 0) result.archiveFloor = state.archiveFloor;
|
|
1447
|
-
const requests = result.requests;
|
|
1448
|
-
const events = result.events;
|
|
1449
|
-
let ri = 0;
|
|
1450
|
-
for (const ev of events) {
|
|
1451
|
-
while (ri < requests.length && requests[ri].seq <= ev.seq) ri++;
|
|
1452
|
-
const next = requests.at(ri);
|
|
1453
|
-
const prev = ri > 0 ? requests.at(ri - 1) : void 0;
|
|
1454
|
-
if (next !== void 0 && typeof next.turn === "number" && typeof next.step === "number") {
|
|
1455
|
-
ev.turn = next.turn;
|
|
1456
|
-
ev.step = next.step;
|
|
1457
|
-
}
|
|
1458
|
-
if (prev !== void 0 && typeof prev.turn === "number" && typeof prev.step === "number") {
|
|
1459
|
-
ev.fromTurn = prev.turn;
|
|
1460
|
-
ev.fromStep = prev.step;
|
|
1461
|
-
}
|
|
1462
|
-
}
|
|
1463
|
-
return result;
|
|
1464
|
-
}
|
|
1465
|
-
function buildTimelineHead(state) {
|
|
1466
|
-
const result = headFieldsOf(state);
|
|
1467
|
-
const turns = new Set();
|
|
1468
|
-
for (const r of state.requests) turns.add(r.turn ?? 0);
|
|
1469
|
-
let injects = 0;
|
|
1470
|
-
let compactions = 0;
|
|
1471
|
-
let prunes = 0;
|
|
1472
|
-
const skills = new Set();
|
|
1473
|
-
for (const e of state.events) {
|
|
1474
|
-
if (e.kind === "inject") injects++;
|
|
1475
|
-
else if (e.kind === "compaction") compactions++;
|
|
1476
|
-
else if (e.kind === "prune") prunes++;
|
|
1477
|
-
if (e.sub === "skill" && typeof e.name === "string" && e.name !== "") skills.add(e.name);
|
|
1478
|
-
}
|
|
1479
|
-
result.counts = {
|
|
1480
|
-
turns: turns.size,
|
|
1481
|
-
steps: state.requests.length,
|
|
1482
|
-
injects,
|
|
1483
|
-
compactions,
|
|
1484
|
-
prunes,
|
|
1485
|
-
skills: skills.size
|
|
1486
|
-
};
|
|
1487
|
-
const last = state.requests.at(-1);
|
|
1488
|
-
if (last !== void 0) result.last = {
|
|
1489
|
-
seq: last.seq,
|
|
1490
|
-
total: last.total,
|
|
1491
|
-
...typeof last.prompt === "number" ? { prompt: last.prompt } : {}
|
|
1492
|
-
};
|
|
1493
|
-
result.detailRev = state.detailRev ?? 0;
|
|
1494
|
-
return result;
|
|
1495
|
-
}
|
|
1496
|
-
function buildTimelineDetail(state, bounds) {
|
|
1497
|
-
return {
|
|
1498
|
-
rev: state.detailRev ?? 0,
|
|
1499
|
-
head: buildTimelineHead(state),
|
|
1500
|
-
...detailCollectionsOf(state, bounds)
|
|
1501
|
-
};
|
|
1502
|
-
}
|
|
1503
|
-
function buildTimelineView(state, bounds) {
|
|
1504
|
-
return {
|
|
1505
|
-
...headFieldsOf(state),
|
|
1506
|
-
...detailCollectionsOf(state, bounds)
|
|
1507
|
-
};
|
|
1508
|
-
}
|
|
1509
1517
|
//#endregion
|
|
1510
1518
|
//#region src/host/config.ts
|
|
1511
1519
|
const DEFAULT_BOUNDS = {
|
|
@@ -1865,7 +1873,7 @@ function billedBucketsOf(value) {
|
|
|
1865
1873
|
const output = tokenCountOf(usage.outputTokens);
|
|
1866
1874
|
if (input === null && cacheRead === null && cacheWrite === null && output === null) return null;
|
|
1867
1875
|
return {
|
|
1868
|
-
|
|
1876
|
+
uncached: input ?? 0,
|
|
1869
1877
|
cacheRead: cacheRead ?? 0,
|
|
1870
1878
|
cacheWrite: cacheWrite ?? 0,
|
|
1871
1879
|
output: output ?? 0
|
|
@@ -1993,7 +2001,7 @@ function applyActivity(state, event) {
|
|
|
1993
2001
|
let cost = prev?.cost;
|
|
1994
2002
|
if (buckets !== null && state.model !== void 0) cost = addBilledUsage(cost, state.provider ?? "", state.model, initiated, buckets);
|
|
1995
2003
|
return withDayEntry(state, key, {
|
|
1996
|
-
tokens: (prev === void 0 ? 0 : prev.tokens) + (buckets === null ? 0 : buckets.
|
|
2004
|
+
tokens: (prev === void 0 ? 0 : prev.tokens) + (buckets === null ? 0 : buckets.uncached + buckets.cacheRead + buckets.cacheWrite + buckets.output),
|
|
1997
2005
|
requests: (prev === void 0 ? 0 : prev.requests) + 1,
|
|
1998
2006
|
...cost !== void 0 ? { cost } : {},
|
|
1999
2007
|
...prev?.skills !== void 0 ? { skills: prev.skills } : {}
|
|
@@ -2007,7 +2015,11 @@ function createContextActivityDefinition() {
|
|
|
2007
2015
|
apply: (state, event) => applyActivity(state, event),
|
|
2008
2016
|
wire: {
|
|
2009
2017
|
viewSchema: contextActivitySchema,
|
|
2010
|
-
view: (state) => ({ days: Object.fromEntries(Object.entries(state.days).map(([k, v]) => [k, {
|
|
2018
|
+
view: (state) => ({ days: Object.fromEntries(Object.entries(state.days).map(([k, v]) => [k, {
|
|
2019
|
+
...v,
|
|
2020
|
+
...v.cost !== void 0 ? { cost: copyCostUsage(v.cost) } : {},
|
|
2021
|
+
...v.skills !== void 0 ? { skills: Object.fromEntries(Object.entries(v.skills).map(([n, t]) => [n, { ...t }])) } : {}
|
|
2022
|
+
}])) })
|
|
2011
2023
|
},
|
|
2012
2024
|
stateVersion: 4
|
|
2013
2025
|
};
|
|
@@ -2172,19 +2184,36 @@ function createToolAttribution(ctx) {
|
|
|
2172
2184
|
return { ownerOf: (name) => mcpSourceOf(name) ?? live.get(name) ?? pinnedSourceOf(name) ?? (boot.has(name) ? "<unknown-plugin>" : void 0) };
|
|
2173
2185
|
}
|
|
2174
2186
|
//#endregion
|
|
2187
|
+
//#region src/host/record.ts
|
|
2188
|
+
function asRecord(value) {
|
|
2189
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2190
|
+
}
|
|
2191
|
+
//#endregion
|
|
2175
2192
|
//#region src/host/connection.ts
|
|
2176
2193
|
function fetchRouteRegistrar(connection) {
|
|
2177
2194
|
return typeof connection?.fetch?.register === "function" ? connection.fetch.register.bind(connection.fetch) : void 0;
|
|
2178
2195
|
}
|
|
2196
|
+
function registerPostRoute(c, connection, path, fetch, label) {
|
|
2197
|
+
const register = fetchRouteRegistrar(connection);
|
|
2198
|
+
if (register === void 0) return false;
|
|
2199
|
+
try {
|
|
2200
|
+
c.effect(() => register({
|
|
2201
|
+
path,
|
|
2202
|
+
methods: ["POST"],
|
|
2203
|
+
requestBody: "buffered",
|
|
2204
|
+
fetch
|
|
2205
|
+
}), label);
|
|
2206
|
+
} catch {
|
|
2207
|
+
return false;
|
|
2208
|
+
}
|
|
2209
|
+
return true;
|
|
2210
|
+
}
|
|
2179
2211
|
//#endregion
|
|
2180
2212
|
//#region src/host/balance.ts
|
|
2181
2213
|
const BALANCE_ROUTE = "/api/dsh-context/balance";
|
|
2182
2214
|
const DEEPSEEK_SETTINGS_NS = "llm-deepseek";
|
|
2183
2215
|
const PUBLIC_BASE_URL = "https://api.deepseek.com";
|
|
2184
2216
|
const FETCH_TIMEOUT_MS = 1e4;
|
|
2185
|
-
function asRecord$2(value) {
|
|
2186
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2187
|
-
}
|
|
2188
2217
|
function amountOf(value) {
|
|
2189
2218
|
const n = typeof value === "string" ? Number(value) : value;
|
|
2190
2219
|
return typeof n === "number" && Number.isFinite(n) && n >= 0 ? n : null;
|
|
@@ -2197,9 +2226,9 @@ function deepseekSectionOf(ctx) {
|
|
|
2197
2226
|
if (!Array.isArray(rows)) return null;
|
|
2198
2227
|
let shaped = null;
|
|
2199
2228
|
for (const row of rows) try {
|
|
2200
|
-
const record = asRecord
|
|
2229
|
+
const record = asRecord(row);
|
|
2201
2230
|
if (record === null) continue;
|
|
2202
|
-
const value = asRecord
|
|
2231
|
+
const value = asRecord(record.value);
|
|
2203
2232
|
if (value === null || typeof value.apiKeyEnv !== "string" || value.apiKeyEnv === "") continue;
|
|
2204
2233
|
if (record.ns === DEEPSEEK_SETTINGS_NS || record.ns === "llm-deepseek-api-key") return value;
|
|
2205
2234
|
shaped ??= value;
|
|
@@ -2232,12 +2261,12 @@ async function resolveFacts(ctx) {
|
|
|
2232
2261
|
};
|
|
2233
2262
|
}
|
|
2234
2263
|
function balanceOfPayload(value) {
|
|
2235
|
-
const data = asRecord
|
|
2264
|
+
const data = asRecord(value);
|
|
2236
2265
|
if (data === null) return null;
|
|
2237
2266
|
const infos = Array.isArray(data.balance_infos) ? data.balance_infos : [];
|
|
2238
2267
|
const balances = [];
|
|
2239
2268
|
for (const info of infos) try {
|
|
2240
|
-
const entry = asRecord
|
|
2269
|
+
const entry = asRecord(info);
|
|
2241
2270
|
if (entry === null) continue;
|
|
2242
2271
|
const currency = entry.currency;
|
|
2243
2272
|
const granted = amountOf(entry.granted_balance);
|
|
@@ -2285,8 +2314,6 @@ async function readBalance(facts) {
|
|
|
2285
2314
|
}
|
|
2286
2315
|
function watchBalanceChannel(ctx) {
|
|
2287
2316
|
ctx.inject(["connection"], (c) => {
|
|
2288
|
-
const register = fetchRouteRegistrar(c.get("connection"));
|
|
2289
|
-
if (register === void 0) return;
|
|
2290
2317
|
const handler = async () => {
|
|
2291
2318
|
const facts = await resolveFacts(ctx);
|
|
2292
2319
|
const value = facts !== null ? await readBalance(facts) : null;
|
|
@@ -2295,16 +2322,7 @@ function watchBalanceChannel(ctx) {
|
|
|
2295
2322
|
value
|
|
2296
2323
|
}, { headers: { "cache-control": "no-store" } });
|
|
2297
2324
|
};
|
|
2298
|
-
|
|
2299
|
-
c.effect(() => register({
|
|
2300
|
-
path: BALANCE_ROUTE,
|
|
2301
|
-
methods: ["POST"],
|
|
2302
|
-
requestBody: "buffered",
|
|
2303
|
-
fetch: handler
|
|
2304
|
-
}), "dsh-context: balance route");
|
|
2305
|
-
} catch {
|
|
2306
|
-
return;
|
|
2307
|
-
}
|
|
2325
|
+
registerPostRoute(c, c.get("connection"), BALANCE_ROUTE, handler, "dsh-context: balance route");
|
|
2308
2326
|
});
|
|
2309
2327
|
}
|
|
2310
2328
|
//#endregion
|
|
@@ -2340,11 +2358,8 @@ function makeColdReadGate(reading = v8Reading) {
|
|
|
2340
2358
|
const BACKFILL_ROUTE = "/api/dsh-context/backfill";
|
|
2341
2359
|
const YIELD_MS = 100;
|
|
2342
2360
|
const UNSUPPORTED_FORMAT = "SessionFormatUnsupported";
|
|
2343
|
-
function asRecord$1(value) {
|
|
2344
|
-
return value !== null && typeof value === "object" ? value : null;
|
|
2345
|
-
}
|
|
2346
2361
|
function headerOf(record) {
|
|
2347
|
-
const header = asRecord
|
|
2362
|
+
const header = asRecord(asRecord(record)?.header);
|
|
2348
2363
|
if (header === null) return null;
|
|
2349
2364
|
if (typeof header.id !== "string" || header.id === "") return null;
|
|
2350
2365
|
return header;
|
|
@@ -2352,7 +2367,7 @@ function headerOf(record) {
|
|
|
2352
2367
|
const PROBE_KEYS = ["contextActivity", "contextTimeline"];
|
|
2353
2368
|
function servesRows(cache, header) {
|
|
2354
2369
|
try {
|
|
2355
|
-
const values = asRecord
|
|
2370
|
+
const values = asRecord(asRecord(cache.cachedSnapshot(header, PROBE_KEYS))?.values);
|
|
2356
2371
|
return values !== null && values.contextActivity !== void 0 && values.contextTimeline !== void 0;
|
|
2357
2372
|
} catch {
|
|
2358
2373
|
return false;
|
|
@@ -2362,7 +2377,7 @@ async function readColdLog(persistence, id, signal) {
|
|
|
2362
2377
|
const handle = await persistence.open(id, "read", { signal });
|
|
2363
2378
|
let events;
|
|
2364
2379
|
try {
|
|
2365
|
-
const result = asRecord
|
|
2380
|
+
const result = asRecord(await handle.read(0, void 0, { signal }))?.events;
|
|
2366
2381
|
events = Array.isArray(result) ? result : [];
|
|
2367
2382
|
} catch (error) {
|
|
2368
2383
|
try {
|
|
@@ -2387,7 +2402,7 @@ function isLive(sessions, id) {
|
|
|
2387
2402
|
}
|
|
2388
2403
|
function isUnsupportedFormat(error) {
|
|
2389
2404
|
try {
|
|
2390
|
-
return String(asRecord
|
|
2405
|
+
return String(asRecord(error)?.name).startsWith(UNSUPPORTED_FORMAT);
|
|
2391
2406
|
} catch {
|
|
2392
2407
|
return false;
|
|
2393
2408
|
}
|
|
@@ -2409,22 +2424,12 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2409
2424
|
launch();
|
|
2410
2425
|
};
|
|
2411
2426
|
const routeFiber = ctx.inject(["connection"], (c) => {
|
|
2412
|
-
const
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
requestBody: "buffered",
|
|
2419
|
-
fetch: () => {
|
|
2420
|
-
requested = true;
|
|
2421
|
-
tryLaunch();
|
|
2422
|
-
return Response.json({ ok: true }, { headers: { "cache-control": "no-store" } });
|
|
2423
|
-
}
|
|
2424
|
-
}), "dsh-context: backfill route");
|
|
2425
|
-
} catch {
|
|
2426
|
-
return;
|
|
2427
|
-
}
|
|
2427
|
+
const handler = () => {
|
|
2428
|
+
requested = true;
|
|
2429
|
+
tryLaunch();
|
|
2430
|
+
return Response.json({ ok: true }, { headers: { "cache-control": "no-store" } });
|
|
2431
|
+
};
|
|
2432
|
+
registerPostRoute(c, c.get("connection"), BACKFILL_ROUTE, handler, "dsh-context: backfill route");
|
|
2428
2433
|
});
|
|
2429
2434
|
const runnerFiber = ctx.inject([
|
|
2430
2435
|
"sessionQuery",
|
|
@@ -2433,13 +2438,13 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2433
2438
|
"sessions"
|
|
2434
2439
|
], (raw) => {
|
|
2435
2440
|
const injected = raw;
|
|
2436
|
-
const query = asRecord
|
|
2437
|
-
const cache = asRecord
|
|
2438
|
-
const persistence = asRecord
|
|
2441
|
+
const query = asRecord(injected.sessionQuery);
|
|
2442
|
+
const cache = asRecord(injected.sessionProjectionCache);
|
|
2443
|
+
const persistence = asRecord(injected.sessionPersistence);
|
|
2439
2444
|
if (query === null || typeof query.listSessions !== "function") return;
|
|
2440
2445
|
if (cache === null || typeof cache.cachedSnapshot !== "function" || typeof cache.coldSnapshot !== "function") return;
|
|
2441
2446
|
if (persistence === null || typeof persistence.open !== "function") return;
|
|
2442
|
-
const sessions = asRecord
|
|
2447
|
+
const sessions = asRecord(injected.sessions);
|
|
2443
2448
|
const abort = new AbortController();
|
|
2444
2449
|
const run = async () => {
|
|
2445
2450
|
const listed = await query.listSessions(abort.signal);
|
|
@@ -2489,9 +2494,6 @@ function watchActivityBackfill(ctx, coldReads = makeColdReadGate()) {
|
|
|
2489
2494
|
for (const fiber of [routeFiber, runnerFiber]) fiber?.dispose?.();
|
|
2490
2495
|
};
|
|
2491
2496
|
}
|
|
2492
|
-
//#endregion
|
|
2493
|
-
//#region src/host/detail.ts
|
|
2494
|
-
const DETAIL_ROUTE = "/api/dsh-context/detail";
|
|
2495
2497
|
function reply(value) {
|
|
2496
2498
|
return Response.json(value, { headers: { "cache-control": "no-store" } });
|
|
2497
2499
|
}
|
|
@@ -2508,9 +2510,8 @@ function watchDetailChannel(ctx, bounds, coldReads = makeColdReadGate()) {
|
|
|
2508
2510
|
const gate = { live: false };
|
|
2509
2511
|
ctx.inject(["connection", "sessions"], (c) => {
|
|
2510
2512
|
const sessions = c.get("sessions");
|
|
2511
|
-
const register = fetchRouteRegistrar(c.get("connection"));
|
|
2512
2513
|
const getSession = typeof sessions?.get === "function" ? sessions.get.bind(sessions) : void 0;
|
|
2513
|
-
if (
|
|
2514
|
+
if (getSession === void 0) return;
|
|
2514
2515
|
const projections = ctx.sessionProjections;
|
|
2515
2516
|
const handler = async (request) => {
|
|
2516
2517
|
let sessionId;
|
|
@@ -2560,16 +2561,7 @@ function watchDetailChannel(ctx, bounds, coldReads = makeColdReadGate()) {
|
|
|
2560
2561
|
return failure("gateway/internal", err instanceof Error ? err.message : String(err));
|
|
2561
2562
|
}
|
|
2562
2563
|
};
|
|
2563
|
-
|
|
2564
|
-
c.effect(() => register({
|
|
2565
|
-
path: DETAIL_ROUTE,
|
|
2566
|
-
methods: ["POST"],
|
|
2567
|
-
requestBody: "buffered",
|
|
2568
|
-
fetch: handler
|
|
2569
|
-
}), "dsh-context: detail route");
|
|
2570
|
-
} catch {
|
|
2571
|
-
return;
|
|
2572
|
-
}
|
|
2564
|
+
if (!registerPostRoute(c, c.get("connection"), "/api/dsh-context/detail", handler, "dsh-context: detail route")) return;
|
|
2573
2565
|
gate.live = true;
|
|
2574
2566
|
return () => {
|
|
2575
2567
|
gate.live = false;
|
|
@@ -2787,9 +2779,6 @@ function watchStepIdentity(ctx) {
|
|
|
2787
2779
|
//#region src/host/skills.ts
|
|
2788
2780
|
const SKILLS_ROUTE = "/api/dsh-context/skills";
|
|
2789
2781
|
const MAX_SKILLS = 500;
|
|
2790
|
-
function asRecord(value) {
|
|
2791
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2792
|
-
}
|
|
2793
2782
|
function stringOf(value) {
|
|
2794
2783
|
return typeof value === "string" && value !== "" ? value : void 0;
|
|
2795
2784
|
}
|
|
@@ -2874,8 +2863,6 @@ async function resolveRegistry(ctx, sessionId, agentPreset) {
|
|
|
2874
2863
|
}
|
|
2875
2864
|
function watchSkillCatalog(ctx) {
|
|
2876
2865
|
ctx.inject(["connection"], (c) => {
|
|
2877
|
-
const register = fetchRouteRegistrar(c.get("connection"));
|
|
2878
|
-
if (register === void 0) return;
|
|
2879
2866
|
const handler = async (request) => {
|
|
2880
2867
|
let value = null;
|
|
2881
2868
|
let lease;
|
|
@@ -2908,16 +2895,7 @@ function watchSkillCatalog(ctx) {
|
|
|
2908
2895
|
value
|
|
2909
2896
|
}, { headers: { "cache-control": "no-store" } });
|
|
2910
2897
|
};
|
|
2911
|
-
|
|
2912
|
-
c.effect(() => register({
|
|
2913
|
-
path: SKILLS_ROUTE,
|
|
2914
|
-
methods: ["POST"],
|
|
2915
|
-
requestBody: "buffered",
|
|
2916
|
-
fetch: handler
|
|
2917
|
-
}), "dsh-context: skills route");
|
|
2918
|
-
} catch {
|
|
2919
|
-
return;
|
|
2920
|
-
}
|
|
2898
|
+
registerPostRoute(c, c.get("connection"), SKILLS_ROUTE, handler, "dsh-context: skills route");
|
|
2921
2899
|
});
|
|
2922
2900
|
}
|
|
2923
2901
|
//#endregion
|