mixdog 1.3.0 → 1.3.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/NOTICE.md +52 -9
- package/package.json +1 -1
- package/src/defaults/shipped-history.json +4 -1
- package/src/defaults/skills/setup/references/actions.md +4 -1
- package/src/defaults/skills/setup-guide/SKILL.md +10 -7
- package/src/output-styles/common.md +13 -8
- package/src/rules/agent-mode/AGENT_MODE.md +1 -1
- package/src/rules/agent-mode/MIXY.md +11 -4
- package/src/runtime/agent/orchestrator/context/role-instructions.mjs +72 -14
- package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-catalog.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/auto-effort.mjs +7 -8
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/lib/tool-call-wire-ids.mjs +65 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-retry-profile.mjs +8 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/openai-responses-input.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/provider-error-kind.mjs +14 -2
- package/src/runtime/agent/orchestrator/providers/retry-executor.mjs +17 -0
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +4 -2
- package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +14 -4
- package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +37 -7
- package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +5 -3
- package/src/runtime/agent/orchestrator/session/agent-room.d.mts +4 -0
- package/src/runtime/agent/orchestrator/session/agent-room.mjs +17 -8
- package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +32 -5
- package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/route-fallback.mjs +108 -6
- package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +8 -14
- package/src/runtime/agent/orchestrator/session/loop/usage.mjs +46 -4
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-commit.mjs +18 -8
- package/src/runtime/agent/orchestrator/session/manager/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +7 -20
- package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +7 -1
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +1 -1
- package/src/runtime/agent/orchestrator/session/mixy-name.mjs +5 -2
- package/src/runtime/agent/orchestrator/session/routine-result.d.mts +17 -1
- package/src/runtime/agent/orchestrator/session/routine-result.mjs +61 -9
- package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +14 -9
- package/src/runtime/agent/orchestrator/session/transcript-restore/user-text.mjs +92 -15
- package/src/runtime/attachments/store.mjs +6 -0
- package/src/runtime/effort-judge/judge-client.mjs +1 -1
- package/src/runtime/effort-judge/model-manifest.json +7 -7
- package/src/runtime/shared/agent-kind.mjs +152 -0
- package/src/runtime/shared/agent-route-config.d.mts +1 -0
- package/src/runtime/shared/agent-route-config.mjs +22 -8
- package/src/runtime/shared/agent-store.mjs +132 -0
- package/src/runtime/shared/bot-split-migration.mjs +457 -0
- package/src/runtime/shared/config-patch.mjs +20 -1
- package/src/runtime/shared/connector-catalog.d.mts +1 -2
- package/src/runtime/shared/connector-catalog.mjs +2 -4
- package/src/runtime/shared/connector-triggers.mjs +2 -0
- package/src/runtime/shared/err-text.mjs +3 -1
- package/src/runtime/shared/error-presentation.mjs +91 -6
- package/src/runtime/shared/handoff-artifacts.d.mts +20 -0
- package/src/runtime/shared/handoff-artifacts.mjs +61 -0
- package/src/runtime/shared/llm/provider-model-identities.mjs +6 -1
- package/src/runtime/shared/llm/usage-accounting.mjs +7 -1
- package/src/runtime/shared/model-route-fallback.mjs +79 -7
- package/src/runtime/shared/plain-preview.mjs +22 -17
- package/src/runtime/shared/sensitive-path-rules.d.mts +15 -0
- package/src/runtime/shared/sensitive-path-rules.mjs +256 -0
- package/src/runtime/shared/usage-readout-totals.mjs +15 -13
- package/src/runtime/shared/user-data-guard.mjs +5 -2
- package/src/session-runtime/agent-home-delivery.mjs +423 -56
- package/src/session-runtime/agent-room-delivery.mjs +45 -4
- package/src/session-runtime/agent-task-sessions.mjs +299 -39
- package/src/session-runtime/boot/apis.mjs +13 -0
- package/src/session-runtime/boot/providers.mjs +14 -4
- package/src/session-runtime/config-lifecycle.mjs +43 -2
- package/src/session-runtime/handoff-attachments.mjs +593 -0
- package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +27 -3
- package/src/session-runtime/model-route/route-persist.mjs +2 -2
- package/src/session-runtime/model-route/route-tuning.mjs +7 -1
- package/src/session-runtime/model-route/set-route.mjs +21 -1
- package/src/session-runtime/native-web-search.mjs +2 -2
- package/src/session-runtime/new-session-config.mjs +6 -1
- package/src/session-runtime/route-resolution.mjs +5 -11
- package/src/session-runtime/services/agent-tool/helpers.mjs +24 -5
- package/src/session-runtime/services/agent-tool/send-flow.mjs +11 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +4 -1
- package/src/session-runtime/services/agent-tool/spawn-preset.mjs +5 -8
- package/src/session-runtime/services/agent-tool/tool-def.mjs +7 -0
- package/src/session-runtime/setup-tool/executor.mjs +12 -1
- package/src/session-runtime/setup-tool/extended-actions.mjs +19 -7
- package/src/session-runtime/setup-tool/settings-contract.mjs +6 -0
- package/src/session-runtime/tool-policy-refresh.mjs +13 -2
- package/src/session-runtime/turn/turn-run/turn-prepare.mjs +11 -0
- package/src/session-runtime/workflow-agents-api/agent-editor.mjs +123 -32
- package/src/session-runtime/workflow-agents-api/agent-route.mjs +67 -7
- package/src/session-runtime/workflow-agents-api/onboarding.mjs +11 -4
- package/src/standalone/daemon-session-control.mjs +13 -5
- package/src/standalone/daemon.mjs +16 -4
- package/src/standalone/session-service/agent-tree/agent-turns.mjs +46 -3
- package/src/standalone/session-service/agent-tree.mjs +4 -3
- package/src/standalone/session-service/session-calls/session-turns.mjs +19 -0
- package/src/tui/dist/index.mjs +70 -9
- package/src/tui/session/notice-surface.mjs +3 -4
- package/src/tui/session/session-api/routes.mjs +14 -3
- package/src/tui/session/transcript-intake.mjs +2 -0
- package/src/tui/session/turn-live-call.mjs +11 -3
- package/src/tui/session/turn.mjs +13 -3
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { createAgentCancellation } from './agent-tree/agent-cancel.mjs';
|
|
11
11
|
import { createAgentRegistry } from './agent-tree/agent-registry.mjs';
|
|
12
12
|
import { createAgentRehydration, lastStoredAgentHandoff } from './agent-tree/agent-rehydrate.mjs';
|
|
13
|
-
import { createAgentTurns } from './agent-tree/agent-turns.mjs';
|
|
13
|
+
import { agentTurnContent, agentTurnTranscriptMeta, createAgentTurns } from './agent-tree/agent-turns.mjs';
|
|
14
14
|
import { randomUUID } from 'node:crypto';
|
|
15
15
|
|
|
16
16
|
export { SESSION_ID_PATTERN } from './agent-tree/agent-registry.mjs';
|
|
@@ -139,12 +139,13 @@ export function createAgentTree({
|
|
|
139
139
|
const cancelEpoch = registry.assertAdmission(descriptor.id);
|
|
140
140
|
const runtime = sessionOwner(descriptor.id)?.runtime;
|
|
141
141
|
if (!runtime || !stateBusy(runtime.getState())) return null;
|
|
142
|
-
const
|
|
142
|
+
const content = agentTurnContent(prompt);
|
|
143
|
+
const accepted = await runtime.submitAsync(content, {
|
|
143
144
|
id: `agent-message-${randomUUID()}`,
|
|
144
145
|
mode: 'prompt',
|
|
145
146
|
priority: 'next',
|
|
146
147
|
context,
|
|
147
|
-
transcriptMeta:
|
|
148
|
+
transcriptMeta: agentTurnTranscriptMeta(content),
|
|
148
149
|
});
|
|
149
150
|
if (accepted === false) throw new Error('agent follow-up was not accepted');
|
|
150
151
|
registry.assertAdmission(descriptor.id, cancelEpoch);
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { providerNativePdf } from '../../../runtime/agent/orchestrator/providers/registry.mjs';
|
|
13
13
|
import { cancelBackgroundTasks } from '../../../runtime/shared/background-tasks.mjs';
|
|
14
14
|
import { isAgentModeSession } from '../../../runtime/agent/orchestrator/session/agent-mode.mjs';
|
|
15
|
+
import { isAgentHomeSessionId } from '../../../runtime/agent/orchestrator/session/agent-home.mjs';
|
|
15
16
|
import { recognisedAgentRoomSlash } from '../../../tui/app/slash-commands.mjs';
|
|
16
17
|
import { promptContentText } from '../../../tui/session/queue-helpers.mjs';
|
|
17
18
|
|
|
@@ -38,6 +39,17 @@ function abortsAgentTurn(id, state, hasAgentSession) {
|
|
|
38
39
|
);
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
/** A prompt the user typed: not an agent's send (`sender: 'lead'`), a hidden
|
|
43
|
+
* wake, a routine fire or any other runtime-made turn. */
|
|
44
|
+
export function isUserTurn(options = {}) {
|
|
45
|
+
return (
|
|
46
|
+
(options.mode || 'prompt') === 'prompt' &&
|
|
47
|
+
options.kickoff !== true &&
|
|
48
|
+
options.isMeta !== true &&
|
|
49
|
+
options.transcriptMeta?.sender !== 'lead'
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
41
53
|
export function createSessionTurnCalls(ctx) {
|
|
42
54
|
const { log, readStoredGoal, listStoredActiveGoalSessionIds, hasAgentSession, sessionResult, advanceForCaller } = ctx;
|
|
43
55
|
const { retainUnwatched } = ctx.retention;
|
|
@@ -88,6 +100,13 @@ export function createSessionTurnCalls(ctx) {
|
|
|
88
100
|
const accepted = await Promise.resolve(target.call(entry.runtime, intake.prompt, submissionOptions));
|
|
89
101
|
if (accepted === true) {
|
|
90
102
|
entry.reservedOnly = false;
|
|
103
|
+
if (isAgentHomeSessionId(id) && isUserTurn(submissionOptions)) {
|
|
104
|
+
// The user spoke in this agent's home: its round trips with other
|
|
105
|
+
// sessions count from zero again, so a capped thread wakes again.
|
|
106
|
+
void import('../../../session-runtime/agent-home-delivery.mjs')
|
|
107
|
+
.then(({ resetAgentTaskRounds }) => resetAgentTaskRounds(id))
|
|
108
|
+
.catch((error) => log(`round reset of ${id} failed: ${error?.message || error}`));
|
|
109
|
+
}
|
|
91
110
|
}
|
|
92
111
|
const step = settleAction(entry, 'headless session submit');
|
|
93
112
|
log(`session submit session=${id} accepted=${accepted === true}`);
|
package/src/tui/dist/index.mjs
CHANGED
|
@@ -42465,8 +42465,19 @@ var CODE_KINDS = new Map(
|
|
|
42465
42465
|
quota_exhausted: ["quota_exceeded", "quota_exhausted", "usage_limit_reached", "provider_accounts_exhausted"],
|
|
42466
42466
|
context_overflow: ["context_length_exceeded", "context_window_exceeded", "model_context_window_exceeded"],
|
|
42467
42467
|
request_too_large: ["request_too_large", "payload_too_large", "request_entity_too_large"],
|
|
42468
|
-
|
|
42469
|
-
|
|
42468
|
+
// Google names a rejected or expired key with an ErrorInfo reason on an
|
|
42469
|
+
// INVALID_ARGUMENT 400; the reason outranks the envelope status.
|
|
42470
|
+
auth: [
|
|
42471
|
+
"invalid_api_key",
|
|
42472
|
+
"authentication_error",
|
|
42473
|
+
"unauthenticated",
|
|
42474
|
+
"unauthorized",
|
|
42475
|
+
"invalid_authentication",
|
|
42476
|
+
"api_key_invalid",
|
|
42477
|
+
"api_key_expired",
|
|
42478
|
+
"access_token_expired"
|
|
42479
|
+
],
|
|
42480
|
+
permission: ["permission_error", "permission_denied", "forbidden", "service_disabled", "api_key_service_blocked"],
|
|
42470
42481
|
overloaded: [
|
|
42471
42482
|
"server_is_overloaded",
|
|
42472
42483
|
"overloaded_error",
|
|
@@ -42504,6 +42515,7 @@ var CODE_KINDS = new Map(
|
|
|
42504
42515
|
"not_found",
|
|
42505
42516
|
"not_found_error",
|
|
42506
42517
|
"model_not_found",
|
|
42518
|
+
"model_not_supported",
|
|
42507
42519
|
"unsupported_parameter"
|
|
42508
42520
|
]
|
|
42509
42521
|
}).flatMap(([kind, codes]) => codes.map((code) => [code, kind]))
|
|
@@ -42854,6 +42866,42 @@ function resetLabel(resetAt) {
|
|
|
42854
42866
|
const time = `${pad(reset.getHours())}:${pad(reset.getMinutes())}`;
|
|
42855
42867
|
return reset.toDateString() === (/* @__PURE__ */ new Date()).toDateString() ? time : `${reset.getMonth() + 1}/${reset.getDate()} ${time}`;
|
|
42856
42868
|
}
|
|
42869
|
+
var MODEL_REFUSAL_KINDS = /* @__PURE__ */ new Set(["invalid_request", "permission", "unknown"]);
|
|
42870
|
+
var MODEL_UNAVAILABLE_CODES = /* @__PURE__ */ new Set(["model_not_found", "model_not_supported"]);
|
|
42871
|
+
var MODEL_REFUSAL_PREDICATE = "(?:(?:is|was|has been)\\s+)?(?:not found|does not exist|doesn'?t exist|not (?:supported|available)|(?:currently\\s+)?unavailable|no longer (?:available|supported)|deprecated|retired|removed)\\b";
|
|
42872
|
+
var SENTENCE_START = "(?:^|[.:;!]\\s+)";
|
|
42873
|
+
var MODEL_UNAVAILABLE_RE = new RegExp(
|
|
42874
|
+
[
|
|
42875
|
+
// "The model `x` does not exist", "models/x is not found", Vertex
|
|
42876
|
+
// "Publisher Model `…` was not found", Ollama `model "x" not found`.
|
|
42877
|
+
`${SENTENCE_START}(?:(?:the|this|that|requested|selected|publisher)\\s+)*models?(?:\\/\\S+|\\s+[\`'"]?[\\w./:@-]+[\`'"]?)?\\s+${MODEL_REFUSAL_PREDICATE}`,
|
|
42878
|
+
// OpenAI "The 'gpt-x' model is not supported when using Codex …".
|
|
42879
|
+
`${SENTENCE_START}(?:the\\s+)?[\`'"][^\`'"\\n]+[\`'"]\\s+model\\s+${MODEL_REFUSAL_PREDICATE}`,
|
|
42880
|
+
`${SENTENCE_START}(?:unknown|invalid|unsupported) model\\b`,
|
|
42881
|
+
// OpenRouter: no provider serves this model id.
|
|
42882
|
+
`${SENTENCE_START}no endpoints found for [\\w.-]+\\/[\\w.:-]+`,
|
|
42883
|
+
"\\bis not a valid model\\b",
|
|
42884
|
+
"^model: \\S+$"
|
|
42885
|
+
].join("|"),
|
|
42886
|
+
"im"
|
|
42887
|
+
);
|
|
42888
|
+
var MODEL_UNAVAILABLE_COPY = [
|
|
42889
|
+
"model-unavailable",
|
|
42890
|
+
"This model isn't available for this account.",
|
|
42891
|
+
"Choose another model, or check the model and endpoint in Providers."
|
|
42892
|
+
];
|
|
42893
|
+
var NOT_FOUND_SUMMARY = "The provider couldn't find the requested model or endpoint.";
|
|
42894
|
+
var TOOL_SCHEMA_RE = /invalid schema for (?:function|tool)\b|\btools\.\d+\.(?:custom\.)?input_schema\b|\bfunction_declarations\[\d+\]\.parameters\b|\btools\[\d+\]\.function\.parameters\b|\binvalid (?:tool|function) (?:schema|parameters|definition)\b/i;
|
|
42895
|
+
var TOOL_SCHEMA_COPY = [
|
|
42896
|
+
"tool-schema",
|
|
42897
|
+
"The provider rejected a tool definition.",
|
|
42898
|
+
"Disable the tool or MCP server named in the details, then try again."
|
|
42899
|
+
];
|
|
42900
|
+
function firstReadableLine(clean3) {
|
|
42901
|
+
const lines = clean3.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
42902
|
+
const first = lines.find((line) => !/^at\s|^\{|^<!doctype|^<html/i.test(line)) || "";
|
|
42903
|
+
return first && !/^[{[]|^<|(?:API|HTTP)\s+[45]\d\d.*[<{]/i.test(first) ? first : "";
|
|
42904
|
+
}
|
|
42857
42905
|
var LEGACY_TEXT_KINDS = [
|
|
42858
42906
|
[/The provider usage limit was reached|quota.*(?:hit|exceed)|usage limit/i, "quota_exhausted"],
|
|
42859
42907
|
[/rate[_ -]?limit|too many requests/i, "rate_limited"]
|
|
@@ -42921,6 +42969,14 @@ function describeError(value) {
|
|
|
42921
42969
|
kind = "image-size";
|
|
42922
42970
|
summary = "An attached image exceeds the provider limit.";
|
|
42923
42971
|
recovery = "Reduce the image dimensions or number of images, then try again.";
|
|
42972
|
+
} else if (clean3 === MODEL_UNAVAILABLE_COPY[1] || MODEL_REFUSAL_KINDS.has(descriptor.kind) && (MODEL_UNAVAILABLE_CODES.has(code) || MODEL_UNAVAILABLE_RE.test(clean3))) {
|
|
42973
|
+
[kind, summary, recovery] = MODEL_UNAVAILABLE_COPY;
|
|
42974
|
+
} else if (clean3 === TOOL_SCHEMA_COPY[1] || ["invalid_request", "unknown"].includes(descriptor.kind) && TOOL_SCHEMA_RE.test(clean3)) {
|
|
42975
|
+
[kind, summary, recovery] = TOOL_SCHEMA_COPY;
|
|
42976
|
+
} else if (clean3 === NOT_FOUND_SUMMARY || MODEL_REFUSAL_KINDS.has(descriptor.kind) && (status === 404 || status === 410)) {
|
|
42977
|
+
kind = "not-found";
|
|
42978
|
+
summary = firstReadableLine(clean3) || NOT_FOUND_SUMMARY;
|
|
42979
|
+
recovery = MODEL_UNAVAILABLE_COPY[2];
|
|
42924
42980
|
} else if (descriptor.kind === "unknown" && /payload too large|request (?:body )?too large|The request exceeds the size limit/i.test(clean3)) {
|
|
42925
42981
|
[kind, summary, recovery] = KIND_COPY.request_too_large;
|
|
42926
42982
|
} else if (copy) {
|
|
@@ -42943,9 +42999,7 @@ function describeError(value) {
|
|
|
42943
42999
|
summary = "The provider rejected this request.";
|
|
42944
43000
|
recovery = "Review the request details before trying again.";
|
|
42945
43001
|
} else {
|
|
42946
|
-
|
|
42947
|
-
const first = lines.find((line) => !/^at\s|^\{|^<!doctype|^<html/i.test(line)) || "";
|
|
42948
|
-
summary = first && !/^[{[]|^<|(?:API|HTTP)\s+[45]\d\d.*[<{]/i.test(first) ? first : "Something went wrong.";
|
|
43002
|
+
summary = firstReadableLine(clean3) || "Something went wrong.";
|
|
42949
43003
|
}
|
|
42950
43004
|
summary = summary.replace(/\s+/g, " ").trim() || "Something went wrong.";
|
|
42951
43005
|
if (summary.length > SUMMARY_LIMIT) summary = `${summary.slice(0, SUMMARY_LIMIT - 1).trimEnd()}\u2026`;
|
|
@@ -43157,7 +43211,9 @@ function typedStreamFailureText(error, text) {
|
|
|
43157
43211
|
}
|
|
43158
43212
|
function presentErrorText(error, options = {}) {
|
|
43159
43213
|
const presentation = describeError(error);
|
|
43160
|
-
if (["image-size", "payload-size", "request"].includes(presentation.kind))
|
|
43214
|
+
if (["image-size", "payload-size", "request", "model-unavailable", "tool-schema"].includes(presentation.kind)) {
|
|
43215
|
+
return presentation.summary;
|
|
43216
|
+
}
|
|
43161
43217
|
const kindLine = hasTypedEvidence(error) ? KIND_LINES[presentation.providerKind] : null;
|
|
43162
43218
|
if (kindLine && presentation.kind !== "unknown") {
|
|
43163
43219
|
return typeof kindLine === "function" ? kindLine(presentation) : kindLine;
|
|
@@ -50766,7 +50822,12 @@ var ANTIGRAVITY_MODELS = Object.freeze([
|
|
|
50766
50822
|
low: "gemini-3.1-pro-low",
|
|
50767
50823
|
high: "gemini-3.1-pro-high"
|
|
50768
50824
|
}),
|
|
50769
|
-
|
|
50825
|
+
// The gateway serves Argon only through per-tier ids; bare `gemini-4-argon` is a 404.
|
|
50826
|
+
fallbackModel("gemini-4-argon", "Gemini 4 Argon", "gemini-pro", 1048576, {
|
|
50827
|
+
low: "gemini-4-argon-low",
|
|
50828
|
+
medium: "gemini-4-argon-medium",
|
|
50829
|
+
high: "gemini-4-argon-high"
|
|
50830
|
+
}),
|
|
50770
50831
|
fallbackModel("claude-opus-4-6-thinking", "Claude Opus 4.6 (Thinking)", null, 25e4, "claude-opus-4-6-thinking", [
|
|
50771
50832
|
"low",
|
|
50772
50833
|
"medium",
|
|
@@ -61755,7 +61816,7 @@ function finishBackup(dataDir2, backupDir, reason) {
|
|
|
61755
61816
|
restoreLookupCache.delete(normalizeDataDir(dataDir2));
|
|
61756
61817
|
legacyEvidenceCache.delete(normalizeDataDir(dataDir2));
|
|
61757
61818
|
}
|
|
61758
|
-
function backupUserData(dataDir2, reason = "snapshot") {
|
|
61819
|
+
function backupUserData(dataDir2, reason = "snapshot", { dirs = [] } = {}) {
|
|
61759
61820
|
if (skipBackups()) return { dir: null, copied: [] };
|
|
61760
61821
|
if (!dataDir2 || !existsSync10(dataDir2)) return { dir: null, copied: [] };
|
|
61761
61822
|
const scopeDir = scopeDirFor(dataDir2);
|
|
@@ -61765,7 +61826,7 @@ function backupUserData(dataDir2, reason = "snapshot") {
|
|
|
61765
61826
|
const src = join11(dataDir2, rel);
|
|
61766
61827
|
if (existsSync10(src)) copyTree(src, join11(backupDir, rel), copied);
|
|
61767
61828
|
}
|
|
61768
|
-
for (const rel of USER_DATA_DIRS) {
|
|
61829
|
+
for (const rel of [...USER_DATA_DIRS, ...dirs]) {
|
|
61769
61830
|
const src = join11(dataDir2, rel);
|
|
61770
61831
|
if (existsSync10(src)) copyTree(src, join11(backupDir, rel), copied);
|
|
61771
61832
|
}
|
|
@@ -59,10 +59,9 @@ export function createNoticeSurface({ getState, set, isDisposed, pushItem, repla
|
|
|
59
59
|
// A schedule result posted into a home thread (routine-result.mjs).
|
|
60
60
|
...(options.routine ? { routine: options.routine } : {}),
|
|
61
61
|
...(options.room ? { room: options.room } : {}),
|
|
62
|
-
// A room user row's files, in the fields a prompt row draws them from
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
: {}),
|
|
62
|
+
// A room user row's files, in the fields a prompt row draws them from;
|
|
63
|
+
// a task report's or member speech's returned files likewise.
|
|
64
|
+
...(Array.isArray(options.attachments) && options.attachments.length ? { attachments: options.attachments } : {}),
|
|
66
65
|
...(userRow && Array.isArray(options.images) && options.images.length ? { images: options.images } : {}),
|
|
67
66
|
// A held request of an unattended run (human-gate/held-message.mjs).
|
|
68
67
|
...(options.heldRequest ? { heldRequest: options.heldRequest } : {}),
|
|
@@ -131,7 +131,10 @@ export function createSessionRouteApi(bag) {
|
|
|
131
131
|
// is the only place the display is touched once the write has started.
|
|
132
132
|
const originGeneration = runtime.sessionGeneration;
|
|
133
133
|
const owned = () => runtime.sessionGeneration === originGeneration;
|
|
134
|
-
|
|
134
|
+
// A conditional fill (only when the route is still empty) may not apply, so
|
|
135
|
+
// it never previews: the runtime's answer is what gets published.
|
|
136
|
+
const onlyIfEmpty = routeOpts.onlyIfEmpty === true;
|
|
137
|
+
const preview = onlyIfEmpty ? null : optimisticRoutePatch(previewedRequest(routeOpts), getState());
|
|
135
138
|
// Preview immediately, serialize persistence without dropping a later
|
|
136
139
|
// click. Earlier completions cannot replace the newest visible choice.
|
|
137
140
|
if (!getState().commandBusy) routeLocked = true;
|
|
@@ -159,7 +162,13 @@ export function createSessionRouteApi(bag) {
|
|
|
159
162
|
const applyToCurrentSession = routeOpts.applyToCurrentSession === true;
|
|
160
163
|
const keepMainModel = routeOpts.keepMainModel !== false;
|
|
161
164
|
const sessionOnly = routeOpts.sessionOnly === true;
|
|
162
|
-
const {
|
|
165
|
+
const {
|
|
166
|
+
applyToCurrentSession: _drop,
|
|
167
|
+
keepMainModel: _keep,
|
|
168
|
+
sessionOnly: _scope,
|
|
169
|
+
onlyIfEmpty: _fill,
|
|
170
|
+
...requested
|
|
171
|
+
} = routeOpts;
|
|
163
172
|
let nextRoute = requested;
|
|
164
173
|
if (sessionOnly) {
|
|
165
174
|
const completed = completeSessionOnlyRequest(requested, previousRoute);
|
|
@@ -175,6 +184,7 @@ export function createSessionRouteApi(bag) {
|
|
|
175
184
|
applyToCurrentSession,
|
|
176
185
|
keepMainModel,
|
|
177
186
|
...(sessionOnly ? { sessionOnly } : {}),
|
|
187
|
+
...(onlyIfEmpty ? { onlyIfEmpty } : {}),
|
|
178
188
|
...(originGeneration !== undefined ? { originGeneration } : {}),
|
|
179
189
|
switchEstablished: true,
|
|
180
190
|
deferUntilNextTurn: true,
|
|
@@ -300,7 +310,8 @@ export function createSessionRouteApi(bag) {
|
|
|
300
310
|
saveLeadPersona: async (text) => runtime.saveLeadPersona?.(text) ?? '',
|
|
301
311
|
getLeadAgentBody: () => runtime.getLeadAgentBody?.() ?? '',
|
|
302
312
|
saveLeadAgentBody: async (text) => runtime.saveLeadAgentBody?.(text) ?? '',
|
|
303
|
-
getLeadStatus: () =>
|
|
313
|
+
getLeadStatus: () =>
|
|
314
|
+
runtime.getLeadStatus?.() ?? { created: null, name: '', avatar: null, homeChatted: false, route: null },
|
|
304
315
|
saveLeadIdentity: async (payload) => runtime.saveLeadIdentity?.(payload) ?? null,
|
|
305
316
|
setLeadCreated: async (created, description) => runtime.setLeadCreated?.(created, description) ?? null,
|
|
306
317
|
saveAgentDefinition: async (payload) => runtime.saveAgentDefinition?.(payload) ?? null,
|
|
@@ -123,6 +123,8 @@ export function createTranscriptIntake({ getState, flags, pushItem, patchItem, t
|
|
|
123
123
|
...routineTriggerField(extra),
|
|
124
124
|
...(extra && typeof extra.sender === 'string' && extra.sender ? { sender: extra.sender } : {}),
|
|
125
125
|
...(extra && typeof extra.device === 'string' && extra.device ? { device: extra.device } : {}),
|
|
126
|
+
// Delivered into the running turn (steering): the desktop row's read mark.
|
|
127
|
+
...(extra?.steered === true ? { steered: true } : {}),
|
|
126
128
|
// Byte-free attachment metadata (name/mime/size) from the queue entry —
|
|
127
129
|
// lets the desktop transcript render image chips without ever carrying
|
|
128
130
|
// base64 payloads through snapshots.
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
* Providers report a call's exact output tokens only when it ends (the usage
|
|
7
7
|
* delta), so mid-stream the count is the runtime's own token estimate of the
|
|
8
8
|
* text and reasoning streamed so far (token-estimate.mjs, measured against a
|
|
9
|
-
* real tokenizer at +6.5% aggregate bias). The clock starts
|
|
10
|
-
*
|
|
9
|
+
* real tokenizer at +6.5% aggregate bias). The clock starts when the provider
|
|
10
|
+
* request starts (markLiveCallRequestStart), the wait for the first token
|
|
11
|
+
* included, the same span as the persisted speed and the usage ledger; with no
|
|
12
|
+
* request-start mark it starts at the first visible text/reasoning token.
|
|
11
13
|
*
|
|
12
14
|
* Published at most every LIVE_CALL_PUBLISH_MS with its own sample time, so the
|
|
13
15
|
* reader divides tokens by (sample time - start) and a pause between samples
|
|
@@ -25,11 +27,16 @@ function publish({ getState, set }, liveCall) {
|
|
|
25
27
|
if (spinner) set({ spinner: { ...spinner, liveCall } });
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/** The provider request of the next call started: its clock starts here. */
|
|
31
|
+
export function markLiveCallRequestStart(stream, now = Date.now()) {
|
|
32
|
+
stream.liveCallRequestAt = now;
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
/** A text or reasoning chunk of the streaming call arrived. */
|
|
29
36
|
export function noteLiveCallText(stream, chunk, now = Date.now()) {
|
|
30
37
|
const text = String(chunk ?? '');
|
|
31
38
|
if (!text || stream.liveCallWithdrawn) return;
|
|
32
|
-
const call = stream.liveCall || { startedAt: now, text: '', publishedAt: 0 };
|
|
39
|
+
const call = stream.liveCall || { startedAt: stream.liveCallRequestAt ?? now, text: '', publishedAt: 0 };
|
|
33
40
|
stream.liveCall = call;
|
|
34
41
|
call.text += text;
|
|
35
42
|
if (call.publishedAt && now - call.publishedAt < LIVE_CALL_PUBLISH_MS) return;
|
|
@@ -52,5 +59,6 @@ export function endLiveCall(stream) {
|
|
|
52
59
|
|
|
53
60
|
export function startNextLiveCall(stream) {
|
|
54
61
|
stream.liveCallWithdrawn = false;
|
|
62
|
+
stream.liveCallRequestAt = null;
|
|
55
63
|
endLiveCall(stream);
|
|
56
64
|
}
|
package/src/tui/session/turn.mjs
CHANGED
|
@@ -54,7 +54,13 @@ import {
|
|
|
54
54
|
startLiveTail,
|
|
55
55
|
} from './turn-tool-cards.mjs';
|
|
56
56
|
import { startQuietWatch } from './turn-quiet.mjs';
|
|
57
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
endLiveCall,
|
|
59
|
+
markLiveCallRequestStart,
|
|
60
|
+
noteLiveCallText,
|
|
61
|
+
startNextLiveCall,
|
|
62
|
+
withdrawLiveCall,
|
|
63
|
+
} from './turn-live-call.mjs';
|
|
58
64
|
|
|
59
65
|
// A usage limit is exactly a spent quota, a plan-gated feature or a billing
|
|
60
66
|
// refusal; overloads, rate limits and server faults recover by waiting.
|
|
@@ -204,8 +210,9 @@ function steeringItemExtras(steeringMeta) {
|
|
|
204
210
|
? { messageId: steeringMeta.messageId }
|
|
205
211
|
: {}),
|
|
206
212
|
// Queue mode + execution provenance: a task notification is rendered as
|
|
207
|
-
// a tool card, never as an injected user bubble.
|
|
208
|
-
|
|
213
|
+
// a tool card, never as an injected user bubble. Anything else is a
|
|
214
|
+
// message the model read inside its running turn (the row's read mark).
|
|
215
|
+
...(steeringMeta?.mode === 'task-notification' ? { mode: 'task-notification' } : { steered: true }),
|
|
209
216
|
...(steeringMeta?.execution && typeof steeringMeta.execution === 'object'
|
|
210
217
|
? { execution: steeringMeta.execution }
|
|
211
218
|
: {}),
|
|
@@ -427,6 +434,9 @@ export function toolHandlers(ctx) {
|
|
|
427
434
|
export function streamHandlers(ctx) {
|
|
428
435
|
const { isCurrentTurn, stream } = ctx;
|
|
429
436
|
return {
|
|
437
|
+
onProviderSendStarted: () => {
|
|
438
|
+
if (isCurrentTurn()) markLiveCallRequestStart(stream);
|
|
439
|
+
},
|
|
430
440
|
onStageChange: async (stage, detail = null) => {
|
|
431
441
|
if (!isCurrentTurn()) return;
|
|
432
442
|
// A runtime notice (e.g. a tool the provider left out of the request)
|