toolroll 0.9.63 → 0.9.65
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/CHANGELOG.md +51 -0
- package/README.md +15 -5
- package/dist/acp-agents.d.ts +43 -0
- package/dist/acp-agents.js +62 -0
- package/dist/acp-attest.d.ts +44 -0
- package/dist/acp-attest.js +269 -0
- package/dist/acp-check.d.ts +28 -0
- package/dist/acp-check.js +410 -0
- package/dist/acp-client.d.ts +163 -0
- package/dist/acp-client.js +738 -0
- package/dist/acp-inspect.d.ts +23 -0
- package/dist/acp-inspect.js +109 -0
- package/dist/agent-board.d.ts +19 -6
- package/dist/agent-board.js +30 -9
- package/dist/agent-fence.d.ts +50 -2
- package/dist/agent-fence.js +157 -10
- package/dist/agent-pulse.js +9 -2
- package/dist/agent-state-words.d.ts +19 -0
- package/dist/agent-state-words.js +20 -0
- package/dist/agent-state.d.ts +65 -0
- package/dist/agent-state.js +229 -0
- package/dist/agentconfig.js +36 -13
- package/dist/agents-board.d.ts +34 -2
- package/dist/agents-board.js +110 -1
- package/dist/approval-rules-ui.js +2 -2
- package/dist/assignment-delivery.d.ts +14 -0
- package/dist/assignment-delivery.js +13 -0
- package/dist/assignment.js +13 -0
- package/dist/attest.js +7 -0
- package/dist/backup-ui.js +2 -2
- package/dist/browser/THIRD_PARTY_NOTICES.txt +48 -0
- package/dist/browser/terminal.css +37 -0
- package/dist/browser/terminal.js +117 -0
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +42 -38
- package/dist/browser-shell.js +6 -3
- package/dist/browser-workspace.d.ts +235 -1
- package/dist/browser-workspace.js +60 -0
- package/dist/builder.d.ts +6 -1
- package/dist/builder.js +34 -13
- package/dist/chat-actions.d.ts +13 -1
- package/dist/chat-actions.js +197 -15
- package/dist/chat-ask.d.ts +4 -0
- package/dist/chat-ask.js +14 -0
- package/dist/chat-channel.js +20 -0
- package/dist/chat-continuity.js +5 -4
- package/dist/chat-decide.d.ts +0 -14
- package/dist/chat-decide.js +4 -1
- package/dist/chat-delivery.d.ts +9 -0
- package/dist/chat-delivery.js +45 -6
- package/dist/chat-messages.d.ts +8 -0
- package/dist/chat-messages.js +36 -4
- package/dist/check-levels-ui.js +2 -2
- package/dist/checkout-proof.d.ts +28 -0
- package/dist/checkout-proof.js +62 -0
- package/dist/claim.d.ts +12 -0
- package/dist/claim.js +19 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +4 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +21 -2
- package/dist/coding-ui.js +6 -4
- package/dist/console-instance.d.ts +124 -0
- package/dist/console-instance.js +337 -0
- package/dist/contracts/chat-actions.d.ts +16 -0
- package/dist/contracts/chat-actions.js +4 -0
- package/dist/contracts/chat-content.d.ts +19 -0
- package/dist/contracts/chat-content.js +6 -0
- package/dist/contracts/console-api.d.ts +12 -4
- package/dist/contracts/console-api.js +12 -4
- package/dist/contracts/flow-card.d.ts +4 -0
- package/dist/contracts/flow-card.js +3 -0
- package/dist/contracts/flow.d.ts +46 -0
- package/dist/contracts/flow.js +11 -2
- package/dist/contracts/lead-tools.d.ts +92 -0
- package/dist/contracts/lead-tools.js +13 -0
- package/dist/contracts/provider.d.ts +11 -1
- package/dist/contracts/provider.js +1 -1
- package/dist/contracts/route.d.ts +76 -1
- package/dist/contracts/route.js +1 -1
- package/dist/contracts/store-json.d.ts +2 -0
- package/dist/control-setup.d.ts +1 -1
- package/dist/control-ui.js +2 -2
- package/dist/converse.d.ts +16 -0
- package/dist/converse.js +32 -4
- package/dist/demo-chat.js +4 -4
- package/dist/demo.js +2 -2
- package/dist/desktop-update-gate.js +6 -0
- package/dist/desktop-update.d.ts +1 -1
- package/dist/discord-chat.js +4 -1
- package/dist/doctor.js +1 -1
- package/dist/egress-bridge.d.ts +17 -0
- package/dist/egress-bridge.js +111 -0
- package/dist/egress.d.ts +119 -0
- package/dist/egress.js +423 -0
- package/dist/exec.d.ts +78 -0
- package/dist/exec.js +367 -9
- package/dist/export-ui.js +2 -2
- package/dist/flow-engine.js +24 -5
- package/dist/flow-gallery-ui.js +2 -2
- package/dist/flow-gallery.js +27 -8
- package/dist/flow-share.js +16 -5
- package/dist/flow-triggers.d.ts +77 -8
- package/dist/flow-triggers.js +517 -70
- package/dist/flows-cli.js +8 -2
- package/dist/flows-ui.d.ts +0 -2
- package/dist/flows-ui.js +52 -4
- package/dist/flows.d.ts +4 -0
- package/dist/flows.js +9 -1
- package/dist/html.d.ts +9 -0
- package/dist/html.js +11 -0
- package/dist/invoke.d.ts +17 -0
- package/dist/invoke.js +217 -21
- package/dist/keys.d.ts +18 -14
- package/dist/keys.js +5 -0
- package/dist/lead-capabilities.js +3 -2
- package/dist/lead-contract.js +2 -0
- package/dist/lead-doors.d.ts +2 -0
- package/dist/lead-doors.js +7 -0
- package/dist/lead-follow.d.ts +2 -0
- package/dist/lead-follow.js +58 -2
- package/dist/lead-progress.js +1 -0
- package/dist/lead-queue-runtime.d.ts +46 -0
- package/dist/lead-queue-runtime.js +191 -0
- package/dist/lead-queue.d.ts +104 -0
- package/dist/lead-queue.js +187 -0
- package/dist/lead-sweep.d.ts +67 -0
- package/dist/lead-sweep.js +99 -0
- package/dist/lead-tools.d.ts +22 -0
- package/dist/lead-tools.js +152 -1
- package/dist/lead.d.ts +13 -5
- package/dist/lead.js +89 -29
- package/dist/limits-ui.d.ts +8 -1
- package/dist/limits-ui.js +26 -0
- package/dist/live-bus.d.ts +8 -0
- package/dist/live-bus.js +40 -4
- package/dist/live-detail.d.ts +27 -0
- package/dist/live-detail.js +57 -0
- package/dist/live-notes.d.ts +20 -0
- package/dist/live-notes.js +47 -0
- package/dist/live-records.d.ts +140 -0
- package/dist/live-records.js +935 -0
- package/dist/live-terminal.d.ts +258 -0
- package/dist/live-terminal.js +649 -0
- package/dist/live.d.ts +38 -27
- package/dist/live.js +142 -124
- package/dist/mcp-oauth.d.ts +6 -3
- package/dist/mcp-oauth.js +8 -4
- package/dist/memory-pass.js +2 -2
- package/dist/mobile-viewport.d.ts +5 -1
- package/dist/mobile-viewport.js +18 -2
- package/dist/model-catalog.js +4 -0
- package/dist/monitoring-ui.js +2 -2
- package/dist/needs-you.d.ts +1 -1
- package/dist/needs-you.js +11 -4
- package/dist/operate.d.ts +2 -0
- package/dist/operate.js +275 -17
- package/dist/passwordless.d.ts +23 -0
- package/dist/passwordless.js +26 -0
- package/dist/peek-cli.d.ts +12 -4
- package/dist/peek-cli.js +19 -11
- package/dist/phase-routing.js +10 -3
- package/dist/planner-source.d.ts +3 -0
- package/dist/planner-source.js +14 -0
- package/dist/planner.d.ts +2 -1
- package/dist/planner.js +7 -1
- package/dist/policy-ui.js +2 -2
- package/dist/policy.d.ts +1 -20
- package/dist/policy.js +29 -2
- package/dist/project-delete-ui.d.ts +12 -0
- package/dist/project-delete-ui.js +41 -9
- package/dist/project-delete.js +2 -2
- package/dist/project-memory.d.ts +3 -1
- package/dist/project-memory.js +57 -25
- package/dist/project-tools.d.ts +5 -3
- package/dist/project-tools.js +12 -9
- package/dist/provider-auth.d.ts +4 -3
- package/dist/provider-auth.js +5 -4
- package/dist/provider-connection.d.ts +2 -1
- package/dist/provider-connection.js +5 -0
- package/dist/provider.d.ts +25 -2
- package/dist/provider.js +63 -9
- package/dist/pull-request-ui.js +2 -2
- package/dist/push.js +1 -1
- package/dist/quick-start.d.ts +24 -0
- package/dist/quick-start.js +127 -0
- package/dist/release.d.ts +3 -0
- package/dist/release.js +14 -8
- package/dist/request-budget-ui.js +2 -2
- package/dist/result-review.d.ts +1 -1
- package/dist/result-review.js +9 -3
- package/dist/retention-ui.js +2 -2
- package/dist/retention.js +10 -1
- package/dist/run-efficiency.d.ts +73 -0
- package/dist/run-efficiency.js +228 -0
- package/dist/runner.d.ts +5 -1
- package/dist/runner.js +22 -1
- package/dist/scope.d.ts +170 -5
- package/dist/scope.js +251 -31
- package/dist/scout-net.d.ts +4 -1
- package/dist/scout-net.js +37 -12
- package/dist/scout.d.ts +20 -6
- package/dist/scout.js +27 -3
- package/dist/serve.js +247 -40
- package/dist/server/chat.d.ts +1 -1
- package/dist/server/chat.js +122 -31
- package/dist/server/chrome.d.ts +6 -1
- package/dist/server/chrome.js +18 -7
- package/dist/server/console.css +52 -38
- package/dist/server/flows.js +38 -8
- package/dist/server/guards.d.ts +1 -0
- package/dist/server/guards.js +23 -9
- package/dist/server/http.d.ts +7 -0
- package/dist/server/http.js +3 -2
- package/dist/server/live.d.ts +34 -1
- package/dist/server/live.js +39 -17
- package/dist/server/pages-assets.js +5 -0
- package/dist/server/pages.js +90 -13
- package/dist/server/people-tokens.d.ts +3 -0
- package/dist/server/people-tokens.js +55 -17
- package/dist/server/remote-hooks.js +12 -6
- package/dist/server/remote.d.ts +2 -1
- package/dist/server/remote.js +14 -5
- package/dist/server/render-chat.d.ts +12 -3
- package/dist/server/render-chat.js +47 -16
- package/dist/server/render-pages.d.ts +4 -1
- package/dist/server/render-pages.js +5 -4
- package/dist/server/render-people.d.ts +3 -2
- package/dist/server/render-people.js +3 -2
- package/dist/server/render-results.d.ts +18 -2
- package/dist/server/render-results.js +37 -28
- package/dist/server/render-settings.js +6 -5
- package/dist/server/render-tasks.d.ts +35 -10
- package/dist/server/render-tasks.js +110 -27
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.js +2 -1
- package/dist/server/route-table.d.ts +3 -0
- package/dist/server/route-table.js +46 -5
- package/dist/server/runtime.d.ts +33 -2
- package/dist/server/session.d.ts +25 -1
- package/dist/server/session.js +18 -4
- package/dist/server/settings.js +121 -10
- package/dist/server/sweeps.d.ts +4 -0
- package/dist/server/sweeps.js +58 -0
- package/dist/server/task-views.d.ts +2 -1
- package/dist/server/task-views.js +96 -6
- package/dist/server/tasks.js +320 -74
- package/dist/server/terminals.d.ts +31 -0
- package/dist/server/terminals.js +365 -0
- package/dist/setup-guide.js +3 -2
- package/dist/slack-chat.js +4 -1
- package/dist/spend-ui.js +3 -3
- package/dist/spend.js +2 -1
- package/dist/steer-capabilities.d.ts +32 -0
- package/dist/steer-capabilities.js +60 -0
- package/dist/steer-controls.d.ts +14 -0
- package/dist/steer-controls.js +36 -0
- package/dist/steer-status.js +2 -2
- package/dist/storage-ui.js +4 -4
- package/dist/store-baseline.d.ts +1 -1
- package/dist/store-baseline.js +1 -1
- package/dist/store.d.ts +430 -15
- package/dist/store.js +1041 -52
- package/dist/subagent-desk.js +1 -1
- package/dist/summary.js +3 -0
- package/dist/task-source.d.ts +58 -0
- package/dist/task-source.js +93 -0
- package/dist/team-leads.js +1 -1
- package/dist/teams-chat.js +4 -1
- package/dist/telegram-lead.d.ts +3 -0
- package/dist/telegram-lead.js +44 -7
- package/dist/telegram.d.ts +11 -2
- package/dist/telegram.js +51 -17
- package/dist/terminal-catalog.d.ts +11 -0
- package/dist/terminal-catalog.js +129 -0
- package/dist/text-limits.d.ts +2 -0
- package/dist/text-limits.js +2 -0
- package/dist/tool-broker.d.ts +2 -0
- package/dist/tool-broker.js +1 -0
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +13 -3
- package/dist/tools-ui.js +2 -2
- package/dist/webhook-limits.d.ts +23 -0
- package/dist/webhook-limits.js +30 -0
- package/dist/webhook-readers.d.ts +56 -0
- package/dist/webhook-readers.js +138 -0
- package/dist/webhook-signing.d.ts +27 -0
- package/dist/webhook-signing.js +119 -0
- package/dist/work-index.d.ts +29 -0
- package/dist/work-index.js +16 -2
- package/dist/workspace-revision.js +3 -1
- package/package.json +11 -2
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type AssignmentSnapshot } from "./assignment.js";
|
|
2
|
+
import { type Store } from "./store.js";
|
|
3
|
+
import { type StopRequest } from "./task-control.js";
|
|
4
|
+
export declare const SWEEP_VERDICTS: readonly ["fixed", "not reproducible", "blocked", "done"];
|
|
5
|
+
export type SweepVerdict = typeof SWEEP_VERDICTS[number];
|
|
6
|
+
/** The line every sweep child's brief asks for, appended to the shared rules. */
|
|
7
|
+
export declare const VERDICT_RULE = "Start your handoff's conclusion with one line: `Verdict: fixed`, `Verdict: not reproducible`, `Verdict: blocked` or `Verdict: done`, then ` \u2014 ` and one sentence why (the root cause, what you tried, or what blocks it).";
|
|
8
|
+
/** A conclusion's verdict line, read strictly. */
|
|
9
|
+
export declare function verdictOf(conclusion: string | null | undefined): {
|
|
10
|
+
verdict: SweepVerdict;
|
|
11
|
+
why: string;
|
|
12
|
+
} | null;
|
|
13
|
+
export type SweepRow = {
|
|
14
|
+
ordinal: number;
|
|
15
|
+
label: string;
|
|
16
|
+
/** The child's family root: its identity in the sweep. */
|
|
17
|
+
task: string;
|
|
18
|
+
/** The task the family is on now (a revision of the child, after one): what an act on this row acts on. */
|
|
19
|
+
active: string;
|
|
20
|
+
state: AssignmentSnapshot["state"] | "missing";
|
|
21
|
+
detail: string;
|
|
22
|
+
verdict: {
|
|
23
|
+
verdict: SweepVerdict;
|
|
24
|
+
why: string;
|
|
25
|
+
} | null;
|
|
26
|
+
/** The child's result, when it has one. */
|
|
27
|
+
result: {
|
|
28
|
+
taskId: string;
|
|
29
|
+
runId: number;
|
|
30
|
+
} | null;
|
|
31
|
+
};
|
|
32
|
+
export type SweepTable = {
|
|
33
|
+
id: number;
|
|
34
|
+
title: string;
|
|
35
|
+
repo: string;
|
|
36
|
+
maxParallel: number;
|
|
37
|
+
rows: SweepRow[];
|
|
38
|
+
counts: {
|
|
39
|
+
settled: number;
|
|
40
|
+
working: number;
|
|
41
|
+
total: number;
|
|
42
|
+
byVerdict: Partial<Record<SweepVerdict, number>>;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/** A sweep as its table shows it; null when there is no such sweep or this reader may not see its project. */
|
|
46
|
+
export declare function sweepTable(store: Store, id: number, now: Date, repos: readonly string[], root?: string): SweepTable | null;
|
|
47
|
+
/** "8 of 11 settled — 5 fixed, 2 not reproducible, 1 blocked": the sweep in one line. */
|
|
48
|
+
export declare function sweepLine(table: SweepTable): string;
|
|
49
|
+
/** Not ready yet: working, being checked, or waiting on a decision — what "cancel the rest" acts on. */
|
|
50
|
+
export declare const SWEEP_OPEN: ReadonlySet<SweepRow["state"]>;
|
|
51
|
+
/** One open item exactly as it stands now: its active task, state, attempt (a running build to stop) and last change. */
|
|
52
|
+
export type SweepOpenItem = {
|
|
53
|
+
label: string;
|
|
54
|
+
task: string;
|
|
55
|
+
state: string;
|
|
56
|
+
run: number | null;
|
|
57
|
+
at: string | null;
|
|
58
|
+
scope: string | null;
|
|
59
|
+
};
|
|
60
|
+
/** Exactly what "cancel the rest" would act on now; any change makes a card or a form for it stale. */
|
|
61
|
+
export declare function sweepOpen(store: Store, table: SweepTable, now: Date): SweepOpenItem[];
|
|
62
|
+
export declare const sweepOpenDigest: (open: readonly SweepOpenItem[]) => string;
|
|
63
|
+
/**
|
|
64
|
+
* Cancel the rest: a running build is stopped through the ordinary stop (process-exit safeguards and all); anything
|
|
65
|
+
* else is cancelled. Every refusal is said, never swallowed. The caller has proved `open` is what stands now.
|
|
66
|
+
*/
|
|
67
|
+
export declare function cancelSweepRest(store: Store, actor: string, open: readonly SweepOpenItem[], now: Date, via: StopRequest["via"]): string;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead fan-out (docs/plans/lead-fan-out.md): a sweep's table and verdicts, read from facts — never a model.
|
|
3
|
+
*
|
|
4
|
+
* Each row is a child's assignment (the same state words the board uses), its verdict, and its result. The verdict is
|
|
5
|
+
* the first line of the child's conclusion, `Verdict: fixed | not reproducible | blocked | done — why`, which the
|
|
6
|
+
* sweep's brief asks for. It is read strictly: anything else reads as no verdict, never a guess.
|
|
7
|
+
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
9
|
+
import { withActor } from "./actor.js";
|
|
10
|
+
import { assignmentOf } from "./assignment.js";
|
|
11
|
+
import { chatTaskRun } from "./chat-task-actions.js";
|
|
12
|
+
import { verifiedAuthor } from "./store.js";
|
|
13
|
+
import { requestTaskStop } from "./task-control.js";
|
|
14
|
+
export const SWEEP_VERDICTS = ["fixed", "not reproducible", "blocked", "done"];
|
|
15
|
+
/** The line every sweep child's brief asks for, appended to the shared rules. */
|
|
16
|
+
export const VERDICT_RULE = "Start your handoff's conclusion with one line: `Verdict: fixed`, `Verdict: not reproducible`, `Verdict: blocked` or `Verdict: done`, then ` — ` and one sentence why (the root cause, what you tried, or what blocks it).";
|
|
17
|
+
/** A conclusion's verdict line, read strictly. */
|
|
18
|
+
export function verdictOf(conclusion) {
|
|
19
|
+
if (typeof conclusion !== "string")
|
|
20
|
+
return null;
|
|
21
|
+
const first = conclusion.split("\n", 1)[0].trim();
|
|
22
|
+
const match = /^Verdict:\s*(fixed|not reproducible|not-reproducible|blocked|done)\s*(?:—|–|-|:)\s*(.{1,300})$/i.exec(first);
|
|
23
|
+
if (match === null)
|
|
24
|
+
return null;
|
|
25
|
+
const verdict = match[1].toLowerCase().replace("-", " ");
|
|
26
|
+
return SWEEP_VERDICTS.includes(verdict) ? { verdict, why: match[2].trim() } : null;
|
|
27
|
+
}
|
|
28
|
+
const SETTLED = new Set(["ready-to-check", "complete", "cancelled", "needs-decision", "missing"]);
|
|
29
|
+
/** A sweep as its table shows it; null when there is no such sweep or this reader may not see its project. */
|
|
30
|
+
export function sweepTable(store, id, now, repos, root) {
|
|
31
|
+
const sweep = store.getSweep(id);
|
|
32
|
+
if (sweep === null || !repos.includes(sweep.repo))
|
|
33
|
+
return null;
|
|
34
|
+
const rows = store.sweepTasks(id).map(child => {
|
|
35
|
+
const assignment = assignmentOf(store, child.rootTask, now, { principal: "operator", repos }, root);
|
|
36
|
+
const run = assignment?.receipt?.runId ?? null;
|
|
37
|
+
const resultTask = assignment?.receipt?.taskId ?? null;
|
|
38
|
+
const conclusion = run === null ? null : store.getRun(run)?.handoff ?? null;
|
|
39
|
+
return {
|
|
40
|
+
ordinal: child.ordinal, label: child.label, task: child.rootTask, active: assignment?.activeTaskId ?? child.rootTask,
|
|
41
|
+
state: assignment?.state ?? "missing", detail: assignment?.detail ?? "This task is gone.",
|
|
42
|
+
verdict: verdictOf(conclusion),
|
|
43
|
+
result: run === null || resultTask === null ? null : { taskId: resultTask, runId: run },
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
const byVerdict = {};
|
|
47
|
+
for (const row of rows)
|
|
48
|
+
if (row.verdict !== null)
|
|
49
|
+
byVerdict[row.verdict.verdict] = (byVerdict[row.verdict.verdict] ?? 0) + 1;
|
|
50
|
+
const settled = rows.filter(row => SETTLED.has(row.state)).length;
|
|
51
|
+
return { id, title: sweep.title, repo: sweep.repo, maxParallel: sweep.maxParallel, rows,
|
|
52
|
+
counts: { settled, working: rows.length - settled, total: rows.length, byVerdict } };
|
|
53
|
+
}
|
|
54
|
+
/** "8 of 11 settled — 5 fixed, 2 not reproducible, 1 blocked": the sweep in one line. */
|
|
55
|
+
export function sweepLine(table) {
|
|
56
|
+
const verdicts = SWEEP_VERDICTS.filter(one => (table.counts.byVerdict[one] ?? 0) > 0).map(one => `${table.counts.byVerdict[one]} ${one}`);
|
|
57
|
+
return `${table.counts.settled} of ${table.counts.total} settled${verdicts.length === 0 ? "" : ` — ${verdicts.join(", ")}`}`;
|
|
58
|
+
}
|
|
59
|
+
/** Not ready yet: working, being checked, or waiting on a decision — what "cancel the rest" acts on. */
|
|
60
|
+
export const SWEEP_OPEN = new Set(["working", "checking", "needs-decision"]);
|
|
61
|
+
/** Exactly what "cancel the rest" would act on now; any change makes a card or a form for it stale. */
|
|
62
|
+
export function sweepOpen(store, table, now) {
|
|
63
|
+
return table.rows.filter(row => SWEEP_OPEN.has(row.state)).map(row => ({
|
|
64
|
+
label: row.label, task: row.active, state: row.state, run: chatTaskRun(store, row.active, "stop", now), at: store.getTask(row.active)?.updatedAt ?? null,
|
|
65
|
+
// The scope's identity too: a goal rewritten in between makes a card or form for it stale (Codex sweep r2).
|
|
66
|
+
scope: store.getScope(row.active)?.digest ?? null,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
export const sweepOpenDigest = (open) => createHash("sha256").update(JSON.stringify(open)).digest("hex");
|
|
70
|
+
/**
|
|
71
|
+
* Cancel the rest: a running build is stopped through the ordinary stop (process-exit safeguards and all); anything
|
|
72
|
+
* else is cancelled. Every refusal is said, never swallowed. The caller has proved `open` is what stands now.
|
|
73
|
+
*/
|
|
74
|
+
export function cancelSweepRest(store, actor, open, now, via) {
|
|
75
|
+
let cancelled = 0, stopping = 0;
|
|
76
|
+
const refused = [];
|
|
77
|
+
for (const item of open) {
|
|
78
|
+
if (item.run !== null) {
|
|
79
|
+
const stop = requestTaskStop(store, { taskId: item.task, runId: item.run, by: verifiedAuthor(actor), via }, now);
|
|
80
|
+
if (stop.ok)
|
|
81
|
+
stopping += 1;
|
|
82
|
+
else
|
|
83
|
+
refused.push(`${item.label} (${stop.detail})`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const result = withActor({ account: actor, lead: false }, () => store.cancelTask(item.task, now));
|
|
87
|
+
if (result.ok)
|
|
88
|
+
cancelled += 1;
|
|
89
|
+
else
|
|
90
|
+
refused.push(`${item.label} (${String(result.reason ?? "refused")})`);
|
|
91
|
+
}
|
|
92
|
+
const parts = [`Cancelled ${cancelled} item${cancelled === 1 ? "" : "s"}.`];
|
|
93
|
+
if (stopping > 0)
|
|
94
|
+
parts.push(`Stop requested for ${stopping} running build${stopping === 1 ? "" : "s"}: ${stopping === 1 ? "it stops" : "they stop"} at the next safe point; cancel ${stopping === 1 ? "it" : "them"} from the task page once stopped.`);
|
|
95
|
+
if (refused.length > 0)
|
|
96
|
+
parts.push(`Not cancelled: ${refused.join("; ")}.`);
|
|
97
|
+
parts.push("Finished results stay.");
|
|
98
|
+
return parts.join(" ");
|
|
99
|
+
}
|
package/dist/lead-tools.d.ts
CHANGED
|
@@ -48,6 +48,12 @@ export type LeadToolContext = {
|
|
|
48
48
|
checkedCapabilities?: Map<string, number>;
|
|
49
49
|
/** Records this turn's one question to its owner; false when it already asked one. Absent: this surface cannot ask. */
|
|
50
50
|
ask?: (question: string, options: readonly string[]) => boolean;
|
|
51
|
+
/** This turn's tool discovery (find_tools): how many searches it made and which deferred tools it found, which the
|
|
52
|
+
* conversation loop advertises from its next request. Absent (a direct call outside a turn): nothing to add to. */
|
|
53
|
+
findTools?: {
|
|
54
|
+
searches: number;
|
|
55
|
+
found: Set<string>;
|
|
56
|
+
};
|
|
51
57
|
};
|
|
52
58
|
export type LeadToolResult = {
|
|
53
59
|
ok: true;
|
|
@@ -105,6 +111,22 @@ export declare const ISO_STAMP_RULE: RegExp;
|
|
|
105
111
|
* through a confirmed card into the one authenticated edit transaction.
|
|
106
112
|
*/
|
|
107
113
|
export declare function agentsOver(store: Store, taskId: string, now: Date): Record<string, unknown> | null;
|
|
114
|
+
/**
|
|
115
|
+
* The tools every request advertises (docs/plans/lead-deferred-tools.md): the ones most replies use, and every tool a
|
|
116
|
+
* guard requires read in an earlier step (search_project_memory before any proposal, get_capabilities before work that
|
|
117
|
+
* needs an agent, get_result before propose_review, get_decision before propose_answer). The rest are found with
|
|
118
|
+
* find_tools and advertised from the next request of the same reply.
|
|
119
|
+
*/
|
|
120
|
+
export declare const LEAD_CORE_TOOLS: ReadonlySet<string>;
|
|
121
|
+
/** At most this many find_tools searches per reply, results per search, and bytes of found tool schemas per reply. */
|
|
122
|
+
export declare const FIND_TOOLS_PER_TURN = 3;
|
|
123
|
+
export declare const FIND_TOOLS_MAX_RESULTS = 6;
|
|
124
|
+
export declare const FIND_TOOLS_SCHEMA_BYTES = 48000;
|
|
125
|
+
/** The deferred tools a query finds, best first: an exact name, then words in the name, keywords and description. */
|
|
126
|
+
export declare function findLeadTools(query: string): {
|
|
127
|
+
name: string;
|
|
128
|
+
summary: string;
|
|
129
|
+
}[];
|
|
108
130
|
/** The lead's tools, in the order the model is shown them: each one's inputSchema is its contract, derived. */
|
|
109
131
|
export declare const LEAD_TOOLS: LeadTool[];
|
|
110
132
|
/** A unified diff, file by file, with each file's added and removed lines. */
|
package/dist/lead-tools.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sweepLine, sweepTable } from "./lead-sweep.js";
|
|
1
2
|
import { TEXT_LIMITS } from "./text-limits.js";
|
|
2
3
|
import { connectionsOf, oneClickOf } from "./mcp-connect.js";
|
|
3
4
|
import { checkLevelFromWords, isCheckLevel } from "./check-levels.js";
|
|
@@ -372,7 +373,102 @@ export function agentsOver(store, taskId, now) {
|
|
|
372
373
|
choices: Object.fromEntries(PHASES.filter(phase => phase !== "review").map(phase => [ROLE_WORD[phase], choices[phase].filter(one => one.selectable).map(one => ({ provider: one.provider, model: one.model, current: one.current }))])),
|
|
373
374
|
};
|
|
374
375
|
}
|
|
376
|
+
/**
|
|
377
|
+
* The tools every request advertises (docs/plans/lead-deferred-tools.md): the ones most replies use, and every tool a
|
|
378
|
+
* guard requires read in an earlier step (search_project_memory before any proposal, get_capabilities before work that
|
|
379
|
+
* needs an agent, get_result before propose_review, get_decision before propose_answer). The rest are found with
|
|
380
|
+
* find_tools and advertised from the next request of the same reply.
|
|
381
|
+
*/
|
|
382
|
+
export const LEAD_CORE_TOOLS = new Set([
|
|
383
|
+
"find_tools", "get_brief", "recap", "list_repos", "get_project_context", "search_project_memory", "get_capabilities",
|
|
384
|
+
"list_tasks", "get_task", "get_result", "get_diff", "get_check_log", "list_decisions", "get_decision",
|
|
385
|
+
"get_actions", "get_action_status", "propose_action", "propose_task", "propose_scope", "propose_steer",
|
|
386
|
+
"propose_answer", "propose_review", "remember", "ask_owner", "commit_to",
|
|
387
|
+
// The lead's queue verbs: basic, and small enough that deferring them saves almost nothing.
|
|
388
|
+
"queue", "propose_next", "propose_reserve", "propose_hold", "propose_unhold", "propose_cancel",
|
|
389
|
+
// Task and result acts a reply uses often (links to a control, a result's images and evidence, the task's own acts):
|
|
390
|
+
// small, so deferral is kept for the large, occasional families (flows, subagents, sweeps, project tools).
|
|
391
|
+
"show_control", "get_controls", "get_result_images", "get_acceptance_evidence", "offer_approval", "propose_task_action", "propose_agents",
|
|
392
|
+
"get_agents", "propose_dependency_repair",
|
|
393
|
+
]);
|
|
394
|
+
/** Words a deferred tool is found by, beyond its name and description. */
|
|
395
|
+
const LEAD_TOOL_KEYWORDS = {
|
|
396
|
+
propose_flow: ["flow", "automation", "workflow", "schedule", "trigger", "every", "when", "email", "inbox", "sort", "follow-up", "nudge"],
|
|
397
|
+
get_flows: ["flow", "automation", "workflow", "running", "card"],
|
|
398
|
+
get_flow_insights: ["flow", "insights", "stats", "how flows"],
|
|
399
|
+
propose_subagent: ["subagent", "assistant", "rep", "support", "sales", "teammate", "rules", "persona"],
|
|
400
|
+
get_subagents: ["subagent", "assistant", "teammate", "rules"],
|
|
401
|
+
propose_sweep: ["sweep", "fan-out", "many", "parallel", "batch", "each", "list of"],
|
|
402
|
+
get_sweep: ["sweep", "fan-out", "batch", "table", "verdict"],
|
|
403
|
+
propose_sweep_cancel: ["sweep", "cancel", "stop the rest"],
|
|
404
|
+
get_models: ["model", "models", "provider", "price"],
|
|
405
|
+
get_project_tools: ["tools", "mcp", "server", "integration", "connect", "stripe", "notion", "linear", "sentry", "jira"],
|
|
406
|
+
get_integrations: ["integration", "slack", "telegram", "discord", "teams", "email", "connected"],
|
|
407
|
+
get_skills: ["skill", "skills", "guide"],
|
|
408
|
+
get_project_knowledge: ["knowledge", "docs", "notes", "memory"],
|
|
409
|
+
get_task_conversation: ["conversation", "chat", "history", "messages"],
|
|
410
|
+
release_commitment: ["promise", "commitment", "release", "forget"],
|
|
411
|
+
get_person: ["person", "people", "who", "member", "teammate"],
|
|
412
|
+
};
|
|
413
|
+
/** At most this many find_tools searches per reply, results per search, and bytes of found tool schemas per reply. */
|
|
414
|
+
export const FIND_TOOLS_PER_TURN = 3;
|
|
415
|
+
export const FIND_TOOLS_MAX_RESULTS = 6;
|
|
416
|
+
export const FIND_TOOLS_SCHEMA_BYTES = 48_000;
|
|
417
|
+
const FIND_TOOLS_NONE = "Nothing matched. The other tools cover flows, subagents, sweeps, agents and models, project tools and integrations, controls and settings pages, holds and the queue, task actions (retry, stop, merge), result images and evidence, people, and promises — search again with one of those words.";
|
|
418
|
+
const MAKE_WORDS = new Set(["make", "add", "create", "set", "draft", "new", "start", "change", "edit", "build", "run", "hold", "cancel", "release", "move", "switch", "turn"]);
|
|
419
|
+
const LOOK_WORDS = new Set(["show", "list", "see", "what", "which", "how", "check", "read", "look", "find", "open", "where"]);
|
|
420
|
+
/** The deferred tools a query finds, best first: an exact name, then words in the name, keywords and description. */
|
|
421
|
+
export function findLeadTools(query) {
|
|
422
|
+
// A plural matches its singular ("sweeps" finds sweep tools).
|
|
423
|
+
const words = query.toLowerCase().split(/[^a-z0-9-]+/).filter(one => one.length >= 3).map(one => one.length > 4 && one.endsWith("s") && !one.endsWith("ss") ? one.slice(0, -1) : one);
|
|
424
|
+
const exact = query.trim().toLowerCase();
|
|
425
|
+
const scored = LEAD_TOOLS.filter(tool => !LEAD_CORE_TOOLS.has(tool.name)).map(tool => {
|
|
426
|
+
const name = tool.name.toLowerCase(), keywords = (LEAD_TOOL_KEYWORDS[tool.name] ?? []).join(" ").toLowerCase();
|
|
427
|
+
const description = tool.description.toLowerCase();
|
|
428
|
+
let score = name === exact ? 100 : 0;
|
|
429
|
+
for (const word of words)
|
|
430
|
+
score += (name.includes(word) ? 5 : 0) + (keywords.includes(word) ? 3 : 0) + (description.includes(word) ? 1 : 0);
|
|
431
|
+
// What the person wants done leans the match: making or changing something → a proposal; looking → a read.
|
|
432
|
+
if (score > 0 && words.some(word => MAKE_WORDS.has(word)))
|
|
433
|
+
score += name.startsWith("propose_") ? 4 : 0;
|
|
434
|
+
if (score > 0 && words.some(word => LOOK_WORDS.has(word)))
|
|
435
|
+
score += name.startsWith("get_") || name === "show_control" ? 4 : 0;
|
|
436
|
+
return { tool, score };
|
|
437
|
+
}).filter(one => one.score > 0).sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name));
|
|
438
|
+
return scored.slice(0, FIND_TOOLS_MAX_RESULTS).map(({ tool }) => ({ name: tool.name, summary: summaryLine(tool.description) }));
|
|
439
|
+
}
|
|
440
|
+
/** A description's first sentence, at most 160 characters. */
|
|
441
|
+
function summaryLine(description) {
|
|
442
|
+
const first = /^(.+?[.!?])(\s|$)/.exec(description)?.[1] ?? description;
|
|
443
|
+
return first.length <= 160 ? first : `${first.slice(0, 157).trimEnd()}…`;
|
|
444
|
+
}
|
|
375
445
|
const LEAD_TOOL_HANDLERS = {
|
|
446
|
+
find_tools: {
|
|
447
|
+
// Counted before the call is read, so an invalid search still uses one of the reply's three.
|
|
448
|
+
prepare: (ctx, raw) => { if (ctx.findTools !== undefined)
|
|
449
|
+
ctx.findTools.searches++; return raw; },
|
|
450
|
+
description: "Find the lead's other tools by what you want to do — flows, subagents, sweeps, agents and models, project tools and integrations, controls and settings pages, holds and the queue, task actions (retry, stop, merge), result images and evidence, people, promises. Search before saying something can't be done. Matching tools become available from your next step in this reply: call them then, not in the same step.",
|
|
451
|
+
handle: (ctx, args) => {
|
|
452
|
+
const state = ctx.findTools;
|
|
453
|
+
if (state === undefined)
|
|
454
|
+
return { ok: false, message: "find_tools works inside a conversation reply." };
|
|
455
|
+
if (state.searches > FIND_TOOLS_PER_TURN)
|
|
456
|
+
return { ok: false, message: `You have searched ${FIND_TOOLS_PER_TURN} times this reply. Use the tools you found, or answer with what you have.` };
|
|
457
|
+
const bytesOf = (name) => Buffer.byteLength(JSON.stringify(LEAD_TOOL_SCHEMAS.find(one => one.name === name) ?? {}), "utf8");
|
|
458
|
+
let used = [...state.found].reduce((sum, name) => sum + bytesOf(name), 0);
|
|
459
|
+
const tools = [];
|
|
460
|
+
for (const one of findLeadTools(args.query)) {
|
|
461
|
+
if (!state.found.has(one.name)) {
|
|
462
|
+
if (used + bytesOf(one.name) > FIND_TOOLS_SCHEMA_BYTES)
|
|
463
|
+
continue;
|
|
464
|
+
used += bytesOf(one.name);
|
|
465
|
+
state.found.add(one.name);
|
|
466
|
+
}
|
|
467
|
+
tools.push(one);
|
|
468
|
+
}
|
|
469
|
+
return { ok: true, body: { tools, next: tools.length === 0 ? FIND_TOOLS_NONE : "These are available from your next step in this reply: call one then." } };
|
|
470
|
+
},
|
|
471
|
+
},
|
|
376
472
|
get_brief: {
|
|
377
473
|
description: 'Read current tasks, decisions, results and project knowledge from the local database. No model or mutation.',
|
|
378
474
|
handle: (ctx, args) => {
|
|
@@ -1235,7 +1331,8 @@ const LEAD_TOOL_HANDLERS = {
|
|
|
1235
1331
|
const thread = ctx.store.liveLeadThreadFor(ctx.who.name, { kind: "task", key: root });
|
|
1236
1332
|
if (thread === null || thread.ceilingDigest !== ctx.who.ceilingDigest)
|
|
1237
1333
|
return { ok: true, body: { task: root, messages: [], notice: "No conversation about this task yet." } };
|
|
1238
|
-
|
|
1334
|
+
// What the lead reads of a task's conversation is what it has been told: admitted messages only (v128).
|
|
1335
|
+
const messages = ctx.store.listLeadHistory(thread.id, limit).map(one => ({ from: one.role === "operator" ? "operator" : "lead", text: one.text.length > 1_200 ? `${one.text.slice(0, 1_200)}…` : one.text, at: one.createdAt }));
|
|
1239
1336
|
return { ok: true, body: { task: root, title: family?.root.title ?? null, messages, notice: messages.length === limit ? "Only the most recent messages are shown." : null } };
|
|
1240
1337
|
},
|
|
1241
1338
|
},
|
|
@@ -1640,6 +1737,60 @@ const LEAD_TOOL_HANDLERS = {
|
|
|
1640
1737
|
return { ok: true, body: { proposal: id, kind: "task", repo: args["repo"], deliverable: report ? "report" : "branch", planning: report ? "not needed for a scout" : planning, awaiting: "the operator's confirmation" } };
|
|
1641
1738
|
},
|
|
1642
1739
|
},
|
|
1740
|
+
propose_sweep: {
|
|
1741
|
+
description: "Several independent items under ONE shared rule set (a bug sweep, a batch of small fixes): 2-20 items, each becomes its own task in its own worktree, started with one approval, at most max_parallel (default 3) at once, each reporting a verdict into one table. brief holds the shared rules every item gets (e.g. reproduce first; 'not reproducible' is a valid result; prove the fix); each item is only its own report. Not for one task, and not for steps that depend on each other.",
|
|
1742
|
+
handle: (ctx, args) => {
|
|
1743
|
+
const repo = repoPathOf(ctx.who, args["repo"]);
|
|
1744
|
+
if (repo === null)
|
|
1745
|
+
return { ok: false, message: "repo must be one of the ids from list_repos" };
|
|
1746
|
+
const items = Array.isArray(args["items"]) ? args["items"] : [];
|
|
1747
|
+
for (const one of [{ title: args["title"], goal: args["brief"] }, ...items.map(item => ({ title: item["title"], goal: item["item"] }))]) {
|
|
1748
|
+
if (typeof one.title !== "string" || typeof one.goal !== "string")
|
|
1749
|
+
return { ok: false, message: "each title, the brief and each item are text" };
|
|
1750
|
+
const bad = validateTaskText({ title: one.title, goal: one.goal, outOfScope: null });
|
|
1751
|
+
if (bad !== null)
|
|
1752
|
+
return { ok: false, message: bad.message };
|
|
1753
|
+
if ([one.title, one.goal].some(text => typeof text === "string" && scanForSecrets(text).length > 0))
|
|
1754
|
+
return { ok: false, message: "Task text cannot contain credentials." };
|
|
1755
|
+
}
|
|
1756
|
+
const acceptance = readAcceptanceArg(args["acceptance"]);
|
|
1757
|
+
if (acceptance === null)
|
|
1758
|
+
return { ok: false, message: "acceptance is required: at least one criterion with an id, statement, and evidence kinds (shared by every item)" };
|
|
1759
|
+
try {
|
|
1760
|
+
const action = prepareSharedAction(ctx.store, ctx.who, "sweep_file", { repo, title: args["title"], brief: args["brief"], items: items.map(item => ({ title: item["title"], item: item["item"] })),
|
|
1761
|
+
acceptance, maxParallel: typeof args["max_parallel"] === "number" ? args["max_parallel"] : 3 }, ctx.evidenceRoot, ctx.now);
|
|
1762
|
+
const id = ctx.draft("action", { ...action });
|
|
1763
|
+
return id === null ? tooMany() : { ok: true, body: { proposal: id, label: action.title, awaiting: "human review in the secure confirmation screen", executed: false } };
|
|
1764
|
+
}
|
|
1765
|
+
catch (error) {
|
|
1766
|
+
return { ok: false, message: error instanceof Error ? error.message : "That sweep couldn't be drafted." };
|
|
1767
|
+
}
|
|
1768
|
+
},
|
|
1769
|
+
},
|
|
1770
|
+
get_sweep: {
|
|
1771
|
+
description: "A sweep's table as facts: each item's state, its verdict (fixed, not reproducible, blocked, done, or none yet) and its result, plus the one-line count. Read this, don't poll each task.",
|
|
1772
|
+
handle: (ctx, args) => {
|
|
1773
|
+
const table = sweepTable(ctx.store, Number(args["sweep"]), ctx.now, ctx.who.repos, ctx.evidenceRoot);
|
|
1774
|
+
if (table === null)
|
|
1775
|
+
return { ok: false, message: "No such sweep in your projects." };
|
|
1776
|
+
return { ok: true, body: { sweep: table.id, title: table.title, line: sweepLine(table), table: `/sweeps/${table.id}`, maxParallel: table.maxParallel,
|
|
1777
|
+
items: table.rows.map(row => ({ item: row.ordinal + 1, label: row.label, task: row.task, state: row.state, detail: row.detail.slice(0, 300),
|
|
1778
|
+
verdict: row.verdict?.verdict ?? null, why: row.verdict?.why ?? null, result: row.result })) } };
|
|
1779
|
+
},
|
|
1780
|
+
},
|
|
1781
|
+
propose_sweep_cancel: {
|
|
1782
|
+
description: "Cancel every item of a sweep that isn't ready yet (finished results stay); one confirmation. To steer, cancel or retry ONE item, use that task's own actions.",
|
|
1783
|
+
handle: (ctx, args) => {
|
|
1784
|
+
try {
|
|
1785
|
+
const action = prepareSharedAction(ctx.store, ctx.who, "sweep_cancel_rest", { sweep: Number(args["sweep"]) }, ctx.evidenceRoot, ctx.now);
|
|
1786
|
+
const id = ctx.draft("action", { ...action });
|
|
1787
|
+
return id === null ? tooMany() : { ok: true, body: { proposal: id, label: action.title, awaiting: "human confirmation", executed: false } };
|
|
1788
|
+
}
|
|
1789
|
+
catch (error) {
|
|
1790
|
+
return { ok: false, message: error instanceof Error ? error.message : "That couldn't be drafted." };
|
|
1791
|
+
}
|
|
1792
|
+
},
|
|
1793
|
+
},
|
|
1643
1794
|
propose_next: {
|
|
1644
1795
|
description: "Move a task to its queue column front; intervening queue changes invalidate confirmation.",
|
|
1645
1796
|
handle: (ctx, args) => {
|
package/dist/lead.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ export type LeadTurnInput = {
|
|
|
27
27
|
queuedMessageId?: number;
|
|
28
28
|
/** Called inside turn admission. A failed queue fence rolls admission back. */
|
|
29
29
|
onAdmitted?: (turn: number) => void;
|
|
30
|
+
/** A personal queue claim (lead-queue.ts) this turn runs: with `queuedMessageId`, the queued message of the person's
|
|
31
|
+
* own thread this turn binds; admission lets it through the person's backlog (store.openLeadTurn). */
|
|
32
|
+
queueClaim?: {
|
|
33
|
+
message: number;
|
|
34
|
+
runner: string;
|
|
35
|
+
generation: number;
|
|
36
|
+
};
|
|
30
37
|
/** Safe, server-authored context for this turn only. Kept out of the
|
|
31
38
|
* visible thread so a task-scoped composer still reads like a normal
|
|
32
39
|
* conversation. */
|
|
@@ -67,8 +74,8 @@ export type LeadTurnInput = {
|
|
|
67
74
|
};
|
|
68
75
|
/** Why a chat's standing changed under a turn: each has its own plain words (LEAD_CHANNEL_COPY). */
|
|
69
76
|
export type LeadChannelProblem = "unpaired" | "not-approver" | "projects-changed" | "projects-unreadable" | "member-changed" | "access-changed";
|
|
70
|
-
export type LeadRefusal = "empty-message" | "secret-in-message" | "secret-in-context" | "standing" | "unpriced" | "ceiling-changed" | "not-yours" | "thread-closed" | "latched" | "concurrent" | "daily-cap" | "session-exhausted" | "session-ended" | "over-budget" | "monthly-budget" | "policy" | "invalid-request" | "request-changed" | "channel";
|
|
71
|
-
export type LeadFailure = "provider-error" | "timeout" | "malformed-reply" | "secret-refused" | "latched" | "revoked" | "superseded";
|
|
77
|
+
export type LeadRefusal = "empty-message" | "secret-in-message" | "secret-in-context" | "standing" | "unpriced" | "ceiling-changed" | "not-yours" | "thread-closed" | "latched" | "concurrent" | "backlog" | "daily-cap" | "session-exhausted" | "session-ended" | "over-budget" | "monthly-budget" | "policy" | "invalid-request" | "request-changed" | "channel";
|
|
78
|
+
export type LeadFailure = "provider-error" | "timeout" | "malformed-reply" | "secret-refused" | "latched" | "revoked" | "superseded" | "over-reservation";
|
|
72
79
|
export type LeadTurnOutcome = {
|
|
73
80
|
ok: true;
|
|
74
81
|
replayed?: false;
|
|
@@ -115,16 +122,17 @@ export declare const LEAD_FAILURE_COPY: {
|
|
|
115
122
|
readonly tooLongUnknownCost: string;
|
|
116
123
|
readonly lostUnknownCost: "The chat provider stopped responding partway through, and the cost isn't known, so chat is paused. Nothing it proposed was kept. Confirm the cost on the Chat page to turn chat back on.";
|
|
117
124
|
readonly unreadableUnknownCost: "The chat provider sent back an answer that couldn't be read, and its cost isn't known, so chat is paused. Nothing it proposed was kept. Confirm the cost on the Chat page to turn chat back on.";
|
|
125
|
+
readonly overReserved: "This reply reported more use than was set aside for it, so its cost is counted as unknown and chat is paused. Nothing it proposed was kept. Confirm the cost on the Chat page to turn chat back on.";
|
|
118
126
|
readonly empty: "The lead sent back an empty answer. Nothing was kept. Send your message again.";
|
|
119
127
|
readonly unusable: "The lead's answer couldn't be used, so it was thrown away. Nothing was kept. Send your message again.";
|
|
120
128
|
};
|
|
121
129
|
/** A failed turn's saved reason as plain words, for a surface that reads the turn back later (a restart, a delivery retry). */
|
|
122
|
-
export declare function leadFailureText(reason: string | null): string;
|
|
130
|
+
export declare function leadFailureText(reason: string | null, unknownSpend?: boolean): string;
|
|
123
131
|
/** How long a provider that ignored its abort at the turn's deadline is waited for before the turn ends without it.
|
|
124
132
|
* Its process group was already killed at the deadline; this only bounds the wait for the transport to say so. */
|
|
125
133
|
export declare const LEAD_ABORT_GRACE_MS = 5000;
|
|
126
134
|
/** The last messages of the thread as provider-neutral history, newest kept first until the byte cap. */
|
|
127
|
-
export declare function historyFor(store: Store, thread: number, queuedMessageId?: number): LeadHistoryMessage[];
|
|
135
|
+
export declare function historyFor(store: Store, thread: number, queuedMessageId?: number, named?: boolean): LeadHistoryMessage[];
|
|
128
136
|
/** "read 3 · proposed 1 · 2 steps" — counts only, never results (ruling 11). */
|
|
129
|
-
export declare function activitySummary(reads: number, proposals: number, steps: number): string;
|
|
137
|
+
export declare function activitySummary(reads: number, proposals: number, steps: number, cacheShare?: number | null): string;
|
|
130
138
|
export declare function runLeadTurn(input: LeadTurnInput): Promise<LeadTurnOutcome>;
|