mixdog 0.9.95 → 0.9.97
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/LICENSES/Apache-2.0.txt +201 -0
- package/LICENSES/MIT.txt +56 -0
- package/LICENSES/codex-NOTICE.txt +6 -0
- package/NOTICE.md +46 -9
- package/README.md +0 -17
- package/package.json +16 -12
- package/scripts/.tmp-coverage-report.mjs +96 -0
- package/scripts/build-tui.mjs +17 -1
- package/scripts/{channel-daemon-stub.mjs → daemon-stub.mjs} +18 -12
- package/scripts/fixtures/patch-replay-corpus.json +98 -0
- package/src/defaults/mixdog-config.template.json +5 -8
- package/src/defaults/skills/setup/SKILL.md +1 -1
- package/src/lib/keychain-cjs.cjs +1 -1
- package/src/lib/mixdog-debug.cjs +2 -3
- package/src/rules/agent/30-explorer.md +7 -4
- package/src/rules/lead/01-general.md +1 -2
- package/src/rules/lead/lead-tool.md +0 -3
- package/src/rules/shared/01-tool.md +21 -29
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +18 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +31 -1
- package/src/runtime/agent/orchestrator/agent-runtime/maintenance-route.mjs +6 -17
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +12 -1
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +4 -13
- package/src/runtime/agent/orchestrator/config.mjs +246 -67
- package/src/runtime/agent/orchestrator/mcp/client.mjs +104 -41
- package/src/runtime/agent/orchestrator/mcp/reconnect-singleflight.mjs +23 -0
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +113 -14
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +32 -11
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +89 -2
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +12 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +19 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +144 -39
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +22 -8
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +15 -1
- package/src/runtime/agent/orchestrator/providers/openai-transport-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +3 -4
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +3 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +67 -7
- package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +291 -0
- package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +21 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +36 -10
- package/src/runtime/agent/orchestrator/session/compact.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +22 -33
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +0 -24
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +21 -29
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +7 -10
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +45 -25
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +2 -3
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +142 -84
- package/src/runtime/agent/orchestrator/session/manager/prefetch-bridge.mjs +12 -6
- package/src/runtime/agent/orchestrator/session/manager/runtime-loaders.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +31 -1
- package/src/runtime/agent/orchestrator/session/manager/session-lock.mjs +38 -2
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +29 -9
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +86 -8
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +10 -3
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +71 -42
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +4 -33
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +4 -5
- package/src/runtime/agent/orchestrator/stall-policy.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +35 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +116 -26
- package/src/runtime/agent/orchestrator/tools/builtin/binary-file.mjs +92 -19
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +8 -9
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/fs-reachability.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/lib/grep-context-expander.mjs +6 -15
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +12 -26
- package/src/runtime/agent/orchestrator/tools/builtin/read-image.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +83 -33
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +42 -45
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +27 -9
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +7 -0
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +17 -39
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +73 -0
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-job-spawn.mjs +0 -2
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +3 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +30 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +5 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +142 -26
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.mjs +12 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +47 -19
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +3 -2
- package/src/runtime/agent/orchestrator/tools/env-scrub.mjs +1 -2
- package/src/runtime/agent/orchestrator/tools/lib/pwsh-standby-pool.mjs +83 -13
- package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +39 -1
- package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +94 -20
- package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +16 -0
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +108 -12
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +12 -11
- package/src/runtime/agent/orchestrator/tools/patch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +63 -9
- package/src/runtime/agent/orchestrator/tools/shell-exec-output.mjs +2 -2
- package/src/runtime/channels/lib/config.mjs +34 -34
- package/src/runtime/channels/lib/inbound-handler.mjs +8 -8
- package/src/runtime/channels/lib/interaction-handlers.mjs +6 -6
- package/src/runtime/channels/lib/memory-client.mjs +31 -157
- package/src/runtime/channels/lib/output-forwarder.mjs +16 -16
- package/src/runtime/channels/lib/owned-runtime.mjs +60 -60
- package/src/runtime/channels/lib/owner-heartbeat.mjs +1 -1
- package/src/runtime/channels/lib/{backend-dispatch.mjs → provider-dispatch.mjs} +6 -6
- package/src/runtime/channels/lib/runtime-paths.mjs +4 -30
- package/src/runtime/channels/lib/scheduler.mjs +2 -2
- package/src/runtime/channels/lib/status-snapshot.mjs +3 -3
- package/src/runtime/channels/lib/tool-dispatch.mjs +4 -4
- package/src/runtime/channels/lib/worker-bootstrap.mjs +1 -1
- package/src/runtime/channels/lib/worker-ipc.mjs +7 -7
- package/src/runtime/channels/lib/worker-main.mjs +38 -38
- package/src/runtime/channels/{backends → providers}/discord-access.mjs +1 -1
- package/src/runtime/channels/{backends → providers}/discord-gateway.mjs +1 -1
- package/src/runtime/channels/{backends → providers}/discord.mjs +3 -3
- package/src/runtime/channels/{backends → providers}/telegram.mjs +12 -12
- package/src/runtime/channels/tool-defs.mjs +1 -1
- package/src/runtime/memory/index.mjs +76 -248
- package/src/runtime/memory/lib/agent-ipc.mjs +146 -81
- package/src/runtime/memory/lib/compact-vector-cache.mjs +88 -0
- package/src/runtime/memory/lib/core-memory-store.mjs +18 -1
- package/src/runtime/memory/lib/cycle-llm-adapters.mjs +13 -34
- package/src/runtime/memory/lib/embedding-provider.mjs +47 -26
- package/src/runtime/memory/lib/embedding-worker.mjs +30 -34
- package/src/runtime/memory/lib/http-router.mjs +9 -6
- package/src/runtime/memory/lib/ko-morph.mjs +3 -20
- package/src/runtime/memory/lib/memory-action-handlers.mjs +2 -1
- package/src/runtime/memory/lib/memory-config-flags.mjs +1 -1
- package/src/runtime/memory/lib/memory-cycle1.mjs +1 -0
- package/src/runtime/memory/lib/memory-cycle2-gate.mjs +4 -2
- package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +1 -0
- package/src/runtime/memory/lib/memory-cycle2-shared.mjs +4 -1
- package/src/runtime/memory/lib/memory-cycle3.mjs +3 -1
- package/src/runtime/memory/lib/memory-daemon-lifecycle.mjs +5 -0
- package/src/runtime/memory/lib/memory-log.mjs +1 -1
- package/src/runtime/memory/lib/memory-process-lock.mjs +5 -60
- package/src/runtime/memory/lib/memory.mjs +1 -1
- package/src/runtime/memory/lib/pg/process.mjs +32 -9
- package/src/runtime/memory/lib/session-ingest.mjs +1 -1
- package/src/runtime/memory/tool-defs.mjs +1 -5
- package/src/runtime/search/index.mjs +2 -2
- package/src/runtime/search/tool-defs.mjs +2 -2
- package/src/runtime/shared/abort-race.mjs +70 -0
- package/src/runtime/shared/agent-route-config.mjs +119 -0
- package/src/runtime/shared/atomic-file.mjs +80 -4
- package/src/runtime/shared/channel-notification-routing.mjs +2 -2
- package/src/runtime/shared/child-guardian.mjs +204 -108
- package/src/runtime/shared/child-spawn-gate.mjs +139 -72
- package/src/runtime/shared/config.mjs +120 -47
- package/src/runtime/shared/llm/index.mjs +1 -1
- package/src/runtime/shared/owner-fair-gate.mjs +134 -0
- package/src/runtime/shared/resource-admission.mjs +150 -100
- package/src/runtime/shared/stream-progress.mjs +6 -0
- package/src/runtime/shared/tool-execution-owner.mjs +12 -0
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +91 -27
- package/src/runtime/shared/tool-workload-gates.mjs +29 -0
- package/src/runtime/shared/turn-snapshot.mjs +47 -6
- package/src/runtime/shared/turn-worktree-snapshot.mjs +14 -2
- package/src/session-runtime/channel-config-api.mjs +5 -5
- package/src/session-runtime/config-helpers.mjs +39 -37
- package/src/session-runtime/config-lifecycle.mjs +27 -27
- package/src/session-runtime/lifecycle-api.mjs +22 -3
- package/src/session-runtime/memory-runtime-prewarm.mjs +15 -0
- package/src/session-runtime/model-route-api.mjs +7 -5
- package/src/session-runtime/prewarm.mjs +1 -1
- package/src/session-runtime/provider-auth-api.mjs +0 -7
- package/src/session-runtime/provider-models.mjs +1 -1
- package/src/session-runtime/remote-control.mjs +6 -7
- package/src/session-runtime/runtime-core.mjs +63 -39
- package/src/session-runtime/runtime-tunables.mjs +4 -4
- package/src/session-runtime/self-update.mjs +1 -1
- package/src/session-runtime/session-lifecycle.mjs +45 -17
- package/src/session-runtime/session-title.mjs +1 -1
- package/src/session-runtime/session-turn-api.mjs +96 -24
- package/src/session-runtime/settings-api.mjs +12 -24
- package/src/session-runtime/tool-defs.mjs +3 -3
- package/src/session-runtime/workflow-agents-api.mjs +55 -81
- package/src/session-runtime/workflow.mjs +14 -24
- package/src/standalone/agent-dispatch-broker.mjs +198 -0
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/agent-tool/spawn-flow.mjs +2 -0
- package/src/standalone/agent-tool/spawn-preset.mjs +11 -21
- package/src/standalone/agent-tool/tool-def.mjs +0 -14
- package/src/standalone/channel-admin.mjs +53 -64
- package/src/standalone/{channel-daemon-client.mjs → channel-client.mjs} +33 -19
- package/src/standalone/{channel-daemon-transport.mjs → channel-transport.mjs} +127 -46
- package/src/standalone/channel-worker.mjs +124 -647
- package/src/standalone/{backend-daemon.mjs → daemon.mjs} +270 -154
- package/src/standalone/explore-tool.mjs +187 -70
- package/src/standalone/fair-call-scheduler.mjs +264 -0
- package/src/standalone/memory-runtime-proxy.mjs +58 -1
- package/src/standalone/session-client.mjs +1134 -0
- package/src/standalone/session-protocol.mjs +192 -0
- package/src/standalone/session-runtime-pool.mjs +393 -0
- package/src/standalone/session-runtime-record.mjs +20 -0
- package/src/standalone/session-runtime-worker.mjs +203 -0
- package/src/standalone/{engine-daemon-service.mjs → session-service.mjs} +481 -224
- package/src/standalone/{engine-daemon-transport.mjs → session-transport.mjs} +390 -121
- package/src/standalone/session-wire.mjs +55 -0
- package/src/tui/App.jsx +34 -21
- package/src/tui/app/app-format.mjs +1 -1
- package/src/tui/app/app-view.jsx +5 -2
- package/src/tui/app/channel-pickers.mjs +41 -41
- package/src/tui/app/core-memory-picker.mjs +19 -19
- package/src/tui/app/doctor.mjs +5 -11
- package/src/tui/app/input-parsers.mjs +2 -2
- package/src/tui/app/message-selector.mjs +103 -0
- package/src/tui/app/onboarding-steps.mjs +3 -4
- package/src/tui/app/project-picker.mjs +80 -56
- package/src/tui/app/prompt-submit.mjs +48 -43
- package/src/tui/app/resume-picker.mjs +2 -2
- package/src/tui/app/route-pickers.mjs +3 -1
- package/src/tui/app/settings-picker.mjs +31 -33
- package/src/tui/app/transcript-window.mjs +38 -0
- package/src/tui/app/use-prompt-draft-flow.mjs +5 -7
- package/src/tui/app/use-prompt-handlers.mjs +86 -21
- package/src/tui/app/use-prompt-hint.mjs +3 -2
- package/src/tui/app/use-prompt-queue-history.mjs +10 -3
- package/src/tui/app/use-transcript-scroll.mjs +10 -3
- package/src/tui/app/use-transcript-window.mjs +50 -17
- package/src/tui/components/PromptInput.jsx +71 -38
- package/src/tui/components/Spinner.jsx +1 -1
- package/src/tui/components/ToolExecution.jsx +1 -1
- package/src/tui/components/prompt-input/edit-helpers.mjs +9 -11
- package/src/tui/components/prompt-input/escape-policy.mjs +42 -0
- package/src/tui/components/prompt-input/immediate-render.mjs +0 -10
- package/src/tui/components/prompt-input/interrupt-policy.mjs +10 -0
- package/src/tui/components/prompt-input/restore-policy.mjs +10 -0
- package/src/tui/components/tool-execution/surface-detail.mjs +1 -1
- package/src/tui/dist/index.mjs +1031 -1676
- package/src/tui/hooks/useSession.mjs +16 -0
- package/src/tui/index.jsx +12 -13
- package/src/tui/{engine → session}/agent-envelope.mjs +3 -3
- package/src/tui/{engine → session}/agent-job-feed.mjs +4 -4
- package/src/tui/{engine → session}/boot-profile.mjs +2 -2
- package/src/tui/{engine → session}/context-state.mjs +3 -3
- package/src/tui/{engine → session}/labels.mjs +2 -2
- package/src/tui/{engine → session}/live-share.mjs +38 -4
- package/src/tui/{engine → session}/notice-text.mjs +2 -2
- package/src/tui/{engine → session}/notification-plan.mjs +3 -3
- package/src/tui/session/oauth-flows.mjs +140 -0
- package/src/tui/{engine → session}/prompt-history.mjs +3 -3
- package/src/tui/{engine → session}/queue-helpers.mjs +2 -2
- package/src/tui/{engine → session}/render-timing.mjs +2 -2
- package/src/tui/{engine → session}/session-api-ext.mjs +30 -20
- package/src/tui/{engine → session}/session-api.mjs +110 -93
- package/src/tui/{engine → session}/session-flow.mjs +8 -2
- package/src/tui/{engine → session}/session-stats.mjs +3 -3
- package/src/tui/{engine → session}/tool-approval.mjs +3 -3
- package/src/tui/{engine → session}/tool-call-fields.mjs +2 -2
- package/src/tui/{engine → session}/tool-card-results.mjs +8 -6
- package/src/tui/{engine → session}/tool-result-status.mjs +5 -5
- package/src/tui/{engine → session}/tool-result-text.mjs +13 -3
- package/src/tui/{engine → session}/transcript-spill.mjs +34 -34
- package/src/tui/{engine → session}/turn.mjs +38 -176
- package/src/tui/{engine-local-session.mjs → session-local.mjs} +103 -103
- package/src/tui/session.mjs +22 -0
- package/src/tui/spinner-meta.mjs +4 -4
- package/src/tui/spinner-verbs.mjs +51 -3
- package/src/ui/statusline-segments.mjs +1 -1
- package/src/ui/statusline.mjs +1 -1
- package/vendor/ink/build/components/App.js +10 -1
- package/src/session-runtime/memory-daemon-probe.mjs +0 -61
- package/src/standalone/engine-daemon-client.mjs +0 -894
- package/src/standalone/engine-daemon-local-bridge.mjs +0 -20
- package/src/standalone/engine-daemon-protocol.mjs +0 -33
- package/src/tui/engine/turn-watchdog.mjs +0 -92
- package/src/tui/engine.mjs +0 -22
- package/src/tui/hooks/useEngine.mjs +0 -16
- /package/src/runtime/agent/orchestrator/session/compact/{engine.mjs → runner.mjs} +0 -0
- /package/src/runtime/channels/{backends → providers}/discord-attachments.mjs +0 -0
- /package/src/tui/{engine → session}/agent-response-tail.mjs +0 -0
- /package/src/tui/{engine → session}/frame-batched-store.mjs +0 -0
- /package/src/tui/{engine → session}/tui-steering-persist.mjs +0 -0
|
@@ -1,24 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* src/tui/
|
|
2
|
+
* src/tui/session/turn.mjs - lead TUI turn session runtime (createRunTurn). Extracted from session-local.mjs.
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { aggregateToolCategoryEntries, aggregateDoneCategories, classifyToolCategory, formatAggregateDetail, summarizeToolResult } from '../../runtime/shared/tool-surface.mjs';
|
|
5
5
|
import { applyUsageDelta } from './session-stats.mjs';
|
|
6
6
|
import { pickVerb, pickDoneVerb, compactEventLabel, compactEventDetail } from './labels.mjs';
|
|
7
|
-
import { toolResultText, toolErrorDisplay } from './tool-result-text.mjs';
|
|
7
|
+
import { toolResultText, toolErrorDisplay, stripShellExitHeader } from './tool-result-text.mjs';
|
|
8
8
|
import { toolCallId, toolResultCallId, toolCallName, toolCallArgs } from './tool-call-fields.mjs';
|
|
9
9
|
import { promptDisplayText, STEERING_SUPPRESSED_DISPLAY } from './queue-helpers.mjs';
|
|
10
10
|
import { TUI_FRAME_MS, yieldToRenderer } from './render-timing.mjs';
|
|
11
|
-
import { createTurnWatchdog } from './turn-watchdog.mjs';
|
|
12
11
|
import { aggregateRawResult, aggregateBucketForCategory, aggregateSummaries, assignAggregateSummaryOrder, failureDetailText, toolCallOutcome } from './tool-result-status.mjs';
|
|
13
12
|
|
|
14
13
|
export const STREAM_BATCH_INTERVAL_MS = TUI_FRAME_MS;
|
|
15
14
|
|
|
16
15
|
export function createRunTurn(bag) {
|
|
17
16
|
const {
|
|
18
|
-
runtime, nextId, tuiDebug,
|
|
17
|
+
runtime, nextId, tuiDebug, flags, pending, itemIndexById, getState, set, flushEmit, flushEmitImmediate, pushItem, appendItems, patchItem, replaceItems, updateStreamingTail: updateStreamingTailFromStore, settleStreamingTail: settleStreamingTailFromStore, clearStreamingTail: clearStreamingTailFromStore, pushNotice, pushUserOrSyntheticItem, markToolCallActive, markToolCallDone, clearActiveToolSummary, agentStatusState, routeState, transcriptRouteMetadata, syncContextStats, denyAllToolApprovals, requestToolApproval, patchToolCardResult, flushToolResults, flushDeferredExecutionPendingResumeKick, drainPendingSteering,
|
|
19
18
|
} = bag;
|
|
20
19
|
// Small fallbacks keep isolated createRunTurn harnesses source-compatible;
|
|
21
|
-
// the real
|
|
20
|
+
// the real session runtime supplies atomic implementations that also maintain revision.
|
|
22
21
|
const updateStreamingTail = updateStreamingTailFromStore || ((id, patch = {}, extra = {}) => {
|
|
23
22
|
set({
|
|
24
23
|
streamingTail: { ...(getState().streamingTail || {}), ...patch, kind: 'assistant', id, streaming: true },
|
|
@@ -48,11 +47,8 @@ export function createRunTurn(bag) {
|
|
|
48
47
|
const turnTranscriptMeta = { ...baseTranscriptMeta, completionVerb };
|
|
49
48
|
flags.pendingTranscriptMeta = null;
|
|
50
49
|
const { at: _userItemAt, ...turnRouteMeta } = turnTranscriptMeta;
|
|
51
|
-
// Per-turn epoch
|
|
52
|
-
//
|
|
53
|
-
// already started a new turn that reuses the per-session mutex — can detect
|
|
54
|
-
// it is stale and skip all shared-getState() writes (busy, flags.activePromptRestore,
|
|
55
|
-
// turndone, drain kick). Neutralizes the stale unwind without touching the mutex.
|
|
50
|
+
// Per-turn epoch prevents a disposed/replaced surface from publishing a
|
|
51
|
+
// terminal snapshot after another turn has become the visible owner.
|
|
56
52
|
const turnEpoch = ++flags.leadTurnEpoch;
|
|
57
53
|
const isCurrentTurn = () => !flags.disposed && flags.leadTurnEpoch === turnEpoch;
|
|
58
54
|
const inputBaseline = getState().stats.inputTokens;
|
|
@@ -79,80 +75,8 @@ export function createRunTurn(bag) {
|
|
|
79
75
|
let assistantText = '';
|
|
80
76
|
let currentAssistantId = null;
|
|
81
77
|
|
|
82
|
-
tuiDebug(`runTurn start turn=${turnIndex} pending=${pending.length}
|
|
83
|
-
|
|
84
|
-
// If this turn stops making observable progress (provider call stuck),
|
|
85
|
-
// trip after the cap: abort the in-flight run via the existing interrupt
|
|
86
|
-
// path (runtime.abort, the same one Esc uses), which rejects the pending
|
|
87
|
-
// runtime.ask() with a SessionClosedError so the normal cancelled-turn
|
|
88
|
-
// teardown runs. Keep this progress-based rather than total wall-clock:
|
|
89
|
-
// long multi-tool turns can legitimately exceed 5m while still producing
|
|
90
|
-
// model/tool events.
|
|
91
|
-
let watchdogGraceTimer = null;
|
|
92
|
-
const configuredLeadToolMaxMs = Number(process.env.MIXDOG_LEAD_TOOL_MAX_MS);
|
|
93
|
-
const leadToolMaxMs = Number.isFinite(configuredLeadToolMaxMs) && configuredLeadToolMaxMs > 0
|
|
94
|
-
? configuredLeadToolMaxMs
|
|
95
|
-
: 30 * 60 * 1000;
|
|
96
|
-
// Scheduling/liveness lives in turn-watchdog.mjs; the trip ACTION stays here
|
|
97
|
-
// because it unwinds this turn's UI state.
|
|
98
|
-
const watchdog = createTurnWatchdog({
|
|
99
|
-
runtime,
|
|
100
|
-
timeoutMs: LEAD_TURN_TIMEOUT_MS,
|
|
101
|
-
toolMaxMs: leadToolMaxMs,
|
|
102
|
-
isCurrentTurn,
|
|
103
|
-
onTrip: ({ idleMs, lastProgressLabel }) => {
|
|
104
|
-
if (_batchTimer !== null) {
|
|
105
|
-
clearTimeout(_batchTimer);
|
|
106
|
-
_batchTimer = null;
|
|
107
|
-
}
|
|
108
|
-
_pendingTextFlush = false;
|
|
109
|
-
_pendingThinkFlush = false;
|
|
110
|
-
_pendingThinkingLastEndedAt = 0;
|
|
111
|
-
const elapsed = Date.now() - startedAt;
|
|
112
|
-
tuiDebug(`runTurn WATCHDOG TRIP turn=${turnIndex} elapsedMs=${elapsed} idleMs=${idleMs} lastProgress=${lastProgressLabel} — aborting stuck turn`);
|
|
113
|
-
pushNotice(`Turn timed out after ${Math.round(idleMs / 1000)}s idle (last progress: ${lastProgressLabel}) — aborting stuck request. Input will be released shortly if abort does not unwind.`, 'warn', { transcript: true });
|
|
114
|
-
try { runtime.abort('watchdog'); } catch {}
|
|
115
|
-
// Belt-and-suspenders: if runtime.abort() did not reject runtime.ask()
|
|
116
|
-
// (unwind starved), hard-release the turn after a short grace so the
|
|
117
|
-
// React store is never left with busy=true and no drain in flight.
|
|
118
|
-
watchdogGraceTimer = setTimeout(() => {
|
|
119
|
-
if (flags.disposed) return;
|
|
120
|
-
if (!getState().busy) return;
|
|
121
|
-
if (flags.leadTurnEpoch !== turnEpoch) return; // a newer turn already owns the store
|
|
122
|
-
tuiDebug(`runTurn WATCHDOG FORCE-RELEASE turn=${turnIndex} — abort unwind starved`);
|
|
123
|
-
denyAllToolApprovals('turn timed out');
|
|
124
|
-
clearActiveToolSummary();
|
|
125
|
-
flushToolResults([], toolCards, cardByCallId, toolGroups, resultsDone, { finalize: true, cancelled: true });
|
|
126
|
-
finalizeToolHeaders();
|
|
127
|
-
clearDeferredTimers();
|
|
128
|
-
flags.flushDeferredBeforeImmediatePush = null;
|
|
129
|
-
if (currentAssistantId && currentAssistantText.trim()) {
|
|
130
|
-
settleStreamingTail(currentAssistantId, { text: currentAssistantText });
|
|
131
|
-
} else {
|
|
132
|
-
clearStreamingTail(currentAssistantId);
|
|
133
|
-
}
|
|
134
|
-
// Bump the epoch FIRST so this (still-stuck) turn's later finally becomes
|
|
135
|
-
// a no-op for shared getState() and cannot corrupt the turn we hand off to.
|
|
136
|
-
flags.leadTurnEpoch++;
|
|
137
|
-
set({ busy: false, spinner: null, thinking: null, lastTurn: null });
|
|
138
|
-
flags.activePromptRestore = null;
|
|
139
|
-
if (flags.draining) flags.draining = false;
|
|
140
|
-
if (pending.length > 0) void drain();
|
|
141
|
-
// busy→false here bypasses both the normal turn-end flush and the
|
|
142
|
-
// drain-finally flush, so a deferred completion kick would never re-arm.
|
|
143
|
-
// Fire it explicitly (idempotent: guarded by deferred flag + !busy).
|
|
144
|
-
flushDeferredExecutionPendingResumeKick();
|
|
145
|
-
flushEmitImmediate?.();
|
|
146
|
-
}, 5_000);
|
|
147
|
-
watchdogGraceTimer.unref?.();
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
const clearWatchdog = () => {
|
|
151
|
-
watchdog.clear();
|
|
152
|
-
if (watchdogGraceTimer) { clearTimeout(watchdogGraceTimer); watchdogGraceTimer = null; }
|
|
153
|
-
};
|
|
154
|
-
const markTurnProgress = (label) => watchdog.markProgress(label);
|
|
155
|
-
watchdog.arm();
|
|
78
|
+
tuiDebug(`runTurn start turn=${turnIndex} pending=${pending.length}`);
|
|
79
|
+
const markTurnProgress = () => isCurrentTurn();
|
|
156
80
|
let currentAssistantText = '';
|
|
157
81
|
// Segments sealed as their own assistant item(s) this turn via
|
|
158
82
|
// commitAssistantSegment (e.g. a tool preamble, then a no-newline tail
|
|
@@ -183,12 +107,6 @@ export function createRunTurn(bag) {
|
|
|
183
107
|
const toolCards = [];
|
|
184
108
|
const toolGroups = new Map();
|
|
185
109
|
const resultsDone = new Set();
|
|
186
|
-
// apply_patch+post_shell twin display: parent callId → synthetic shell
|
|
187
|
-
// callId. The protocol stays ONE call/ONE result, but the transcript shows
|
|
188
|
-
// TWO cards (edit + verify shell) so a long post_shell no longer looks
|
|
189
|
-
// like a stuck 'Editing 1 file'. deliverToolResultMessage splits the
|
|
190
|
-
// combined result text back between the two cards.
|
|
191
|
-
const postShellTwins = new Map();
|
|
192
110
|
// ── Live shell-output tail → running tool card ─────────────────────────
|
|
193
111
|
// 1 s poll of orchestrator liveness while this turn runs. When exactly one
|
|
194
112
|
// standalone (non-aggregate) card is unresolved and the runtime reports a
|
|
@@ -591,11 +509,11 @@ export function createRunTurn(bag) {
|
|
|
591
509
|
let _lastNewlineIdx = -1; // offset of the last completed-line '\n' found so far
|
|
592
510
|
let _emittedNewlineIdx = -2; // newline offset backing _emittedVisibleText (-2 forces first compute)
|
|
593
511
|
let _emittedVisibleText = ''; // cached visible slice for the current newline offset
|
|
594
|
-
//
|
|
512
|
+
// Session runtime-local streaming scalars. Neither responseLength nor thinkingText is
|
|
595
513
|
// rendered per-token by any consumer: App reads getState().thinking only as a
|
|
596
514
|
// boolean (App.jsx `!!(getState().thinking || liveSpinner?.thinking)`) and the
|
|
597
515
|
// Spinner takes outputTokens, not responseLength. So we keep these growing
|
|
598
|
-
// values in
|
|
516
|
+
// values in session runtime-local vars and publish to the store only on a visible
|
|
599
517
|
// transition (thinking on↔off), a completed visible text line, tool/usage
|
|
600
518
|
// updates, or finalization — not on every 8ms streaming flush.
|
|
601
519
|
let _publishedThinkingActive = false; // last thinking boolean pushed to store
|
|
@@ -696,7 +614,7 @@ export function createRunTurn(bag) {
|
|
|
696
614
|
// reads the thinking flag + timing anchors — none of them render the
|
|
697
615
|
// growing thinkingText. So publish the thinking boolean only on the
|
|
698
616
|
// OFF→ON transition (or when compacting toggles the flag), not on every
|
|
699
|
-
// 8ms reasoning chunk. The full thinkingText stays
|
|
617
|
+
// 8ms reasoning chunk. The full thinkingText stays session runtime-local and is
|
|
700
618
|
// emitted at finalize via the normal spinner/thinking teardown.
|
|
701
619
|
const nextThinkingActive = !compactingActive;
|
|
702
620
|
// Skip the push when the published thinking boolean is unchanged: neither
|
|
@@ -748,7 +666,9 @@ export function createRunTurn(bag) {
|
|
|
748
666
|
// the provider's isError/error-tool envelope drives failure counts/red.
|
|
749
667
|
const { exitCode, isExitError, isCallError } = toolCallOutcome(message, rawText);
|
|
750
668
|
const isError = isCallError;
|
|
751
|
-
const text = isError
|
|
669
|
+
const text = isError
|
|
670
|
+
? toolErrorDisplay(rawText, callRec.name || 'tool')
|
|
671
|
+
: (isExitError ? stripShellExitHeader(rawText) : rawText);
|
|
752
672
|
callRec.summary = !isError ? summarizeToolResult(callRec.name, callRec.args, rawText, isError) : null;
|
|
753
673
|
assignAggregateSummaryOrder(aggregate, callRec);
|
|
754
674
|
callRec.isError = isError;
|
|
@@ -805,49 +725,7 @@ export function createRunTurn(bag) {
|
|
|
805
725
|
const earlyCallId = toolResultCallId(message);
|
|
806
726
|
if (earlyCallId) {
|
|
807
727
|
markToolCardCompletedState(earlyCallId, message);
|
|
808
|
-
const earlyTwin = postShellTwins.get(earlyCallId);
|
|
809
|
-
if (earlyTwin) markToolCardCompletedState(earlyTwin, message);
|
|
810
|
-
}
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
const parentCallId = toolResultCallId(message);
|
|
814
|
-
const twinCallId = parentCallId ? postShellTwins.get(parentCallId) : null;
|
|
815
|
-
if (twinCallId && !resultsDone.has(twinCallId)) {
|
|
816
|
-
const combined = String(toolResultText(message?.content) ?? '');
|
|
817
|
-
// tool-exec composes `${patch}\n\n${header}\n${shell}` (or appends the
|
|
818
|
-
// skipped marker to a failed patch). Split on those exact seams.
|
|
819
|
-
const headerMatch = combined.match(/\n+--- post_shell( FAILED[^\n]*)? ---\n?/);
|
|
820
|
-
const skippedMatch = headerMatch ? null : combined.match(/\n+--- post_shell skipped: patch failed ---\s*$/);
|
|
821
|
-
let patchPart = combined;
|
|
822
|
-
let shellPart = null;
|
|
823
|
-
if (headerMatch) {
|
|
824
|
-
patchPart = combined.slice(0, headerMatch.index);
|
|
825
|
-
shellPart = combined.slice(headerMatch.index + headerMatch[0].length);
|
|
826
|
-
// Keep the FAILED banner on the shell card so its error state and
|
|
827
|
-
// fix-and-re-verify guidance survive the split.
|
|
828
|
-
if (headerMatch[1]) shellPart = `Error: post_shell FAILED (patch is applied; fix and re-verify)\n${shellPart}`;
|
|
829
|
-
} else if (skippedMatch) {
|
|
830
|
-
patchPart = combined.slice(0, skippedMatch.index);
|
|
831
|
-
shellPart = 'Error: post_shell skipped: patch failed';
|
|
832
728
|
}
|
|
833
|
-
if (shellPart !== null) {
|
|
834
|
-
flushToolResults([
|
|
835
|
-
{
|
|
836
|
-
role: 'tool',
|
|
837
|
-
tool_call_id: parentCallId,
|
|
838
|
-
content: patchPart,
|
|
839
|
-
...(Object.hasOwn(message || {}, 'uiDiff') ? { uiDiff: message.uiDiff } : {}),
|
|
840
|
-
},
|
|
841
|
-
{ role: 'tool', tool_call_id: twinCallId, content: shellPart },
|
|
842
|
-
], toolCards, cardByCallId, toolGroups, resultsDone);
|
|
843
|
-
return;
|
|
844
|
-
}
|
|
845
|
-
// Unsplittable (offloaded/preview-shaped result): parent keeps the
|
|
846
|
-
// combined text; settle the twin instead of leaving it Running.
|
|
847
|
-
flushToolResults([
|
|
848
|
-
message,
|
|
849
|
-
{ role: 'tool', tool_call_id: twinCallId, content: '(post_shell output included in the patch result above)' },
|
|
850
|
-
], toolCards, cardByCallId, toolGroups, resultsDone);
|
|
851
729
|
return;
|
|
852
730
|
}
|
|
853
731
|
flushToolResults([message], toolCards, cardByCallId, toolGroups, resultsDone);
|
|
@@ -918,24 +796,7 @@ export function createRunTurn(bag) {
|
|
|
918
796
|
}
|
|
919
797
|
const batchCalls = (calls || []).filter(Boolean);
|
|
920
798
|
if (batchCalls.length === 0) return;
|
|
921
|
-
|
|
922
|
-
// synthetic trailing shell call, so the (possibly long) verify phase
|
|
923
|
-
// renders as its own Running command card in call order.
|
|
924
|
-
const displayCalls = [];
|
|
925
|
-
for (const c of batchCalls) {
|
|
926
|
-
displayCalls.push(c);
|
|
927
|
-
if (toolCallName(c) !== 'apply_patch') continue;
|
|
928
|
-
let patchCallArgs = toolCallArgs(c);
|
|
929
|
-
if (typeof patchCallArgs === 'string') {
|
|
930
|
-
try { patchCallArgs = JSON.parse(patchCallArgs); } catch { patchCallArgs = null; }
|
|
931
|
-
}
|
|
932
|
-
const postShellCmd = typeof patchCallArgs?.post_shell === 'string' ? patchCallArgs.post_shell.trim() : '';
|
|
933
|
-
const parentCallId = toolCallId(c);
|
|
934
|
-
if (!postShellCmd || !parentCallId) continue;
|
|
935
|
-
const twinCallId = `${parentCallId}::post_shell`;
|
|
936
|
-
postShellTwins.set(parentCallId, twinCallId);
|
|
937
|
-
displayCalls.push({ id: twinCallId, name: 'shell', args: { command: postShellCmd } });
|
|
938
|
-
}
|
|
799
|
+
const displayCalls = batchCalls;
|
|
939
800
|
const agentBatch = ++providerToolBatch;
|
|
940
801
|
const committedAssistantSegment = commitAssistantSegment({ sealToolBlock: true });
|
|
941
802
|
if (committedAssistantSegment) {
|
|
@@ -972,10 +833,11 @@ export function createRunTurn(bag) {
|
|
|
972
833
|
const bucket = aggregateBucketForCategory(category, { agentBatch });
|
|
973
834
|
const callId = toolCallId(c);
|
|
974
835
|
const callKey = callId || `__tool_${toolCards.length}_${i}`;
|
|
975
|
-
// The old App scan counted multi-pattern calls via
|
|
976
|
-
//
|
|
836
|
+
// The old App scan counted multi-pattern calls via category work
|
|
837
|
+
// units, not a flat 1. Derive the same
|
|
977
838
|
// count here so the incremental Explore/Search summary matches.
|
|
978
|
-
const
|
|
839
|
+
const categoryEntries = aggregateToolCategoryEntries(name, args, category);
|
|
840
|
+
const activeCount = categoryEntries.reduce((total, entry) => total + Number(entry.count || 1), 0);
|
|
979
841
|
// Track Explore/Search calls as active for the incremental prompt-
|
|
980
842
|
// line summary; cleared when their result lands or the turn ends.
|
|
981
843
|
markToolCallActive(callKey, category, activeCount, Date.now());
|
|
@@ -1024,15 +886,16 @@ export function createRunTurn(bag) {
|
|
|
1024
886
|
continue;
|
|
1025
887
|
}
|
|
1026
888
|
|
|
1027
|
-
const categoryEntry = aggregateToolCategoryEntry(name, args, category);
|
|
1028
889
|
const aggregateCard = ensureAggregateCard(bucket);
|
|
1029
890
|
if (shellAfterEdit) aggregateCard.verifyShell = true;
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
891
|
+
for (const categoryEntry of categoryEntries) {
|
|
892
|
+
if (!aggregateCard.categories.has(categoryEntry.key)) aggregateCard.categoryOrder.push(categoryEntry.key);
|
|
893
|
+
const prevCategory = aggregateCard.categories.get(categoryEntry.key);
|
|
894
|
+
aggregateCard.categories.set(categoryEntry.key, {
|
|
895
|
+
...categoryEntry,
|
|
896
|
+
count: Number(prevCategory?.count || 0) + Number(categoryEntry.count || 1),
|
|
897
|
+
});
|
|
898
|
+
}
|
|
1036
899
|
aggregateCard.calls.set(callKey, { name, args, category, summary: null, summarySeq: null, isError: false, isCallError: false, isExitError: false, exitCode: null, resultText: null, resolved: false, completedEarly: false });
|
|
1037
900
|
touchedAggregates.add(aggregateCard);
|
|
1038
901
|
const card = { itemId: aggregateCard.itemId, callId: callKey, done: false, aggregate: aggregateCard };
|
|
@@ -1227,11 +1090,14 @@ export function createRunTurn(bag) {
|
|
|
1227
1090
|
flushStreamBatch();
|
|
1228
1091
|
},
|
|
1229
1092
|
onReasoningDelta: (chunk) => {
|
|
1230
|
-
if (!isCurrentTurn()
|
|
1093
|
+
if (!isCurrentTurn()) return;
|
|
1231
1094
|
if (String(chunk ?? '')) {
|
|
1232
1095
|
if (!markTurnProgress('reasoning-delta')) return;
|
|
1233
|
-
markPromptCommitted();
|
|
1234
1096
|
}
|
|
1097
|
+
// Reasoning is NOT a commit boundary (Claude Code parity): a turn
|
|
1098
|
+
// interrupted while it is still thinking produced no model-visible
|
|
1099
|
+
// message, so Esc must hand the prompt back to the input box. Text,
|
|
1100
|
+
// tool calls and turn end still commit it below.
|
|
1235
1101
|
startThinkingSegment();
|
|
1236
1102
|
thinkingText += String(chunk ?? '');
|
|
1237
1103
|
// Accumulate reasoning text; fire at most one render per STREAM_BATCH_INTERVAL_MS.
|
|
@@ -1341,13 +1207,9 @@ export function createRunTurn(bag) {
|
|
|
1341
1207
|
} finally {
|
|
1342
1208
|
const isStaleUnwind = !isCurrentTurn();
|
|
1343
1209
|
if (!isStaleUnwind) denyAllToolApprovals(cancelled ? 'turn cancelled' : 'turn finished');
|
|
1344
|
-
// Turn is unwinding normally (or via abort) — cancel the idle watchdog and
|
|
1345
|
-
// its force-release grace so they never fire on a live turn.
|
|
1346
|
-
clearWatchdog();
|
|
1347
1210
|
clearLiveTailTimer();
|
|
1348
|
-
//
|
|
1349
|
-
//
|
|
1350
|
-
// unwind must NOT write shared getState() or it corrupts that turn.
|
|
1211
|
+
// A replaced/disposed surface must not write shared state owned by the
|
|
1212
|
+
// current visible turn.
|
|
1351
1213
|
let closingItems = [];
|
|
1352
1214
|
if (deferredEntries.length) {
|
|
1353
1215
|
if (!isStaleUnwind) {
|
|
@@ -1367,7 +1229,7 @@ export function createRunTurn(bag) {
|
|
|
1367
1229
|
if (!isStaleUnwind) flags.flushDeferredBeforeImmediatePush = null;
|
|
1368
1230
|
closeThinkingSegment();
|
|
1369
1231
|
if (isStaleUnwind) {
|
|
1370
|
-
tuiDebug(`runTurn STALE UNWIND turn=${turnIndex} —
|
|
1232
|
+
tuiDebug(`runTurn STALE UNWIND turn=${turnIndex} — skipping shared UI/state writes`);
|
|
1371
1233
|
} else {
|
|
1372
1234
|
if (currentAssistantId && getState().streamingTail?.id === currentAssistantId) {
|
|
1373
1235
|
if (currentAssistantText.trim()) {
|
|
@@ -1383,7 +1245,7 @@ export function createRunTurn(bag) {
|
|
|
1383
1245
|
flags.activePromptRestore = null;
|
|
1384
1246
|
const elapsedMs = Date.now() - startedAt;
|
|
1385
1247
|
const thinkingElapsedMs = thinkingStartedAt ? accumulatedThinkingMs : 0;
|
|
1386
|
-
// responseLength is
|
|
1248
|
+
// responseLength is session runtime-local now (not pushed per-token), so compute the
|
|
1387
1249
|
// fallback from the live accumulator instead of the possibly-stale
|
|
1388
1250
|
// getState().spinner.responseLength. Final-only / non-streaming turns never
|
|
1389
1251
|
// accumulate `assistantText` (only currentAssistantText is set at the
|
|
@@ -1434,7 +1296,7 @@ export function createRunTurn(bag) {
|
|
|
1434
1296
|
flushEmit?.();
|
|
1435
1297
|
_publishedThinkingActive = false; // turn teardown cleared getState().thinking
|
|
1436
1298
|
const finalStatus = cancelled ? 'cancelled' : (failed ? 'failed' : 'done');
|
|
1437
|
-
tuiDebug(`runTurn end turn=${turnIndex} status=${finalStatus} elapsedMs=${Date.now() - startedAt}
|
|
1299
|
+
tuiDebug(`runTurn end turn=${turnIndex} status=${finalStatus} elapsedMs=${Date.now() - startedAt} pending=${pending.length}`);
|
|
1438
1300
|
return finalStatus;
|
|
1439
1301
|
}
|
|
1440
1302
|
|