mixdog 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -5
- package/package.json +1 -1
- package/src/defaults/shipped-history.json +4 -0
- package/src/defaults/skills/pptx/SKILL.md +6 -6
- package/src/defaults/skills/pptx/references/review.md +6 -4
- package/src/defaults/skills/pptx/scripts/source-extract.mjs +1 -1
- package/src/defaults/skills/setup/references/actions.md +13 -3
- package/src/defaults/skills/visualize/SKILL.md +12 -9
- package/src/rules/shared/60-verification.md +3 -1
- package/src/rules/shared/70-delivery.md +4 -2
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +26 -5
- package/src/runtime/agent/orchestrator/config.mjs +10 -4
- package/src/runtime/agent/orchestrator/context/collect.mjs +2 -1
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +11 -5
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +74 -21
- package/src/runtime/agent/orchestrator/mcp/client-config.mjs +86 -8
- package/src/runtime/agent/orchestrator/mcp/client-handshake.mjs +5 -1
- package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +65 -7
- package/src/runtime/agent/orchestrator/mcp/client.mjs +128 -44
- package/src/runtime/agent/orchestrator/mcp/lazy-output-validator.mjs +25 -0
- package/src/runtime/agent/orchestrator/mcp/plugin-placeholders.mjs +54 -0
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +108 -17
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +19 -11
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +9 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +337 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-tokens.mjs +159 -0
- package/src/runtime/agent/orchestrator/providers/command-code-oauth.mjs +444 -0
- package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/custom-provider.mjs +7 -4
- package/src/runtime/agent/orchestrator/providers/effort-configuration.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +41 -28
- package/src/runtime/agent/orchestrator/providers/lib/gemini-model-catalog.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/model-proxy-bridge.mjs +1080 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.d.mts +15 -0
- package/src/runtime/agent/orchestrator/providers/model-proxy-channel.mjs +35 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +12 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +6 -5
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-options.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +9 -3
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +4 -4
- package/src/runtime/agent/orchestrator/providers/registry.mjs +35 -9
- package/src/runtime/agent/orchestrator/runtime-core/effort.mjs +3 -0
- package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +15 -55
- package/src/runtime/agent/orchestrator/runtime-core/goal-control.mjs +15 -2
- package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +267 -84
- package/src/runtime/agent/orchestrator/runtime-core/skill-tool-loading.mjs +4 -1
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog-schema.mjs +21 -0
- package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +54 -3
- package/src/runtime/agent/orchestrator/session/catalog-db/index.mjs +284 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +268 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/sqlite-gate.mjs +27 -0
- package/src/runtime/agent/orchestrator/session/catalog-db/worker.mjs +628 -0
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +184 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +136 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +128 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +127 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +101 -0
- package/src/runtime/agent/orchestrator/session/explicit-skills.mjs +83 -5
- package/src/runtime/agent/orchestrator/session/imported-message.mjs +11 -0
- package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +3 -2
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +6 -4
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +12 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-auto-effort.mjs +20 -12
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +17 -4
- package/src/runtime/agent/orchestrator/session/manager.mjs +0 -1
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +6 -2
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +817 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +19 -12
- package/src/runtime/agent/orchestrator/session/store-summary-reader-catalog-fixture.mjs +158 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +183 -374
- package/src/runtime/agent/orchestrator/session/synthetic-user-envelope.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch/pre-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +21 -2
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +38 -17
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-range-index.mjs +173 -22
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-guards.mjs +8 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +5 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-source-windows.mjs +15 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +13 -10
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +17 -12
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/root-resolution.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/codex-batch.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/patch/apply-patch/route.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/read-redirects.mjs +34 -30
- package/src/runtime/agent/orchestrator/tools/patch/sequence/units.mjs +7 -7
- package/src/runtime/agent/orchestrator/tools/patch/sequence.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -0
- package/src/runtime/attachments/store.d.mts +3 -0
- package/src/runtime/channels/lib/owned-runtime/owned-start.mjs +1 -1
- package/src/runtime/channels/lib/webhook/session-dispatch.mjs +16 -4
- package/src/runtime/channels/lib/worker-main.mjs +17 -14
- package/src/runtime/computer-bridge/linux-readiness.mjs +0 -2
- package/src/runtime/effort-judge/judge-client.mjs +56 -18
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/session-ingest.mjs +2 -2
- package/src/runtime/shared/atomic-file.mjs +25 -4
- package/src/runtime/shared/extension-scopes.mjs +5 -3
- package/src/runtime/shared/file-lock.mjs +37 -11
- package/src/runtime/shared/llm/anthropic-effort.mjs +14 -0
- package/src/runtime/shared/llm/model-catalog.mjs +0 -12
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +6 -0
- package/src/runtime/shared/plugin-manifest.mjs +18 -9
- package/src/runtime/shared/pristine-execution-contract.json +9 -2
- package/src/runtime/shared/pristine-execution.mjs +28 -4
- package/src/runtime/shared/provider-accounts.mjs +124 -20
- package/src/runtime/shared/provider-api-key.mjs +12 -0
- package/src/runtime/shared/shell-display.mjs +9 -3
- package/src/runtime/shared/skill-mentions.d.mts +10 -0
- package/src/runtime/shared/skill-mentions.mjs +133 -0
- package/src/runtime/shared/skill-script-runtime.mjs +264 -0
- package/src/runtime/shared/tool-primitives.mjs +35 -2
- package/src/runtime/shared/turn-worktree-snapshot.mjs +25 -5
- package/src/runtime/shared/worker-requests.mjs +15 -2
- package/src/session-runtime/automation-agents.mjs +8 -2
- package/src/session-runtime/boot/apis.mjs +55 -0
- package/src/session-runtime/boot/config.mjs +5 -2
- package/src/session-runtime/boot/facade.mjs +1 -0
- package/src/session-runtime/boot/infrastructure.mjs +29 -18
- package/src/session-runtime/conversation-import/discovery.mjs +698 -0
- package/src/session-runtime/conversation-import/service.mjs +369 -0
- package/src/session-runtime/cwd-plugins/cwd-apply.mjs +10 -5
- package/src/session-runtime/cwd-plugins/plugin-status.mjs +47 -42
- package/src/session-runtime/mcp-glue/connect.mjs +57 -10
- package/src/session-runtime/mcp-glue/plugin-servers.mjs +499 -0
- package/src/session-runtime/mcp-glue/server-catalog.mjs +115 -30
- package/src/session-runtime/mcp-glue.mjs +22 -2
- package/src/session-runtime/new-session-config.mjs +3 -2
- package/src/session-runtime/notification-bus.mjs +9 -2
- package/src/session-runtime/provider-auth/accounts.mjs +33 -15
- package/src/session-runtime/provider-models/web-search-catalog.mjs +5 -1
- package/src/session-runtime/provider-readiness.mjs +16 -10
- package/src/session-runtime/resource-extension-sync.mjs +20 -5
- package/src/session-runtime/resource-mcp-api.mjs +101 -77
- package/src/session-runtime/resource-plugins-api.mjs +29 -41
- package/src/session-runtime/resource-scope-decorate.mjs +6 -8
- package/src/session-runtime/resource-skills-api.mjs +23 -2
- package/src/session-runtime/schedule-session-run.mjs +1 -1
- package/src/session-runtime/services/channel-session-router.mjs +4 -1
- package/src/session-runtime/services/hook-bus/command-handler.mjs +4 -1
- package/src/session-runtime/services/hook-bus/handlers.mjs +7 -3
- package/src/session-runtime/services/provider-admin.mjs +64 -18
- package/src/session-runtime/services/usage-dashboard-model.mjs +3 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +1 -0
- package/src/session-runtime/setup-tool/settings-contract.mjs +1 -0
- package/src/session-runtime/setup-tool/tool-defs.mjs +7 -1
- package/src/session-runtime/skills-api.mjs +7 -3
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/webhook-session-run.mjs +16 -4
- package/src/skill-script-entry.mjs +36 -0
- package/src/standalone/daemon-stored-session-views.mjs +11 -3
- package/src/standalone/daemon.mjs +41 -4
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-service/session-calls/session-action.mjs +6 -1
- package/src/tui/App.jsx +9 -1
- package/src/tui/app/app-view/floating-panel.jsx +9 -1
- package/src/tui/app/app-view.jsx +6 -0
- package/src/tui/app/extension-pickers/plugins-pickers.mjs +35 -16
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/app/skill-mention-palette.mjs +88 -0
- package/src/tui/app/slash-palette.mjs +23 -7
- package/src/tui/app/transcript-row-estimate.mjs +11 -3
- package/src/tui/app/use-prompt-draft-flow.mjs +7 -2
- package/src/tui/app/use-prompt-state.mjs +5 -0
- package/src/tui/components/Message.jsx +22 -1
- package/src/tui/components/PromptInput.jsx +21 -3
- package/src/tui/components/SlashCommandPalette.jsx +12 -3
- package/src/tui/components/TranscriptItem.jsx +9 -1
- package/src/tui/components/prompt-input/key-handler.mjs +21 -8
- package/src/tui/components/user-message-skills.mjs +38 -0
- package/src/tui/dist/index.mjs +507 -171
- package/src/tui/session/queue-helpers.mjs +7 -2
- package/src/tui/session/session-api/extensions.mjs +4 -2
- package/src/tui/session/session-api/settings.mjs +7 -0
- package/src/tui/session/session-flow/drain.mjs +14 -4
- package/src/tui/session/tui-steering-persist.mjs +25 -9
- package/src/tui/session/turn.mjs +17 -0
- package/src/runtime/effort-judge/previous-human-request.mjs +0 -162
- package/src/runtime/effort-judge/verified-context-input.mjs +0 -10
|
@@ -175,7 +175,9 @@ export function mergePastedImages(entries) {
|
|
|
175
175
|
|
|
176
176
|
// Byte-free image metadata for the user transcript item. Prompt content carries
|
|
177
177
|
// only a content-addressed attachment ref after daemon intake; transcript items
|
|
178
|
-
// and desktop snapshots carry
|
|
178
|
+
// and desktop snapshots carry name/mime/size plus, for attachment-reference
|
|
179
|
+
// parts, the `attachmentRef` so the desktop can rebuild thumbnails from the
|
|
180
|
+
// stored original.
|
|
179
181
|
export function promptContentImageMeta(content, pastedImages) {
|
|
180
182
|
const parts = Array.isArray(content) ? content.filter((part) => part?.type === 'image') : [];
|
|
181
183
|
if (parts.length === 0) return null;
|
|
@@ -190,6 +192,7 @@ export function promptContentImageMeta(content, pastedImages) {
|
|
|
190
192
|
name: String(meta?.filename || `Image ${index + 1}`),
|
|
191
193
|
mimeType: String(part.mimeType || part.mediaType || meta?.mediaType || 'image/png'),
|
|
192
194
|
bytes: Number(part.sizeBytes) || data.length,
|
|
195
|
+
...(isAttachmentReference(part) ? { attachmentRef: part.attachmentRef } : {}),
|
|
193
196
|
};
|
|
194
197
|
});
|
|
195
198
|
}
|
|
@@ -202,6 +205,8 @@ export function callCommitCallbacks(entries) {
|
|
|
202
205
|
for (const entry of entries || []) {
|
|
203
206
|
try {
|
|
204
207
|
entry?.onCommitted?.();
|
|
205
|
-
} catch {
|
|
208
|
+
} catch {
|
|
209
|
+
// A throwing commit callback must not block the remaining entries.
|
|
210
|
+
}
|
|
206
211
|
}
|
|
207
212
|
}
|
|
@@ -83,8 +83,10 @@ export function createSessionExtensionsApi(bag) {
|
|
|
83
83
|
}
|
|
84
84
|
return await runtime.setExtensionScope(kind, name, projects);
|
|
85
85
|
},
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
// `options.cwd`: list and scope skills for that folder instead of this
|
|
87
|
+
// session's (the desktop resolves a new-task draft's Project to it).
|
|
88
|
+
skillsStatus: (options) => {
|
|
89
|
+
return runtime.skillsStatus?.(options) || { cwd: getState().cwd, count: 0, skills: [] };
|
|
88
90
|
},
|
|
89
91
|
skillContent: (name) => {
|
|
90
92
|
return runtime.skillContent?.(name);
|
|
@@ -154,6 +154,13 @@ export function createSessionSettingsApi(bag) {
|
|
|
154
154
|
inspectHuggingFaceModel: (options) => runtime.inspectHuggingFaceModel(options),
|
|
155
155
|
registerHuggingFaceModel: (previewId, licenseAccepted) =>
|
|
156
156
|
runtime.registerHuggingFaceModel(previewId, licenseAccepted),
|
|
157
|
+
// Conversation import (advertised session actions; one object argument).
|
|
158
|
+
// Background jobs, so never behind commandBusy.
|
|
159
|
+
listImportableConversations: (params) => runtime.listImportableConversations(params),
|
|
160
|
+
getConversationImportJobs: (params) => runtime.getConversationImportJobs(params),
|
|
161
|
+
registerConversationImportFile: (params) => runtime.registerConversationImportFile(params),
|
|
162
|
+
startConversationImport: (params) => runtime.startConversationImport(params),
|
|
163
|
+
cancelConversationImport: (params) => runtime.cancelConversationImport(params),
|
|
157
164
|
getChannelSettings: (options = {}) => {
|
|
158
165
|
return (
|
|
159
166
|
runtime.getChannelSettings?.(options) || {
|
|
@@ -65,7 +65,19 @@ function renderBatchItems(batch, pushUserOrSyntheticItem) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const COMPLETION_WAKE_MODES = new Set(['task-notification', 'pending-resume']);
|
|
69
|
+
|
|
70
|
+
// Trusted provenance of a drained batch: Goal turns keep their own source; a
|
|
71
|
+
// batch made only of completion wakes (task notifications, pending resumes)
|
|
72
|
+
// is the runtime reporting, carried as a task notification so the runtime
|
|
73
|
+
// stores it as one and never treats its text as a user skill selection.
|
|
74
|
+
function batchPromptSource(batch) {
|
|
75
|
+
if (isGoalQueuedEntry(batch[0])) return batch[0].mode;
|
|
76
|
+
if (batch.length > 0 && batch.every((entry) => COMPLETION_WAKE_MODES.has(entry?.mode))) return 'task-notification';
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function turnOptionsForBatch(batch, steering) {
|
|
69
81
|
const nonEditable = batch.filter((entry) => !isQueuedEntryEditable(entry));
|
|
70
82
|
// A completion resume is owned by the completion that woke it. Esc
|
|
71
83
|
// consumes that ownership; unlike ordinary notifications it must never
|
|
@@ -75,7 +87,7 @@ function turnOptionsForBatch(batch, steering) {
|
|
|
75
87
|
(entry) => entry?.abortDiscardOnAbort === true || entry?.mode === 'pending-resume'
|
|
76
88
|
);
|
|
77
89
|
return {
|
|
78
|
-
promptSource:
|
|
90
|
+
promptSource: batchPromptSource(batch),
|
|
79
91
|
retryFailedTurn: batch[0]?.retryFailedTurn === true,
|
|
80
92
|
displayText: batch
|
|
81
93
|
.map((entry) => entry.text)
|
|
@@ -114,8 +126,6 @@ function turnOptionsForBatch(batch, steering) {
|
|
|
114
126
|
};
|
|
115
127
|
}
|
|
116
128
|
|
|
117
|
-
const COMPLETION_WAKE_MODES = new Set(['task-notification', 'pending-resume']);
|
|
118
|
-
|
|
119
129
|
export function createDrainLoop(
|
|
120
130
|
bag,
|
|
121
131
|
{ queue, steering, submissions, flushDeferredClearedSessionUi, autoClearBeforeWake }
|
|
@@ -15,11 +15,19 @@ const STALE_STEERING_RESTORE_TTL_MS = 30 * 60 * 1000;
|
|
|
15
15
|
// Cross-process mutual exclusion still comes from the shared lock protocol;
|
|
16
16
|
// this chain only orders same-process operations that were previously
|
|
17
17
|
// naturally ordered by the synchronous call site.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
// One chain per session key so a slow write for one session never delays
|
|
19
|
+
// another; an entry is removed once its chain is idle.
|
|
20
|
+
const _persistChains = new Map();
|
|
21
|
+
function _serialize(key, task) {
|
|
22
|
+
const prev = _persistChains.get(key) || Promise.resolve();
|
|
23
|
+
const run = prev.then(task, task);
|
|
21
24
|
// Never let a rejection poison the chain; each op logs its own error.
|
|
22
|
-
|
|
25
|
+
const tail = run
|
|
26
|
+
.catch(() => {})
|
|
27
|
+
.then(() => {
|
|
28
|
+
if (_persistChains.get(key) === tail) _persistChains.delete(key);
|
|
29
|
+
});
|
|
30
|
+
_persistChains.set(key, tail);
|
|
23
31
|
return run;
|
|
24
32
|
}
|
|
25
33
|
|
|
@@ -159,7 +167,7 @@ export function appendTuiSteeringPersist(leadSessionId, entry) {
|
|
|
159
167
|
...(submissionId ? { submissionId } : {}),
|
|
160
168
|
...(Number.isFinite(submittedAt) && submittedAt > 0 ? { submittedAt } : {}),
|
|
161
169
|
};
|
|
162
|
-
return _serialize(async () => {
|
|
170
|
+
return _serialize(key, async () => {
|
|
163
171
|
try {
|
|
164
172
|
await updatePendingShard(key, (raw) => {
|
|
165
173
|
const next = normalizePendingStore(raw);
|
|
@@ -184,7 +192,7 @@ export function dropTuiSteeringPersist(leadSessionId, entries) {
|
|
|
184
192
|
if (!key) return Promise.resolve();
|
|
185
193
|
const batch = Array.isArray(entries) ? entries : [];
|
|
186
194
|
if (batch.length === 0) return Promise.resolve();
|
|
187
|
-
return _serialize(async () => {
|
|
195
|
+
return _serialize(key, async () => {
|
|
188
196
|
try {
|
|
189
197
|
await updatePendingShard(key, (raw) => {
|
|
190
198
|
const next = normalizePendingStore(raw);
|
|
@@ -207,8 +215,16 @@ export function dropTuiSteeringPersist(leadSessionId, entries) {
|
|
|
207
215
|
});
|
|
208
216
|
}
|
|
209
217
|
|
|
210
|
-
export function flushTuiSteeringPersist() {
|
|
211
|
-
|
|
218
|
+
export async function flushTuiSteeringPersist() {
|
|
219
|
+
// Loop: chains started while waiting are awaited too.
|
|
220
|
+
while (_persistChains.size > 0) {
|
|
221
|
+
await Promise.all([..._persistChains.values()]);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Test hook: number of live per-key chains.
|
|
226
|
+
export function _steeringPersistChainCount() {
|
|
227
|
+
return _persistChains.size;
|
|
212
228
|
}
|
|
213
229
|
|
|
214
230
|
function drainedRowToRestore(row) {
|
|
@@ -233,7 +249,7 @@ function drainedRowToRestore(row) {
|
|
|
233
249
|
export function drainTuiSteeringPersist(leadSessionId) {
|
|
234
250
|
const key = tuiSteeringSessionKey(leadSessionId);
|
|
235
251
|
if (!key) return Promise.resolve([]);
|
|
236
|
-
return _serialize(async () => {
|
|
252
|
+
return _serialize(key, async () => {
|
|
237
253
|
let drained = [];
|
|
238
254
|
let droppedStale = 0;
|
|
239
255
|
try {
|
package/src/tui/session/turn.mjs
CHANGED
|
@@ -322,9 +322,26 @@ function applyTurnUsageDelta({ turn, getState, set, syncContextStats }, delta) {
|
|
|
322
322
|
set({ stats: { ...getState().stats }, ...(spinner ? { spinner: { ...spinner, inputTokens, outputTokens } } : {}) });
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
+
// The runtime reports the skills a user turn actually loaded (`Skill:` header
|
|
326
|
+
// or inline `$name`); the prompt row carries them as `appliedSkills`, the same
|
|
327
|
+
// field a restored row reads from the persisted transcript metadata.
|
|
328
|
+
function applySkillsToPromptRow({ turn, getState, patchItem }, names, detail = {}) {
|
|
329
|
+
const appliedSkills = (Array.isArray(names) ? names : []).filter((name) => typeof name === 'string' && name);
|
|
330
|
+
if (!appliedSkills.length) return;
|
|
331
|
+
const messageId = typeof detail?.messageId === 'string' ? detail.messageId : '';
|
|
332
|
+
const submitted = turn.submittedIds[0];
|
|
333
|
+
const row = getState().items.findLast(
|
|
334
|
+
(item) => item?.kind === 'user' && (messageId ? item.messageId === messageId : item.id === submitted)
|
|
335
|
+
);
|
|
336
|
+
if (row) patchItem(row.id, { appliedSkills });
|
|
337
|
+
}
|
|
338
|
+
|
|
325
339
|
function turnHandlers(ctx) {
|
|
326
340
|
const { isCurrentTurn, drainPendingSteering } = ctx;
|
|
327
341
|
return {
|
|
342
|
+
onSkillsApplied: (names, detail) => {
|
|
343
|
+
if (isCurrentTurn()) applySkillsToPromptRow(ctx, names, detail);
|
|
344
|
+
},
|
|
328
345
|
drainSteering: (_sessionId, drainOptions) =>
|
|
329
346
|
isCurrentTurn() ? drainPendingSteering({ ...drainOptions, turnEpoch: ctx.turn.epoch }) : [],
|
|
330
347
|
onStreamDelta: () => {},
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
// Pure pre-turn extraction of the previous human request and the assistant
|
|
2
|
-
// text around it, from the session history as it stands BEFORE the current
|
|
3
|
-
// turn is committed (the boundary resolveTurnAutoEffort runs at). Nothing here
|
|
4
|
-
// reads the current prompt's outcome; nothing is mutated; no text is matched
|
|
5
|
-
// against word lists. Ownership comes only from typed provenance that the
|
|
6
|
-
// runtime already writes (meta.runtimeUserContext, meta.synthetic, meta.source,
|
|
7
|
-
// the compaction/skill/reminder predicates in compact/messages.mjs).
|
|
8
|
-
//
|
|
9
|
-
// Result of previousHumanContext(messages, { retryPrompt }):
|
|
10
|
-
// {
|
|
11
|
-
// version: 1,
|
|
12
|
-
// boundary: number, // messages[0..boundary) were considered
|
|
13
|
-
// retryTrimmedIndex: number, // index of the unanswered resubmitted prompt
|
|
14
|
-
// // dropped from the view, or -1
|
|
15
|
-
// prevHuman: { text, index, source, runtimeContext } | null,
|
|
16
|
-
// // latest actual human message before the boundary. `text` is the
|
|
17
|
-
// // runtime-context-stripped, trimmed text (untruncated). `source` is
|
|
18
|
-
// // meta.source or null ('steering' = a human interjection).
|
|
19
|
-
// // `runtimeContext` is 'stripped' | 'none'.
|
|
20
|
-
// prevHumanMissing: 'empty-history' | 'no-human-request' | null,
|
|
21
|
-
// canonicalReply: { text, index } | null,
|
|
22
|
-
// // exactly what the shipped rp `prev` is: the latest non-empty
|
|
23
|
-
// // assistant message before the boundary, whatever turn it is from.
|
|
24
|
-
// pairedReply: { text, index } | null,
|
|
25
|
-
// // latest non-empty assistant text inside prevHuman's own turn span
|
|
26
|
-
// // (after prevHuman up to the next human message / boundary). Never
|
|
27
|
-
// // falls back to another turn: a tool-only or unanswered turn gives
|
|
28
|
-
// // null with pairedMissing set.
|
|
29
|
-
// pairedMissing: 'no-human-request' | 'no-assistant-text-in-turn' | null,
|
|
30
|
-
// replyIsPaired: boolean, // canonicalReply and pairedReply are the same message
|
|
31
|
-
// skipped: [{ index, role, reason }], // user messages passed over after
|
|
32
|
-
// // prevHuman's search began (newest first); reasons: 'summary',
|
|
33
|
-
// // 'protected-context', 'skill-body', 'synthetic-flag',
|
|
34
|
-
// // 'typed-source', 'runtime-owned', 'empty'.
|
|
35
|
-
// }
|
|
36
|
-
//
|
|
37
|
-
// Policy decisions (PREVIOUS_HUMAN_POLICY):
|
|
38
|
-
// synthetic meta.synthetic === true, or a source the runtime stores as
|
|
39
|
-
// "not the user speaking" (task-notification, skill-context),
|
|
40
|
-
// or anything isActualUserInstructionMessage rejects
|
|
41
|
-
// (goal-continuation/closeout, compact-*, *-recovery, control
|
|
42
|
-
// lines), is skipped, not treated as a request.
|
|
43
|
-
// steering meta.source === 'steering' is a human interjection (the
|
|
44
|
-
// provider layer keeps it as its own user turn for that
|
|
45
|
-
// reason) and counts as a human request.
|
|
46
|
-
// retry when retryPrompt repeats the trailing unanswered user prompt
|
|
47
|
-
// (trailingUnansweredPromptIndex), that stale copy is excluded
|
|
48
|
-
// so the prompt is never its own "previous request".
|
|
49
|
-
// summary compact summaries are skipped; nothing before them is
|
|
50
|
-
// recovered, so history truncated by compaction yields
|
|
51
|
-
// 'no-human-request' rather than a guess.
|
|
52
|
-
// Limitation: user messages stored without meta (old transcripts) cannot be
|
|
53
|
-
// told apart from the human when a runtime wrapper was never recorded; they
|
|
54
|
-
// are accepted as human, and a wrapper with stale provenance stays unstripped.
|
|
55
|
-
import { stripRuntimeUserContext } from '../agent/orchestrator/session/runtime-user-context.mjs';
|
|
56
|
-
import {
|
|
57
|
-
isActualUserInstructionMessage,
|
|
58
|
-
isInjectedSkillBodyMessage,
|
|
59
|
-
isProtectedContextUserMessage,
|
|
60
|
-
isSummaryMessage,
|
|
61
|
-
} from '../agent/orchestrator/session/compact/messages.mjs';
|
|
62
|
-
import { trailingUnansweredPromptIndex } from '../agent/orchestrator/session/manager/failed-turn-rewind.mjs';
|
|
63
|
-
import { promptContentText } from '../agent/orchestrator/session/manager/prompt-utils.mjs';
|
|
64
|
-
|
|
65
|
-
export const PREVIOUS_HUMAN_POLICY = Object.freeze({
|
|
66
|
-
synthetic: 'skip',
|
|
67
|
-
steering: 'human',
|
|
68
|
-
retry: 'exclude-trailing-unanswered-copy',
|
|
69
|
-
summary: 'skip-no-recovery',
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
const TYPED_NON_HUMAN_SOURCES = new Set(['task-notification', 'skill-context']);
|
|
73
|
-
|
|
74
|
-
const textOf = (message) => promptContentText(message?.content).trim();
|
|
75
|
-
|
|
76
|
-
/** { human, reason?, message } for a user message; null for other roles. */
|
|
77
|
-
function classify(message) {
|
|
78
|
-
if (message?.role !== 'user') return null;
|
|
79
|
-
const stripped = stripRuntimeUserContext(message);
|
|
80
|
-
const meta = stripped.meta && typeof stripped.meta === 'object' ? stripped.meta : {};
|
|
81
|
-
const no = (reason) => ({ human: false, reason, message: stripped });
|
|
82
|
-
if (isSummaryMessage(stripped)) return no('summary');
|
|
83
|
-
if (isProtectedContextUserMessage(stripped)) return no('protected-context');
|
|
84
|
-
if (isInjectedSkillBodyMessage(stripped)) return no('skill-body');
|
|
85
|
-
if (meta.synthetic === true) return no('synthetic-flag');
|
|
86
|
-
if (TYPED_NON_HUMAN_SOURCES.has(String(meta.source || ''))) return no('typed-source');
|
|
87
|
-
if (!isActualUserInstructionMessage(stripped)) return no('runtime-owned');
|
|
88
|
-
if (!textOf(stripped)) return no('empty');
|
|
89
|
-
return { human: true, message: stripped, stripped: stripped !== message };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function latestAssistant(messages, from, to) {
|
|
93
|
-
for (let index = to - 1; index >= from; index -= 1) {
|
|
94
|
-
if (messages[index]?.role !== 'assistant') continue;
|
|
95
|
-
const text = textOf(messages[index]);
|
|
96
|
-
if (text) return { text, index };
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function previousHumanContext(messages, { retryPrompt } = {}) {
|
|
102
|
-
const list = Array.isArray(messages) ? messages : [];
|
|
103
|
-
const retryTrimmedIndex = retryPrompt == null ? -1 : trailingUnansweredPromptIndex(list, retryPrompt);
|
|
104
|
-
const boundary = retryTrimmedIndex >= 0 ? retryTrimmedIndex : list.length;
|
|
105
|
-
const verdicts = [];
|
|
106
|
-
for (let index = 0; index < boundary; index += 1) verdicts.push(classify(list[index]));
|
|
107
|
-
|
|
108
|
-
const skipped = [];
|
|
109
|
-
let humanIndex = -1;
|
|
110
|
-
for (let index = boundary - 1; index >= 0; index -= 1) {
|
|
111
|
-
const verdict = verdicts[index];
|
|
112
|
-
if (!verdict) continue;
|
|
113
|
-
if (verdict.human) {
|
|
114
|
-
humanIndex = index;
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
skipped.push({ index, role: 'user', reason: verdict.reason });
|
|
118
|
-
// A summary replaces earlier conversational context; do not recover a
|
|
119
|
-
// request from an older retained fragment behind that boundary.
|
|
120
|
-
if (verdict.reason === 'summary') break;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const canonicalReply = latestAssistant(list, 0, boundary);
|
|
124
|
-
let prevHuman = null;
|
|
125
|
-
let pairedReply = null;
|
|
126
|
-
let pairedMissing = 'no-human-request';
|
|
127
|
-
if (humanIndex >= 0) {
|
|
128
|
-
const verdict = verdicts[humanIndex];
|
|
129
|
-
const source = verdict.message.meta?.source;
|
|
130
|
-
prevHuman = {
|
|
131
|
-
text: textOf(verdict.message),
|
|
132
|
-
index: humanIndex,
|
|
133
|
-
source: typeof source === 'string' && source ? source : null,
|
|
134
|
-
runtimeContext: verdict.stripped ? 'stripped' : 'none',
|
|
135
|
-
};
|
|
136
|
-
let end = boundary;
|
|
137
|
-
for (let index = humanIndex + 1; index < boundary; index += 1) {
|
|
138
|
-
if (verdicts[index]?.human) {
|
|
139
|
-
end = index;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
pairedReply = latestAssistant(list, humanIndex + 1, end);
|
|
144
|
-
pairedMissing = pairedReply ? null : 'no-assistant-text-in-turn';
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
let prevHumanMissing = null;
|
|
148
|
-
if (!prevHuman) prevHumanMissing = boundary === 0 ? 'empty-history' : 'no-human-request';
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
version: 1,
|
|
152
|
-
boundary,
|
|
153
|
-
retryTrimmedIndex,
|
|
154
|
-
prevHuman,
|
|
155
|
-
prevHumanMissing,
|
|
156
|
-
canonicalReply,
|
|
157
|
-
pairedReply,
|
|
158
|
-
pairedMissing,
|
|
159
|
-
replyIsPaired: Boolean(pairedReply && canonicalReply && pairedReply.index === canonicalReply.index),
|
|
160
|
-
skipped,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// Experimental input only. An unavailable verified request preserves rp exactly.
|
|
2
|
-
// Ownership and pairing are established by the caller, never inferred here.
|
|
3
|
-
export function verifiedContextText({ request, prev, prevRequestVerified } = {}) {
|
|
4
|
-
const current = String(request || '').slice(0, 1500);
|
|
5
|
-
const reply = String(prev || '').slice(-1000);
|
|
6
|
-
const prior = Array.from(String(prevRequestVerified || ''))
|
|
7
|
-
.slice(0, 300)
|
|
8
|
-
.join('');
|
|
9
|
-
return `request: ${current}${prior ? `\nprevious request: ${prior}` : ''}\nprevious reply: ${reply}`;
|
|
10
|
-
}
|