mixdog 0.9.87 → 0.9.89
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 +13 -7
- package/scripts/tool-failures.mjs +60 -24
- package/src/agents/heavy-worker/AGENT.md +3 -4
- package/src/agents/worker/AGENT.md +1 -2
- package/src/cli.mjs +8 -0
- package/src/defaults/cycle3-review-prompt.md +4 -4
- package/src/rules/agent/00-core.md +3 -0
- package/src/rules/agent/42-cycle3-agent.md +5 -6
- package/src/rules/lead/01-general.md +2 -0
- package/src/rules/shared/01-tool.md +29 -35
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +3 -51
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +59 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +2 -2
- package/src/runtime/agent/orchestrator/agent-runtime/title-completion.mjs +67 -0
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +57 -4
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +2 -3
- package/src/runtime/agent/orchestrator/config.mjs +29 -11
- package/src/runtime/agent/orchestrator/context/collect.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +1 -1
- package/src/runtime/agent/orchestrator/mcp/client.mjs +0 -24
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +25 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +321 -22
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +35 -22
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +28 -23
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +10 -2
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth-tokens.mjs +0 -1
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +2 -5
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-native-blocks.mjs +27 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/lib/stream-outcome.mjs +329 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +23 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +107 -20
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +4 -3
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +124 -12
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +19 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +110 -75
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +96 -113
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +160 -11
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +18 -1
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +147 -117
- package/src/runtime/agent/orchestrator/session/loop/stop-hooks.mjs +88 -0
- package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +50 -8
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +25 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +47 -6
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +485 -24
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +100 -2
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +80 -14
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +142 -2
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +128 -32
- package/src/runtime/agent/orchestrator/session/manager.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/save-session-worker.mjs +77 -4
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +70 -39
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +91 -0
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +141 -64
- package/src/runtime/agent/orchestrator/session/store/live-state.mjs +253 -0
- package/src/runtime/agent/orchestrator/session/store/load-cache.mjs +211 -28
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +313 -0
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +622 -53
- package/src/runtime/agent/orchestrator/session/store/serialize.mjs +43 -10
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +53 -8
- package/src/runtime/agent/orchestrator/session/store/summary-rebuild-worker.mjs +20 -0
- package/src/runtime/agent/orchestrator/session/store/write-guards.mjs +113 -9
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +476 -52
- package/src/runtime/agent/orchestrator/session/store.mjs +721 -196
- package/src/runtime/agent/orchestrator/session/token-native.mjs +2 -4
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +4 -6
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +146 -90
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +93 -17
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +5 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +85 -5
- package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +52 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +54 -51
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +14 -15
- package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +132 -8
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +86 -3
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +210 -38
- package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +23 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +87 -19
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -8
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +12 -2
- package/src/runtime/media/lanes.mjs +2 -2
- package/src/runtime/media/renditions.mjs +101 -17
- package/src/runtime/media/renditions.test.mjs +54 -0
- package/src/runtime/media/store.mjs +111 -43
- package/src/runtime/media/store.test.mjs +53 -11
- package/src/runtime/memory/index.mjs +26 -50
- package/src/runtime/memory/lib/core-memory-candidates.mjs +2 -7
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -9
- package/src/runtime/memory/lib/cycle-scheduler.mjs +10 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +3 -3
- package/src/runtime/memory/lib/embedding-worker.mjs +60 -15
- package/src/runtime/memory/lib/http-router.mjs +4 -0
- package/src/runtime/memory/lib/ko-morph.mjs +49 -6
- package/src/runtime/memory/lib/memory-action-handlers.mjs +21 -18
- package/src/runtime/memory/lib/memory-cycle2.mjs +3 -3
- package/src/runtime/memory/lib/memory-cycle3.mjs +1 -3
- package/src/runtime/memory/lib/memory-recall-store.mjs +24 -0
- package/src/runtime/memory/lib/query-handlers.mjs +26 -28
- package/src/runtime/memory/tool-defs.mjs +3 -3
- package/src/runtime/shared/atomic-file.mjs +5 -1
- package/src/runtime/shared/child-guardian.mjs +73 -2
- package/src/runtime/shared/provider-api-key.mjs +22 -5
- package/src/runtime/shared/tool-execution-contract.mjs +53 -0
- package/src/session-runtime/config-helpers.mjs +6 -5
- package/src/session-runtime/lifecycle-api.mjs +16 -4
- package/src/session-runtime/media-api.mjs +31 -16
- package/src/session-runtime/prewarm.mjs +2 -24
- package/src/session-runtime/runtime-core.mjs +33 -15
- package/src/session-runtime/runtime-tunables.mjs +0 -3
- package/src/session-runtime/session-lifecycle.mjs +0 -6
- package/src/session-runtime/session-title.mjs +228 -0
- package/src/session-runtime/session-turn-api.mjs +11 -7
- package/src/session-runtime/workflow-agents-api.mjs +16 -0
- package/src/session-runtime/workflow.mjs +7 -5
- package/src/standalone/agent-tool/job-views.mjs +90 -36
- package/src/standalone/agent-tool/spawn-flow.mjs +25 -216
- package/src/standalone/agent-tool/worker-index.mjs +8 -0
- package/src/standalone/agent-tool/worker-rows.mjs +2 -1
- package/src/standalone/agent-tool.mjs +17 -17
- package/src/standalone/agent-watchdog-registry.mjs +19 -2
- package/src/standalone/channel-daemon.mjs +8 -0
- package/src/standalone/explore-tool.mjs +1 -1
- package/src/standalone/memory-runtime-proxy.mjs +4 -7
- package/src/standalone/projects.mjs +4 -1
- package/src/standalone/usage-dashboard.mjs +25 -3
- package/src/tui/App.jsx +5 -3
- package/src/tui/app/resume-picker.mjs +7 -2
- package/src/tui/app/route-pickers.mjs +11 -117
- package/src/tui/app/slash-dispatch.mjs +13 -3
- package/src/tui/app/transcript-row-estimate.mjs +1 -1
- package/src/tui/app/transcript-window.mjs +17 -93
- package/src/tui/app/use-transcript-scroll.mjs +32 -2
- package/src/tui/app/use-transcript-window.mjs +64 -114
- package/src/tui/components/Markdown.jsx +19 -2
- package/src/tui/components/Message.jsx +8 -3
- package/src/tui/components/ToolExecution.jsx +7 -3
- package/src/tui/dist/index.mjs +243 -223
- package/src/tui/engine/live-share.mjs +15 -5
- package/src/tui/engine/render-timing.mjs +2 -2
- package/src/tui/engine/session-api-ext.mjs +74 -4
- package/src/tui/engine/session-flow.mjs +3 -1
- package/src/tui/engine.mjs +2 -2
- package/src/tui/hooks/useSharedTick.mjs +0 -2
- package/src/tui/index.jsx +5 -5
- package/src/ui/statusline-agents.mjs +44 -11
- package/src/vendor/statusline/bin/statusline-route.mjs +26 -3
- package/src/workflows/default/WORKFLOW.md +3 -3
- package/src/workflows/solo/WORKFLOW.md +5 -3
- package/src/runtime/media/index.mjs +0 -18
- package/src/runtime/memory/lib/embedding-warmup.mjs +0 -68
- package/src/standalone/agent-shard/shard-child.mjs +0 -300
- package/src/standalone/agent-shard/shard-pool.mjs +0 -443
|
@@ -70,8 +70,18 @@ export function createLiveShare({
|
|
|
70
70
|
onRemoteAbort,
|
|
71
71
|
onOwnerClosed,
|
|
72
72
|
viewerApply,
|
|
73
|
+
viewerRetryMinMs = LIVE_CONNECT_RETRY_MIN_MS,
|
|
74
|
+
viewerRetryMaxMs = LIVE_CONNECT_RETRY_MAX_MS,
|
|
73
75
|
}) {
|
|
74
76
|
let disposed = false;
|
|
77
|
+
const clientRetryMinimumMs = Math.max(
|
|
78
|
+
LIVE_CONNECT_RETRY_MIN_MS,
|
|
79
|
+
Number(viewerRetryMinMs) || LIVE_CONNECT_RETRY_MIN_MS,
|
|
80
|
+
);
|
|
81
|
+
const clientRetryMaximumMs = Math.max(
|
|
82
|
+
clientRetryMinimumMs,
|
|
83
|
+
Number(viewerRetryMaxMs) || LIVE_CONNECT_RETRY_MAX_MS,
|
|
84
|
+
);
|
|
75
85
|
// ---- owner: pipe server + delta publisher ----
|
|
76
86
|
let server = null;
|
|
77
87
|
let serverId = '';
|
|
@@ -335,7 +345,7 @@ export function createLiveShare({
|
|
|
335
345
|
let lastSyncRequestAt = 0;
|
|
336
346
|
let clientRetryTimer = null;
|
|
337
347
|
let clientRetryId = '';
|
|
338
|
-
let clientRetryDelayMs =
|
|
348
|
+
let clientRetryDelayMs = clientRetryMinimumMs;
|
|
339
349
|
const viewerSyncWaiters = new Set();
|
|
340
350
|
|
|
341
351
|
const settleViewerSync = (id, synced) => {
|
|
@@ -429,8 +439,8 @@ export function createLiveShare({
|
|
|
429
439
|
const target = String(id || '');
|
|
430
440
|
if (disposed || !target || client || clientRetryTimer || String(viewerSessionId() || '') !== target) return;
|
|
431
441
|
const delay = clientRetryDelayMs;
|
|
432
|
-
clientRetryDelayMs = Math.min(
|
|
433
|
-
|
|
442
|
+
clientRetryDelayMs = Math.min(clientRetryMaximumMs, Math.max(
|
|
443
|
+
clientRetryMinimumMs,
|
|
434
444
|
clientRetryDelayMs * 2,
|
|
435
445
|
));
|
|
436
446
|
clientRetryId = target;
|
|
@@ -481,7 +491,7 @@ export function createLiveShare({
|
|
|
481
491
|
|
|
482
492
|
const stopClient = () => {
|
|
483
493
|
clearClientRetry();
|
|
484
|
-
clientRetryDelayMs =
|
|
494
|
+
clientRetryDelayMs = clientRetryMinimumMs;
|
|
485
495
|
const closing = client;
|
|
486
496
|
const closingId = clientId;
|
|
487
497
|
const wasUp = clientUp;
|
|
@@ -520,7 +530,7 @@ export function createLiveShare({
|
|
|
520
530
|
if (client !== socket) return;
|
|
521
531
|
clientUp = true;
|
|
522
532
|
clearClientRetry();
|
|
523
|
-
clientRetryDelayMs =
|
|
533
|
+
clientRetryDelayMs = clientRetryMinimumMs;
|
|
524
534
|
});
|
|
525
535
|
const down = (ownerClosed) => {
|
|
526
536
|
const wasUp = clientUp && client === socket;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Extracted from engine.mjs (no behavior change originally).
|
|
5
5
|
*
|
|
6
|
-
* Ink renders through a maxFps throttle (
|
|
6
|
+
* Ink renders through a maxFps throttle (120fps in index.jsx, ≈8.3ms). A plain
|
|
7
7
|
* setImmediate only yields to the event loop; if Ink already painted within the
|
|
8
8
|
* current throttle window, the next paint may still be queued and our following
|
|
9
9
|
* transcript mutation can coalesce into the same visible frame. When we
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
const RENDER_ACK_FALLBACK_MS = 32;
|
|
21
21
|
const RENDER_ACK_HANG_GUARD_MS = 250;
|
|
22
22
|
const RENDER_SETTLE_IDLE_MS = 64;
|
|
23
|
-
export const TUI_RENDER_FPS =
|
|
23
|
+
export const TUI_RENDER_FPS = 120;
|
|
24
24
|
// Ink uses Math.ceil(1000 / maxFps); share that exact cadence with the store.
|
|
25
25
|
export const TUI_FRAME_MS = Math.ceil(1000 / TUI_RENDER_FPS);
|
|
26
26
|
|
|
@@ -9,6 +9,7 @@ import { flushTuiSteeringPersist } from './tui-steering-persist.mjs';
|
|
|
9
9
|
import { getVoiceStatus, toggleVoice } from '../lib/voice-setup.mjs';
|
|
10
10
|
import { aggregateToolCategoryEntry, aggregateDoneCategories, classifyToolCategory, formatAggregateDetail, summarizeToolResult } from '../../runtime/shared/tool-surface.mjs';
|
|
11
11
|
import { aggregateBucketForCategory, aggregateRawResult, failureDetailText, shellCommandExitCode } from './tool-result-status.mjs';
|
|
12
|
+
import { isInternalTranscriptDisplayText } from '../../runtime/shared/tool-execution-contract.mjs';
|
|
12
13
|
|
|
13
14
|
export function restoredTranscriptMetadata(message) {
|
|
14
15
|
const value = message?.meta?.transcript;
|
|
@@ -221,9 +222,7 @@ function restoredUserTranscriptItems(message, nextId) {
|
|
|
221
222
|
const text = (typeof message?.content === 'string'
|
|
222
223
|
? message.content
|
|
223
224
|
: toolResultText(message?.content)).trim();
|
|
224
|
-
if (
|
|
225
|
-
return [];
|
|
226
|
-
}
|
|
225
|
+
if (isInternalTranscriptDisplayText(text)) return [];
|
|
227
226
|
if (!text) return [];
|
|
228
227
|
const synthetic = parseSyntheticAgentMessage(text);
|
|
229
228
|
if (!synthetic) {
|
|
@@ -311,6 +310,55 @@ export function restoreTranscriptItems(messages, {
|
|
|
311
310
|
return restored.length > limit ? restored.slice(-limit) : restored;
|
|
312
311
|
}
|
|
313
312
|
|
|
313
|
+
export function sessionContextSnapshotProjection(session, contextStatus) {
|
|
314
|
+
if (!contextStatus) return {};
|
|
315
|
+
const usedSource = String(contextStatus.usedSource || '').toLowerCase();
|
|
316
|
+
const estimatedTokens = Math.max(0, Number(
|
|
317
|
+
contextStatus.currentEstimatedTokens
|
|
318
|
+
?? contextStatus.usedTokens
|
|
319
|
+
?? 0,
|
|
320
|
+
));
|
|
321
|
+
const lastApiRequestTokens = Math.max(0, Number(
|
|
322
|
+
contextStatus.lastApiRequestTokens
|
|
323
|
+
?? contextStatus.usage?.lastContextTokens
|
|
324
|
+
?? 0,
|
|
325
|
+
));
|
|
326
|
+
return {
|
|
327
|
+
stats: {
|
|
328
|
+
currentContextTokens: usedSource === 'last_api_request'
|
|
329
|
+
? lastApiRequestTokens
|
|
330
|
+
: 0,
|
|
331
|
+
currentEstimatedContextTokens: estimatedTokens,
|
|
332
|
+
currentContextSource: usedSource === 'last_api_request'
|
|
333
|
+
? 'last_api_request'
|
|
334
|
+
: estimatedTokens > 0 ? 'estimated' : null,
|
|
335
|
+
currentContextUpdatedAt: Date.now(),
|
|
336
|
+
},
|
|
337
|
+
contextWindow: Math.max(
|
|
338
|
+
0,
|
|
339
|
+
Number(session?.contextWindow || contextStatus.effectiveContextWindow || 0),
|
|
340
|
+
),
|
|
341
|
+
rawContextWindow: Math.max(
|
|
342
|
+
0,
|
|
343
|
+
Number(session?.rawContextWindow || contextStatus.rawContextWindow || 0),
|
|
344
|
+
),
|
|
345
|
+
effectiveContextWindowPercent: Number(
|
|
346
|
+
session?.effectiveContextWindowPercent
|
|
347
|
+
?? contextStatus.effectiveContextWindowPercent
|
|
348
|
+
?? 0,
|
|
349
|
+
),
|
|
350
|
+
displayContextWindow: Math.max(0, Number(contextStatus.contextWindow || 0)),
|
|
351
|
+
compactBoundaryTokens: Math.max(
|
|
352
|
+
0,
|
|
353
|
+
Number(contextStatus.compaction?.boundaryTokens || 0),
|
|
354
|
+
),
|
|
355
|
+
autoCompactTokenLimit: Math.max(
|
|
356
|
+
0,
|
|
357
|
+
Number(contextStatus.compaction?.triggerTokens || 0),
|
|
358
|
+
),
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
314
362
|
export function createEngineApiB(bag) {
|
|
315
363
|
const {
|
|
316
364
|
runtime, nextId, flags, lifecycle, listeners, getState, set, flushEmitImmediate, disposeEmit, replaceItems, pushNotice, removeNotice, setProgressHint, clearToastTimers, disposeTranscriptSpill, routeState, syncContextStats, finishToolApproval, denyAllToolApprovals, restoreLeadSteeringFromDisk, resetStats, clearUiActivityBeforeContextSync, resetTuiForPendingSessionReset, snapshotTuiBeforeSessionReset, restoreTuiAfterFailedSessionReset, commitTuiSessionReset, resetStatsAndSyncContext,
|
|
@@ -565,6 +613,15 @@ export function createEngineApiB(bag) {
|
|
|
565
613
|
getUsageDashboard: async (options = {}) => {
|
|
566
614
|
return await runtime.getUsageDashboard?.(options);
|
|
567
615
|
},
|
|
616
|
+
consumeCodexRateLimitResetCredit: async (options = {}) => {
|
|
617
|
+
// Desktop capability parity: without this delegation the engine surface
|
|
618
|
+
// rejects the sidebar's reset-credit invoke as unsupported even though
|
|
619
|
+
// the session runtime implements it.
|
|
620
|
+
if (typeof runtime.consumeCodexRateLimitResetCredit !== 'function') {
|
|
621
|
+
throw new Error('Codex reset is unavailable');
|
|
622
|
+
}
|
|
623
|
+
return await runtime.consumeCodexRateLimitResetCredit(options);
|
|
624
|
+
},
|
|
568
625
|
getTurnReviewDiff: async () => {
|
|
569
626
|
return (await runtime.getTurnReviewDiff?.()) ?? { supported: false, files: [], patch: '' };
|
|
570
627
|
},
|
|
@@ -693,6 +750,7 @@ export function createEngineApiB(bag) {
|
|
|
693
750
|
listMediaLanes: () => runtime.listMediaLanes?.(),
|
|
694
751
|
listMediaAssets: (options) => runtime.listMediaAssets?.(options),
|
|
695
752
|
readMediaAsset: (id, options) => runtime.readMediaAsset?.(id, options),
|
|
753
|
+
cacheMediaThumbnail: (id, input) => runtime.cacheMediaThumbnail?.(id, input),
|
|
696
754
|
resolveMediaFile: (id, options) => runtime.resolveMediaFile?.(id, options),
|
|
697
755
|
getMediaJob: (id) => runtime.getMediaJob?.(id),
|
|
698
756
|
listMediaJobs: () => runtime.listMediaJobs?.(),
|
|
@@ -702,7 +760,7 @@ export function createEngineApiB(bag) {
|
|
|
702
760
|
cancelMediaJob: (id) => runtime.cancelMediaJob?.(id),
|
|
703
761
|
deleteMediaAsset: (id) => runtime.deleteMediaAsset?.(id),
|
|
704
762
|
openMediaAsset: (id) => runtime.openMediaAsset?.(id),
|
|
705
|
-
openMediaFolder: () => runtime.openMediaFolder?.(),
|
|
763
|
+
openMediaFolder: (id) => runtime.openMediaFolder?.(id),
|
|
706
764
|
setWebhookConfig: async (patch) => {
|
|
707
765
|
const result = await runtime.setWebhookConfig(patch);
|
|
708
766
|
pushNotice('webhook config updated', 'info');
|
|
@@ -800,6 +858,9 @@ export function createEngineApiB(bag) {
|
|
|
800
858
|
listSessions: (options) => {
|
|
801
859
|
return runtime.listSessions(options);
|
|
802
860
|
},
|
|
861
|
+
renameSessionTitle: (id, title) => {
|
|
862
|
+
return runtime.renameSessionTitle?.(id, title) ?? false;
|
|
863
|
+
},
|
|
803
864
|
// Desktop sidebar watcher hook: EngineHost fs.watches this directory so
|
|
804
865
|
// heartbeat sidecar create/delete pushes instant working/dot updates.
|
|
805
866
|
// Without it the watcher silently no-ops and the sidebar falls back to
|
|
@@ -898,6 +959,10 @@ export function createEngineApiB(bag) {
|
|
|
898
959
|
sessionId: null,
|
|
899
960
|
stats: { ...getState().stats },
|
|
900
961
|
});
|
|
962
|
+
// Publish the blank session boundary before runtime session creation can
|
|
963
|
+
// block on disk/provider work. Otherwise the old transcript remains the
|
|
964
|
+
// last committed React snapshot until the async command completes.
|
|
965
|
+
flushEmitImmediate();
|
|
901
966
|
try {
|
|
902
967
|
await runtime.newSession();
|
|
903
968
|
clearUiActivityBeforeContextSync();
|
|
@@ -912,6 +977,9 @@ export function createEngineApiB(bag) {
|
|
|
912
977
|
} finally {
|
|
913
978
|
flags.pendingSessionReset = false;
|
|
914
979
|
set({ commandBusy: false });
|
|
980
|
+
// Match resume's atomic handoff: callers (and the forced terminal
|
|
981
|
+
// repaint triggered by /new) must observe the completed empty session.
|
|
982
|
+
flushEmitImmediate();
|
|
915
983
|
}
|
|
916
984
|
},
|
|
917
985
|
// Desktop split panes: read-only transcript + route peek of an idle
|
|
@@ -922,6 +990,7 @@ export function createEngineApiB(bag) {
|
|
|
922
990
|
if (!session) return null;
|
|
923
991
|
const sessionId = String(session.id || id);
|
|
924
992
|
const limit = Number(options.transcriptItemLimit);
|
|
993
|
+
const contextStatus = runtime.contextStatusForSession?.(session) || null;
|
|
925
994
|
return {
|
|
926
995
|
sessionId,
|
|
927
996
|
items: restoreTranscriptItems(session.messages, {
|
|
@@ -935,6 +1004,7 @@ export function createEngineApiB(bag) {
|
|
|
935
1004
|
cwd: session.cwd || '',
|
|
936
1005
|
desktopSession: session.desktopSession || null,
|
|
937
1006
|
workflow: session.workflow || null,
|
|
1007
|
+
...sessionContextSnapshotProjection(session, contextStatus),
|
|
938
1008
|
};
|
|
939
1009
|
},
|
|
940
1010
|
resume: async (id, options = {}) => {
|
|
@@ -357,7 +357,9 @@ export function createSessionFlow(bag) {
|
|
|
357
357
|
if (isQueuedEntryVisible(entry)) restored.push(entry);
|
|
358
358
|
}
|
|
359
359
|
if (restored.length > 0) set({ queued: [...getState().queued, ...restored] });
|
|
360
|
-
|
|
360
|
+
// Recovery must not create a user turn by itself. An idle reconnect leaves
|
|
361
|
+
// the restored rows visible/editable in the queue; a real active-turn
|
|
362
|
+
// boundary or later submit will invoke the normal drain path.
|
|
361
363
|
}
|
|
362
364
|
|
|
363
365
|
async function autoClearBeforeSubmit() {
|
package/src/tui/engine.mjs
CHANGED
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
summarizeToolResult,
|
|
24
24
|
} from '../runtime/shared/tool-surface.mjs';
|
|
25
25
|
import {
|
|
26
|
+
isInternalTranscriptDisplayText,
|
|
26
27
|
isModelVisibleToolCompletionWrapper,
|
|
27
|
-
isLikelyToolCompletionWrapper,
|
|
28
28
|
} from '../runtime/shared/tool-execution-contract.mjs';
|
|
29
29
|
import { isLateToolAnnouncement } from '../session-runtime/session-text.mjs';
|
|
30
30
|
import { presentErrorText } from '../runtime/shared/err-text.mjs';
|
|
@@ -624,7 +624,7 @@ export async function createEngineSession({
|
|
|
624
624
|
// the text is known to have been synthesized by the runtime, not typed
|
|
625
625
|
// by the user. Direct user submissions always go through the strict
|
|
626
626
|
// detector only, same as before this change.
|
|
627
|
-
if (origin === 'injected' &&
|
|
627
|
+
if (origin === 'injected' && isInternalTranscriptDisplayText(text)) return;
|
|
628
628
|
if (isModelVisibleToolCompletionWrapper(text)) return;
|
|
629
629
|
// Late-MCP deferred-tool announcement (model-visible <system-reminder>):
|
|
630
630
|
// keep it in model context, but render NOTHING user-facing — not even the
|
package/src/tui/index.jsx
CHANGED
|
@@ -621,11 +621,11 @@ export async function runTui({ provider, model, toolMode, remote, forceOnboardin
|
|
|
621
621
|
if (mouseTracking && typeof instance.getSelectionRows === 'function') {
|
|
622
622
|
store.getRenderSelectionRows = instance.getSelectionRows;
|
|
623
623
|
}
|
|
624
|
-
// [mixdog] One-shot full clear+repaint.
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
//
|
|
628
|
-
if (
|
|
624
|
+
// [mixdog] One-shot full clear+repaint. Mouse selection uses it to dismiss
|
|
625
|
+
// WT's native highlight; session replacement also uses it to erase physical
|
|
626
|
+
// rows from a taller outgoing transcript, so expose it independently of
|
|
627
|
+
// whether mouse tracking is enabled.
|
|
628
|
+
if (typeof instance.forceFullRepaint === 'function') {
|
|
629
629
|
store.forceRenderRepaint = instance.forceFullRepaint;
|
|
630
630
|
}
|
|
631
631
|
await waitUntilExit();
|
|
@@ -12,13 +12,16 @@ import { classifyToolCategory } from '../runtime/shared/tool-surface.mjs';
|
|
|
12
12
|
import { num, GRN, R, B } from './statusline-format.mjs';
|
|
13
13
|
|
|
14
14
|
const DEFAULT_HIDDEN_STATUSLINE_AGENTS = Object.freeze(['explorer', 'cycle1-agent', 'cycle2-agent', 'cycle3-agent', 'scheduler-task', 'webhook-handler']);
|
|
15
|
+
const TERMINAL_AGENT_STATUS = /idle|done|complete|success|closed|error|fail|cancel|killed|timeout/i;
|
|
16
|
+
const ACTIVE_AGENT_STATUS = /^(?:connecting|requesting|streaming|tool[-_\s]?running|running|queued|pending|starting)$/i;
|
|
17
|
+
const QUEUED_AGENT_STATUS = /^(?:queued|pending|starting)$/i;
|
|
15
18
|
let _hiddenStatuslineAgents = null;
|
|
16
19
|
|
|
17
20
|
function normalizeAgentWorkerForStatusline(worker = {}) {
|
|
18
21
|
const tag = String(worker.tag || worker.agent || worker.name || '').trim();
|
|
19
22
|
if (!tag) return null;
|
|
20
|
-
const
|
|
21
|
-
const status =
|
|
23
|
+
const statuses = agentStatusValues(worker);
|
|
24
|
+
const status = isActiveAgentEntry(statuses) ? 'running' : 'idle';
|
|
22
25
|
return {
|
|
23
26
|
tag,
|
|
24
27
|
status,
|
|
@@ -32,14 +35,15 @@ function normalizeAgentWorkerForStatusline(worker = {}) {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
function normalizeAgentJobForStatusline(job = {}) {
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
38
|
+
const statuses = agentStatusValues(job);
|
|
39
|
+
if (!statuses.length) return null;
|
|
40
|
+
const statusText = statuses[0].toLowerCase();
|
|
37
41
|
const taskId = String(job.task_id || job.taskId || '').trim();
|
|
38
42
|
const tag = String(job.tag || job.agent || job.type || taskId || '').trim();
|
|
39
43
|
if (!tag && !taskId) return null;
|
|
40
44
|
const startedAtMs = timeMs(job.startedAt);
|
|
41
45
|
const finishedAtMs = timeMs(job.finishedAt);
|
|
42
|
-
if (
|
|
46
|
+
if (isTerminalAgentEntry(statuses) && finishedAtMs > 0) {
|
|
43
47
|
return {
|
|
44
48
|
tag,
|
|
45
49
|
taskId,
|
|
@@ -54,11 +58,11 @@ function normalizeAgentJobForStatusline(job = {}) {
|
|
|
54
58
|
model: job.model || null,
|
|
55
59
|
};
|
|
56
60
|
}
|
|
57
|
-
if (
|
|
61
|
+
if (!isActiveAgentEntry(statuses)) return null;
|
|
58
62
|
return {
|
|
59
63
|
tag,
|
|
60
64
|
taskId,
|
|
61
|
-
status: 'running',
|
|
65
|
+
status: isQueuedAgentEntry(statuses) ? 'queued' : 'running',
|
|
62
66
|
startedAtMs,
|
|
63
67
|
agent: job.agent || null,
|
|
64
68
|
stage: job.stage || job.workerStatus || job.status || null,
|
|
@@ -70,10 +74,13 @@ function normalizeAgentJobForStatusline(job = {}) {
|
|
|
70
74
|
|
|
71
75
|
export function agentStatuslinePayload(agentWorkers = [], agentJobs = []) {
|
|
72
76
|
const byTag = new Map();
|
|
77
|
+
const workerByTag = new Map();
|
|
73
78
|
const finishedJobs = [];
|
|
74
79
|
for (const worker of Array.isArray(agentWorkers) ? agentWorkers : []) {
|
|
75
80
|
const row = normalizeAgentWorkerForStatusline(worker);
|
|
76
|
-
if (row)
|
|
81
|
+
if (!row) continue;
|
|
82
|
+
workerByTag.set(row.tag, row);
|
|
83
|
+
byTag.set(row.tag, row);
|
|
77
84
|
}
|
|
78
85
|
for (const job of Array.isArray(agentJobs) ? agentJobs : []) {
|
|
79
86
|
const row = normalizeAgentJobForStatusline(job);
|
|
@@ -82,8 +89,13 @@ export function agentStatuslinePayload(agentWorkers = [], agentJobs = []) {
|
|
|
82
89
|
finishedJobs.push(row);
|
|
83
90
|
continue;
|
|
84
91
|
}
|
|
85
|
-
const
|
|
86
|
-
|
|
92
|
+
const worker = workerByTag.get(row.tag);
|
|
93
|
+
// Once a worker exists it is authoritative over its spawn job. Active
|
|
94
|
+
// workers already represent the work, while terminal/inactive workers
|
|
95
|
+
// suppress a lagging `running` job. Only a genuinely queued reuse may
|
|
96
|
+
// replace an inactive worker until the new worker starts.
|
|
97
|
+
if (worker && (worker.status === 'running' || row.status !== 'queued')) continue;
|
|
98
|
+
byTag.set(row.tag, row);
|
|
87
99
|
}
|
|
88
100
|
const workers = [...byTag.values()];
|
|
89
101
|
return {
|
|
@@ -179,7 +191,28 @@ export function activeHiddenAgentWorkers({ sessionId = '', clientHostPid = 0 } =
|
|
|
179
191
|
}
|
|
180
192
|
|
|
181
193
|
function isTerminalBridgeStatus(statusText) {
|
|
182
|
-
return
|
|
194
|
+
return TERMINAL_AGENT_STATUS.test(String(statusText || ''));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function agentStatusValues(value = {}) {
|
|
198
|
+
return [value.stage, value.status]
|
|
199
|
+
.map((status) => String(status || '').trim())
|
|
200
|
+
.filter((status, index, values) => Boolean(status) && values.indexOf(status) === index);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function isTerminalAgentEntry(statuses = []) {
|
|
204
|
+
return statuses.some((status) => isTerminalBridgeStatus(status));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function isActiveAgentEntry(statuses = []) {
|
|
208
|
+
return statuses.length > 0
|
|
209
|
+
&& !isTerminalAgentEntry(statuses)
|
|
210
|
+
&& statuses.some((status) => ACTIVE_AGENT_STATUS.test(status));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function isQueuedAgentEntry(statuses = []) {
|
|
214
|
+
return isActiveAgentEntry(statuses)
|
|
215
|
+
&& statuses.every((status) => QUEUED_AGENT_STATUS.test(status));
|
|
183
216
|
}
|
|
184
217
|
|
|
185
218
|
// Agent-side web search activity for the L2 "Web Searching" segment: any live
|
|
@@ -723,6 +723,20 @@ export function formatGatewayLimitSegments(status, fmt) {
|
|
|
723
723
|
const maxWindows = COLS >= 120 ? 3 : COLS >= 80 ? 2 : 1;
|
|
724
724
|
const routeSpend = num(status.routeSpend?.costUsd, null);
|
|
725
725
|
const routeSpendLabel = cleanString(status.routeSpend?.label) || (COLS >= 120 ? 'SESS' : 'S');
|
|
726
|
+
// Fixed columns for the numeric fields of the quota segments: the percentage
|
|
727
|
+
// and the `↻ <reset>` time are right-aligned inside their own segment so the
|
|
728
|
+
// separators stop drifting horizontally as the values change width
|
|
729
|
+
// (`5%` → `35%` → `100%`, `7:59` → `07:59`). Disabled below 80 columns so the
|
|
730
|
+
// narrow/truncating layout keeps its current byte-for-byte behavior.
|
|
731
|
+
const alignColumns = COLS >= 80;
|
|
732
|
+
const PCT_COLUMN_WIDTH = 4; // '100%'
|
|
733
|
+
const RESET_COLUMN_WIDTH = 5; // 'HH:MM'
|
|
734
|
+
const visibleLength = (text) => String(text ?? '').replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
735
|
+
const padLeftVisible = (text, width) => {
|
|
736
|
+
const value = String(text ?? '');
|
|
737
|
+
const pad = Math.max(0, Number(width) - visibleLength(value));
|
|
738
|
+
return pad > 0 ? `${' '.repeat(pad)}${value}` : value;
|
|
739
|
+
};
|
|
726
740
|
const windowResetText = (window) => {
|
|
727
741
|
if (isLocalEstimateWindow(window)) return '';
|
|
728
742
|
const at = num(window?.resetAt, null);
|
|
@@ -733,9 +747,14 @@ export function formatGatewayLimitSegments(status, fmt) {
|
|
|
733
747
|
const pad = (n) => String(n).padStart(2, '0');
|
|
734
748
|
return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
735
749
|
};
|
|
750
|
+
const shownWindows = windows.slice(0, maxWindows);
|
|
751
|
+
// Each segment right-aligns its own time to the HH:MM column width; the rarer
|
|
752
|
+
// `MM-DD HH:MM` form (reset more than 24h out) simply overflows its own
|
|
753
|
+
// column instead of padding the neighbouring segments with dead space.
|
|
754
|
+
const resetColumnWidth = alignColumns ? RESET_COLUMN_WIDTH : 0;
|
|
736
755
|
const withReset = (segment, window) => {
|
|
737
756
|
const reset = windowResetText(window);
|
|
738
|
-
return reset ? `${segment} ${D}↻ ${reset}${R}` : segment;
|
|
757
|
+
return reset ? `${segment} ${D}↻ ${padLeftVisible(reset, resetColumnWidth)}${R}` : segment;
|
|
739
758
|
};
|
|
740
759
|
const addRouteSpend = () => {
|
|
741
760
|
if (routeSpend !== null && routeSpend > 0) {
|
|
@@ -757,7 +776,7 @@ export function formatGatewayLimitSegments(status, fmt) {
|
|
|
757
776
|
if (addApiBalance()) return segments;
|
|
758
777
|
if (segments.length) return segments;
|
|
759
778
|
}
|
|
760
|
-
for (const w of
|
|
779
|
+
for (const w of shownWindows) {
|
|
761
780
|
const label = String(w?.label || 'USE').toUpperCase();
|
|
762
781
|
const pct = num(w?.usedPct, null);
|
|
763
782
|
const remaining = isOpenAiOAuth ? null : num(w?.remainingUsd, null);
|
|
@@ -781,7 +800,11 @@ export function formatGatewayLimitSegments(status, fmt) {
|
|
|
781
800
|
} else if (usedCredits !== null && limitCredits !== null) {
|
|
782
801
|
segments.push(withReset(`${D}${label}${R} ${estimated ? 'est ' : ''}${compactNumber(usedCredits)}/${compactNumber(limitCredits)}`, w));
|
|
783
802
|
} else if (pct !== null) {
|
|
784
|
-
|
|
803
|
+
const pctText = colourPct(Math.round(pct));
|
|
804
|
+
segments.push(withReset(
|
|
805
|
+
`${D}${label}${R} ${estimated ? 'est ' : ''}${alignColumns ? padLeftVisible(pctText, PCT_COLUMN_WIDTH) : pctText}`,
|
|
806
|
+
w,
|
|
807
|
+
));
|
|
785
808
|
}
|
|
786
809
|
}
|
|
787
810
|
addRouteSpend();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: default
|
|
3
|
-
name:
|
|
4
|
-
description: "
|
|
3
|
+
name: Cowork
|
|
4
|
+
description: "Parallel delegation."
|
|
5
5
|
agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# Cowork
|
|
9
9
|
|
|
10
10
|
Lead is the orchestrator: consult the user and build the plan together.
|
|
11
11
|
Before the user explicitly approves the latest plan, work is read-only
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: solo
|
|
3
3
|
name: Solo
|
|
4
|
-
description: "Lead
|
|
4
|
+
description: "Lead works alone."
|
|
5
5
|
agents:
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -15,9 +15,11 @@ changed request resets planning; a scope change requires fresh approval.
|
|
|
15
15
|
On approval, Lead executes all work itself — never spawn, send, or delegate
|
|
16
16
|
to agents. Complete in-scope fixes without reapproval.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Verification is single-pass: run the one check that most directly proves the
|
|
19
|
+
deliverable exactly once; a pass is final. Iterate only on a failing check,
|
|
20
|
+
re-running just that check after each fix, or report the blocker.
|
|
19
21
|
|
|
20
|
-
Report the
|
|
22
|
+
Report the result and its proving check against the approved plan. Build, deploy, commit,
|
|
21
23
|
and push happen only on an explicit user request.
|
|
22
24
|
|
|
23
25
|
On direction change, pause and re-consult the user.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Media studio surface (image / video generation).
|
|
3
|
-
*
|
|
4
|
-
* Single entry point for the session runtime: lane catalog, job control, and
|
|
5
|
-
* the on-disk asset store. Adapters are imported lazily by the job runner so a
|
|
6
|
-
* boot that never generates never pays for them.
|
|
7
|
-
*/
|
|
8
|
-
export { MEDIA_KINDS, listMediaLanes, getMediaLane } from './lanes.mjs';
|
|
9
|
-
export { startMediaJob, getMediaJob, listMediaJobs, cancelMediaJob } from './jobs.mjs';
|
|
10
|
-
export {
|
|
11
|
-
listMediaAssets,
|
|
12
|
-
readMediaAsset,
|
|
13
|
-
resolveMediaFile,
|
|
14
|
-
deleteMediaAsset,
|
|
15
|
-
mediaAssetPath,
|
|
16
|
-
openMediaAsset,
|
|
17
|
-
openMediaFolder,
|
|
18
|
-
} from './store.mjs';
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// Boot-edge embedding warmup queue, extracted from index.mjs (pass 2).
|
|
2
|
-
//
|
|
3
|
-
// ONNX session creation on the embedding worker thread is CPU-heavy, so it must
|
|
4
|
-
// not overlap the worker's own init (DB open, schema, cycle wiring). The warmup
|
|
5
|
-
// is queued during _initStore and fired at the _initRuntime completion edge, so
|
|
6
|
-
// it starts the instant boot's CPU-heavy work is done — no magic-number delay.
|
|
7
|
-
//
|
|
8
|
-
// This is a small pure factory: index.mjs owns the DATA_DIR-derived meta path
|
|
9
|
-
// and the embedding-provider imports, injecting them here as callbacks. No
|
|
10
|
-
// import-time side effects.
|
|
11
|
-
export function createEmbeddingWarmup({
|
|
12
|
-
canStart,
|
|
13
|
-
warmup,
|
|
14
|
-
getDims,
|
|
15
|
-
persistMeta,
|
|
16
|
-
log = () => {},
|
|
17
|
-
}) {
|
|
18
|
-
let _pending = null
|
|
19
|
-
// Fired latch: an init() retry after the early (PG-wait-edge) fire must not
|
|
20
|
-
// re-schedule and run the warmup twice (double ONNX session create +
|
|
21
|
-
// double embedding-meta persist). reset() clears it for true re-inits.
|
|
22
|
-
let _fired = false
|
|
23
|
-
|
|
24
|
-
// Queue the warmup; fireDeferred() runs it once boot completes. Re-queuing
|
|
25
|
-
// overwrites any prior pending closure (matches the original single-slot
|
|
26
|
-
// module var). MIXDOG_EMBED_WARMUP=0 (checked via canStart) disables it.
|
|
27
|
-
function schedule(metaPath, metaKey) {
|
|
28
|
-
if (_fired) return
|
|
29
|
-
if (!canStart()) {
|
|
30
|
-
// Silent skip here previously made "warmup never ran" boots
|
|
31
|
-
// indistinguishable from failed warmups. One line, boot-edge only.
|
|
32
|
-
log('[memory-service] embedding warmup skipped (disabled by env/secondary mode) — recall stays lexical until first embed\n')
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
_pending = () => {
|
|
36
|
-
const startedAt = Date.now()
|
|
37
|
-
log('[memory-service] embedding warmup start\n')
|
|
38
|
-
warmup()
|
|
39
|
-
.then(() => {
|
|
40
|
-
log(`[memory-service] embedding warmup ready in ${Date.now() - startedAt}ms\n`)
|
|
41
|
-
const measured = Number(getDims())
|
|
42
|
-
try {
|
|
43
|
-
persistMeta(metaPath, { ...metaKey, dims: measured })
|
|
44
|
-
} catch (e) {
|
|
45
|
-
log(`[memory-service] could not persist embedding-meta: ${e?.message || e}\n`)
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
.catch(err => {
|
|
49
|
-
log(`[memory-service] background warmup failed: ${err?.message || err}\n`)
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function fireDeferred() {
|
|
55
|
-
const fire = _pending
|
|
56
|
-
if (!fire) return
|
|
57
|
-
_pending = null
|
|
58
|
-
_fired = true
|
|
59
|
-
fire()
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function reset() {
|
|
63
|
-
_pending = null
|
|
64
|
-
_fired = false
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { schedule, fireDeferred, reset }
|
|
68
|
-
}
|