@intentic/sandbox-contract 1.317.0 → 1.319.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -6
- package/dist/chores/chores.js +1 -1
- package/dist/chores/chores.js.map +1 -1
- package/dist/chores/probes.js +1 -1
- package/dist/chores/probes.js.map +1 -1
- package/dist/contracts/accounts.contract.d.ts +75 -0
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/accounts.contract.js +10 -1
- package/dist/contracts/accounts.contract.js.map +1 -1
- package/dist/contracts/agent.contract.d.ts +62 -1
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.d.ts +830 -93
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +12 -12
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/ci.contract.d.ts +22 -4
- package/dist/contracts/ci.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.d.ts +38 -0
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.js +2 -0
- package/dist/contracts/device.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +23 -0
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +6 -1
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/extensions.contract.d.ts +12 -0
- package/dist/contracts/extensions.contract.d.ts.map +1 -1
- package/dist/contracts/needs.contract.d.ts +2 -0
- package/dist/contracts/needs.contract.d.ts.map +1 -1
- package/dist/contracts/providers.contract.d.ts +4 -0
- package/dist/contracts/providers.contract.d.ts.map +1 -1
- package/dist/contracts/runner.contract.d.ts +143 -124
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.d.ts +37 -0
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +20 -1
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +4 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +31 -4
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.js +20 -1
- package/dist/contracts/settings.contract.js.map +1 -1
- package/dist/contracts/system.contract.d.ts +102 -464
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.js +2 -12
- package/dist/contracts/system.contract.js.map +1 -1
- package/dist/contracts/translator.contract.d.ts +7 -0
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.js.map +1 -1
- package/dist/contracts/webext.contract.d.ts +38 -0
- package/dist/contracts/webext.contract.d.ts.map +1 -1
- package/dist/contracts/webext.contract.js +3 -0
- package/dist/contracts/webext.contract.js.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +1 -133
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +1 -37
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +21 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +11 -0
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/agent-words.d.ts +1 -0
- package/dist/events/agent-words.d.ts.map +1 -1
- package/dist/events/agent-words.js +1 -1
- package/dist/events/agent-words.js.map +1 -1
- package/dist/events/land-breakage.d.ts.map +1 -1
- package/dist/events/land-breakage.js.map +1 -1
- package/dist/events/resume.d.ts +6 -1
- package/dist/events/resume.d.ts.map +1 -1
- package/dist/events/resume.js +17 -10
- package/dist/events/resume.js.map +1 -1
- package/dist/events/sandbox-notice.d.ts +183 -0
- package/dist/events/sandbox-notice.d.ts.map +1 -0
- package/dist/events/sandbox-notice.js +56 -0
- package/dist/events/sandbox-notice.js.map +1 -0
- package/dist/events/system-events.d.ts +50 -18
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/system-events.js +4 -2
- package/dist/events/system-events.js.map +1 -1
- package/dist/events/transcript.d.ts +24 -0
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +3 -1
- package/dist/events/transcript.js.map +1 -1
- package/dist/front/generated/browser-wire.d.ts +13 -0
- package/dist/front/generated/browser-wire.d.ts.map +1 -1
- package/dist/front/generated/wire.d.ts +4 -0
- package/dist/front/generated/wire.d.ts.map +1 -1
- package/dist/ids/conversation-ids.d.ts +1 -3
- package/dist/ids/conversation-ids.d.ts.map +1 -1
- package/dist/ids/conversation-ids.js +1 -3
- package/dist/ids/conversation-ids.js.map +1 -1
- package/dist/ids/project-dir.d.ts +6 -0
- package/dist/ids/project-dir.d.ts.map +1 -0
- package/dist/ids/project-dir.js +43 -0
- package/dist/ids/project-dir.js.map +1 -0
- package/dist/index.d.ts +11543 -11039
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/models/agent-runtimes.d.ts.map +1 -1
- package/dist/models/agent-runtimes.js +2 -2
- package/dist/models/agent-runtimes.js.map +1 -1
- package/dist/models/model-roles.d.ts +1 -9
- package/dist/models/model-roles.d.ts.map +1 -1
- package/dist/models/model-roles.js +1 -9
- package/dist/models/model-roles.js.map +1 -1
- package/dist/policy/command-classes.d.ts.map +1 -1
- package/dist/policy/command-classes.js +52 -3
- package/dist/policy/command-classes.js.map +1 -1
- package/dist/policy/safety-policy.d.ts +7 -1
- package/dist/policy/safety-policy.d.ts.map +1 -1
- package/dist/policy/safety-policy.js +2 -0
- package/dist/policy/safety-policy.js.map +1 -1
- package/dist/policy/secret-hosts.d.ts +13 -0
- package/dist/policy/secret-hosts.d.ts.map +1 -0
- package/dist/policy/secret-hosts.js +41 -0
- package/dist/policy/secret-hosts.js.map +1 -0
- package/dist/policy/turned-away.d.ts.map +1 -1
- package/dist/policy/turned-away.js +1 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/raw-routes.d.ts +12 -0
- package/dist/protocol/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw-routes.js +5 -0
- package/dist/protocol/raw-routes.js.map +1 -1
- package/dist/protocol/routes.d.ts +2 -6
- package/dist/protocol/routes.d.ts.map +1 -1
- package/dist/protocol/routes.js +2 -3
- package/dist/protocol/routes.js.map +1 -1
- package/dist/protocol/stream-of.d.ts +6 -0
- package/dist/protocol/stream-of.d.ts.map +1 -0
- package/dist/protocol/stream-of.js +4 -0
- package/dist/protocol/stream-of.js.map +1 -0
- package/dist/protocol/vitals.d.ts +8 -0
- package/dist/protocol/vitals.d.ts.map +1 -0
- package/dist/protocol/vitals.js +16 -0
- package/dist/protocol/vitals.js.map +1 -0
- package/dist/schemas/activity.js +1 -1
- package/dist/schemas/activity.js.map +1 -1
- package/dist/schemas/agent.d.ts +25 -2
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +14 -3
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +67 -0
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +36 -0
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/automations.d.ts +20 -0
- package/dist/schemas/automations.d.ts.map +1 -1
- package/dist/schemas/capabilities.d.ts +2 -0
- package/dist/schemas/capabilities.d.ts.map +1 -1
- package/dist/schemas/capabilities.js +34 -4
- package/dist/schemas/capabilities.js.map +1 -1
- package/dist/schemas/ci.d.ts +69 -9
- package/dist/schemas/ci.d.ts.map +1 -1
- package/dist/schemas/ci.js +29 -8
- package/dist/schemas/ci.js.map +1 -1
- package/dist/schemas/context-trim.d.ts +5 -1
- package/dist/schemas/context-trim.d.ts.map +1 -1
- package/dist/schemas/context-trim.js +8 -4
- package/dist/schemas/context-trim.js.map +1 -1
- package/dist/schemas/devices.d.ts +23 -0
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +16 -1
- package/dist/schemas/devices.js.map +1 -1
- package/dist/schemas/environment.d.ts +48 -0
- package/dist/schemas/environment.d.ts.map +1 -1
- package/dist/schemas/environment.js +15 -0
- package/dist/schemas/environment.js.map +1 -1
- package/dist/schemas/extension-updates.d.ts +24 -0
- package/dist/schemas/extension-updates.d.ts.map +1 -1
- package/dist/schemas/git/git.d.ts +13 -0
- package/dist/schemas/git/git.d.ts.map +1 -1
- package/dist/schemas/git/git.js +11 -1
- package/dist/schemas/git/git.js.map +1 -1
- package/dist/schemas/hosts.d.ts +2 -0
- package/dist/schemas/hosts.d.ts.map +1 -1
- package/dist/schemas/hosts.js +2 -1
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/keep-warm.d.ts +4 -0
- package/dist/schemas/keep-warm.d.ts.map +1 -1
- package/dist/schemas/keep-warm.js +15 -5
- package/dist/schemas/keep-warm.js.map +1 -1
- package/dist/schemas/loopback-catch.d.ts +33 -0
- package/dist/schemas/loopback-catch.d.ts.map +1 -0
- package/dist/schemas/loopback-catch.js +20 -0
- package/dist/schemas/loopback-catch.js.map +1 -0
- package/dist/schemas/maintenance.js +1 -1
- package/dist/schemas/maintenance.js.map +1 -1
- package/dist/schemas/needs.d.ts +3 -0
- package/dist/schemas/needs.d.ts.map +1 -1
- package/dist/schemas/needs.js +10 -3
- package/dist/schemas/needs.js.map +1 -1
- package/dist/schemas/personas.d.ts.map +1 -1
- package/dist/schemas/personas.js +6 -3
- package/dist/schemas/personas.js.map +1 -1
- package/dist/schemas/providers/provider-oauth.d.ts +87 -0
- package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/providers/provider-oauth.js +20 -0
- package/dist/schemas/providers/provider-oauth.js.map +1 -1
- package/dist/schemas/secrets.d.ts +66 -0
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js +50 -0
- package/dist/schemas/secrets.js.map +1 -1
- package/dist/schemas/settings-history.d.ts +2 -2
- package/dist/schemas/settings-history.d.ts.map +1 -1
- package/dist/schemas/settings-history.js +2 -0
- package/dist/schemas/settings-history.js.map +1 -1
- package/dist/schemas/settings.d.ts +42 -4
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +26 -8
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/terminal.d.ts +2 -3
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js +12 -4
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/webext.d.ts +3 -0
- package/dist/schemas/webext.d.ts.map +1 -1
- package/dist/schemas/webext.js +1 -0
- package/dist/schemas/webext.js.map +1 -1
- package/dist/schemas/workflows.js +3 -3
- package/dist/schemas/workflows.js.map +1 -1
- package/dist/schemas/workspace/workspace-tree.d.ts +2 -56
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +7 -15
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/definition.d.ts +12 -8
- package/dist/state/definition.d.ts.map +1 -1
- package/dist/state/history-state.d.ts.map +1 -1
- package/dist/state/history-state.js +7 -0
- package/dist/state/history-state.js.map +1 -1
- package/dist/state/runtime-state.d.ts +0 -3
- package/dist/state/runtime-state.d.ts.map +1 -1
- package/dist/state/runtime-state.js +0 -1
- package/dist/state/runtime-state.js.map +1 -1
- package/dist/state/workspace-state.d.ts +0 -5
- package/dist/state/workspace-state.d.ts.map +1 -1
- package/dist/state/workspace-state.js +0 -6
- package/dist/state/workspace-state.js.map +1 -1
- package/dist/text/documents.d.ts +3 -0
- package/dist/text/documents.d.ts.map +1 -1
- package/dist/text/documents.js +14 -0
- package/dist/text/documents.js.map +1 -1
- package/dist/text/transcript-fold.d.ts +4 -3
- package/dist/text/transcript-fold.d.ts.map +1 -1
- package/dist/text/transcript-fold.js +137 -31
- package/dist/text/transcript-fold.js.map +1 -1
- package/dist/webext/index.d.ts +1 -0
- package/dist/webext/index.d.ts.map +1 -1
- package/dist/webext/index.js +1 -0
- package/dist/webext/index.js.map +1 -1
- package/package.json +5 -5
- package/src/chores/chores.ts +2 -2
- package/src/chores/probes.ts +1 -1
- package/src/contracts/accounts.contract.ts +12 -0
- package/src/contracts/agents.contract.ts +13 -13
- package/src/contracts/device.contract.ts +5 -0
- package/src/contracts/endpoints.contract.ts +20 -4
- package/src/contracts/secrets.contract.ts +28 -0
- package/src/contracts/settings.contract.ts +29 -0
- package/src/contracts/system.contract.ts +5 -14
- package/src/contracts/translator.contract.ts +2 -1
- package/src/contracts/webext.contract.ts +7 -1
- package/src/contracts/workspace.contract.ts +0 -49
- package/src/events/agent-events.ts +18 -1
- package/src/events/agent-words.ts +4 -1
- package/src/events/land-breakage.ts +3 -4
- package/src/events/resume.test.ts +13 -2
- package/src/events/resume.ts +25 -12
- package/src/events/sandbox-notice.ts +92 -0
- package/src/events/system-events.ts +12 -5
- package/src/events/transcript.ts +7 -1
- package/src/events/verify-nudge.ts +3 -3
- package/src/front/generated/browser-wire.json +95 -0
- package/src/front/generated/browser-wire.ts +36 -0
- package/src/front/generated/front-wire.json +25 -0
- package/src/front/generated/wire.ts +2 -2
- package/src/front/wire-manifests.test.ts +7 -0
- package/src/ids/conversation-ids.test.ts +2 -26
- package/src/ids/conversation-ids.ts +6 -12
- package/src/ids/project-dir.fixture.json +65 -0
- package/src/ids/project-dir.test.ts +60 -0
- package/src/ids/project-dir.ts +70 -0
- package/src/index.ts +13 -4
- package/src/models/agent-catalog.test.ts +7 -1
- package/src/models/agent-runtimes.ts +7 -5
- package/src/models/model-roles.ts +1 -9
- package/src/policy/command-classes.test.ts +39 -0
- package/src/policy/command-classes.ts +70 -3
- package/src/policy/safety-policy.ts +10 -0
- package/src/policy/secret-hosts.test.ts +89 -0
- package/src/policy/secret-hosts.ts +73 -0
- package/src/policy/turned-away.ts +1 -0
- package/src/protocol/raw-routes.ts +8 -1
- package/src/protocol/routes.test.ts +6 -6
- package/src/protocol/routes.ts +2 -9
- package/src/protocol/stream-of.ts +13 -0
- package/src/protocol/vitals.test.ts +46 -0
- package/src/protocol/vitals.ts +38 -0
- package/src/schemas/activity.ts +1 -1
- package/src/schemas/agent.ts +20 -3
- package/src/schemas/agents.ts +58 -4
- package/src/schemas/automations.ts +2 -2
- package/src/schemas/capabilities.ts +44 -7
- package/src/schemas/ci.ts +56 -11
- package/src/schemas/context-trim.ts +11 -6
- package/src/schemas/devices.ts +38 -2
- package/src/schemas/environment.ts +39 -0
- package/src/schemas/git/git.ts +20 -2
- package/src/schemas/hosts.ts +4 -1
- package/src/schemas/keep-warm.ts +19 -6
- package/src/schemas/loopback-catch.ts +45 -0
- package/src/schemas/maintenance.ts +1 -1
- package/src/schemas/needs.ts +12 -3
- package/src/schemas/personas.ts +8 -3
- package/src/schemas/providers/provider-oauth.ts +35 -0
- package/src/schemas/secrets.ts +70 -0
- package/src/schemas/settings-history.ts +3 -0
- package/src/schemas/settings.test.ts +19 -1
- package/src/schemas/settings.ts +59 -16
- package/src/schemas/speaker.ts +5 -5
- package/src/schemas/terminal.ts +19 -6
- package/src/schemas/webext.ts +3 -0
- package/src/schemas/workflows.ts +5 -5
- package/src/schemas/workspace/workspace-tree.ts +12 -20
- package/src/state/fix-attempt-plan.test.ts +1 -1
- package/src/state/fix-stance.ts +1 -1
- package/src/state/history-state.ts +14 -0
- package/src/state/runtime-state.ts +0 -3
- package/src/state/workspace-state.ts +0 -6
- package/src/text/documents.test.ts +25 -1
- package/src/text/documents.ts +24 -0
- package/src/text/title.ts +1 -1
- package/src/text/transcript-fold.test.ts +218 -25
- package/src/text/transcript-fold.ts +166 -45
- package/src/webext/index.ts +1 -0
- package/dist/schemas/workspace/push-checks.d.ts +0 -222
- package/dist/schemas/workspace/push-checks.d.ts.map +0 -1
- package/dist/schemas/workspace/push-checks.js +0 -97
- package/dist/schemas/workspace/push-checks.js.map +0 -1
- package/dist/state/red-streak.d.ts +0 -7
- package/dist/state/red-streak.d.ts.map +0 -1
- package/dist/state/red-streak.js +0 -11
- package/dist/state/red-streak.js.map +0 -1
- package/src/schemas/workspace/push-checks.test.ts +0 -28
- package/src/schemas/workspace/push-checks.ts +0 -155
- package/src/state/red-streak.test.ts +0 -28
- package/src/state/red-streak.ts +0 -28
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { STATE_DIR } from "@intentic/constants";
|
|
2
2
|
import type { AgentEvent } from "../events/agent-events.js";
|
|
3
|
-
import type
|
|
3
|
+
import { type TranscriptPatch, type TranscriptRow, TranscriptRowSchema } from "../events/transcript.js";
|
|
4
|
+
import { sandboxNoticeOf } from "../events/sandbox-notice.js";
|
|
4
5
|
import { watchWakePrompt } from "../events/watch-wake.js";
|
|
5
6
|
import { LAND_CONFLICT_OPENING } from "../events/land-conflict.js";
|
|
6
7
|
import { RESUME_NOTES } from "../events/resume.js";
|
|
@@ -11,6 +12,10 @@ import { applyTranscriptPatch, foldTurn, TranscriptFold, userRow } from "./trans
|
|
|
11
12
|
const SENT_AT = 1_767_225_600_000;
|
|
12
13
|
const openingOf = (prompt: string): TranscriptRow[] => [userRow(prompt, SENT_AT, [])];
|
|
13
14
|
const foldOf = (prompt: string, events: readonly AgentEvent[]): TranscriptRow[] => foldTurn(openingOf(prompt), events);
|
|
15
|
+
// What an armed credential renewal's row promises.
|
|
16
|
+
const RENEWING_TEXT = "The credential is being renewed and this turn continues automatically.";
|
|
17
|
+
// The same row as a code, which an app words in its reader's language (sandbox-notice.ts).
|
|
18
|
+
const RENEWING_CODE = { code: "renewing", params: { message: "Token refused.", error: "claude-token-refused" } };
|
|
14
19
|
|
|
15
20
|
// The one fold every window and the stored record draw from; pins what a live, reopened and stored chat all show.
|
|
16
21
|
describe("foldTurn", () => {
|
|
@@ -223,20 +228,6 @@ describe("foldTurn", () => {
|
|
|
223
228
|
expect(foldOf("delegate", events).slice(1)).toEqual([{ role: "assistant", text: "delegating" }]);
|
|
224
229
|
});
|
|
225
230
|
|
|
226
|
-
it("reads one subagent's stream as a transcript of its own", () => {
|
|
227
|
-
const questions = [{ question: "Which?", header: "Pick", multiSelect: false, options: [{ label: "A", description: "a" }] }];
|
|
228
|
-
const events: AgentEvent[] = [
|
|
229
|
-
{ kind: "delta", text: "parent prose" },
|
|
230
|
-
{ kind: "tool_call", id: "t1", name: "Grep", category: "search", status: "completed" },
|
|
231
|
-
{ kind: "delta", text: "found it", parentToolUseId: "task-1" },
|
|
232
|
-
{ kind: "tool_call", id: "t2", name: "Read", category: "read", status: "completed", parentToolUseId: "task-1" },
|
|
233
|
-
{ kind: "question", requestId: "q1", questions },
|
|
234
|
-
];
|
|
235
|
-
expect(foldTurn([], events, "settled", "task-1")).toEqual([
|
|
236
|
-
{ role: "assistant", text: "found it", tools: [{ id: "t2", name: "Read", category: "read", status: "completed" }] },
|
|
237
|
-
]);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
231
|
it("records the thinking a turn showed", () => {
|
|
241
232
|
const events: AgentEvent[] = [
|
|
242
233
|
{ kind: "thinking", text: "hm, " },
|
|
@@ -313,24 +304,62 @@ describe("foldTurn", () => {
|
|
|
313
304
|
];
|
|
314
305
|
// The row states what happened and nothing more: what happens next, and the one control that changes it, are
|
|
315
306
|
// the chat card's, asked once (ChatContinueStrip), not a second switch on a transcript line.
|
|
316
|
-
expect(foldOf("hi", outage).at(-1)).toEqual({
|
|
307
|
+
expect(foldOf("hi", outage).at(-1)).toEqual({
|
|
308
|
+
role: "notice",
|
|
309
|
+
text: "Anthropic is down. Retrying by itself: attempt 2 of 6.",
|
|
310
|
+
noticeCode: { code: "retrying", params: { message: "Anthropic is down.", error: "provider-outage", attempt: 2, of: 6 } },
|
|
311
|
+
});
|
|
317
312
|
const renewal: AgentEvent[] = [{ kind: "error", code: "claude-token-refused", message: "Token refused.", autoResume: "scheduled" }];
|
|
318
313
|
expect(foldOf("hi", renewal).at(-1)).toEqual({
|
|
319
314
|
role: "notice",
|
|
320
315
|
text: "Token refused. The credential is being renewed and this turn continues automatically.",
|
|
321
316
|
noticeWait: "credentialRenewal",
|
|
317
|
+
noticeCode: RENEWING_CODE,
|
|
322
318
|
});
|
|
323
319
|
});
|
|
324
320
|
|
|
321
|
+
// The sandbox keeps one hold per run and each failure replaces it: a stop right after an armed renewal is what it acts
|
|
322
|
+
// on, so the renewal row must stop promising a continuation that is never coming (one sat in a chat for 41 minutes).
|
|
323
|
+
it("takes back a renewal's promise when a later failure in the same run stops the turn", () => {
|
|
324
|
+
const refused: AgentEvent = { kind: "error", code: "claude-token-refused", message: "Token refused.", autoResume: "scheduled" };
|
|
325
|
+
const stopped: AgentEvent = { kind: "error", message: "Claude Code returned an error result: 401." };
|
|
326
|
+
const fold = new TranscriptFold(openingOf("hi"));
|
|
327
|
+
fold.apply(refused);
|
|
328
|
+
const patches = fold.apply(stopped);
|
|
329
|
+
// The code moves with the words, so an app wording the row itself says the stop too, not the old promise.
|
|
330
|
+
const withdrawn: TranscriptRow = {
|
|
331
|
+
role: "notice",
|
|
332
|
+
text: "Token refused. The credential was being renewed, but the turn stopped before it could continue: it will not carry on by itself, so press Continue to pick it back up.",
|
|
333
|
+
noticeCode: { code: "renewalWithdrawn", params: { message: "Token refused.", error: "claude-token-refused" } },
|
|
334
|
+
};
|
|
335
|
+
// The live window hears the rewrite as a patch on the row it already drew, then the stop's own row.
|
|
336
|
+
expect(patches).toEqual([
|
|
337
|
+
{ op: "replace", index: 1, row: withdrawn },
|
|
338
|
+
{ op: "append", row: { role: "notice", text: "Claude Code returned an error result: 401." } },
|
|
339
|
+
]);
|
|
340
|
+
expect(fold.rows.slice(1)).toEqual([withdrawn, { role: "notice", text: "Claude Code returned an error result: 401." }]);
|
|
341
|
+
// A renewal armed again keeps its promise.
|
|
342
|
+
const again = new TranscriptFold(openingOf("hi"));
|
|
343
|
+
again.apply(refused);
|
|
344
|
+
const renewing: TranscriptRow = { role: "notice", text: `Token refused. ${RENEWING_TEXT}`, noticeWait: "credentialRenewal", noticeCode: RENEWING_CODE };
|
|
345
|
+
expect(again.apply(refused)).toEqual([{ op: "append", row: renewing }]);
|
|
346
|
+
expect(again.rows[1]).toEqual(renewing);
|
|
347
|
+
});
|
|
348
|
+
|
|
325
349
|
// The count lives in the record, so a reader scrolling back sees how many times a stuck turn was sent again.
|
|
326
350
|
it("says on a stopped turn's row which automatic try comes next, or that the ladder stood down", () => {
|
|
327
351
|
const timedOut = "Google turn timed out waiting for OpenCode.";
|
|
328
352
|
const booked: AgentEvent[] = [{ kind: "error", message: timedOut, autoResume: "scheduled", nextAt: 1, retries: { made: 1, max: 3 } }];
|
|
329
|
-
expect(foldOf("hi", booked).at(-1)).toEqual({
|
|
353
|
+
expect(foldOf("hi", booked).at(-1)).toEqual({
|
|
354
|
+
role: "notice",
|
|
355
|
+
text: `${timedOut} Retrying by itself: attempt 2 of 3.`,
|
|
356
|
+
noticeCode: { code: "retrying", params: { message: timedOut, attempt: 2, of: 3 } },
|
|
357
|
+
});
|
|
330
358
|
const spent: AgentEvent[] = [{ kind: "error", message: timedOut, autoResume: "available", retries: { made: 3, max: 3 } }];
|
|
331
359
|
expect(foldOf("hi", spent).at(-1)).toEqual({
|
|
332
360
|
role: "notice",
|
|
333
361
|
text: `${timedOut} Retried 3 of 3 times by itself; nothing more is sent automatically.`,
|
|
362
|
+
noticeCode: { code: "retried", params: { message: timedOut, made: 3, of: 3 } },
|
|
334
363
|
});
|
|
335
364
|
// An outage nobody armed says so, instead of promising the breaker's retry.
|
|
336
365
|
const unarmed: AgentEvent[] = [
|
|
@@ -346,6 +375,7 @@ describe("foldTurn", () => {
|
|
|
346
375
|
expect(foldOf("hi", unarmed).at(-1)).toEqual({
|
|
347
376
|
role: "notice",
|
|
348
377
|
text: "Anthropic is down. Nothing is retrying it, so the turn is waiting here.",
|
|
378
|
+
noticeCode: { code: "outageWaiting", params: { message: "Anthropic is down.", error: "provider-outage" } },
|
|
349
379
|
});
|
|
350
380
|
});
|
|
351
381
|
|
|
@@ -357,18 +387,78 @@ describe("foldTurn", () => {
|
|
|
357
387
|
{ kind: "landed", landed: true, deps: { missing: 1, started: ["deps-1"], deferred: false } },
|
|
358
388
|
];
|
|
359
389
|
expect(foldOf("go", events).slice(1)).toEqual([
|
|
360
|
-
{
|
|
390
|
+
{
|
|
391
|
+
role: "notice",
|
|
392
|
+
text: "Your workspace moved on while this agent waited, its branch was rebased onto your latest 2 commits.",
|
|
393
|
+
noticeCode: { code: "synced", params: { commits: 2 } },
|
|
394
|
+
},
|
|
361
395
|
{ role: "assistant", text: "on it" },
|
|
362
|
-
{ role: "notice", text: "Context compacted to free up space." },
|
|
396
|
+
{ role: "notice", text: "Context compacted to free up space.", noticeCode: { code: "compacted" } },
|
|
363
397
|
{
|
|
364
398
|
role: "notice",
|
|
365
399
|
text: "Changes landed in your workspace: review them in the Changes panel. Installing 1 dependency it added or changed; the project's checks run when that finishes, and the outcome lands in Activity.",
|
|
366
400
|
noticeAction: "depsInstall",
|
|
401
|
+
noticeCode: { code: "landed", params: { deps: 1 } },
|
|
367
402
|
},
|
|
368
403
|
]);
|
|
369
|
-
expect(foldOf("go", [{ kind: "landed", landed: true, held: true }]).at(-1)
|
|
370
|
-
|
|
404
|
+
expect(foldOf("go", [{ kind: "landed", landed: true, held: true }]).at(-1)).toEqual({
|
|
405
|
+
role: "notice",
|
|
406
|
+
text: "Finished: the work is on this agent's branch, ready to land from its review.",
|
|
407
|
+
noticeCode: { code: "landHeld" },
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
// An agent's own install, let through the command gate, says where it writes before its output arrives.
|
|
412
|
+
it("says where an agent's own install writes, naming its projects", () => {
|
|
413
|
+
expect(foldOf("go", [{ kind: "install", reach: "own-copy", projects: ["video"] }]).at(-1)).toEqual({
|
|
414
|
+
role: "notice",
|
|
415
|
+
text: "Installing packages in video/ into this conversation's own copy. The manifest and lockfile land with the work, and the review lists what it adds.",
|
|
416
|
+
noticeCode: { code: "installing", params: { ownCopy: true, projects: "video/" } },
|
|
417
|
+
});
|
|
418
|
+
expect(foldOf("go", [{ kind: "install", reach: "main-tree", projects: [""] }]).at(-1)).toEqual({
|
|
419
|
+
role: "notice",
|
|
420
|
+
text: "Installing packages in the workspace root in the main tree, one install at a time.",
|
|
421
|
+
noticeCode: { code: "installing", params: { ownCopy: false, root: true } },
|
|
422
|
+
});
|
|
423
|
+
// The workspace root is named first, and counts toward the three named.
|
|
424
|
+
expect(foldOf("go", [{ kind: "install", reach: "main-tree", projects: ["a", "", "b", "c", "d"] }]).at(-1)).toEqual({
|
|
425
|
+
role: "notice",
|
|
426
|
+
text: "Installing packages in the workspace root, a/, b/ and 2 more in the main tree, one install at a time.",
|
|
427
|
+
noticeCode: { code: "installing", params: { ownCopy: false, root: true, projects: "a/, b/", more: 2 } },
|
|
428
|
+
});
|
|
429
|
+
expect(foldOf("go", [{ kind: "install", reach: "main-tree", projects: ["a", "b", "c", "d", "e"] }]).at(-1)?.text).toBe(
|
|
430
|
+
"Installing packages in a/, b/, c/ and 2 more in the main tree, one install at a time.",
|
|
371
431
|
);
|
|
432
|
+
expect(foldOf("go", [{ kind: "install", reach: "own-copy", projects: [] }]).at(-1)?.text).toBe(
|
|
433
|
+
"Installing packages into this conversation's own copy. The manifest and lockfile land with the work, and the review lists what it adds.",
|
|
434
|
+
);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// The reconciler starts a land's install within seconds, in the install lane; it never waits for turns to end, so
|
|
438
|
+
// the notice must not say it does.
|
|
439
|
+
it("says a land's dependency install is on its way, not waiting for other agents", () => {
|
|
440
|
+
expect(foldOf("go", [{ kind: "landed", landed: true, deps: { missing: 3, started: [], deferred: true } }]).at(-1)).toEqual({
|
|
441
|
+
role: "notice",
|
|
442
|
+
text: "Changes landed in your workspace: review them in the Changes panel. 3 dependencies it added or changed are being installed in your tree: the install waits for any other install to finish, appears in Work terminals, and its outcome lands in Activity.",
|
|
443
|
+
noticeAction: "landHold",
|
|
444
|
+
noticeCode: { code: "landed", params: { deps: 3, queued: true } },
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// A spawned child's work goes into its parent's checkout, as the parent's in-process subagents' edits do: the row
|
|
449
|
+
// says so, never that it reached the owner's workspace, and says who is to bring in a clash.
|
|
450
|
+
it("says a child's work went into its parent's checkout, or was held off it by a clash", () => {
|
|
451
|
+
expect(foldOf("go", [{ kind: "landed", landed: true, into: "p1" }]).at(-1)).toEqual({
|
|
452
|
+
role: "notice",
|
|
453
|
+
text: "Changes went into the parent agent's checkout, as its in-process subagents' edits do: they reach your workspace with its land.",
|
|
454
|
+
noticeCode: { code: "intoParent" },
|
|
455
|
+
});
|
|
456
|
+
const clash: AgentEvent = { kind: "landed", landed: false, into: "p1", conflicts: [{ repo: "root", paths: [{ path: "app.ts", reason: "diverged" }], clean: 0 }] };
|
|
457
|
+
expect(foldOf("go", [clash]).at(-1)).toEqual({
|
|
458
|
+
role: "notice",
|
|
459
|
+
text: "1 file(s) clash with the parent agent's own edits, so nothing was written into its checkout. The parent was told, and can bring the changes in to resolve.",
|
|
460
|
+
noticeCode: { code: "intoParentClash", params: { files: 1 } },
|
|
461
|
+
});
|
|
372
462
|
});
|
|
373
463
|
|
|
374
464
|
// A resolve turn exists because the branch couldn't rebase; its own opening rebase failing the same way is that
|
|
@@ -382,11 +472,17 @@ describe("foldTurn", () => {
|
|
|
382
472
|
{
|
|
383
473
|
role: "notice",
|
|
384
474
|
text: "Couldn't rebase onto your workspace in intentic: the turn is running from the older base, so its land may need a resolve.",
|
|
475
|
+
noticeCode: { code: "synced", params: { commits: 0, blocked: "intentic" } },
|
|
385
476
|
},
|
|
386
477
|
]);
|
|
387
478
|
const mixed: AgentEvent = { kind: "worktree", branch: "agent/x", base: "abc1234", sync: { commits: 3, blocked: ["intentic"] } };
|
|
479
|
+
// The code leaves out what the words leave out: the resolve turn is not told its own errand in any language.
|
|
388
480
|
expect(foldOf(resolve, [mixed]).slice(1)).toEqual([
|
|
389
|
-
{
|
|
481
|
+
{
|
|
482
|
+
role: "notice",
|
|
483
|
+
text: "Your workspace moved on while this agent waited, its branch was rebased onto your latest 3 commits.",
|
|
484
|
+
noticeCode: { code: "synced", params: { commits: 3 } },
|
|
485
|
+
},
|
|
390
486
|
]);
|
|
391
487
|
});
|
|
392
488
|
|
|
@@ -513,7 +609,7 @@ describe("foldTurn", () => {
|
|
|
513
609
|
const events: AgentEvent[] = [{ kind: "credential_offer", requestId: "c1", offer }];
|
|
514
610
|
expect(foldTurn(openingOf("post it"), events, "stopped").slice(1)).toEqual([
|
|
515
611
|
{ role: "assistant", text: "", credentialOffer: { requestId: "c1", offer, status: "cancelled" } },
|
|
516
|
-
{ role: "notice", text: "Stopped." },
|
|
612
|
+
{ role: "notice", text: "Stopped.", noticeCode: { code: "stopped" } },
|
|
517
613
|
]);
|
|
518
614
|
});
|
|
519
615
|
|
|
@@ -524,7 +620,7 @@ describe("foldTurn", () => {
|
|
|
524
620
|
];
|
|
525
621
|
expect(foldTurn(openingOf("go"), events, "stopped").slice(1)).toEqual([
|
|
526
622
|
{ role: "assistant", text: "half", question: { requestId: "q1", questions: [], status: "cancelled" } },
|
|
527
|
-
{ role: "notice", text: "Stopped." },
|
|
623
|
+
{ role: "notice", text: "Stopped.", noticeCode: { code: "stopped" } },
|
|
528
624
|
]);
|
|
529
625
|
});
|
|
530
626
|
});
|
|
@@ -756,7 +852,13 @@ describe(`a refusal that ran nothing`, () => {
|
|
|
756
852
|
const fold = new TranscriptFold(openingOf(`land it`));
|
|
757
853
|
const patches = fold.apply(REFUSED);
|
|
758
854
|
|
|
759
|
-
expect(fold.rows).toEqual([
|
|
855
|
+
expect(fold.rows).toEqual([
|
|
856
|
+
{
|
|
857
|
+
role: `notice`,
|
|
858
|
+
text: expect.stringContaining(`held for you to send again`),
|
|
859
|
+
noticeCode: { code: `undelivered`, params: { message: REFUSED.message, error: REFUSED.code } },
|
|
860
|
+
},
|
|
861
|
+
]);
|
|
760
862
|
expect(fold.ranNothing).toBe(true);
|
|
761
863
|
// Dropped ahead of the notice that stands in for it: a window applies patches in order, and an append first
|
|
762
864
|
// would have it renumber every row under an index that is about to move.
|
|
@@ -843,3 +945,94 @@ describe(`a refusal that ran nothing`, () => {
|
|
|
843
945
|
});
|
|
844
946
|
});
|
|
845
947
|
});
|
|
948
|
+
|
|
949
|
+
// The sandbox's own notices ride as a code beside their English words, so an app can say them in the reader's language
|
|
950
|
+
// and words (sandbox-notice.ts). The words stay exactly as they were: older apps, stored records and agents read them.
|
|
951
|
+
describe(`the code beside a notice's words`, () => {
|
|
952
|
+
const GIB = 1024 ** 3;
|
|
953
|
+
const lowMemory = {
|
|
954
|
+
kind: `error`,
|
|
955
|
+
code: `sandbox-memory-low`,
|
|
956
|
+
message: `Sandbox memory is low: 15.9 GiB of 16.0 GiB used.`,
|
|
957
|
+
memory: { limitBytes: 16 * GIB, residentBytes: 15.9 * GIB, swapBytes: 0 },
|
|
958
|
+
} as const satisfies AgentEvent;
|
|
959
|
+
const lastOf = (events: readonly AgentEvent[]): TranscriptRow | undefined => foldOf(`land it`, events).at(-1);
|
|
960
|
+
|
|
961
|
+
it(`names each land outcome, with the counts and repos its sentence was worded from`, () => {
|
|
962
|
+
expect(lastOf([{ kind: `landed`, landed: true }])).toEqual({
|
|
963
|
+
role: `notice`,
|
|
964
|
+
text: `Changes landed in your workspace: review them in the Changes panel.`,
|
|
965
|
+
noticeAction: `landHold`,
|
|
966
|
+
noticeCode: { code: `landed` },
|
|
967
|
+
});
|
|
968
|
+
expect(lastOf([{ kind: `landed`, landed: true, deps: { missing: 2, started: [], deferred: true } }])?.noticeCode).toEqual({
|
|
969
|
+
code: `landed`,
|
|
970
|
+
params: { deps: 2, queued: true },
|
|
971
|
+
});
|
|
972
|
+
const conflicts = [
|
|
973
|
+
{ repo: `root`, paths: [{ path: `a.ts`, reason: `diverged` as const }], clean: 0 },
|
|
974
|
+
{ repo: `web`, paths: [{ path: `b.ts`, reason: `diverged` as const }, { path: `c.ts`, reason: `diverged` as const }], clean: 0 },
|
|
975
|
+
];
|
|
976
|
+
expect(lastOf([{ kind: `landed`, landed: false, conflicts }])).toEqual({
|
|
977
|
+
role: `notice`,
|
|
978
|
+
text: `3 file(s) couldn't land automatically in root, web. Open the agent's review to see what blocked them and land from there.`,
|
|
979
|
+
noticeCode: { code: `landConflict`, params: { files: 3, repos: `root, web` } },
|
|
980
|
+
});
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
it(`names each memory hold by where the message waits`, () => {
|
|
984
|
+
expect(lastOf([lowMemory])?.noticeCode).toEqual({ code: `memoryHeld`, params: { message: lowMemory.message, error: `sandbox-memory-low` } });
|
|
985
|
+
expect(lastOf([{ ...lowMemory, held: { ran: false } }])?.noticeCode).toEqual({
|
|
986
|
+
code: `kept`,
|
|
987
|
+
params: { message: lowMemory.message, error: `sandbox-memory-low`, memory: true },
|
|
988
|
+
});
|
|
989
|
+
expect(lastOf([{ ...lowMemory, unattended: true }])?.noticeCode).toEqual({
|
|
990
|
+
code: `undelivered`,
|
|
991
|
+
params: { message: lowMemory.message, error: `sandbox-memory-low`, unattended: true },
|
|
992
|
+
});
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
it(`codes a failure the sandbox names, and leaves a provider's own words to themselves`, () => {
|
|
996
|
+
const busy = `This agent is already running a turn, wait for it to finish.`;
|
|
997
|
+
expect(lastOf([{ kind: `error`, code: `agent-busy`, message: busy }])).toEqual({
|
|
998
|
+
role: `notice`,
|
|
999
|
+
text: busy,
|
|
1000
|
+
noticeCode: { code: `failed`, params: { message: busy, error: `agent-busy` } },
|
|
1001
|
+
});
|
|
1002
|
+
expect(lastOf([{ kind: `error`, message: `Overloaded.` }])).toEqual({ role: `notice`, text: `Overloaded.` });
|
|
1003
|
+
expect(lastOf([{ kind: `error`, code: `claude-token-refused`, message: `Token refused.` }])).toEqual({
|
|
1004
|
+
role: `notice`,
|
|
1005
|
+
text: `Token refused. Reconnect the account to pick this conversation back up.`,
|
|
1006
|
+
noticeCode: { code: `reconnect`, params: { message: `Token refused.`, error: `claude-token-refused` } },
|
|
1007
|
+
});
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
// A reader decodes a code with this build's own schema: every code the fold writes has to be one it knows.
|
|
1011
|
+
it(`writes only codes this build can read back`, () => {
|
|
1012
|
+
const events: AgentEvent[][] = [
|
|
1013
|
+
[{ kind: `worktree`, branch: `agent/x`, base: `abc1234`, sync: { commits: 1, blocked: [`web`] } }],
|
|
1014
|
+
[{ kind: `compact`, trigger: `auto` }],
|
|
1015
|
+
[{ kind: `landed`, landed: true, into: `p1` }],
|
|
1016
|
+
[{ kind: `landed`, landed: false, into: `p1`, conflicts: [] }],
|
|
1017
|
+
[{ kind: `landed`, landed: true, held: true }],
|
|
1018
|
+
[{ kind: `error`, code: `provider-outage`, message: `Down.`, autoResume: `available` }],
|
|
1019
|
+
[lowMemory],
|
|
1020
|
+
[{ ...lowMemory, held: { ran: false } }],
|
|
1021
|
+
[{ kind: `error`, code: `claude-token-refused`, message: `Token refused.`, autoResume: `scheduled` }, { kind: `error`, message: `401.` }],
|
|
1022
|
+
];
|
|
1023
|
+
const rows = events.flatMap((turn) => foldTurn(openingOf(`go`), turn, `stopped`)).filter((row) => row.noticeCode !== undefined);
|
|
1024
|
+
expect(rows.filter((row) => sandboxNoticeOf(row) === undefined)).toEqual([]);
|
|
1025
|
+
expect(new Set(rows.map((row) => row.noticeCode?.code))).toEqual(
|
|
1026
|
+
new Set([`synced`, `compacted`, `intoParent`, `intoParentClash`, `landHeld`, `outageWaiting`, `memoryHeld`, `kept`, `renewalWithdrawn`, `stopped`]),
|
|
1027
|
+
);
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
// A newer sandbox's code must not cost an older app the whole page: the row parses, and the reader draws its words.
|
|
1031
|
+
it(`reads a row whose code this build does not know, and one written before rows carried codes`, () => {
|
|
1032
|
+
const newer: TranscriptRow = { role: `notice`, text: `Something new happened.`, noticeCode: { code: `somethingNew`, params: { count: 2 } } };
|
|
1033
|
+
expect(TranscriptRowSchema.parse(newer)).toEqual(newer);
|
|
1034
|
+
expect(sandboxNoticeOf(newer)).toBeUndefined();
|
|
1035
|
+
expect(TranscriptRowSchema.parse({ role: `notice`, text: `Stopped.` })).toEqual({ role: `notice`, text: `Stopped.` });
|
|
1036
|
+
expect(sandboxNoticeOf({ noticeCode: { code: `landConflict`, params: { files: `three` } } })).toBeUndefined();
|
|
1037
|
+
});
|
|
1038
|
+
});
|