mixdog 1.4.0 → 1.4.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/package.json +1 -1
- package/scripts/check-voice-runtime-inputs.mjs +25 -0
- package/scripts/gate-local.mjs +12 -3
- package/scripts/latest-guard.mjs +21 -9
- package/scripts/lib/isolated-test-env.mjs +10 -5
- package/scripts/lib/run-node-tests.mjs +37 -37
- package/scripts/lib/scoped-temp.d.mts +16 -0
- package/scripts/lib/scoped-temp.mjs +123 -0
- package/scripts/lib/stale-temp.mjs +44 -0
- package/scripts/post-release-check.mjs +1 -6
- package/scripts/pptx-kit-index.mjs +17 -4
- package/scripts/suite-health.mjs +10 -1
- package/scripts/test-data-dir.mjs +10 -7
- package/src/app.mjs +4 -0
- package/src/defaults/shipped-history.json +5 -0
- package/src/defaults/skills/browser-use/SKILL.md +6 -4
- package/src/defaults/skills/computer-use/SKILL.md +4 -2
- package/src/lib/rules-builder.cjs +29 -12
- package/src/output-styles/common.md +2 -2
- package/src/output-styles/simple.md +1 -1
- package/src/rules/agent/AGENT.md +5 -4
- package/src/rules/lead/LEAD.md +10 -5
- package/src/rules/shared/10-tool-workflow.md +3 -1
- package/src/rules/shared/45-destructive.md +0 -2
- package/src/rules/shared/50-execution.md +2 -0
- package/src/rules/shared/70-delivery.md +7 -9
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +29 -6
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +2 -0
- package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +1 -1
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +3 -1
- package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +11 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-api-recovery.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-api-transport.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens-recovery.mjs +6 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-request/initial-status.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +6 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-turn-result.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/command-code-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/cursor.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/devin-wire-transport.mjs +1 -1
- package/src/runtime/agent/orchestrator/providers/devin.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +210 -20
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-prefix-trace.mjs +76 -11
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +45 -6
- package/src/runtime/agent/orchestrator/providers/lib/first-output-window.mjs +58 -0
- package/src/runtime/agent/orchestrator/providers/lib/listen-on.mjs +14 -0
- package/src/runtime/agent/orchestrator/providers/mimo-oauth-login.mjs +1 -10
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +14 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +4 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream-common.mjs +5 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events/output-items.mjs +5 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +13 -3
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-watchdogs.mjs +81 -42
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +136 -5
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +20 -12
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-watchdogs.mjs +48 -22
- package/src/runtime/agent/orchestrator/providers/registry.mjs +12 -0
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +41 -13
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +7 -6
- package/src/runtime/agent/orchestrator/runtime-core/session-text.mjs +7 -3
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +3 -1
- package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +1 -3
- package/src/runtime/agent/orchestrator/session/cache-warm.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +4 -1
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +1 -8
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +23 -0
- package/src/runtime/agent/orchestrator/session/compact/observation-supersession.mjs +103 -23
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +160 -36
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/conversation-import/claude.mjs +163 -22
- package/src/runtime/agent/orchestrator/session/conversation-import/codex.mjs +132 -17
- package/src/runtime/agent/orchestrator/session/conversation-import/convert.mjs +38 -7
- package/src/runtime/agent/orchestrator/session/conversation-import/imported-session.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/conversation-import/turns.mjs +90 -22
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +33 -3
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +7 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/loop/provider-tool-exclusions.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +13 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +39 -21
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/manager/owner-route-fallbacks.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/manager/route-fallback-chain.mjs +2 -1
- package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +27 -9
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +61 -6
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +19 -8
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +12 -5
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -3
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-context.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +5 -1
- package/src/runtime/agent/orchestrator/session/prompt-cache-touch-store.mjs +30 -7
- package/src/runtime/agent/orchestrator/session/restart-prefix-parity.fixture.mjs +154 -0
- package/src/runtime/agent/orchestrator/session/store/session-delete.mjs +7 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store-summary-fields.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +37 -8
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +61 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/invocation-plan.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +4 -2
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +46 -20
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +31 -5
- package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +22 -8
- package/src/runtime/agent/orchestrator/tools/builtin/lib/scoped-search-flight.mjs +9 -5
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-stream.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +6 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-dispatch.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-publication.mjs +23 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-snapshot.mjs +6 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +1 -8
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch/federation.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/isolated-test-env.mjs +4 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-warm-standby.mjs +26 -4
- package/src/runtime/channels/lib/webhook/signature.mjs +4 -1
- package/src/runtime/channels/lib/whisper-port.mjs +10 -1
- package/src/runtime/computer-bridge/action-schema.mjs +2 -2
- package/src/runtime/computer-bridge/core-actions.mjs +2 -2
- package/src/runtime/computer-bridge/error-recovery.mjs +5 -4
- package/src/runtime/computer-bridge/linux-action-capabilities.mjs +24 -5
- package/src/runtime/computer-bridge/linux-readiness.d.mts +7 -2
- package/src/runtime/local-provider/server-process.mjs +2 -1
- package/src/runtime/media/adapters/gemini-video.mjs +4 -1
- package/src/runtime/media/adapters/xai-media.mjs +2 -1
- package/src/runtime/memory/lib/embedding-worker.mjs +6 -3
- package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +1 -7
- package/src/runtime/memory/lib/memory-chunk-quality.mjs +1 -6
- package/src/runtime/office/authoring/pdf-author-action.mjs +1 -6
- package/src/runtime/office/design/design-art-direction.mjs +29 -27
- package/src/runtime/office/pdf/pdf-writer.mjs +6 -1
- package/src/runtime/office/portable/portable-snapshot-docx.mjs +7 -1
- package/src/runtime/office/portable/portable-snapshot-shared.mjs +6 -1
- package/src/runtime/office/quality/assurance-rendered.mjs +9 -2
- package/src/runtime/office/quality/assurance-structure-docx.mjs +3 -1
- package/src/runtime/office/quality/design-review.mjs +1 -5
- package/src/runtime/office/quality/document-brief.mjs +1 -5
- package/src/runtime/office/quality/forced-break-pages.mjs +9 -6
- package/src/runtime/office/quality/quality-pipeline.mjs +1 -1
- package/src/runtime/shared/bot-owned-work.mjs +56 -0
- package/src/runtime/shared/defaults-separation.mjs +1 -4
- package/src/runtime/shared/fetch-safe-listen.d.mts +16 -0
- package/src/runtime/shared/fetch-safe-listen.mjs +50 -0
- package/src/runtime/shared/handoff-artifacts.d.mts +2 -1
- package/src/runtime/shared/handoff-artifacts.mjs +18 -8
- package/src/runtime/shared/idle-auto-clear-gate.mjs +29 -7
- package/src/runtime/shared/llm/cost.mjs +5 -1
- package/src/runtime/shared/loopback-listener.mjs +25 -2
- package/src/runtime/shared/model-route-chain.d.mts +7 -2
- package/src/runtime/shared/model-route-chain.mjs +22 -4
- package/src/runtime/shared/open-url.mjs +10 -0
- package/src/runtime/shared/session-activity-signal.mjs +14 -0
- package/src/runtime/shared/session-scratch.mjs +37 -0
- package/src/runtime/shared/tool-card-model/agent-surface.mjs +1 -3
- package/src/runtime/shared/tool-card-model/card-status.mjs +15 -2
- package/src/runtime/shared/tool-result-summary.mjs +1 -1
- package/src/runtime/shared/tool-surface.mjs +3 -0
- package/src/runtime/shared/tool-work-units.mjs +2 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +13 -6
- package/src/runtime/shared/worktrees/contract.mjs +4 -1
- package/src/runtime/shared/worktrees/git.mjs +15 -0
- package/src/runtime/shared/worktrees/manager.mjs +87 -38
- package/src/runtime/shared/worktrees/test-support.mjs +6 -10
- package/src/runtime/visualize-bridge/client.mjs +2 -0
- package/src/session-runtime/agent-home-delivery.mjs +41 -0
- package/src/session-runtime/agent-task-sessions.mjs +152 -63
- package/src/session-runtime/agent-tool-routing.mjs +8 -41
- package/src/session-runtime/boot/tools.mjs +5 -1
- package/src/session-runtime/bot-status.mjs +12 -6
- package/src/session-runtime/bot-target.mjs +38 -0
- package/src/session-runtime/channel-config-api.mjs +6 -1
- package/src/session-runtime/conversation-import/codex-titles.mjs +88 -0
- package/src/session-runtime/conversation-import/discovery.mjs +271 -25
- package/src/session-runtime/conversation-import/service.mjs +26 -5
- package/src/session-runtime/handoff-attachments.mjs +82 -31
- package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +12 -13
- package/src/session-runtime/internal-tool-executor/bridge-tools.mjs +1 -0
- package/src/session-runtime/internal-tool-executor/reaction-tool.mjs +4 -1
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +8 -2
- package/src/session-runtime/lifecycle/cold-heir.mjs +11 -6
- package/src/session-runtime/lifecycle/session-catalog.mjs +9 -1
- package/src/session-runtime/model-route/set-route.mjs +11 -2
- package/src/session-runtime/provider-catalog-cache.mjs +82 -36
- package/src/session-runtime/provider-models/catalog-load.mjs +23 -6
- package/src/session-runtime/provider-models.mjs +4 -2
- package/src/session-runtime/resource-recall-api.mjs +6 -1
- package/src/session-runtime/runtime-feature-gates.mjs +5 -1
- package/src/session-runtime/services/agent-tool/execute.mjs +14 -9
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +20 -4
- package/src/session-runtime/services/agent-tool/model-select.mjs +48 -7
- package/src/session-runtime/services/agent-tool/render.mjs +71 -17
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +6 -2
- package/src/session-runtime/services/agent-tool/tool-def.mjs +9 -9
- package/src/session-runtime/services/provider-admin.mjs +2 -1
- package/src/session-runtime/tool-policy/policy-stage.mjs +1 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +5 -1
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +15 -4
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +3 -3
- package/src/session-runtime/workspace/transitions.mjs +25 -0
- package/src/session-runtime/workspace/worktree-tool.mjs +26 -9
- package/src/standalone/daemon-session-control.mjs +18 -2
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +16 -12
- package/src/standalone/session-service/session-calls/session-action.mjs +10 -3
- package/src/standalone/session-transport/client-registry/client-grace.mjs +12 -9
- package/src/tui/app/app-view/floating-panel.jsx +7 -4
- package/src/tui/app/model-picker/route-selection/fast-parameters.mjs +1 -3
- package/src/tui/app/model-picker/route-selection.mjs +5 -6
- package/src/tui/app/provider-setup/oauth-actions.mjs +38 -20
- package/src/tui/app/provider-setup/provider-items.mjs +8 -2
- package/src/tui/app/provider-setup-picker.mjs +9 -5
- package/src/tui/components/QuestionPanel.jsx +13 -4
- package/src/tui/dist/index.mjs +75 -28
- package/src/tui/session/session-flow/queue/take-entries.mjs +11 -0
- package/src/ui/statusline-agents.mjs +1 -3
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Per-session scratch directory under Mixdog's data directory. Processes the
|
|
2
|
+
// `shell` tool starts see it as TEMP/TMP/TMPDIR, so scratch files never land in
|
|
3
|
+
// the project, and it is removed with its session (session-delete.mjs).
|
|
4
|
+
import { mkdirSync, rmSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { resolvePluginData } from './plugin-paths.mjs';
|
|
7
|
+
|
|
8
|
+
const SESSION_ID = /^[A-Za-z0-9_-]+$/;
|
|
9
|
+
|
|
10
|
+
/** The session's scratch path (not created), or '' for an unusable id. */
|
|
11
|
+
export function sessionScratchDir(sessionId) {
|
|
12
|
+
const id = typeof sessionId === 'string' ? sessionId : '';
|
|
13
|
+
return SESSION_ID.test(id) ? join(resolvePluginData(), 'scratch', id) : '';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Create the session's scratch directory if absent; returns its path ('' without a session id). */
|
|
17
|
+
export function ensureSessionScratchDir(sessionId) {
|
|
18
|
+
const dir = sessionScratchDir(sessionId);
|
|
19
|
+
if (dir) mkdirSync(dir, { recursive: true });
|
|
20
|
+
return dir;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function removeSessionScratchDir(sessionId) {
|
|
24
|
+
const dir = sessionScratchDir(sessionId);
|
|
25
|
+
if (dir) rmSync(dir, { recursive: true, force: true });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Point an env's temp variables at the session's scratch directory. */
|
|
29
|
+
export function applySessionScratchEnv(env, sessionId) {
|
|
30
|
+
const dir = ensureSessionScratchDir(sessionId);
|
|
31
|
+
if (dir) {
|
|
32
|
+
env.TEMP = dir;
|
|
33
|
+
env.TMP = dir;
|
|
34
|
+
env.TMPDIR = dir;
|
|
35
|
+
}
|
|
36
|
+
return env;
|
|
37
|
+
}
|
|
@@ -38,9 +38,7 @@ function agentNameFromResult(resultText) {
|
|
|
38
38
|
// The agent identity a card shows: the call's own fields, else the result
|
|
39
39
|
// envelope when the call only carried a tag/task id.
|
|
40
40
|
function agentDisplayName(args, resultText = '') {
|
|
41
|
-
return (
|
|
42
|
-
titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '') || agentNameFromResult(resultText)
|
|
43
|
-
);
|
|
41
|
+
return titleizeAgentName(args?.agent || args?.subagent_type || args?.name || '') || agentNameFromResult(resultText);
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
function agentModelLabel(args) {
|
|
@@ -7,13 +7,26 @@ import { backgroundTaskFailureStatusLabel } from '../err-text.mjs';
|
|
|
7
7
|
import { agentTerminalDetail, isAgentTool } from './agent-surface.mjs';
|
|
8
8
|
import { backgroundTaskElapsed, backgroundTaskFailureDetail, isBackgroundTaskTool } from './background-task.mjs';
|
|
9
9
|
import { shellDisplayStatus } from './shell-surface.mjs';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
normalizeTerminalStatus,
|
|
12
|
+
resultControlStatus,
|
|
13
|
+
resultEnvelopeStatus,
|
|
14
|
+
shellResultElapsed,
|
|
15
|
+
} from './terminal-status.mjs';
|
|
11
16
|
import { mediaTerminalStatus } from './media-result.mjs';
|
|
12
17
|
import { gitTerminalStatus } from './git-result.mjs';
|
|
13
18
|
import { isUserControlCancellation } from '../tool-status.mjs';
|
|
14
19
|
|
|
15
20
|
// Tools whose result opens with a task/bridge envelope that reports the call's status.
|
|
16
|
-
const ENVELOPE_STATUS_TOOLS = new Set([
|
|
21
|
+
const ENVELOPE_STATUS_TOOLS = new Set([
|
|
22
|
+
'agent',
|
|
23
|
+
'bridge',
|
|
24
|
+
'task',
|
|
25
|
+
'web_search',
|
|
26
|
+
'search_query',
|
|
27
|
+
'image_query',
|
|
28
|
+
'web_search_call',
|
|
29
|
+
]);
|
|
17
30
|
|
|
18
31
|
function shellFragments(base, display, isShellSurface) {
|
|
19
32
|
if (!isShellSurface) return { shellStatus: '', shellElapsed: '' };
|
|
@@ -648,7 +648,7 @@ const summarizeAskUserResult = ({ text, translate }) => {
|
|
|
648
648
|
|
|
649
649
|
const TOOL_RESULT_SUMMARIZERS = new Map(
|
|
650
650
|
[
|
|
651
|
-
[['ask_user'], summarizeAskUserResult],
|
|
651
|
+
[['ask_user', 'handoff_user'], summarizeAskUserResult],
|
|
652
652
|
[['read', 'view_image', 'read_mcp_resource'], summarizeReadResult],
|
|
653
653
|
[['apply_patch'], summarizePatchResult],
|
|
654
654
|
[['grep'], summarizeGrepResult],
|
|
@@ -151,6 +151,7 @@ export function displayToolName(name, args = {}) {
|
|
|
151
151
|
case 'request_user_input':
|
|
152
152
|
return 'Ask User';
|
|
153
153
|
case 'ask_user':
|
|
154
|
+
case 'handoff_user':
|
|
154
155
|
return 'Question';
|
|
155
156
|
case 'update_plan':
|
|
156
157
|
return 'Plan';
|
|
@@ -239,6 +240,8 @@ export function summarizeToolArgs(name, args, { max = DEFAULT_SUMMARY_MAX } = {}
|
|
|
239
240
|
return summarizeGithub(a, max);
|
|
240
241
|
case 'goal':
|
|
241
242
|
return compactParts([String(a.action || ''), truncateToolText(a.objective, max)]);
|
|
243
|
+
case 'handoff_user':
|
|
244
|
+
return '';
|
|
242
245
|
case 'ask_user':
|
|
243
246
|
return truncateToolText(
|
|
244
247
|
(Array.isArray(a.questions) ? a.questions : [])
|
|
@@ -91,6 +91,7 @@ const TOOL_CATEGORY = new Map([
|
|
|
91
91
|
['goal', 'Setup'],
|
|
92
92
|
['request_user_input', 'Setup'],
|
|
93
93
|
['ask_user', 'Setup'],
|
|
94
|
+
['handoff_user', 'Setup'],
|
|
94
95
|
['update_plan', 'Setup'],
|
|
95
96
|
['skill', 'Skill'],
|
|
96
97
|
['skill_execute', 'Skill'],
|
|
@@ -734,6 +735,7 @@ const TOOL_UNITS = new Map([
|
|
|
734
735
|
['code_graph', codeGraphUnit],
|
|
735
736
|
['request_user_input', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
|
|
736
737
|
['ask_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
|
|
738
|
+
['handoff_user', () => unitDescriptor('Setup', { active: 'Asking', done: 'Asked', noun: 'user' })],
|
|
737
739
|
['update_plan', () => unitDescriptor('Setup', { active: 'Updating', done: 'Updated', noun: 'plan' })],
|
|
738
740
|
['list_mcp_resources', () => unitDescriptor('Setup', { active: 'Listing', done: 'Listed', noun: 'MCP resource' })],
|
|
739
741
|
[
|
|
@@ -117,16 +117,23 @@ function recordPath(sessionId) {
|
|
|
117
117
|
function chain(sessionId, task) {
|
|
118
118
|
const previous = writeChains.get(sessionId) || Promise.resolve();
|
|
119
119
|
const next = previous.then(task, task);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
() => undefined,
|
|
124
|
-
() => undefined
|
|
125
|
-
)
|
|
120
|
+
const settled = next.then(
|
|
121
|
+
() => undefined,
|
|
122
|
+
() => undefined
|
|
126
123
|
);
|
|
124
|
+
writeChains.set(sessionId, settled);
|
|
125
|
+
// A settled chain with nothing queued behind it holds no order to keep.
|
|
126
|
+
void settled.then(() => {
|
|
127
|
+
if (writeChains.get(sessionId) === settled) writeChains.delete(sessionId);
|
|
128
|
+
});
|
|
127
129
|
return next;
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
/** Sessions with a write chain still held (tests). */
|
|
133
|
+
export function _turnSnapshotWriteChainCountForTest() {
|
|
134
|
+
return writeChains.size;
|
|
135
|
+
}
|
|
136
|
+
|
|
130
137
|
async function readRecordFile(path) {
|
|
131
138
|
try {
|
|
132
139
|
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
@@ -27,6 +27,7 @@ const WORKTREE_ENTRY_STATES = Object.freeze(['creating', 'ready', 'deleting', 'r
|
|
|
27
27
|
export const WORKTREE_ERROR_CODES = Object.freeze({
|
|
28
28
|
WORKTREE_BUSY_JOBS: 'WORKTREE_BUSY_JOBS',
|
|
29
29
|
WORKTREE_BRANCH_OCCUPIED: 'WORKTREE_BRANCH_OCCUPIED',
|
|
30
|
+
WORKTREE_DEFAULT_BRANCH: 'WORKTREE_DEFAULT_BRANCH',
|
|
30
31
|
WORKTREE_DISK_INSUFFICIENT: 'WORKTREE_DISK_INSUFFICIENT',
|
|
31
32
|
WORKTREE_LARGE_REPO_CONFIRM: 'WORKTREE_LARGE_REPO_CONFIRM',
|
|
32
33
|
WORKTREE_DIRTY: 'WORKTREE_DIRTY',
|
|
@@ -54,6 +55,8 @@ export const WORKTREE_ERROR_CODES = Object.freeze({
|
|
|
54
55
|
const DEFAULT_ERROR_MESSAGES = Object.freeze({
|
|
55
56
|
WORKTREE_BUSY_JOBS: 'The session has running jobs; wait for them or stop them before changing its workspace.',
|
|
56
57
|
WORKTREE_BRANCH_OCCUPIED: 'The branch is checked out in another worktree.',
|
|
58
|
+
WORKTREE_DEFAULT_BRANCH:
|
|
59
|
+
"The repository's default branch can't be opened in a worktree: the project folder could not switch to it while the worktree exists. Check it out in the project folder, or create a new branch for the worktree.",
|
|
57
60
|
WORKTREE_DISK_INSUFFICIENT: 'Not enough free disk space to create the worktree.',
|
|
58
61
|
WORKTREE_LARGE_REPO_CONFIRM: 'The repository is large; confirm before creating a worktree.',
|
|
59
62
|
WORKTREE_DIRTY: 'The worktree has uncommitted changes.',
|
|
@@ -193,7 +196,7 @@ function record(value, name) {
|
|
|
193
196
|
* @property {string|null} worktreeId Managed worktree id; null when running in the project folder.
|
|
194
197
|
* @property {string|null} branch Checked-out branch at `cwd`; null when detached or not a repository.
|
|
195
198
|
* @property {string|null} baseCommit Commit the worktree branch was created from.
|
|
196
|
-
* @property {string|null} mergeTarget Branch the worktree merges into (the project folder's branch).
|
|
199
|
+
* @property {string|null} mergeTarget Branch the worktree merges into (the project folder's branch); null for an existing branch until a merge records it.
|
|
197
200
|
* @property {number} revision Monotonic; advances on every committed workspace change.
|
|
198
201
|
* @property {WorkspaceTransition} transition In-flight transition marker.
|
|
199
202
|
*/
|
|
@@ -186,6 +186,21 @@ export async function localBranches(cwd, { signal, prefix = '' } = {}) {
|
|
|
186
186
|
return lines(result.stdout);
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
/** The local branch names the repository's remotes declare as their default (`refs/remotes/<remote>/HEAD`). */
|
|
190
|
+
export async function remoteDefaultBranches(cwd) {
|
|
191
|
+
const result = await runGit(cwd, ['for-each-ref', '--format=%(refname) %(symref)', 'refs/remotes'], {
|
|
192
|
+
readOnly: true,
|
|
193
|
+
});
|
|
194
|
+
const names = [];
|
|
195
|
+
for (const line of lines(result.stdout)) {
|
|
196
|
+
const [ref, target] = line.split(' ');
|
|
197
|
+
if (!ref.endsWith('/HEAD') || !target) continue;
|
|
198
|
+
const remote = ref.slice(0, -'HEAD'.length);
|
|
199
|
+
if (target.startsWith(remote)) names.push(target.slice(remote.length));
|
|
200
|
+
}
|
|
201
|
+
return names;
|
|
202
|
+
}
|
|
203
|
+
|
|
189
204
|
export async function validBranchName(cwd, branch) {
|
|
190
205
|
if (typeof branch !== 'string' || !branch.trim() || branch.startsWith('-')) return false;
|
|
191
206
|
const result = await runGit(cwd, ['check-ref-format', '--branch', branch], { allowFailure: true });
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
WORKTREE_SNAPSHOT_KIND,
|
|
50
50
|
worktreeBranchName,
|
|
51
51
|
worktreeError,
|
|
52
|
+
worktreeRefusal,
|
|
52
53
|
} from './contract.mjs';
|
|
53
54
|
import {
|
|
54
55
|
assertCarryable,
|
|
@@ -68,6 +69,7 @@ import {
|
|
|
68
69
|
listWorktrees,
|
|
69
70
|
localBranches,
|
|
70
71
|
parseStatusPaths,
|
|
72
|
+
remoteDefaultBranches,
|
|
71
73
|
runGit,
|
|
72
74
|
throwIfAborted,
|
|
73
75
|
validBranchName,
|
|
@@ -757,6 +759,11 @@ export async function resolveBranchWorkspace({
|
|
|
757
759
|
repoCommonDir: repo.repoCommonDir,
|
|
758
760
|
};
|
|
759
761
|
}
|
|
762
|
+
// Checked out in a managed worktree, the branch a remote declares its
|
|
763
|
+
// default would stay locked away from the project folder.
|
|
764
|
+
if (!create && (await remoteDefaultBranches(repo.projectPath)).includes(branch)) {
|
|
765
|
+
throw worktreeError('WORKTREE_DEFAULT_BRANCH', undefined, { branch });
|
|
766
|
+
}
|
|
760
767
|
const entry = await createManagedWorktree({
|
|
761
768
|
projectPath,
|
|
762
769
|
sessionId,
|
|
@@ -770,10 +777,6 @@ export async function resolveBranchWorkspace({
|
|
|
770
777
|
confirmLarge,
|
|
771
778
|
signal,
|
|
772
779
|
});
|
|
773
|
-
const record = await getRecord(entry.id);
|
|
774
|
-
record.mergeTarget = repo.currentBranch;
|
|
775
|
-
await putRecord(record);
|
|
776
|
-
entry.mergeTarget = repo.currentBranch;
|
|
777
780
|
return { path: entry.path, branch, entry, created: true, repoCommonDir: repo.repoCommonDir };
|
|
778
781
|
});
|
|
779
782
|
}
|
|
@@ -1219,7 +1222,10 @@ export async function createManagedWorktree({
|
|
|
1219
1222
|
path: managedWorktreePath(repo.repoCommonDir, slug),
|
|
1220
1223
|
branch,
|
|
1221
1224
|
baseCommit,
|
|
1222
|
-
|
|
1225
|
+
// An existing branch has no base it branched from: it merges where a
|
|
1226
|
+
// merge first takes it (recorded then), and until that its own work is
|
|
1227
|
+
// what it gained here since baseCommit.
|
|
1228
|
+
mergeTarget: existingBranch ? null : mergeTarget,
|
|
1223
1229
|
createdAt: Date.now(),
|
|
1224
1230
|
ownerSessionId: owner.sessionId,
|
|
1225
1231
|
existingBranch,
|
|
@@ -1400,9 +1406,7 @@ export async function removeSessionSnapshots(sessionId, { txIds = null } = {}) {
|
|
|
1400
1406
|
const only = txIds ? new Set(txIds) : null;
|
|
1401
1407
|
const held = Object.values((await readRegistry()).entries).filter(
|
|
1402
1408
|
(record) =>
|
|
1403
|
-
record.kind === WORKTREE_SNAPSHOT_KIND &&
|
|
1404
|
-
record.holderSessionId === sessionId &&
|
|
1405
|
-
(!only || only.has(record.txId))
|
|
1409
|
+
record.kind === WORKTREE_SNAPSHOT_KIND && record.holderSessionId === sessionId && (!only || only.has(record.txId))
|
|
1406
1410
|
);
|
|
1407
1411
|
for (const record of held) {
|
|
1408
1412
|
const row = { id: record.id, txId: record.txId };
|
|
@@ -1854,19 +1858,59 @@ export async function removeManagedWorktree({
|
|
|
1854
1858
|
if (!current && !expected) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1855
1859
|
return skipped;
|
|
1856
1860
|
}
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
+
return removeLocked(current, { force, sessionId, preserveBranch, safeOnly });
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
/** The removal of `current`, under its repository lock. */
|
|
1866
|
+
async function removeLocked(current, { force, sessionId, preserveBranch = false, safeOnly = false }) {
|
|
1867
|
+
assertNotShared(current, sessionId);
|
|
1868
|
+
if (current.state === 'creating' || current.state === 'recovery') {
|
|
1869
|
+
const rollback = await rollbackCreation(current);
|
|
1870
|
+
return rollback.complete ? { removed: true } : { removed: false, retryable: true, remaining: rollback.remaining };
|
|
1871
|
+
}
|
|
1872
|
+
// Every deletion attempt of a snapshot, a resumed one included, waits
|
|
1873
|
+
// for (refuses on) its consumers.
|
|
1874
|
+
const release = current.kind === WORKTREE_SNAPSHOT_KIND ? holdSnapshotFolder(current) : () => {};
|
|
1875
|
+
try {
|
|
1876
|
+
return await decideAndFinishDeletion(current, { force, preserveBranch, safeOnly });
|
|
1877
|
+
} finally {
|
|
1878
|
+
release();
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
/**
|
|
1883
|
+
* Remove a worktree whose owner is gone, on an explicit request: under the
|
|
1884
|
+
* repository lock its retention is read again right before anything moves,
|
|
1885
|
+
* so an owner that came back (a live session, a running lease holder) or a
|
|
1886
|
+
* session the store still keeps it for refuses (WORKTREE_BUSY_JOBS). Then
|
|
1887
|
+
* the ordinary removal guards apply (dirty or unmerged work needs `force`).
|
|
1888
|
+
* @param {{ entryId: string, force?: boolean, liveSessionIds?: string[], retainedSessionIds?: string[] }} input
|
|
1889
|
+
*/
|
|
1890
|
+
export async function removeOrphanedWorktree({
|
|
1891
|
+
entryId,
|
|
1892
|
+
force = false,
|
|
1893
|
+
liveSessionIds = [],
|
|
1894
|
+
retainedSessionIds = [],
|
|
1895
|
+
} = {}) {
|
|
1896
|
+
const record = await getRecord(entryId);
|
|
1897
|
+
if (!record) throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1898
|
+
return withRepoLock(record.repoCommonDir, async () => {
|
|
1899
|
+
const current = await getRecord(entryId);
|
|
1900
|
+
if (!current || current.kind === WORKTREE_SNAPSHOT_KIND) {
|
|
1901
|
+
throw worktreeError('WORKTREE_MISSING', undefined, { entryId });
|
|
1861
1902
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1903
|
+
const { ownerLive, removable } = await retentionOf(current, new Set(liveSessionIds), new Set(retainedSessionIds));
|
|
1904
|
+
if (ownerLive) throw worktreeRefusal('workspace-lease', { entryId });
|
|
1905
|
+
if (!removable) {
|
|
1906
|
+
// Retained recovery data names itself; otherwise sessions still keep it.
|
|
1907
|
+
await assertRecoveryStoresClear(current);
|
|
1908
|
+
throw worktreeRefusal('workspace-retained', {
|
|
1909
|
+
entryId,
|
|
1910
|
+
sessions: [current.ownerSessionId, ...(current.sharedSessionIds ?? [])].filter(Boolean),
|
|
1911
|
+
});
|
|
1869
1912
|
}
|
|
1913
|
+
return removeLocked(current, { force });
|
|
1870
1914
|
});
|
|
1871
1915
|
}
|
|
1872
1916
|
|
|
@@ -1900,25 +1944,7 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
|
|
|
1900
1944
|
const retained = new Set(retainedSessionIds);
|
|
1901
1945
|
const rows = [];
|
|
1902
1946
|
for (const record of Object.values((await readRegistry()).entries)) {
|
|
1903
|
-
const
|
|
1904
|
-
const ownerLive = snapshot
|
|
1905
|
-
? await snapshotHolderLive(record, live)
|
|
1906
|
-
: (!!record.ownerSessionId && live.has(record.ownerSessionId)) ||
|
|
1907
|
-
leaseProcessAlive(await readOwnerLease(record));
|
|
1908
|
-
const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
|
|
1909
|
-
// A snapshot outlives no holder: the prune removes it, changes and all.
|
|
1910
|
-
let removable = snapshot
|
|
1911
|
-
? !ownerLive
|
|
1912
|
-
: !record.sharedSessionIds?.length &&
|
|
1913
|
-
(record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
|
|
1914
|
-
if (removable) {
|
|
1915
|
-
try {
|
|
1916
|
-
await assertRecoveryStoresClear(record);
|
|
1917
|
-
} catch (error) {
|
|
1918
|
-
if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
|
|
1919
|
-
removable = false;
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1947
|
+
const { ownerLive, retained: isRetained, removable } = await retentionOf(record, live, retained);
|
|
1922
1948
|
rows.push({
|
|
1923
1949
|
...entryView(record),
|
|
1924
1950
|
projectPath: record.projectPath,
|
|
@@ -1930,6 +1956,29 @@ export async function listManagedWorktrees({ liveSessionIds = [], retainedSessio
|
|
|
1930
1956
|
return rows;
|
|
1931
1957
|
}
|
|
1932
1958
|
|
|
1959
|
+
/** Who keeps `record` (listManagedWorktrees): `live` and `retained` are session id sets. */
|
|
1960
|
+
async function retentionOf(record, live, retained) {
|
|
1961
|
+
const snapshot = record.kind === WORKTREE_SNAPSHOT_KIND;
|
|
1962
|
+
const ownerLive = snapshot
|
|
1963
|
+
? await snapshotHolderLive(record, live)
|
|
1964
|
+
: (!!record.ownerSessionId && live.has(record.ownerSessionId)) || leaseProcessAlive(await readOwnerLease(record));
|
|
1965
|
+
const isRetained = !!record.ownerSessionId && retained.has(record.ownerSessionId);
|
|
1966
|
+
// A snapshot outlives no holder: the prune removes it, changes and all.
|
|
1967
|
+
let removable = snapshot
|
|
1968
|
+
? !ownerLive
|
|
1969
|
+
: !record.sharedSessionIds?.length &&
|
|
1970
|
+
(record.state !== 'ready' || (!ownerLive && (record.disposable === true || !isRetained)));
|
|
1971
|
+
if (removable) {
|
|
1972
|
+
try {
|
|
1973
|
+
await assertRecoveryStoresClear(record);
|
|
1974
|
+
} catch (error) {
|
|
1975
|
+
if (error?.code !== 'WORKTREE_FILE_RECOVERY') throw error;
|
|
1976
|
+
removable = false;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return { ownerLive, retained: isRetained, removable };
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1933
1982
|
/**
|
|
1934
1983
|
* Conservative reconcile (daemon startup, and the manual prune). Always:
|
|
1935
1984
|
* resumes interrupted deletions, rolls back interrupted creations of no
|
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
// Temporary git repositories and data dirs for the worktree suites.
|
|
2
2
|
import '../git-direct.test-support.mjs';
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
|
-
import { appendFileSync, chmodSync, cpSync, existsSync,
|
|
5
|
-
import { tmpdir } from 'node:os';
|
|
4
|
+
import { appendFileSync, chmodSync, cpSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
6
5
|
import { dirname, join } from 'node:path';
|
|
6
|
+
import { makeTempDirSync, removeTempDirSync } from '../../../../scripts/lib/scoped-temp.mjs';
|
|
7
7
|
|
|
8
8
|
const created = [];
|
|
9
9
|
|
|
10
|
+
// A suite that never calls cleanupTempDirs still has its directories removed
|
|
11
|
+
// when the process exits.
|
|
10
12
|
export function tempDir(prefix = 'mixdog-wt-') {
|
|
11
|
-
const dir =
|
|
13
|
+
const dir = makeTempDirSync(prefix);
|
|
12
14
|
created.push(dir);
|
|
13
15
|
return dir;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export function cleanupTempDirs() {
|
|
17
|
-
for (const dir of created.splice(0))
|
|
18
|
-
try {
|
|
19
|
-
rmSync(dir, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
|
|
20
|
-
} catch {
|
|
21
|
-
/* best effort */
|
|
22
|
-
}
|
|
23
|
-
}
|
|
19
|
+
for (const dir of created.splice(0)) removeTempDirSync(dir);
|
|
24
20
|
}
|
|
25
21
|
|
|
26
22
|
const GIT_ENV = { ...process.env, GIT_TERMINAL_PROMPT: '0', GIT_EDITOR: 'true' };
|
|
@@ -163,6 +163,8 @@ export async function executeVisualizeTool(args, options = {}) {
|
|
|
163
163
|
cwd: options.cwd || process.cwd(),
|
|
164
164
|
action: validated.action,
|
|
165
165
|
input: validated.input,
|
|
166
|
+
// The call's id: the host names it in its turn-end record of opens whose tab is gone.
|
|
167
|
+
...(options.callId ? { callId: String(options.callId) } : {}),
|
|
166
168
|
};
|
|
167
169
|
let discovery = readBridgeDiscovery(DISCOVERY_FILE);
|
|
168
170
|
if (!discovery) return toolError(unavailableMessage());
|
|
@@ -332,6 +332,9 @@ export function createRoutineResultQueue(
|
|
|
332
332
|
rounds: section(doc, 'rounds'),
|
|
333
333
|
// Reporting turns not yet queued, by submission id (agent-task-sessions.mjs).
|
|
334
334
|
watches: section(doc, 'watches'),
|
|
335
|
+
// The bot-sent turns that hold no watch (reports off, or a watch that could
|
|
336
|
+
// not be stored), by submission id: work a restart re-attaches.
|
|
337
|
+
owned: section(doc, 'owned'),
|
|
335
338
|
// Posted task results whose wake turn was not taken yet, per home.
|
|
336
339
|
wakes: section(doc, 'wakes'),
|
|
337
340
|
});
|
|
@@ -559,6 +562,26 @@ export function createRoutineResultQueue(
|
|
|
559
562
|
return { ...doc, watches };
|
|
560
563
|
});
|
|
561
564
|
},
|
|
565
|
+
/** Keep `work` ({ runId, agentId, taskSessionId, owner, at }): a bot-sent
|
|
566
|
+
* turn that reports nothing, until its work ends. It is no watch: it
|
|
567
|
+
* owes no report, starts no hand-off and takes no part in a watch cap. */
|
|
568
|
+
async own(work) {
|
|
569
|
+
await update((doc) => ({ ...doc, owned: { ...doc.owned, [work.runId]: work } }));
|
|
570
|
+
},
|
|
571
|
+
/** Every stored record of bot-sent work that reports nothing, oldest first. */
|
|
572
|
+
async owned() {
|
|
573
|
+
return Object.values((await read()).owned);
|
|
574
|
+
},
|
|
575
|
+
/** Drop the records of `runIds` (a run id or a list; their work ended), in one write. */
|
|
576
|
+
async disown(runIds) {
|
|
577
|
+
const ids = [runIds].flat();
|
|
578
|
+
await update((doc) => {
|
|
579
|
+
if (!ids.some((runId) => doc.owned[runId])) return undefined;
|
|
580
|
+
const owned = { ...doc.owned };
|
|
581
|
+
for (const runId of ids) delete owned[runId];
|
|
582
|
+
return { ...doc, owned };
|
|
583
|
+
});
|
|
584
|
+
},
|
|
562
585
|
/** The user spoke in `homeId`: its round trips count from zero again. */
|
|
563
586
|
async resetRounds(homeId) {
|
|
564
587
|
await update((doc) => {
|
|
@@ -1351,6 +1374,9 @@ export function createAgentHomeDelivery({
|
|
|
1351
1374
|
unwatchTask: (runId) => queue.unwatch(runId),
|
|
1352
1375
|
followTask: (runId, submissionId) => queue.followWatch(runId, submissionId),
|
|
1353
1376
|
taskWatches: () => queue.watches(),
|
|
1377
|
+
ownTask: (work) => queue.own(work),
|
|
1378
|
+
disownTask: (runId) => queue.disown(runId),
|
|
1379
|
+
ownedTasks: () => queue.owned(),
|
|
1354
1380
|
resetRounds: (homeId) => queue.resetRounds(homeId),
|
|
1355
1381
|
};
|
|
1356
1382
|
}
|
|
@@ -1446,6 +1472,21 @@ export async function followAgentTask(runId, submissionId) {
|
|
|
1446
1472
|
return (await processDelivery()).followTask(runId, submissionId);
|
|
1447
1473
|
}
|
|
1448
1474
|
|
|
1475
|
+
/** Keep the record of one bot-sent turn that reports nothing until its work ends. */
|
|
1476
|
+
export async function ownAgentTask(work) {
|
|
1477
|
+
return (await processDelivery()).ownTask(work);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
/** Drop the record of one bot-sent turn that reports nothing (its work ended). */
|
|
1481
|
+
export async function disownAgentTask(runId) {
|
|
1482
|
+
return (await processDelivery()).disownTask(runId);
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
/** The bot-sent turns that report nothing and whose work was not seen to end. */
|
|
1486
|
+
export async function agentOwnedTasks() {
|
|
1487
|
+
return (await processDelivery()).ownedTasks();
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1449
1490
|
/** A user's own message in `homeId`: its round trips with every target restart. */
|
|
1450
1491
|
export async function resetAgentTaskRounds(homeId) {
|
|
1451
1492
|
return (await processDelivery()).resetRounds(homeId);
|