mixdog 0.9.83 → 0.9.85
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/package.json +1 -1
- package/scripts/channel-daemon-stub.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +30 -3
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +38 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +48 -32
- package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +25 -14
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +38 -1
- package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +44 -73
- package/src/runtime/channels/lib/owned-runtime.mjs +6 -8
- package/src/runtime/channels/lib/parent-bridge.mjs +27 -15
- package/src/runtime/channels/lib/worker-ipc.mjs +17 -4
- package/src/runtime/memory/index.mjs +14 -5
- package/src/runtime/memory/lib/agent-ipc.mjs +11 -12
- package/src/runtime/shared/atomic-file.mjs +51 -24
- package/src/runtime/shared/err-text.mjs +1 -0
- package/src/runtime/shared/safe-ipc-send.mjs +34 -0
- package/src/session-runtime/lifecycle-api.mjs +9 -3
- package/src/session-runtime/runtime-core.mjs +5 -1
- package/src/standalone/channel-daemon.mjs +2 -1
- package/src/standalone/channel-worker.mjs +21 -19
- package/src/standalone/memory-runtime-proxy.mjs +98 -23
- package/src/tui/app/slash-dispatch.mjs +23 -13
- package/src/tui/app/theme-effort-pickers.mjs +3 -1
- package/src/tui/dist/index.mjs +115 -57
- package/src/tui/engine/live-share.mjs +2 -2
- package/src/tui/engine/session-flow.mjs +20 -10
- package/src/tui/engine/turn.mjs +28 -16
- package/src/tui/engine.mjs +17 -1
|
@@ -43,8 +43,12 @@ export function createSessionFlow(bag) {
|
|
|
43
43
|
const mode = options.mode || 'prompt';
|
|
44
44
|
const priority = options.priority || defaultQueuePriority(mode);
|
|
45
45
|
const displayText = promptDisplayText(text, options);
|
|
46
|
+
const submittedAt = Number(options.submittedAt);
|
|
46
47
|
return {
|
|
47
48
|
id: options.id || nextId(),
|
|
49
|
+
submittedAt: Number.isFinite(submittedAt) && submittedAt > 0
|
|
50
|
+
? Math.round(submittedAt)
|
|
51
|
+
: Date.now(),
|
|
48
52
|
text: displayText,
|
|
49
53
|
content: text,
|
|
50
54
|
pastedImages: options.pastedImages && typeof options.pastedImages === 'object' ? options.pastedImages : null,
|
|
@@ -283,6 +287,8 @@ export function createSessionFlow(bag) {
|
|
|
283
287
|
set({ queued: [...getState().queued, entry] });
|
|
284
288
|
if (isQueuedEntryEditable(entry)) flushEmitImmediate?.();
|
|
285
289
|
}
|
|
290
|
+
const queueAgeMs = Math.max(0, Date.now() - Number(entry.submittedAt || Date.now()));
|
|
291
|
+
tuiDebug(`prompt-queued id=${String(entry.id)} busy=${getState().busy ? 1 : 0} ageMs=${queueAgeMs}`);
|
|
286
292
|
if (getState().busy) tuiDebug(`busy-queue enqueue mode=${entry.mode} pending=${pending.length}`);
|
|
287
293
|
void drain();
|
|
288
294
|
return true;
|
|
@@ -309,24 +315,28 @@ export function createSessionFlow(bag) {
|
|
|
309
315
|
if (batch.length === 0) break;
|
|
310
316
|
for (const entry of batch) {
|
|
311
317
|
const content = entry.content;
|
|
318
|
+
const steeringMeta = {
|
|
319
|
+
id: entry.id,
|
|
320
|
+
submittedAt: entry.submittedAt,
|
|
321
|
+
...(Array.isArray(entry.images) && entry.images.length ? { images: entry.images } : {}),
|
|
322
|
+
};
|
|
312
323
|
if (entry.suppressDisplay) {
|
|
313
324
|
// Model-visible twin of an already-rendered live completion: deliver
|
|
314
325
|
// content to the model but flag onSteerMessage to skip the duplicate
|
|
315
326
|
// transcript card (no fall-back to content-derived display text).
|
|
316
327
|
if (Array.isArray(content) ? content.length > 0 : String(content ?? '').trim().length > 0) {
|
|
317
|
-
out.push({ text: STEERING_SUPPRESSED_DISPLAY, content });
|
|
328
|
+
out.push({ ...steeringMeta, text: STEERING_SUPPRESSED_DISPLAY, content });
|
|
318
329
|
}
|
|
319
330
|
continue;
|
|
320
331
|
}
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
out.push(value);
|
|
332
|
+
const displayText = String(entry.text || '').trim();
|
|
333
|
+
if (typeof content === 'string') {
|
|
334
|
+
const value = content.trim();
|
|
335
|
+
if (value.length > 0) out.push({ ...steeringMeta, text: displayText || value, content: value });
|
|
336
|
+
} else if (Array.isArray(content)) {
|
|
337
|
+
if (content.length > 0) out.push({ ...steeringMeta, text: displayText, content });
|
|
338
|
+
} else if (String(content ?? '').trim().length > 0) {
|
|
339
|
+
out.push({ ...steeringMeta, text: displayText, content });
|
|
330
340
|
}
|
|
331
341
|
}
|
|
332
342
|
commitSteeringQueueEntries(batch);
|
package/src/tui/engine/turn.mjs
CHANGED
|
@@ -17,8 +17,11 @@ export function createRunTurn(bag) {
|
|
|
17
17
|
} = bag;
|
|
18
18
|
// Small fallbacks keep isolated createRunTurn harnesses source-compatible;
|
|
19
19
|
// the real engine supplies atomic implementations that also maintain revision.
|
|
20
|
-
const updateStreamingTail = updateStreamingTailFromStore || ((id, patch = {}) => {
|
|
21
|
-
set({
|
|
20
|
+
const updateStreamingTail = updateStreamingTailFromStore || ((id, patch = {}, extra = {}) => {
|
|
21
|
+
set({
|
|
22
|
+
streamingTail: { ...(getState().streamingTail || {}), ...patch, kind: 'assistant', id, streaming: true },
|
|
23
|
+
...extra,
|
|
24
|
+
});
|
|
22
25
|
return true;
|
|
23
26
|
});
|
|
24
27
|
const settleStreamingTail = settleStreamingTailFromStore || ((id, patch = {}) => {
|
|
@@ -671,7 +674,12 @@ export function createRunTurn(bag) {
|
|
|
671
674
|
patch.spinner = { ...getState().spinner, responseLength: responseLengthVal, thinking: false, thinkingLastEndedAt: _pendingThinkingLastEndedAt || getState().spinner.thinkingLastEndedAt, mode: compactingActive ? 'compacting' : 'responding' };
|
|
672
675
|
_publishedThinkingActive = false;
|
|
673
676
|
}
|
|
674
|
-
if (
|
|
677
|
+
if (patch.streamingTail) {
|
|
678
|
+
const { streamingTail, ...extra } = patch;
|
|
679
|
+
updateStreamingTail(streamingTail.id, streamingTail, extra);
|
|
680
|
+
} else if (Object.keys(patch).length > 0) {
|
|
681
|
+
set(patch);
|
|
682
|
+
}
|
|
675
683
|
_pendingThinkingLastEndedAt = 0;
|
|
676
684
|
}
|
|
677
685
|
if (_pendingThinkFlush) {
|
|
@@ -800,7 +808,7 @@ export function createRunTurn(bag) {
|
|
|
800
808
|
onStreamDelta: () => {
|
|
801
809
|
markTurnProgress('stream-delta');
|
|
802
810
|
},
|
|
803
|
-
onSteerMessage: (text) => {
|
|
811
|
+
onSteerMessage: (text, steeringMeta = {}) => {
|
|
804
812
|
if (!markTurnProgress('steer-message')) return;
|
|
805
813
|
// A suppressed live-completion twin is model-visible only; its
|
|
806
814
|
// Response card was already pushed at delivery time. Skip the
|
|
@@ -826,7 +834,17 @@ export function createRunTurn(bag) {
|
|
|
826
834
|
// same-category tool call opens a fresh card instead of reusing
|
|
827
835
|
// one whose count would then change ABOVE this steered user item.
|
|
828
836
|
clearAggregateContinuation();
|
|
829
|
-
|
|
837
|
+
const steeringIds = Array.isArray(steeringMeta?.ids)
|
|
838
|
+
? steeringMeta.ids.filter((id) => id !== undefined && id !== null)
|
|
839
|
+
: [];
|
|
840
|
+
pushUserOrSyntheticItem(
|
|
841
|
+
value,
|
|
842
|
+
steeringIds[0],
|
|
843
|
+
'injected',
|
|
844
|
+
Array.isArray(steeringMeta?.images) && steeringMeta.images.length
|
|
845
|
+
? { images: steeringMeta.images }
|
|
846
|
+
: null,
|
|
847
|
+
);
|
|
830
848
|
}
|
|
831
849
|
},
|
|
832
850
|
onToolCall: async (_iter, calls) => {
|
|
@@ -1091,17 +1109,11 @@ export function createRunTurn(bag) {
|
|
|
1091
1109
|
_emittedVisibleText = '';
|
|
1092
1110
|
if (currentAssistantId) {
|
|
1093
1111
|
if (currentAssistantText) {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
text: currentAssistantText,
|
|
1100
|
-
streaming: true,
|
|
1101
|
-
at: getState().streamingTail?.at || Date.now(),
|
|
1102
|
-
...turnRouteMeta,
|
|
1103
|
-
},
|
|
1104
|
-
});
|
|
1112
|
+
updateStreamingTail(currentAssistantId, {
|
|
1113
|
+
text: currentAssistantText,
|
|
1114
|
+
at: getState().streamingTail?.at || Date.now(),
|
|
1115
|
+
...turnRouteMeta,
|
|
1116
|
+
}, {}, { resetText: true });
|
|
1105
1117
|
} else {
|
|
1106
1118
|
clearStreamingTail(currentAssistantId);
|
|
1107
1119
|
currentAssistantId = null;
|
package/src/tui/engine.mjs
CHANGED
|
@@ -537,12 +537,28 @@ export async function createEngineSession({
|
|
|
537
537
|
...extra,
|
|
538
538
|
});
|
|
539
539
|
};
|
|
540
|
-
|
|
540
|
+
// Non-enumerable so the marker never enters persisted transcript items,
|
|
541
|
+
// live-share JSON, or renderer snapshots. The desktop host reads the shared
|
|
542
|
+
// Symbol.for key before cloning and uses it to prove that a growing text is
|
|
543
|
+
// an append, avoiding an O(total text) startsWith check on every frame.
|
|
544
|
+
const streamingTailTextEpochKey = Symbol.for('mixdog.streaming-tail-text-epoch');
|
|
545
|
+
let streamingTailTextEpoch = 0;
|
|
546
|
+
const updateStreamingTail = (id, patch = {}, extra = {}, { resetText = false } = {}) => {
|
|
541
547
|
if (id == null) return false;
|
|
542
548
|
const current = state.streamingTail?.id === id
|
|
543
549
|
? state.streamingTail
|
|
544
550
|
: { kind: 'assistant', id, text: '', streaming: true };
|
|
545
551
|
const next = { ...current, ...patch, kind: 'assistant', id, streaming: true };
|
|
552
|
+
const currentTextEpoch = current[streamingTailTextEpochKey];
|
|
553
|
+
const textEpoch = !resetText && Number.isSafeInteger(currentTextEpoch)
|
|
554
|
+
? currentTextEpoch
|
|
555
|
+
: ++streamingTailTextEpoch;
|
|
556
|
+
Object.defineProperty(next, streamingTailTextEpochKey, {
|
|
557
|
+
value: textEpoch,
|
|
558
|
+
enumerable: false,
|
|
559
|
+
configurable: false,
|
|
560
|
+
writable: false,
|
|
561
|
+
});
|
|
546
562
|
let changed = state.streamingTail !== current;
|
|
547
563
|
if (!changed) {
|
|
548
564
|
for (const [key, value] of Object.entries(next)) {
|