@crazyhappyone/dsh-tui 0.1.0-alpha.5 → 0.1.0-alpha.7
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/dist/index.js +951 -11
- package/package.json +1 -1
- package/tui/cordis.patch.yml +30 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as __nodeModule from 'node:module'; const require = __nodeModule.createRequire(import.meta.url);
|
|
2
1
|
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -31876,6 +31875,126 @@ function assertNever(value, context) {
|
|
|
31876
31875
|
const rendered = JSON.stringify(value) ?? String(value);
|
|
31877
31876
|
throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
|
|
31878
31877
|
}
|
|
31878
|
+
function hasIntrinsicConstructor(prototype, name2) {
|
|
31879
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, "constructor");
|
|
31880
|
+
const constructor = descriptor?.value;
|
|
31881
|
+
if (typeof constructor !== "function") return false;
|
|
31882
|
+
try {
|
|
31883
|
+
return constructor.name === name2 && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name2}() { [native code] }`;
|
|
31884
|
+
} catch {
|
|
31885
|
+
return false;
|
|
31886
|
+
}
|
|
31887
|
+
}
|
|
31888
|
+
function isIntrinsicObjectPrototype(value) {
|
|
31889
|
+
return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, "Object");
|
|
31890
|
+
}
|
|
31891
|
+
function hasPlainArrayPrototype(value) {
|
|
31892
|
+
const prototype = Object.getPrototypeOf(value);
|
|
31893
|
+
if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, "Array")) return false;
|
|
31894
|
+
const objectPrototype = Object.getPrototypeOf(prototype);
|
|
31895
|
+
return typeof objectPrototype === "object" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);
|
|
31896
|
+
}
|
|
31897
|
+
function hasPlainObjectPrototype(value) {
|
|
31898
|
+
const prototype = Object.getPrototypeOf(value);
|
|
31899
|
+
return prototype === null || typeof prototype === "object" && isIntrinsicObjectPrototype(prototype);
|
|
31900
|
+
}
|
|
31901
|
+
function enumerableStringKeys(value) {
|
|
31902
|
+
const keys = Reflect.ownKeys(value);
|
|
31903
|
+
if (keys.some((key) => typeof key !== "string" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;
|
|
31904
|
+
return keys;
|
|
31905
|
+
}
|
|
31906
|
+
function walkJsonValue(value, detach) {
|
|
31907
|
+
const ancestors = /* @__PURE__ */ new Set();
|
|
31908
|
+
let root;
|
|
31909
|
+
const assign = (destination, item) => {
|
|
31910
|
+
if (destination === void 0) return;
|
|
31911
|
+
if (destination.kind === "root") {
|
|
31912
|
+
root = item;
|
|
31913
|
+
} else if (destination.kind === "array") {
|
|
31914
|
+
destination.target[destination.index] = item;
|
|
31915
|
+
} else {
|
|
31916
|
+
Object.defineProperty(destination.target, destination.key, {
|
|
31917
|
+
value: item,
|
|
31918
|
+
enumerable: true,
|
|
31919
|
+
configurable: true,
|
|
31920
|
+
writable: true
|
|
31921
|
+
});
|
|
31922
|
+
}
|
|
31923
|
+
};
|
|
31924
|
+
const tasks = [{
|
|
31925
|
+
kind: "visit",
|
|
31926
|
+
value,
|
|
31927
|
+
...detach ? { destination: { kind: "root" } } : {}
|
|
31928
|
+
}];
|
|
31929
|
+
for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {
|
|
31930
|
+
if (task.kind === "leave") {
|
|
31931
|
+
ancestors.delete(task.source);
|
|
31932
|
+
continue;
|
|
31933
|
+
}
|
|
31934
|
+
if (task.kind === "array-item") {
|
|
31935
|
+
if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;
|
|
31936
|
+
tasks.push({
|
|
31937
|
+
kind: "visit",
|
|
31938
|
+
value: task.source[task.index],
|
|
31939
|
+
...task.target === void 0 ? {} : { destination: { kind: "array", target: task.target, index: task.index } }
|
|
31940
|
+
});
|
|
31941
|
+
continue;
|
|
31942
|
+
}
|
|
31943
|
+
if (task.kind === "object-property") {
|
|
31944
|
+
tasks.push({
|
|
31945
|
+
kind: "visit",
|
|
31946
|
+
value: task.source[task.key],
|
|
31947
|
+
...task.target === void 0 ? {} : { destination: { kind: "object", target: task.target, key: task.key } }
|
|
31948
|
+
});
|
|
31949
|
+
continue;
|
|
31950
|
+
}
|
|
31951
|
+
const current = task.value;
|
|
31952
|
+
if (current === null) {
|
|
31953
|
+
assign(task.destination, null);
|
|
31954
|
+
continue;
|
|
31955
|
+
}
|
|
31956
|
+
if (typeof current === "boolean" || typeof current === "string") {
|
|
31957
|
+
assign(task.destination, current);
|
|
31958
|
+
continue;
|
|
31959
|
+
}
|
|
31960
|
+
if (typeof current === "number") {
|
|
31961
|
+
if (!Number.isFinite(current) || Object.is(current, -0)) return void 0;
|
|
31962
|
+
assign(task.destination, current);
|
|
31963
|
+
continue;
|
|
31964
|
+
}
|
|
31965
|
+
if (typeof current !== "object") return void 0;
|
|
31966
|
+
if (ancestors.has(current)) return void 0;
|
|
31967
|
+
if (Array.isArray(current)) {
|
|
31968
|
+
if (!hasPlainArrayPrototype(current)) return void 0;
|
|
31969
|
+
const length = current.length;
|
|
31970
|
+
if (Reflect.ownKeys(current).length !== length + 1) return void 0;
|
|
31971
|
+
const target2 = detach ? [] : void 0;
|
|
31972
|
+
if (target2 !== void 0) assign(task.destination, target2);
|
|
31973
|
+
ancestors.add(current);
|
|
31974
|
+
tasks.push({ kind: "leave", source: current });
|
|
31975
|
+
for (let index2 = length - 1; index2 >= 0; index2--) {
|
|
31976
|
+
tasks.push({ kind: "array-item", source: current, index: index2, ...target2 === void 0 ? {} : { target: target2 } });
|
|
31977
|
+
}
|
|
31978
|
+
continue;
|
|
31979
|
+
}
|
|
31980
|
+
if (!hasPlainObjectPrototype(current)) return void 0;
|
|
31981
|
+
const keys = enumerableStringKeys(current);
|
|
31982
|
+
if (keys === void 0) return void 0;
|
|
31983
|
+
const target = detach ? {} : void 0;
|
|
31984
|
+
if (target !== void 0) assign(task.destination, target);
|
|
31985
|
+
ancestors.add(current);
|
|
31986
|
+
tasks.push({ kind: "leave", source: current });
|
|
31987
|
+
for (let index2 = keys.length - 1; index2 >= 0; index2--) {
|
|
31988
|
+
const key = keys[index2];
|
|
31989
|
+
if (key === void 0) return void 0;
|
|
31990
|
+
tasks.push({ kind: "object-property", source: current, key, ...target === void 0 ? {} : { target } });
|
|
31991
|
+
}
|
|
31992
|
+
}
|
|
31993
|
+
return detach ? root : true;
|
|
31994
|
+
}
|
|
31995
|
+
function snapshotJsonValue(value) {
|
|
31996
|
+
return walkJsonValue(value, true);
|
|
31997
|
+
}
|
|
31879
31998
|
function deepFreeze(value) {
|
|
31880
31999
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
31881
32000
|
const pending = [{ kind: "visit", node: value }];
|
|
@@ -32970,10 +33089,763 @@ var UserQuestionError = class extends HarnessError {
|
|
|
32970
33089
|
}
|
|
32971
33090
|
};
|
|
32972
33091
|
|
|
33092
|
+
// ../deepseek-harness/packages/core/session/src/index.ts
|
|
33093
|
+
import { isAbsolute } from "node:path";
|
|
33094
|
+
|
|
32973
33095
|
// ../deepseek-harness/packages/core/session/src/types.ts
|
|
32974
33096
|
function SessionId(id) {
|
|
32975
33097
|
return brandString(id);
|
|
32976
33098
|
}
|
|
33099
|
+
var SESSION_FORMAT_VERSION = 0;
|
|
33100
|
+
|
|
33101
|
+
// ../deepseek-harness/packages/core/session/src/surface.ts
|
|
33102
|
+
var SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
33103
|
+
"user/message",
|
|
33104
|
+
"assistant/message",
|
|
33105
|
+
"tool/result"
|
|
33106
|
+
]);
|
|
33107
|
+
function isSurfaceEligibleType(type) {
|
|
33108
|
+
return SURFACE_EVENT_TYPES.has(type);
|
|
33109
|
+
}
|
|
33110
|
+
function deriveEventMessage(event) {
|
|
33111
|
+
switch (event.type) {
|
|
33112
|
+
// Ordinary prompts and injected context project in user role: the event's
|
|
33113
|
+
// model-facing content stays verbatim. Do NOT re-add per-type framing
|
|
33114
|
+
// (e.g. `<context>`) here: framing is caller-owned — a producer bakes it
|
|
33115
|
+
// into `content`, as agent-instructions does with `<system-reminder>` — or,
|
|
33116
|
+
// if reintroduced, must be driven by the event `meta` map and a dedicated
|
|
33117
|
+
// renderer, keeping this projection a verbatim pass-through. See the
|
|
33118
|
+
// deferred design note in
|
|
33119
|
+
// ../../../../.agents/notes/implemented/simplification/2026-07-20-unwrap-injected-content-envelopes.md
|
|
33120
|
+
case "user/message": {
|
|
33121
|
+
return event.data;
|
|
33122
|
+
}
|
|
33123
|
+
case "assistant/message": {
|
|
33124
|
+
if (event.data.message.content.length === 0) return null;
|
|
33125
|
+
return event.data.message;
|
|
33126
|
+
}
|
|
33127
|
+
case "tool/result": {
|
|
33128
|
+
return event.data.message;
|
|
33129
|
+
}
|
|
33130
|
+
default:
|
|
33131
|
+
return null;
|
|
33132
|
+
}
|
|
33133
|
+
}
|
|
33134
|
+
function createFoldState() {
|
|
33135
|
+
return { nodes: [], replaceGeneration: 0 };
|
|
33136
|
+
}
|
|
33137
|
+
function isEventSeq(value) {
|
|
33138
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
33139
|
+
}
|
|
33140
|
+
function isReplaceOp(value) {
|
|
33141
|
+
const op = value;
|
|
33142
|
+
return Object.keys(op).length === 3 && Object.hasOwn(op, "op") && Object.hasOwn(op, "start") && Object.hasOwn(op, "end") && op["op"] === "replace" && isEventSeq(op["start"]) && isEventSeq(op["end"]);
|
|
33143
|
+
}
|
|
33144
|
+
function surfaceOpOf(event) {
|
|
33145
|
+
const raw = event;
|
|
33146
|
+
if (!isSurfaceEligibleType(event.type)) {
|
|
33147
|
+
if (raw.surfaceOp !== void 0) {
|
|
33148
|
+
throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry surfaceOp`);
|
|
33149
|
+
}
|
|
33150
|
+
if (raw.sourceEventSeqs !== void 0) {
|
|
33151
|
+
throw new Error(`session event "${event.type}" is not surface-eligible and cannot carry sourceEventSeqs`);
|
|
33152
|
+
}
|
|
33153
|
+
return;
|
|
33154
|
+
}
|
|
33155
|
+
const op = raw.surfaceOp;
|
|
33156
|
+
if (op === void 0) {
|
|
33157
|
+
throw new Error(`session event "${event.type}" is surface-eligible and requires a surfaceOp marker`);
|
|
33158
|
+
}
|
|
33159
|
+
if (op === "append") return op;
|
|
33160
|
+
if (op === null || typeof op !== "object" || Array.isArray(op)) {
|
|
33161
|
+
throw new Error(`session event "${event.type}" carries an invalid surfaceOp`);
|
|
33162
|
+
}
|
|
33163
|
+
if (!isReplaceOp(op)) {
|
|
33164
|
+
throw new Error(`session event "${event.type}" carries an invalid replace surfaceOp`);
|
|
33165
|
+
}
|
|
33166
|
+
return op;
|
|
33167
|
+
}
|
|
33168
|
+
function assertProvenance(event, shadowedSeqs) {
|
|
33169
|
+
const raw = event.sourceEventSeqs;
|
|
33170
|
+
const sources = /* @__PURE__ */ new Set();
|
|
33171
|
+
if (raw !== void 0) {
|
|
33172
|
+
if (!Array.isArray(raw)) {
|
|
33173
|
+
throw new Error(`sourceEventSeqs on event at seq ${event.seq} must be an array when present`);
|
|
33174
|
+
}
|
|
33175
|
+
if (raw.length === 0 && event.type !== "assistant/message") {
|
|
33176
|
+
throw new Error("sourceEventSeqs must not be empty except on assistant/message");
|
|
33177
|
+
}
|
|
33178
|
+
let nonEarlierSource;
|
|
33179
|
+
for (const source of raw) {
|
|
33180
|
+
if (!isEventSeq(source)) {
|
|
33181
|
+
throw new Error(`session event "${event.type}" sourceEventSeqs must densely contain non-negative safe integers`);
|
|
33182
|
+
}
|
|
33183
|
+
sources.add(source);
|
|
33184
|
+
if (nonEarlierSource === void 0 && source >= event.seq) nonEarlierSource = source;
|
|
33185
|
+
}
|
|
33186
|
+
if (sources.size !== raw.length) {
|
|
33187
|
+
throw new Error("sourceEventSeqs must not contain duplicates");
|
|
33188
|
+
}
|
|
33189
|
+
if (nonEarlierSource !== void 0) {
|
|
33190
|
+
throw new Error(`sourceEventSeqs must reference earlier events: ${nonEarlierSource} >= current seq ${event.seq}`);
|
|
33191
|
+
}
|
|
33192
|
+
}
|
|
33193
|
+
const missing = shadowedSeqs.filter((seq) => !sources.has(seq));
|
|
33194
|
+
if (missing.length > 0) {
|
|
33195
|
+
throw new Error(`surface replace: sourceEventSeqs must include every shadowed surface node; missing ${missing.join(", ")}`);
|
|
33196
|
+
}
|
|
33197
|
+
}
|
|
33198
|
+
function replacementRange(state, op) {
|
|
33199
|
+
const startIdx = state.nodes.indexOf(op.start);
|
|
33200
|
+
if (startIdx === -1) {
|
|
33201
|
+
throw new Error(`surface replace: start seq ${op.start} not found in surface`);
|
|
33202
|
+
}
|
|
33203
|
+
const endIdx = state.nodes.indexOf(op.end);
|
|
33204
|
+
if (endIdx === -1) {
|
|
33205
|
+
throw new Error(`surface replace: end seq ${op.end} not found in surface`);
|
|
33206
|
+
}
|
|
33207
|
+
if (startIdx > endIdx) {
|
|
33208
|
+
throw new Error(`surface replace: start seq ${op.start} (index ${startIdx}) is after end seq ${op.end} (index ${endIdx})`);
|
|
33209
|
+
}
|
|
33210
|
+
return {
|
|
33211
|
+
startIdx,
|
|
33212
|
+
endIdx,
|
|
33213
|
+
shadowedSeqs: state.nodes.slice(startIdx, endIdx + 1)
|
|
33214
|
+
};
|
|
33215
|
+
}
|
|
33216
|
+
function isDeepEqualJson(a, b) {
|
|
33217
|
+
if (a === b) return true;
|
|
33218
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
33219
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
33220
|
+
return a.every((item, i) => isDeepEqualJson(item, b[i]));
|
|
33221
|
+
}
|
|
33222
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
33223
|
+
const aKeys = Object.keys(a);
|
|
33224
|
+
const bRecord = b;
|
|
33225
|
+
if (aKeys.length !== Object.keys(b).length) return false;
|
|
33226
|
+
return aKeys.every((key) => Object.hasOwn(b, key) && isDeepEqualJson(a[key], bRecord[key]));
|
|
33227
|
+
}
|
|
33228
|
+
function assertToolResultRewrite(event, shadowedSeqs, events, baseSeq) {
|
|
33229
|
+
if (event.type !== "tool/result") return;
|
|
33230
|
+
if (shadowedSeqs.length !== 1) {
|
|
33231
|
+
throw new Error("tool/result surface replacement must rewrite exactly one current node");
|
|
33232
|
+
}
|
|
33233
|
+
for (const originalSeq of shadowedSeqs) {
|
|
33234
|
+
const original = events[originalSeq - baseSeq];
|
|
33235
|
+
if (original?.type !== "tool/result") {
|
|
33236
|
+
throw new Error("tool/result surface replacement must target a current tool/result");
|
|
33237
|
+
}
|
|
33238
|
+
const originalRest = { ...original.data };
|
|
33239
|
+
const replacementRest = { ...event.data };
|
|
33240
|
+
const originalResult = original.data.message.content[0];
|
|
33241
|
+
const replacementResult = event.data.message.content[0];
|
|
33242
|
+
originalRest["message"] = {
|
|
33243
|
+
...original.data.message,
|
|
33244
|
+
content: [{ ...originalResult, content: null }]
|
|
33245
|
+
};
|
|
33246
|
+
replacementRest["message"] = {
|
|
33247
|
+
...event.data.message,
|
|
33248
|
+
content: [{ ...replacementResult, content: null }]
|
|
33249
|
+
};
|
|
33250
|
+
if (!isDeepEqualJson(originalRest, replacementRest)) {
|
|
33251
|
+
throw new Error("tool/result surface replacement may change only content");
|
|
33252
|
+
}
|
|
33253
|
+
}
|
|
33254
|
+
}
|
|
33255
|
+
function planSurfaceEvent(state, event, expectedSeq, events, baseSeq) {
|
|
33256
|
+
if (event.seq !== expectedSeq) {
|
|
33257
|
+
throw new Error(`session event seq ${event.seq} is not contiguous; expected ${expectedSeq}`);
|
|
33258
|
+
}
|
|
33259
|
+
const surfaceOp = surfaceOpOf(event);
|
|
33260
|
+
if (surfaceOp === void 0) return;
|
|
33261
|
+
if (surfaceOp === "append") {
|
|
33262
|
+
assertProvenance(event, []);
|
|
33263
|
+
return { kind: "append", seq: event.seq };
|
|
33264
|
+
}
|
|
33265
|
+
const range = replacementRange(state, surfaceOp);
|
|
33266
|
+
assertProvenance(event, range.shadowedSeqs);
|
|
33267
|
+
assertToolResultRewrite(event, range.shadowedSeqs, events, baseSeq);
|
|
33268
|
+
return {
|
|
33269
|
+
kind: "replace",
|
|
33270
|
+
seq: event.seq,
|
|
33271
|
+
start: surfaceOp.start,
|
|
33272
|
+
end: surfaceOp.end,
|
|
33273
|
+
...range
|
|
33274
|
+
};
|
|
33275
|
+
}
|
|
33276
|
+
function applySurfaceEvent(state, event, expectedSeq, events, baseSeq) {
|
|
33277
|
+
const plan = planSurfaceEvent(state, event, expectedSeq, events, baseSeq);
|
|
33278
|
+
return applySurfacePlan(state, plan);
|
|
33279
|
+
}
|
|
33280
|
+
function applySurfacePlan(state, plan) {
|
|
33281
|
+
if (plan?.kind === "append") {
|
|
33282
|
+
state.nodes.push(plan.seq);
|
|
33283
|
+
} else if (plan?.kind === "replace") {
|
|
33284
|
+
state.nodes.splice(plan.startIdx, plan.endIdx - plan.startIdx + 1, plan.seq);
|
|
33285
|
+
state.replaceGeneration += 1;
|
|
33286
|
+
}
|
|
33287
|
+
if (plan?.kind !== "replace") return;
|
|
33288
|
+
return {
|
|
33289
|
+
seq: plan.seq,
|
|
33290
|
+
start: plan.start,
|
|
33291
|
+
end: plan.end,
|
|
33292
|
+
shadowedSeqs: plan.shadowedSeqs
|
|
33293
|
+
};
|
|
33294
|
+
}
|
|
33295
|
+
var SurfaceManager = class {
|
|
33296
|
+
/**
|
|
33297
|
+
* @param log - Contiguous complete log or loaded event window.
|
|
33298
|
+
* @param baseSeq - Absolute sequence of the window's first event.
|
|
33299
|
+
*/
|
|
33300
|
+
constructor(log, baseSeq = 0) {
|
|
33301
|
+
this.log = log;
|
|
33302
|
+
this.baseSeq = baseSeq;
|
|
33303
|
+
this._lastProcessedSeq = baseSeq - 1;
|
|
33304
|
+
}
|
|
33305
|
+
log;
|
|
33306
|
+
baseSeq;
|
|
33307
|
+
/** Shared transition state; replacement history is not retained. */
|
|
33308
|
+
_state = createFoldState();
|
|
33309
|
+
/** Last processed absolute seq. */
|
|
33310
|
+
_lastProcessedSeq;
|
|
33311
|
+
/** Candidate already validated by `validateNext`, pending exact log admission. */
|
|
33312
|
+
_pendingPlan;
|
|
33313
|
+
/**
|
|
33314
|
+
* Validate the next candidate without mutating the committed surface.
|
|
33315
|
+
* @param event - candidate event that has not entered the log yet.
|
|
33316
|
+
*/
|
|
33317
|
+
validateNext(event) {
|
|
33318
|
+
if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
|
|
33319
|
+
const expectedSeq = this.baseSeq + this.log.length;
|
|
33320
|
+
this._pendingPlan = {
|
|
33321
|
+
event,
|
|
33322
|
+
expectedSeq,
|
|
33323
|
+
plan: planSurfaceEvent(this._state, event, expectedSeq, this.log, this.baseSeq)
|
|
33324
|
+
};
|
|
33325
|
+
}
|
|
33326
|
+
/** Monotonic count of folded positional replacements. */
|
|
33327
|
+
get replaceGeneration() {
|
|
33328
|
+
if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
|
|
33329
|
+
return this._state.replaceGeneration;
|
|
33330
|
+
}
|
|
33331
|
+
/** Surface event sequences in model-visible order. */
|
|
33332
|
+
get nodes() {
|
|
33333
|
+
if (this._lastProcessedSeq < this.baseSeq + this.log.length - 1) this._processDelta();
|
|
33334
|
+
return this._state.nodes;
|
|
33335
|
+
}
|
|
33336
|
+
/** Fold events appended since the previous access. */
|
|
33337
|
+
_processDelta() {
|
|
33338
|
+
const tailSeq = this.baseSeq + this.log.length - 1;
|
|
33339
|
+
for (let seq = this._lastProcessedSeq + 1; seq <= tailSeq; seq++) {
|
|
33340
|
+
const index2 = seq - this.baseSeq;
|
|
33341
|
+
const event = this.log[index2];
|
|
33342
|
+
const pending = this._pendingPlan;
|
|
33343
|
+
if (pending?.event === event && pending.expectedSeq === seq) {
|
|
33344
|
+
applySurfacePlan(this._state, pending.plan);
|
|
33345
|
+
} else {
|
|
33346
|
+
applySurfaceEvent(this._state, event, seq, this.log, this.baseSeq);
|
|
33347
|
+
}
|
|
33348
|
+
if (pending !== void 0 && pending.expectedSeq <= seq) this._pendingPlan = void 0;
|
|
33349
|
+
this._lastProcessedSeq = seq;
|
|
33350
|
+
}
|
|
33351
|
+
}
|
|
33352
|
+
};
|
|
33353
|
+
|
|
33354
|
+
// ../deepseek-harness/packages/core/session/src/request-header.ts
|
|
33355
|
+
function canonicalHeader(header) {
|
|
33356
|
+
const adapterDefaults = header.adapterDefaults;
|
|
33357
|
+
return {
|
|
33358
|
+
config: header.config,
|
|
33359
|
+
...adapterDefaults?.reasoningEffort === true || adapterDefaults?.maxTokens === true ? { adapterDefaults } : {},
|
|
33360
|
+
...header.system !== void 0 && header.system.length > 0 ? { system: header.system } : {},
|
|
33361
|
+
...header.tools !== void 0 && header.tools.length > 0 ? { tools: header.tools } : {}
|
|
33362
|
+
};
|
|
33363
|
+
}
|
|
33364
|
+
function foldRequestHeader(events, from2) {
|
|
33365
|
+
let state = from2;
|
|
33366
|
+
for (const event of events) {
|
|
33367
|
+
if (event.type === "request/header") state = canonicalHeader(event.data.header);
|
|
33368
|
+
}
|
|
33369
|
+
return state;
|
|
33370
|
+
}
|
|
33371
|
+
|
|
33372
|
+
// ../deepseek-harness/packages/core/session/src/index.ts
|
|
33373
|
+
function validateSessionHeader(id, input) {
|
|
33374
|
+
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
33375
|
+
throw new Error("session header is not a plain JSON record");
|
|
33376
|
+
}
|
|
33377
|
+
const record2 = input;
|
|
33378
|
+
if (record2.version !== SESSION_FORMAT_VERSION) {
|
|
33379
|
+
throw new Error(`session header version must be ${SESSION_FORMAT_VERSION}, got ${String(record2.version)}`);
|
|
33380
|
+
}
|
|
33381
|
+
if (record2.id !== id) {
|
|
33382
|
+
throw new Error(`session header id "${String(record2.id)}" does not match session id "${id}"`);
|
|
33383
|
+
}
|
|
33384
|
+
if (typeof record2.createdAt !== "number" || !Number.isSafeInteger(record2.createdAt) || record2.createdAt < 0) {
|
|
33385
|
+
throw new Error("session header createdAt must be a non-negative safe integer");
|
|
33386
|
+
}
|
|
33387
|
+
if (record2.cwd !== void 0) {
|
|
33388
|
+
if (typeof record2.cwd !== "string") throw new Error("session header cwd must be a string");
|
|
33389
|
+
if (!isAbsolute(record2.cwd)) {
|
|
33390
|
+
throw new Error(`session header cwd must be an absolute path, got "${record2.cwd}"`);
|
|
33391
|
+
}
|
|
33392
|
+
}
|
|
33393
|
+
if (record2.parentSession !== void 0 && typeof record2.parentSession !== "string") {
|
|
33394
|
+
throw new Error("session header parentSession must be a string");
|
|
33395
|
+
}
|
|
33396
|
+
if (record2.seedLength !== void 0 && (typeof record2.seedLength !== "number" || !Number.isSafeInteger(record2.seedLength) || record2.seedLength < 0)) {
|
|
33397
|
+
throw new Error("session header seedLength must be a non-negative safe integer");
|
|
33398
|
+
}
|
|
33399
|
+
if (record2.origin !== void 0 && record2.origin !== "subagent") {
|
|
33400
|
+
throw new Error('session header origin must be "subagent"');
|
|
33401
|
+
}
|
|
33402
|
+
if (record2.delegationDepth !== void 0 && (typeof record2.delegationDepth !== "number" || !Number.isSafeInteger(record2.delegationDepth) || record2.delegationDepth < 0)) {
|
|
33403
|
+
throw new Error("session header delegationDepth must be a non-negative safe integer");
|
|
33404
|
+
}
|
|
33405
|
+
if (record2.agentPreset !== void 0 && typeof record2.agentPreset !== "string") {
|
|
33406
|
+
throw new Error("session header agentPreset must be a string");
|
|
33407
|
+
}
|
|
33408
|
+
return deepFreeze(record2);
|
|
33409
|
+
}
|
|
33410
|
+
function validateRestoredSessionHeader(id, input) {
|
|
33411
|
+
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
33412
|
+
const prototype = Reflect.getPrototypeOf(input);
|
|
33413
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
33414
|
+
throw new Error("session header is not a plain JSON record");
|
|
33415
|
+
}
|
|
33416
|
+
}
|
|
33417
|
+
return validateSessionHeader(id, input);
|
|
33418
|
+
}
|
|
33419
|
+
function snapshotSessionHeader(id, source) {
|
|
33420
|
+
const input = source === void 0 ? { version: SESSION_FORMAT_VERSION, id, createdAt: Date.now() } : source;
|
|
33421
|
+
const snapshot = snapshotJsonValue(input);
|
|
33422
|
+
if (snapshot === void 0) throw new Error("session header is not losslessly JSON-serializable");
|
|
33423
|
+
return validateSessionHeader(id, snapshot);
|
|
33424
|
+
}
|
|
33425
|
+
function freezeRestoredObject(value) {
|
|
33426
|
+
const pending = [value];
|
|
33427
|
+
while (pending.length > 0) {
|
|
33428
|
+
const current = pending.pop();
|
|
33429
|
+
Object.freeze(current);
|
|
33430
|
+
for (const key in current) {
|
|
33431
|
+
const child = current[key];
|
|
33432
|
+
if (child !== null && typeof child === "object") pending.push(child);
|
|
33433
|
+
}
|
|
33434
|
+
}
|
|
33435
|
+
return value;
|
|
33436
|
+
}
|
|
33437
|
+
function assertSessionEventEnvelope(value, index2) {
|
|
33438
|
+
const event = value;
|
|
33439
|
+
if (event["type"] === "request/header-delta") {
|
|
33440
|
+
throw new Error(`seed event at index ${index2} uses unsupported legacy request/header-delta format`);
|
|
33441
|
+
}
|
|
33442
|
+
for (const key in event) {
|
|
33443
|
+
switch (key) {
|
|
33444
|
+
case "type":
|
|
33445
|
+
case "seq":
|
|
33446
|
+
case "time":
|
|
33447
|
+
case "data":
|
|
33448
|
+
case "surfaceOp":
|
|
33449
|
+
case "sourceEventSeqs":
|
|
33450
|
+
case "ignorable":
|
|
33451
|
+
break;
|
|
33452
|
+
default:
|
|
33453
|
+
throw new Error(`seed event at index ${index2} has an invalid event envelope`);
|
|
33454
|
+
}
|
|
33455
|
+
}
|
|
33456
|
+
const type = event["type"];
|
|
33457
|
+
const seq = event["seq"];
|
|
33458
|
+
const time3 = event["time"];
|
|
33459
|
+
if (typeof type !== "string" || typeof seq !== "number" || !Number.isSafeInteger(seq) || seq < 0 || typeof time3 !== "number" || !Number.isSafeInteger(time3) || event["data"] === void 0 || event["ignorable"] !== void 0 && event["ignorable"] !== true) {
|
|
33460
|
+
throw new Error(`seed event at index ${index2} has an invalid event envelope`);
|
|
33461
|
+
}
|
|
33462
|
+
switch (type) {
|
|
33463
|
+
case "request/header":
|
|
33464
|
+
case "user/message":
|
|
33465
|
+
case "assistant/message":
|
|
33466
|
+
case "tool/result":
|
|
33467
|
+
assertCurrentLlmShape(event, index2);
|
|
33468
|
+
break;
|
|
33469
|
+
}
|
|
33470
|
+
}
|
|
33471
|
+
function assertCurrentLlmShape(event, index2) {
|
|
33472
|
+
const data = event["data"];
|
|
33473
|
+
const record2 = typeof data === "object" && data !== null ? data : void 0;
|
|
33474
|
+
if (event["type"] === "request/header") {
|
|
33475
|
+
const header = record2?.["header"];
|
|
33476
|
+
const headerRecord = typeof header === "object" && header !== null && !Array.isArray(header) ? header : void 0;
|
|
33477
|
+
const config2 = headerRecord?.["config"];
|
|
33478
|
+
if (!hasProviderModel(config2)) throw new Error(`seed request/header at index ${index2} lacks provider/model`);
|
|
33479
|
+
const configRecord = config2;
|
|
33480
|
+
const reasoningEffort = configRecord["reasoningEffort"];
|
|
33481
|
+
if (reasoningEffort !== void 0 && (typeof reasoningEffort !== "string" || reasoningEffort.length === 0)) {
|
|
33482
|
+
throw new Error(`seed request/header at index ${index2} has an invalid reasoningEffort`);
|
|
33483
|
+
}
|
|
33484
|
+
assertAdapterDefaults(headerRecord?.["adapterDefaults"], configRecord, index2);
|
|
33485
|
+
}
|
|
33486
|
+
const type = event["type"];
|
|
33487
|
+
if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return;
|
|
33488
|
+
assertMessageEventShape(event, `seed ${type} at index ${index2}`);
|
|
33489
|
+
}
|
|
33490
|
+
var allowedAdapterKeys = /* @__PURE__ */ new Set(["reasoningEffort", "maxTokens"]);
|
|
33491
|
+
function assertAdapterDefaults(value, config2, index2) {
|
|
33492
|
+
if (value === void 0) return;
|
|
33493
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
33494
|
+
throw new Error(`seed request/header at index ${index2} has invalid adapterDefaults`);
|
|
33495
|
+
}
|
|
33496
|
+
const defaults = value;
|
|
33497
|
+
if (Object.keys(defaults).some((key) => !allowedAdapterKeys.has(key)) || Object.values(defaults).some((marker) => marker !== true) || defaults["reasoningEffort"] === true && config2["reasoningEffort"] === void 0 || defaults["maxTokens"] === true && config2["maxTokens"] === void 0) {
|
|
33498
|
+
throw new Error(`seed request/header at index ${index2} has invalid adapterDefaults`);
|
|
33499
|
+
}
|
|
33500
|
+
}
|
|
33501
|
+
function assertMessageEventShape(event, subject) {
|
|
33502
|
+
const type = event["type"];
|
|
33503
|
+
if (type !== "user/message" && type !== "assistant/message" && type !== "tool/result") return;
|
|
33504
|
+
const data = event["data"];
|
|
33505
|
+
const record2 = typeof data === "object" && data !== null ? data : void 0;
|
|
33506
|
+
const message = type === "user/message" ? record2 : record2?.["message"];
|
|
33507
|
+
if (typeof message !== "object" || message === null || typeof message["id"] !== "string" || message["id"] === "") {
|
|
33508
|
+
throw new Error(`${subject} lacks an identified message`);
|
|
33509
|
+
}
|
|
33510
|
+
const messageRecord = message;
|
|
33511
|
+
const expectedRole = type === "assistant/message" ? "assistant" : "user";
|
|
33512
|
+
if (messageRecord["role"] !== expectedRole) {
|
|
33513
|
+
throw new Error(`${subject} message must have role "${expectedRole}"`);
|
|
33514
|
+
}
|
|
33515
|
+
const source = messageRecord["source"];
|
|
33516
|
+
if (typeof source !== "object" || source === null || typeof source["kind"] !== "string" || source["kind"] === "") {
|
|
33517
|
+
throw new Error(`${subject} message has invalid source`);
|
|
33518
|
+
}
|
|
33519
|
+
if (!Array.isArray(messageRecord["content"])) {
|
|
33520
|
+
throw new Error(`${subject} message has invalid content`);
|
|
33521
|
+
}
|
|
33522
|
+
const sourceRecord = source;
|
|
33523
|
+
if (type === "assistant/message") {
|
|
33524
|
+
if (sourceRecord["kind"] !== "model" || !hasProviderModel(sourceRecord)) {
|
|
33525
|
+
throw new Error(`${subject} message must have model source`);
|
|
33526
|
+
}
|
|
33527
|
+
return;
|
|
33528
|
+
}
|
|
33529
|
+
if (type !== "tool/result") return;
|
|
33530
|
+
if (sourceRecord["kind"] !== "tool" || typeof sourceRecord["callId"] !== "string" || sourceRecord["callId"] === "") {
|
|
33531
|
+
throw new Error(`${subject} message must have tool source`);
|
|
33532
|
+
}
|
|
33533
|
+
const content3 = messageRecord["content"];
|
|
33534
|
+
const block = content3[0];
|
|
33535
|
+
if (content3.length !== 1 || typeof block !== "object" || block === null || block["type"] !== "tool-result" || !Array.isArray(block["content"])) {
|
|
33536
|
+
throw new Error(`${subject} message must contain one tool-result block`);
|
|
33537
|
+
}
|
|
33538
|
+
if (block["toolCallId"] !== sourceRecord["callId"]) {
|
|
33539
|
+
throw new Error(`${subject} message has mismatched tool call ids`);
|
|
33540
|
+
}
|
|
33541
|
+
}
|
|
33542
|
+
function hasProviderModel(value) {
|
|
33543
|
+
if (typeof value !== "object" || value === null) return false;
|
|
33544
|
+
const pair = value;
|
|
33545
|
+
return typeof pair["provider"] === "string" && pair["provider"].length > 0 && typeof pair["model"] === "string" && pair["model"].length > 0;
|
|
33546
|
+
}
|
|
33547
|
+
function assertSupportedRequestHeader(type, data, location) {
|
|
33548
|
+
if (type === "request/header-delta") {
|
|
33549
|
+
throw new Error(`${location} uses unsupported legacy request/header-delta format`);
|
|
33550
|
+
}
|
|
33551
|
+
if (type === "request/header" && data !== null && typeof data === "object" && !Array.isArray(data) && data["reason"] === "fallback") {
|
|
33552
|
+
throw new Error(`${location} uses unsupported legacy request/header reason "fallback"`);
|
|
33553
|
+
}
|
|
33554
|
+
}
|
|
33555
|
+
function collectSessionCallbacks(ctx, args) {
|
|
33556
|
+
return [...ctx.events.dispatch("emit", args)];
|
|
33557
|
+
}
|
|
33558
|
+
function invokeContainedSessionObservers(ctx, name2, id, args, callbacks) {
|
|
33559
|
+
for (const callback of callbacks) {
|
|
33560
|
+
try {
|
|
33561
|
+
const returned = callback(...args);
|
|
33562
|
+
void Promise.resolve(returned).catch((error51) => {
|
|
33563
|
+
ctx.logger.warn(`session "${id}": ${name2} listener rejected: ${String(error51)}`);
|
|
33564
|
+
});
|
|
33565
|
+
} catch (error51) {
|
|
33566
|
+
ctx.logger.warn(`session "${id}": ${name2} listener threw: ${String(error51)}`);
|
|
33567
|
+
}
|
|
33568
|
+
}
|
|
33569
|
+
}
|
|
33570
|
+
var attachments = /* @__PURE__ */ new WeakMap();
|
|
33571
|
+
var Session = class _Session {
|
|
33572
|
+
log = [];
|
|
33573
|
+
/** Single incremental owner of surface acceptance and projection state. */
|
|
33574
|
+
surfaceManager = new SurfaceManager(this.log);
|
|
33575
|
+
/** The ordered surface over this session's event log. */
|
|
33576
|
+
get surface() {
|
|
33577
|
+
return this.surfaceManager;
|
|
33578
|
+
}
|
|
33579
|
+
/**
|
|
33580
|
+
* Detached, deep-frozen creation metadata (format version, cwd, lineage,
|
|
33581
|
+
* seed boundary). Supplied by the store via `ctx.sessions.create()`. When a
|
|
33582
|
+
* `Session` is created without a store-owned header, a minimal header is
|
|
33583
|
+
* synthesized (stamped with the current {@link SESSION_FORMAT_VERSION}) so
|
|
33584
|
+
* `session.header` is always present. Kept out of the event log — it is a
|
|
33585
|
+
* storage concern, not replayable conversation state.
|
|
33586
|
+
*/
|
|
33587
|
+
header;
|
|
33588
|
+
/** The session identity, derived from its durable header's single copy. */
|
|
33589
|
+
get id() {
|
|
33590
|
+
return this.header.id;
|
|
33591
|
+
}
|
|
33592
|
+
/**
|
|
33593
|
+
* The first seq appended IN THIS PROCESS: the length of the constructor
|
|
33594
|
+
* seed (0 without one). Events with smaller seq values entered through
|
|
33595
|
+
* construction — replay, fork, or resume — and were never published on the
|
|
33596
|
+
* `session/event` firehose (constructor seeds do not emit), so consumers
|
|
33597
|
+
* that replay the log as a publication substitute (telemetry adoption)
|
|
33598
|
+
* start here. Distinct from `header.seedLength`, the DURABLE fork-lineage
|
|
33599
|
+
* boundary: a resumed session's constructor seed is its full stored log,
|
|
33600
|
+
* while its header keeps the original fork value — this field is the
|
|
33601
|
+
* in-process construction fact.
|
|
33602
|
+
*
|
|
33603
|
+
* Not persisted itself: a seeded session projects it into the log as the
|
|
33604
|
+
* `session/end-seed` event, which is what a consumer reading STORED history
|
|
33605
|
+
* reads. Locate the LAST such event, not necessarily one at this seq — a
|
|
33606
|
+
* seed already ending in one is not re-marked, so reopening an untouched
|
|
33607
|
+
* session leaves that event at a smaller seq than `firstLiveSeq`. Prefer
|
|
33608
|
+
* this field in-process: it is exact before the marker reaches storage.
|
|
33609
|
+
*
|
|
33610
|
+
* When this lifecycle appends the marker, it occupies this seq before the
|
|
33611
|
+
* store attaches and therefore does not publish either. Otherwise this seq
|
|
33612
|
+
* holds an ordinary published write.
|
|
33613
|
+
*/
|
|
33614
|
+
firstLiveSeq;
|
|
33615
|
+
/**
|
|
33616
|
+
* Create a detached session by validating and snapshotting borrowed seed
|
|
33617
|
+
* events and storage metadata.
|
|
33618
|
+
* @param id - session identity.
|
|
33619
|
+
* @param seed - optional borrowed replay or fork events.
|
|
33620
|
+
* @param header - optional borrowed storage metadata.
|
|
33621
|
+
* @returns a detached session.
|
|
33622
|
+
*/
|
|
33623
|
+
static create(id, seed, header) {
|
|
33624
|
+
return new _Session(id, seed, header);
|
|
33625
|
+
}
|
|
33626
|
+
/**
|
|
33627
|
+
* Restore a detached session by taking ownership of fresh persistence values.
|
|
33628
|
+
* The storage format, event envelopes, sequence continuity, surface transitions,
|
|
33629
|
+
* and header fields are validated before the restored objects are frozen.
|
|
33630
|
+
* @param id - restored session identity.
|
|
33631
|
+
* @param seed - fresh detached events whose ownership is transferred.
|
|
33632
|
+
* @param header - fresh detached metadata whose ownership is transferred.
|
|
33633
|
+
* @returns a restored detached session.
|
|
33634
|
+
*/
|
|
33635
|
+
static fromRestore(id, seed, header) {
|
|
33636
|
+
return new _Session(id, seed, header, "restore");
|
|
33637
|
+
}
|
|
33638
|
+
constructor(id, seed, header, mode = "snapshot") {
|
|
33639
|
+
const restoredHeader = mode === "restore" ? validateRestoredSessionHeader(id, header) : void 0;
|
|
33640
|
+
if (seed !== void 0) {
|
|
33641
|
+
for (const [index2, source] of seed.entries()) {
|
|
33642
|
+
const snapshot = mode === "restore" ? source : snapshotJsonValue(source);
|
|
33643
|
+
if (snapshot === void 0) {
|
|
33644
|
+
throw new Error(`seed event at index ${index2} is not losslessly JSON-serializable`);
|
|
33645
|
+
}
|
|
33646
|
+
assertSessionEventEnvelope(snapshot, index2);
|
|
33647
|
+
assertSupportedRequestHeader(snapshot.type, snapshot.data, `seed event at index ${index2}`);
|
|
33648
|
+
if (snapshot.seq !== index2) {
|
|
33649
|
+
throw new Error(`seed event at index ${index2} has seq ${snapshot.seq} (expected ${index2}); seed must be contiguous from 0`);
|
|
33650
|
+
}
|
|
33651
|
+
try {
|
|
33652
|
+
this.surfaceManager.validateNext(snapshot);
|
|
33653
|
+
} catch (error51) {
|
|
33654
|
+
throw new Error(`invalid seed event at index ${index2}: ${error51 instanceof Error ? error51.message : "invalid surface metadata"}`);
|
|
33655
|
+
}
|
|
33656
|
+
this.log.push(mode === "restore" ? freezeRestoredObject(snapshot) : deepFreeze(snapshot));
|
|
33657
|
+
}
|
|
33658
|
+
}
|
|
33659
|
+
this.firstLiveSeq = this.log.length;
|
|
33660
|
+
this.header = restoredHeader ?? snapshotSessionHeader(id, header);
|
|
33661
|
+
if (seed !== void 0 && this.log.at(-1)?.type !== "session/end-seed") {
|
|
33662
|
+
this.append("session/end-seed", {});
|
|
33663
|
+
}
|
|
33664
|
+
}
|
|
33665
|
+
/** Cached immutable public snapshot of the private append-only log. */
|
|
33666
|
+
eventsSnapshot;
|
|
33667
|
+
/**
|
|
33668
|
+
* An immutable snapshot of the append-only event log. The snapshot is reused
|
|
33669
|
+
* until the next append; a previously returned array does not grow later.
|
|
33670
|
+
* Events and their nested data are deep-frozen at acceptance, so neither a
|
|
33671
|
+
* cast nor ordinary JavaScript can rewrite durable history.
|
|
33672
|
+
*/
|
|
33673
|
+
get events() {
|
|
33674
|
+
this.eventsSnapshot ??= Object.freeze([...this.log]);
|
|
33675
|
+
return this.eventsSnapshot;
|
|
33676
|
+
}
|
|
33677
|
+
/** The next event's sequence number — always the log length (the `seq = log.length` contiguity contract). */
|
|
33678
|
+
get seq() {
|
|
33679
|
+
return this.log.length;
|
|
33680
|
+
}
|
|
33681
|
+
/**
|
|
33682
|
+
* Append one typed event to the log and synchronously notify observers via
|
|
33683
|
+
* the store-owned, module-private publication hooks. The hot path never blocks
|
|
33684
|
+
* on I/O — persistence plugins buffer asynchronously. Once the event enters
|
|
33685
|
+
* the log, the append is committed: observer failures are logged and
|
|
33686
|
+
* contained per listener, so they do not change the return value or prevent
|
|
33687
|
+
* later listeners from observing the same accepted event.
|
|
33688
|
+
*
|
|
33689
|
+
* @param type - The event type (key of {@link SessionEventMap}).
|
|
33690
|
+
* @param data - The event payload; must be JSON-serializable.
|
|
33691
|
+
* @param opts - Surface metadata: `surfaceOp` controls how the event enters
|
|
33692
|
+
* the ordered surface; `sourceEventSeqs` lists the seq numbers of earlier
|
|
33693
|
+
* events this one derives from. REQUIRED for
|
|
33694
|
+
* {@link SurfaceEventType} events (every message-producing event must
|
|
33695
|
+
* declare how it joins the surface, the sole source of derived model
|
|
33696
|
+
* history) and
|
|
33697
|
+
* rejected by the compiler for non-surface types like `turn/start` or
|
|
33698
|
+
* `assistant/chunk`.
|
|
33699
|
+
* @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of
|
|
33700
|
+
* `data` that entered the log, so reading `event.data` back sees the logged
|
|
33701
|
+
* value, never the caller's still-mutable input.
|
|
33702
|
+
* @throws if `data` or surface metadata is not losslessly JSON-serializable
|
|
33703
|
+
* (BigInt, function, symbol, undefined, negative zero, non-finite number,
|
|
33704
|
+
* circular reference, sparse array, or an exotic object such as
|
|
33705
|
+
* Map/Set/Date/class instance), or when the candidate violates the
|
|
33706
|
+
* canonical surface contract (marker shape and eligibility, unique
|
|
33707
|
+
* earlier source-event references, positional replacement validity, and complete
|
|
33708
|
+
* shadowed-node coverage). One iterative pass reads, validates, and
|
|
33709
|
+
* copies each nested value once, so a stateful getter cannot supply one value
|
|
33710
|
+
* to validation and another to storage. The event log is the durable source
|
|
33711
|
+
* of truth, so a bad event fails at the append site rather than later during
|
|
33712
|
+
* a backend flush. A synchronous internal dispatch validation failure or an
|
|
33713
|
+
* append reentered while this acceptance/publication boundary is open also
|
|
33714
|
+
* rejects before the log changes.
|
|
33715
|
+
*/
|
|
33716
|
+
append(type, data, ...opts) {
|
|
33717
|
+
const surfaceOpts = opts[0];
|
|
33718
|
+
const surfaceMetadata = {
|
|
33719
|
+
...surfaceOpts?.sourceEventSeqs === void 0 ? {} : { sourceEventSeqs: surfaceOpts.sourceEventSeqs },
|
|
33720
|
+
...surfaceOpts?.surfaceOp === void 0 ? {} : { surfaceOp: surfaceOpts.surfaceOp }
|
|
33721
|
+
};
|
|
33722
|
+
const dataSnapshot = snapshotJsonValue(data);
|
|
33723
|
+
if (dataSnapshot === void 0) {
|
|
33724
|
+
throw new Error(`session event "${type}" carries non-JSON-serializable data`);
|
|
33725
|
+
}
|
|
33726
|
+
assertSupportedRequestHeader(type, dataSnapshot, `session event "${type}"`);
|
|
33727
|
+
const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata);
|
|
33728
|
+
if (surfaceMetadataSnapshot === void 0) {
|
|
33729
|
+
throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`);
|
|
33730
|
+
}
|
|
33731
|
+
const entry = attachments.get(this);
|
|
33732
|
+
if (entry?.appending) {
|
|
33733
|
+
throw new Error("session append cannot reenter while another append is being published");
|
|
33734
|
+
}
|
|
33735
|
+
const event = deepFreeze({
|
|
33736
|
+
type,
|
|
33737
|
+
seq: this.log.length,
|
|
33738
|
+
time: Date.now(),
|
|
33739
|
+
data: dataSnapshot,
|
|
33740
|
+
...surfaceMetadataSnapshot
|
|
33741
|
+
});
|
|
33742
|
+
this.surfaceManager.validateNext(event);
|
|
33743
|
+
if (entry !== void 0) entry.appending = true;
|
|
33744
|
+
try {
|
|
33745
|
+
let callbacks;
|
|
33746
|
+
const callbackArgs = [this, event];
|
|
33747
|
+
if (entry !== void 0) {
|
|
33748
|
+
callbacks = collectSessionCallbacks(entry.emitCtx, [entry.carrier, "session/event", ...callbackArgs]);
|
|
33749
|
+
}
|
|
33750
|
+
this.log.push(event);
|
|
33751
|
+
this.eventsSnapshot = void 0;
|
|
33752
|
+
if (callbacks !== void 0 && entry !== void 0) {
|
|
33753
|
+
invokeContainedSessionObservers(entry.emitCtx, "session/event", entry.id, callbackArgs, callbacks);
|
|
33754
|
+
}
|
|
33755
|
+
return event;
|
|
33756
|
+
} finally {
|
|
33757
|
+
if (entry !== void 0) {
|
|
33758
|
+
entry.appending = false;
|
|
33759
|
+
if (entry.detachRequested && !entry.announcing) entry.detach();
|
|
33760
|
+
}
|
|
33761
|
+
}
|
|
33762
|
+
}
|
|
33763
|
+
/** Cached fold of the request-header events — see {@link requestHeader}. */
|
|
33764
|
+
headerFold;
|
|
33765
|
+
/** Log position (events consumed) the header fold has reached. */
|
|
33766
|
+
headerFoldSeq = 0;
|
|
33767
|
+
/**
|
|
33768
|
+
* The {@link EpochHeader} in force after the log's last header event — the
|
|
33769
|
+
* header the NEXT request will be compared against — or undefined before
|
|
33770
|
+
* the first `request/header` snapshot. The live, incrementally-maintained
|
|
33771
|
+
* form of `foldRequestHeader(session.events)`: each header event is folded
|
|
33772
|
+
* once, when first seen, so a per-step read costs O(new events).
|
|
33773
|
+
* @returns the folded header, or undefined when no header event exists yet.
|
|
33774
|
+
*/
|
|
33775
|
+
requestHeader() {
|
|
33776
|
+
if (this.headerFoldSeq < this.log.length) {
|
|
33777
|
+
this.headerFold = deepFreeze(foldRequestHeader(this.log.slice(this.headerFoldSeq), this.headerFold));
|
|
33778
|
+
this.headerFoldSeq = this.log.length;
|
|
33779
|
+
}
|
|
33780
|
+
return this.headerFold;
|
|
33781
|
+
}
|
|
33782
|
+
/** Cached fold of `request/context` events. */
|
|
33783
|
+
contextFold;
|
|
33784
|
+
contextFoldSeq = 0;
|
|
33785
|
+
/**
|
|
33786
|
+
* Return the latest resolved route metadata, or `undefined` before the first
|
|
33787
|
+
* `request/context` event. Each event is folded once.
|
|
33788
|
+
* @returns the latest immutable route metadata.
|
|
33789
|
+
*/
|
|
33790
|
+
requestContext() {
|
|
33791
|
+
if (this.contextFoldSeq < this.log.length) {
|
|
33792
|
+
for (const event of this.log.slice(this.contextFoldSeq)) {
|
|
33793
|
+
if (event.type === "request/context") this.contextFold = deepFreeze({ ...event.data });
|
|
33794
|
+
}
|
|
33795
|
+
this.contextFoldSeq = this.log.length;
|
|
33796
|
+
}
|
|
33797
|
+
return this.contextFold;
|
|
33798
|
+
}
|
|
33799
|
+
/** The derived-message cache: frozen projections, extended per unseen node. */
|
|
33800
|
+
derived = [];
|
|
33801
|
+
/** Surface position (nodes projected) the cache has reached. */
|
|
33802
|
+
derivedNodes = 0;
|
|
33803
|
+
/** {@link SurfaceManager.replaceGeneration} the cache was built under. */
|
|
33804
|
+
derivedGeneration = 0;
|
|
33805
|
+
/**
|
|
33806
|
+
* Derive the LLM message history by walking the ordered sequences of
|
|
33807
|
+
* message-producing events maintained by `surfaceOp` markers. The
|
|
33808
|
+
* surface is the single source of derived history: every message-producing
|
|
33809
|
+
* append records its `surfaceOp`, so a raw event with no marker (a chunk, a
|
|
33810
|
+
* turn boundary) is correctly absent, and a compaction `replace` deletes the
|
|
33811
|
+
* shadowed nodes from the derivation. The projection rules are
|
|
33812
|
+
* {@link deriveEventMessage}, folded per node.
|
|
33813
|
+
*
|
|
33814
|
+
* CACHED: each surface node is projected exactly once, when first seen — a
|
|
33815
|
+
* call costs O(new nodes), and a surface rewrite (a `replace`;
|
|
33816
|
+
* {@link SessionSurface.replaceGeneration}) rebuilds. The returned array is
|
|
33817
|
+
* a fresh snapshot per call (later appends never grow an array a caller
|
|
33818
|
+
* already holds); the `Message` objects in it are SHARED and **deep-frozen**.
|
|
33819
|
+
* Their content reuses the already frozen durable event data, so the cache
|
|
33820
|
+
* needs no second deep clone and consumers still cannot mutate the log.
|
|
33821
|
+
* @returns a fresh array of the shared, frozen derived history.
|
|
33822
|
+
*/
|
|
33823
|
+
deriveMessages() {
|
|
33824
|
+
const surface = this.surface;
|
|
33825
|
+
const nodes = surface.nodes;
|
|
33826
|
+
const generation = surface.replaceGeneration;
|
|
33827
|
+
if (generation !== this.derivedGeneration) {
|
|
33828
|
+
this.derived = [];
|
|
33829
|
+
this.derivedNodes = 0;
|
|
33830
|
+
this.derivedGeneration = generation;
|
|
33831
|
+
}
|
|
33832
|
+
for (const seq of nodes.slice(this.derivedNodes)) {
|
|
33833
|
+
const msg = this.deriveEventMessage(this.log[seq]);
|
|
33834
|
+
if (msg) this.derived.push(msg);
|
|
33835
|
+
}
|
|
33836
|
+
this.derivedNodes = nodes.length;
|
|
33837
|
+
return [...this.derived];
|
|
33838
|
+
}
|
|
33839
|
+
/**
|
|
33840
|
+
* Instance face of the pure per-node `deriveEventMessage` export from
|
|
33841
|
+
* `surface.ts`.
|
|
33842
|
+
* @param event - the event to project.
|
|
33843
|
+
* @returns the derived message, or null when the event produces none.
|
|
33844
|
+
*/
|
|
33845
|
+
deriveEventMessage(event) {
|
|
33846
|
+
return deriveEventMessage(event);
|
|
33847
|
+
}
|
|
33848
|
+
};
|
|
32977
33849
|
|
|
32978
33850
|
// ../deepseek-harness/node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
32979
33851
|
var external_exports = {};
|
|
@@ -58245,7 +59117,7 @@ function producedPathsForTurn(cards) {
|
|
|
58245
59117
|
|
|
58246
59118
|
// ../deepseek-harness/packages/tui/tui-render/src/stream-view.tsx
|
|
58247
59119
|
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
58248
|
-
import { isAbsolute as
|
|
59120
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
58249
59121
|
|
|
58250
59122
|
// ../deepseek-harness/packages/tui/tui-render/src/markdown.tsx
|
|
58251
59123
|
var import_react34 = __toESM(require_react(), 1);
|
|
@@ -69430,7 +70302,7 @@ function toolCardOriginalText(card, options) {
|
|
|
69430
70302
|
}
|
|
69431
70303
|
|
|
69432
70304
|
// ../deepseek-harness/packages/tui/tui-render/src/tool-cards.ts
|
|
69433
|
-
import { isAbsolute } from "node:path";
|
|
70305
|
+
import { isAbsolute as isAbsolute2 } from "node:path";
|
|
69434
70306
|
import { pathToFileURL } from "node:url";
|
|
69435
70307
|
function toolCardDisplayStatus(card) {
|
|
69436
70308
|
const terminal = card.resultView?.card === "terminal" ? card.resultView : void 0;
|
|
@@ -69593,7 +70465,7 @@ function fileUrlFromToolArguments(argumentsJson) {
|
|
|
69593
70465
|
const record2 = parsed;
|
|
69594
70466
|
for (const key of FILE_PATH_KEYS) {
|
|
69595
70467
|
const value = record2[key];
|
|
69596
|
-
if (typeof value !== "string" || !
|
|
70468
|
+
if (typeof value !== "string" || !isAbsolute2(value)) continue;
|
|
69597
70469
|
if (/[\u0000-\u001f\u007f]/.test(value)) continue;
|
|
69598
70470
|
return pathToFileURL(value).href;
|
|
69599
70471
|
}
|
|
@@ -74614,7 +75486,7 @@ function StreamView({
|
|
|
74614
75486
|
prefix = " \xB7 ";
|
|
74615
75487
|
}
|
|
74616
75488
|
const segment2 = styled(escapeContent(`${prefix}${path2}`), "fgDim");
|
|
74617
|
-
const href =
|
|
75489
|
+
const href = isAbsolute3(path2) ? pathToFileURL2(path2).href : void 0;
|
|
74618
75490
|
const run2 = hyperlinksEnabled() && href !== void 0 && isOsc8Href(href) ? wrapOsc8(segment2, href) : segment2;
|
|
74619
75491
|
rowRuns.push(run2);
|
|
74620
75492
|
rowWidth += displayWidth(`${prefix}${path2}`);
|
|
@@ -78877,6 +79749,7 @@ function createProjector() {
|
|
|
78877
79749
|
return {
|
|
78878
79750
|
push: push3,
|
|
78879
79751
|
seed(events) {
|
|
79752
|
+
if (!events || typeof events[Symbol.iterator] !== "function") return;
|
|
78880
79753
|
for (const event of events) push3(event);
|
|
78881
79754
|
},
|
|
78882
79755
|
snapshot() {
|
|
@@ -79141,7 +80014,9 @@ async function exportSessionMarkdown(session, dir) {
|
|
|
79141
80014
|
throw new Error("session export target must be a direct child of the export directory");
|
|
79142
80015
|
}
|
|
79143
80016
|
await mkdir(resolvedDir, { recursive: true });
|
|
79144
|
-
|
|
80017
|
+
const legacy = session;
|
|
80018
|
+
const events = typeof legacy.snapshotEvents === "function" ? legacy.snapshotEvents() : session.events;
|
|
80019
|
+
await writeFile(target, renderSessionMarkdown(events), "utf8");
|
|
79145
80020
|
return target;
|
|
79146
80021
|
}
|
|
79147
80022
|
|
|
@@ -79245,6 +80120,51 @@ function settingsRowsFromDescribe(descriptors, read) {
|
|
|
79245
80120
|
}
|
|
79246
80121
|
|
|
79247
80122
|
// ../deepseek-harness/packages/tui/tui/src/index.ts
|
|
80123
|
+
try {
|
|
80124
|
+
if (typeof Session === "function" && !("events" in Session.prototype)) {
|
|
80125
|
+
Object.defineProperty(Session.prototype, "events", {
|
|
80126
|
+
get() {
|
|
80127
|
+
return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
|
|
80128
|
+
},
|
|
80129
|
+
configurable: true,
|
|
80130
|
+
enumerable: false
|
|
80131
|
+
});
|
|
80132
|
+
}
|
|
80133
|
+
} catch {
|
|
80134
|
+
}
|
|
80135
|
+
function ensureSessionEventsCompat(session) {
|
|
80136
|
+
if (!session || typeof session !== "object") return;
|
|
80137
|
+
try {
|
|
80138
|
+
const proto2 = Object.getPrototypeOf(session);
|
|
80139
|
+
if (proto2 && typeof proto2 === "object" && !("events" in proto2)) {
|
|
80140
|
+
Object.defineProperty(proto2, "events", {
|
|
80141
|
+
get() {
|
|
80142
|
+
return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
|
|
80143
|
+
},
|
|
80144
|
+
configurable: true,
|
|
80145
|
+
enumerable: false
|
|
80146
|
+
});
|
|
80147
|
+
} else if (!("events" in session)) {
|
|
80148
|
+
Object.defineProperty(session, "events", {
|
|
80149
|
+
get() {
|
|
80150
|
+
return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
|
|
80151
|
+
},
|
|
80152
|
+
configurable: true,
|
|
80153
|
+
enumerable: false
|
|
80154
|
+
});
|
|
80155
|
+
}
|
|
80156
|
+
} catch {
|
|
80157
|
+
}
|
|
80158
|
+
}
|
|
80159
|
+
function getSessionEvents(session) {
|
|
80160
|
+
if (!session || typeof session !== "object") return [];
|
|
80161
|
+
const s = session;
|
|
80162
|
+
if (s.events !== void 0) return s.events;
|
|
80163
|
+
if (typeof s.snapshotEvents === "function") {
|
|
80164
|
+
return s.snapshotEvents();
|
|
80165
|
+
}
|
|
80166
|
+
return [];
|
|
80167
|
+
}
|
|
79248
80168
|
var FEEDBACK_MS = 2e3;
|
|
79249
80169
|
var FEEDBACK_COPY = {
|
|
79250
80170
|
// Safe copy: tells the user the action failed and they can retry. The
|
|
@@ -79992,7 +80912,7 @@ var RuntimeController = class _RuntimeController {
|
|
|
79992
80912
|
*/
|
|
79993
80913
|
getTitle() {
|
|
79994
80914
|
if (this.session === void 0) return "";
|
|
79995
|
-
return topBarTitle(this.session
|
|
80915
|
+
return topBarTitle(getSessionEvents(this.session));
|
|
79996
80916
|
}
|
|
79997
80917
|
/**
|
|
79998
80918
|
* Return the current session-directory state.
|
|
@@ -81754,7 +82674,7 @@ var RuntimeController = class _RuntimeController {
|
|
|
81754
82674
|
* in those cases and is not appropriate here.
|
|
81755
82675
|
*/
|
|
81756
82676
|
notifySessionTitle() {
|
|
81757
|
-
return this.session === void 0 ? void 0 : notifySessionTitle(this.session
|
|
82677
|
+
return this.session === void 0 ? void 0 : notifySessionTitle(getSessionEvents(this.session));
|
|
81758
82678
|
}
|
|
81759
82679
|
/** Record local user input for the notification quiet window. */
|
|
81760
82680
|
noteUserActivity() {
|
|
@@ -82180,8 +83100,9 @@ var RuntimeController = class _RuntimeController {
|
|
|
82180
83100
|
});
|
|
82181
83101
|
const allocated = await this.allocateCandidate(request);
|
|
82182
83102
|
candidate = allocated.handle;
|
|
83103
|
+
ensureSessionEventsCompat(candidate.agent.session);
|
|
82183
83104
|
const projector = createProjector();
|
|
82184
|
-
projector.seed(candidate.agent.session
|
|
83105
|
+
projector.seed(getSessionEvents(candidate.agent.session));
|
|
82185
83106
|
this.setTransition({ phase: "binding", intent: request.intent });
|
|
82186
83107
|
this.commitCandidate({ ...allocated, projector });
|
|
82187
83108
|
} catch (primaryError) {
|
|
@@ -83159,10 +84080,11 @@ var RuntimeController = class _RuntimeController {
|
|
|
83159
84080
|
}
|
|
83160
84081
|
/** Fold the bound live session into a directory row without waiting for persistence. */
|
|
83161
84082
|
rowForLiveSession(session) {
|
|
84083
|
+
const events = getSessionEvents(session);
|
|
83162
84084
|
return {
|
|
83163
84085
|
id: session.id,
|
|
83164
|
-
title: listTitleOf(
|
|
83165
|
-
updatedAt:
|
|
84086
|
+
title: listTitleOf(events),
|
|
84087
|
+
updatedAt: events.at(-1)?.time ?? session.header.createdAt
|
|
83166
84088
|
};
|
|
83167
84089
|
}
|
|
83168
84090
|
/** Fold one listed session into a directory row; corrupt logs degrade to the id. */
|
|
@@ -83646,6 +84568,7 @@ var RuntimeController = class _RuntimeController {
|
|
|
83646
84568
|
}
|
|
83647
84569
|
};
|
|
83648
84570
|
function topBarTitle(events) {
|
|
84571
|
+
if (!Array.isArray(events)) return "";
|
|
83649
84572
|
const folded = foldSessionTitle(events);
|
|
83650
84573
|
if (folded === void 0) return "";
|
|
83651
84574
|
if (folded.source.kind === "fallback" && events.some(isHumanUserMessage)) {
|
|
@@ -83654,9 +84577,11 @@ function topBarTitle(events) {
|
|
|
83654
84577
|
return folded.title;
|
|
83655
84578
|
}
|
|
83656
84579
|
function notifySessionTitle(events) {
|
|
84580
|
+
if (!Array.isArray(events)) return void 0;
|
|
83657
84581
|
return foldTitle(events);
|
|
83658
84582
|
}
|
|
83659
84583
|
function foldTitle(events) {
|
|
84584
|
+
if (!Array.isArray(events)) return void 0;
|
|
83660
84585
|
const folded = foldSessionTitle(events);
|
|
83661
84586
|
if (folded !== void 0) return folded.title;
|
|
83662
84587
|
const firstUser = events.find(isHumanUserMessage);
|
|
@@ -83672,6 +84597,7 @@ function foldTitle(events) {
|
|
|
83672
84597
|
return void 0;
|
|
83673
84598
|
}
|
|
83674
84599
|
function listTitleOf(events) {
|
|
84600
|
+
if (!Array.isArray(events)) return "\u672A\u547D\u540D\u4F1A\u8BDD";
|
|
83675
84601
|
return foldTitle(events) ?? "\u672A\u547D\u540D\u4F1A\u8BDD";
|
|
83676
84602
|
}
|
|
83677
84603
|
function firstLine2(text4) {
|
|
@@ -83977,6 +84903,18 @@ async function run(ctx, config2, io) {
|
|
|
83977
84903
|
}
|
|
83978
84904
|
}
|
|
83979
84905
|
function apply(ctx, config2) {
|
|
84906
|
+
try {
|
|
84907
|
+
if (typeof Session === "function" && !("events" in Session.prototype)) {
|
|
84908
|
+
Object.defineProperty(Session.prototype, "events", {
|
|
84909
|
+
get() {
|
|
84910
|
+
return typeof this.snapshotEvents === "function" ? this.snapshotEvents() : [];
|
|
84911
|
+
},
|
|
84912
|
+
configurable: true,
|
|
84913
|
+
enumerable: false
|
|
84914
|
+
});
|
|
84915
|
+
}
|
|
84916
|
+
} catch {
|
|
84917
|
+
}
|
|
83980
84918
|
const exit3 = ctx.get("appExit");
|
|
83981
84919
|
if (exit3 === void 0) {
|
|
83982
84920
|
throw new Error(
|
|
@@ -84023,6 +84961,8 @@ export {
|
|
|
84023
84961
|
RuntimeController,
|
|
84024
84962
|
SEARCH_DEBOUNCE_MS,
|
|
84025
84963
|
apply,
|
|
84964
|
+
ensureSessionEventsCompat,
|
|
84965
|
+
getSessionEvents,
|
|
84026
84966
|
inject,
|
|
84027
84967
|
internals,
|
|
84028
84968
|
name,
|
package/package.json
CHANGED
package/tui/cordis.patch.yml
CHANGED
|
@@ -35,12 +35,40 @@
|
|
|
35
35
|
openAt: first-search
|
|
36
36
|
|
|
37
37
|
- insert:
|
|
38
|
+
# Code Mode is a core execution capability, not a Web component.
|
|
39
|
+
- id: code-runtime
|
|
40
|
+
name: "@deepseek-ai/dsh-code-runtime-worker-thread"
|
|
41
|
+
|
|
42
|
+
# Per-round token/duration stats for the terminal status line.
|
|
43
|
+
- id: session-stats
|
|
44
|
+
name: "@deepseek-ai/dsh-session-stats"
|
|
45
|
+
|
|
46
|
+
# Base owns the shared storage/domain/projection-cache stack. This layer
|
|
47
|
+
# contributes only the TUI-facing feedback consumer over that stack.
|
|
48
|
+
- id: message-feedback
|
|
49
|
+
name: "@deepseek-ai/dsh-message-feedback"
|
|
50
|
+
config:
|
|
51
|
+
maxNoteBytes: 8192
|
|
52
|
+
|
|
53
|
+
- id: tool-ask-user
|
|
54
|
+
name: "@deepseek-ai/dsh-tool-ask-user"
|
|
55
|
+
|
|
38
56
|
- id: tui-startup
|
|
39
|
-
name: "
|
|
57
|
+
name: "@deepseek-ai/dsh-tui/startup"
|
|
58
|
+
|
|
59
|
+
# Zero-config official OpenAI/Anthropic routes. They register
|
|
60
|
+
# openai-official / anthropic-official so they do not collide with the
|
|
61
|
+
# dormant llm-pi-ai catalog keys openai / anthropic that the Web Models
|
|
62
|
+
# page already owns.
|
|
63
|
+
- id: llm-openai
|
|
64
|
+
name: "@deepseek-ai/dsh-llm-openai"
|
|
65
|
+
|
|
66
|
+
- id: llm-anthropic
|
|
67
|
+
name: "@deepseek-ai/dsh-llm-anthropic"
|
|
40
68
|
|
|
41
69
|
# Reads its task from the ordinary tuiStartup provider.
|
|
42
70
|
- id: tui-runtime
|
|
43
|
-
name: "
|
|
71
|
+
name: "@deepseek-ai/dsh-tui"
|
|
44
72
|
inject: [tuiStartup]
|
|
45
73
|
config:
|
|
46
74
|
task: !!js ctx.tuiStartup.task
|