@intentic/sandbox-contract 1.317.0 → 1.318.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 +12 -4
- 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 +55 -1
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.d.ts +796 -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 -2
- 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 +96 -435
- 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 -80
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +0 -27
- 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 +46 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/system-events.js +2 -0
- 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/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 +11570 -11030
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -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 +7 -0
- package/dist/protocol/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw-routes.js +4 -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/schemas/activity.js +1 -1
- package/dist/schemas/activity.js.map +1 -1
- package/dist/schemas/agent.d.ts +19 -2
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +2 -1
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents.d.ts +61 -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 +18 -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 +1 -1
- package/dist/schemas/settings-history.d.ts.map +1 -1
- package/dist/schemas/settings-history.js +1 -0
- package/dist/schemas/settings-history.js.map +1 -1
- package/dist/schemas/settings.d.ts +42 -2
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +26 -4
- 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 -0
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +4 -0
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/definition.d.ts +12 -4
- 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 -37
- 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 +7 -0
- package/src/events/transcript.ts +7 -1
- package/src/events/verify-nudge.ts +3 -3
- 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 +12 -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 +5 -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/schemas/activity.ts +1 -1
- package/src/schemas/agent.ts +4 -1
- 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 +2 -0
- package/src/schemas/settings.test.ts +19 -1
- package/src/schemas/settings.ts +58 -9
- 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 +7 -0
- 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
|
@@ -4,6 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
import { DeviceAgentFlowSchema, DeviceFlowLineSchema, DeviceReportSchema, DeviceSandboxFlowSchema } from "../schemas/devices.js";
|
|
5
5
|
import { DeviceScopesSchema } from "../schemas/capabilities.js";
|
|
6
6
|
import { DeviceFactsSchema } from "../schemas/hosts.js";
|
|
7
|
+
import { LoopbackCatchEventSchema, LoopbackCatchSchema } from "../schemas/loopback-catch.js";
|
|
7
8
|
import { OkSchema } from "../schemas/shared.js";
|
|
8
9
|
|
|
9
10
|
// What a connected device can be asked, over the socket it opened; the machine is the oRPC server, the daemon the
|
|
@@ -26,4 +27,8 @@ export const deviceContract = {
|
|
|
26
27
|
runSandboxFlow: oc.input(DeviceSandboxFlowSchema).output(streamOf(DeviceFlowLineSchema)),
|
|
27
28
|
// Spawns the work detached from the socket, so restarting the agent process cannot brick a swap in progress.
|
|
28
29
|
runAgentFlow: oc.input(DeviceAgentFlowSchema).output(streamOf(DeviceFlowLineSchema)),
|
|
30
|
+
// Watches one loopback address on this machine for a sign-in's redirect (schemas/loopback-catch.ts); only the
|
|
31
|
+
// daemon arms it, never a tool, and aborting the stream is how it stops. Sent only to an agent advertising
|
|
32
|
+
// `loopback-catch`.
|
|
33
|
+
catchLoopback: oc.input(LoopbackCatchSchema).output(streamOf(LoopbackCatchEventSchema)),
|
|
29
34
|
};
|
|
@@ -34,12 +34,21 @@ export type TrialStatusResponse = z.infer<typeof TrialStatusSchema>;
|
|
|
34
34
|
export const LocalModelGpuSchema = z.enum(["granted", "unsupported", "absent"]);
|
|
35
35
|
export type LocalModelGpu = z.infer<typeof LocalModelGpuSchema>;
|
|
36
36
|
|
|
37
|
+
// Which one device a model runs at full speed on: the GPU when one reached this sandbox, else the host's RAM. One, never
|
|
38
|
+
// a sum: a model split between a card and the CPU runs at the CPU's pace.
|
|
39
|
+
export const LocalModelDeviceSchema = z.enum(["gpu", "host"]);
|
|
40
|
+
export type LocalModelDevice = z.infer<typeof LocalModelDeviceSchema>;
|
|
41
|
+
|
|
37
42
|
// One window rung priced against one model, so a surface never has to redo the arithmetic the start check will.
|
|
38
43
|
const LocalModelWindowFitSchema = z.object({
|
|
39
44
|
tokens: z.number().int().positive(),
|
|
40
45
|
// Weights + KV cache + the runtime's own floor: the same estimate the admission check refuses a start on.
|
|
41
46
|
totalBytes: z.number().int().nonnegative(),
|
|
47
|
+
// Whether it can load at all, GPU and host together: what a start is refused on.
|
|
42
48
|
fits: z.boolean(),
|
|
49
|
+
// Whether all of it fits in the free memory of the one device, so it runs at that device's pace. A rung can fit and
|
|
50
|
+
// still run mostly on the CPU. Absent from a daemon older than the distinction.
|
|
51
|
+
fullSpeed: z.boolean().optional(),
|
|
43
52
|
});
|
|
44
53
|
|
|
45
54
|
const LocalModelOptionFitSchema = z.object({
|
|
@@ -72,14 +81,21 @@ export const LocalModelFitSchema = z.object({
|
|
|
72
81
|
memoryCapped: z.boolean(),
|
|
73
82
|
gpu: LocalModelGpuSchema,
|
|
74
83
|
gpuMemoryBytes: z.number().int().nonnegative(),
|
|
75
|
-
// The
|
|
76
|
-
|
|
84
|
+
// The GPU's free memory, on the card with the most of it; zero before the grant. Absent from an older daemon.
|
|
85
|
+
gpuFreeBytes: z.number().int().nonnegative().optional(),
|
|
86
|
+
// What a start is refused on: the host and the GPU together, since llama.cpp can split a model between them. Only a
|
|
87
|
+
// model that cannot load at all is turned away here; a model that fits only this way runs mostly on the CPU.
|
|
77
88
|
budgetBytes: z.number().int().nonnegative(),
|
|
89
|
+
// What a model may take and still run at full speed: the free memory of one device (fullSpeedDevice), plus whatever
|
|
90
|
+
// this sandbox's own local model holds there now, since a start stops it first. Both offers are sized against this,
|
|
91
|
+
// never against the sum. Zero means unmeasurable. Absent from a daemon older than the distinction.
|
|
92
|
+
fullSpeedBytes: z.number().int().nonnegative().optional(),
|
|
93
|
+
fullSpeedDevice: LocalModelDeviceSchema.optional(),
|
|
78
94
|
// Whether llama-server is in this image. False means the local lane costs a rebuild before it can serve anything.
|
|
79
95
|
serverReady: z.boolean(),
|
|
80
96
|
options: z.array(LocalModelOptionFitSchema),
|
|
81
97
|
// The two the connect view offers by name. Each is a model plus the window it was priced at, ready to be added
|
|
82
|
-
// verbatim; absent where nothing on the list
|
|
98
|
+
// verbatim, and each runs at full speed; absent where nothing on the list does, which is an answer, not an error.
|
|
83
99
|
instant: z.object({ model: z.string(), context: z.string() }).optional(),
|
|
84
100
|
best: z.object({ model: z.string(), context: z.string() }).optional(),
|
|
85
101
|
prefetch: LocalModelPrefetchSchema,
|
|
@@ -114,7 +130,7 @@ export const endpointsContract = {
|
|
|
114
130
|
path: "/endpoints/local-model/fit",
|
|
115
131
|
summary: "Which local models this machine can actually run",
|
|
116
132
|
description:
|
|
117
|
-
"The memory this sandbox may use, whether a GPU reached it, and every curated model priced
|
|
133
|
+
"The memory this sandbox may use, whether a GPU reached it, and every curated model priced two ways: whether it fits on one device's free memory and so runs at full speed, and whether it can load at all. The two the connect view offers, one that downloads in a minute and the best this machine runs at full speed, come from the first; a start is refused only on the second.",
|
|
118
134
|
})
|
|
119
135
|
.output(LocalModelFitSchema),
|
|
120
136
|
// Start or stop fetching the instant model's weights before anyone has asked for them, so the first local turn does
|
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
SecretKeyParamSchema,
|
|
10
10
|
SecretGeneratedSchema,
|
|
11
11
|
SecretGenerateSchema,
|
|
12
|
+
SecretHostGuardSetResultSchema,
|
|
13
|
+
SecretHostGuardSetSchema,
|
|
14
|
+
SecretHostGuardsSchema,
|
|
12
15
|
SecretKeysSchema,
|
|
13
16
|
SecretRevealSchema,
|
|
14
17
|
SecretSetSchema,
|
|
@@ -113,6 +116,31 @@ export const secretsContract = {
|
|
|
113
116
|
})
|
|
114
117
|
.input(CredentialGuardSubjectParamSchema)
|
|
115
118
|
.output(OkSchema),
|
|
119
|
+
// The host guard, the gate's second half: kept beside the gates, off the agent-editable config for the same reason. The
|
|
120
|
+
// agent reads it so a use can aim where it may go, and may tighten it; loosening waits for the owner's click.
|
|
121
|
+
hosts: secretRoute
|
|
122
|
+
.route({
|
|
123
|
+
method: "GET",
|
|
124
|
+
path: "/secrets/hosts",
|
|
125
|
+
summary: "Which secrets are host-guarded, and where they may go",
|
|
126
|
+
description:
|
|
127
|
+
"Every secret and connected account whose host guard is set, on or off, and its hosts. With the guard on, a use aimed off the list, or anywhere a command's text does not show, asks a person first, whatever the safety judge says. Names and hosts only, never values.",
|
|
128
|
+
})
|
|
129
|
+
// The `secrets gates` and `secrets hosts` CLI's read, on the agent token.
|
|
130
|
+
.meta({ agent: true })
|
|
131
|
+
.output(SecretHostGuardsSchema),
|
|
132
|
+
setHosts: secretRoute
|
|
133
|
+
.route({
|
|
134
|
+
method: "PUT",
|
|
135
|
+
path: "/secrets/hosts/{subject}",
|
|
136
|
+
summary: "Turn a secret's host guard on or off, and set its hosts",
|
|
137
|
+
description:
|
|
138
|
+
"Replaces one secret's host guard. Anybody who may use secrets can turn it on or take hosts away; turning it off or adding a host is the owner's: from the agent it raises a card for the owner in the live conversation and waits for their answer.",
|
|
139
|
+
})
|
|
140
|
+
// The `secrets hosts` CLI's edits, on the agent token; the route itself decides what needs the owner.
|
|
141
|
+
.meta({ agent: true })
|
|
142
|
+
.input(SecretHostGuardSetSchema)
|
|
143
|
+
.output(SecretHostGuardSetResultSchema),
|
|
116
144
|
request: secretRoute
|
|
117
145
|
.route({
|
|
118
146
|
method: "POST",
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { FIELD_NOTES_FILE } from "@intentic/constants";
|
|
2
2
|
import { procedure } from "../protocol/route-meta.js";
|
|
3
3
|
import {
|
|
4
|
+
AudienceAnswerSchema,
|
|
5
|
+
AudienceStateSchema,
|
|
4
6
|
BuiltinPromptSchema,
|
|
7
|
+
MemberAudienceSchema,
|
|
5
8
|
BuiltinPromptTextSchema,
|
|
6
9
|
FieldNotesStatusSchema,
|
|
7
10
|
REPO_CHECKS_FILE,
|
|
@@ -103,6 +106,32 @@ export const settingsContract = {
|
|
|
103
106
|
})
|
|
104
107
|
.input(TimezoneOfferSchema)
|
|
105
108
|
.output(TimezoneStateSchema),
|
|
109
|
+
// A person's own preference rather than a sandbox setting: kept per member, so every device a person opens this
|
|
110
|
+
// sandbox on reads it, and nobody's answer changes another member's screen. Anyone signed in may read and give their
|
|
111
|
+
// own, a guest included, since it changes nothing but the words they are shown.
|
|
112
|
+
audience: procedure
|
|
113
|
+
.route({
|
|
114
|
+
method: "GET",
|
|
115
|
+
path: "/settings/audience",
|
|
116
|
+
summary: "Which words the editor uses for you here",
|
|
117
|
+
description:
|
|
118
|
+
"Whether your editor speaks git's own words (developer) or plain ones (maker) on this sandbox, in every browser and on every device. Absent until you have chosen here.",
|
|
119
|
+
})
|
|
120
|
+
.meta({ guest: true })
|
|
121
|
+
.output(MemberAudienceSchema),
|
|
122
|
+
// A browser handing over the answer it kept on its own must not overwrite one the person already gave on another
|
|
123
|
+
// device, which is what `offer` says; a plain answer replaces it.
|
|
124
|
+
setAudience: procedure
|
|
125
|
+
.route({
|
|
126
|
+
method: "POST",
|
|
127
|
+
path: "/settings/audience",
|
|
128
|
+
summary: "Choose which words the editor uses for you here",
|
|
129
|
+
description:
|
|
130
|
+
"Sets whether your editor speaks git's own words (developer) or plain ones (maker) on this sandbox, for every browser and device you open it on. Other members keep their own. With `offer` it is taken only while you have none kept, and the kept answer comes back unchanged.",
|
|
131
|
+
})
|
|
132
|
+
.meta({ guest: true, floor: "viewer" })
|
|
133
|
+
.input(AudienceAnswerSchema)
|
|
134
|
+
.output(AudienceStateSchema),
|
|
106
135
|
adoptRepoChecks: procedure
|
|
107
136
|
.route({
|
|
108
137
|
method: "POST",
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { procedure } from "../protocol/route-meta.js";
|
|
2
2
|
import { streamOf } from "../protocol/routes.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import { SessionTranscriptSchema } from "../events/transcript.js";
|
|
5
4
|
import { SystemEventSchema } from "../events/system-events.js";
|
|
6
5
|
import {
|
|
7
6
|
DeviceAgentFlowInputSchema,
|
|
@@ -19,7 +18,6 @@ import { SkipUpdateInputSchema } from "../schemas/updates.js";
|
|
|
19
18
|
import {
|
|
20
19
|
BrowserNameParamSchema,
|
|
21
20
|
BrowsersListSchema,
|
|
22
|
-
SubagentIdParamSchema,
|
|
23
21
|
SubagentsListSchema,
|
|
24
22
|
TerminalNameParamSchema,
|
|
25
23
|
TerminalScrollbackQuerySchema,
|
|
@@ -228,26 +226,19 @@ export const systemContract = {
|
|
|
228
226
|
})
|
|
229
227
|
.input(BrowserNameParamSchema)
|
|
230
228
|
.output(OkSchema),
|
|
231
|
-
//
|
|
229
|
+
// In-process and spawned alike: the board draws each under the card of the conversation that started it, and a chat
|
|
230
|
+
// draws it on the card of the call that started it. Pushed through the `subagents` runtime domain, never polled. A
|
|
231
|
+
// subagent's work is read where it lives: an in-process one's on its delegation's card in its parent's record, a
|
|
232
|
+
// spawned one's in its own conversation (agents.transcript), so there is no second transcript door here.
|
|
232
233
|
subagents: systemRoute
|
|
233
234
|
.route({
|
|
234
235
|
method: "GET",
|
|
235
236
|
path: "/system/subagents",
|
|
236
237
|
summary: "Subagents the agents have started",
|
|
237
238
|
description:
|
|
238
|
-
"Every subagent
|
|
239
|
+
"Every subagent that conversations the caller can see have delegated work to, whichever tool started it, with what each one is doing: all that are still working, and the most recent that have settled.",
|
|
239
240
|
})
|
|
240
241
|
.output(SubagentsListSchema),
|
|
241
|
-
subagentTranscript: systemRoute
|
|
242
|
-
.route({
|
|
243
|
-
method: "GET",
|
|
244
|
-
path: "/system/subagents/{id}/transcript",
|
|
245
|
-
summary: "A subagent's record",
|
|
246
|
-
description:
|
|
247
|
-
"The full record of one delegated subagent, in the same shape as any other conversation. It comes live from the parent turn while it works, and from stored history once it has finished.",
|
|
248
|
-
})
|
|
249
|
-
.input(SubagentIdParamSchema)
|
|
250
|
-
.output(SessionTranscriptSchema),
|
|
251
242
|
// On the contract, not a hand-written route beside it: this payload is what every "do it out there" button is
|
|
252
243
|
// gated on, so its shape has to be fingerprinted like any other, or a daemon older than the app disagrees about
|
|
253
244
|
// it silently and the buttons just stop being drawn.
|
|
@@ -12,7 +12,8 @@ import { OkSchema } from "../schemas/shared.js";
|
|
|
12
12
|
//
|
|
13
13
|
// Two login shapes ride one pair of routes. Codex, Grok and Kimi use device authorization: the translator polls
|
|
14
14
|
// to completion in the background, so the UI polls the attempt. Google redirects the browser to a loopback
|
|
15
|
-
// URL this sandbox can't receive
|
|
15
|
+
// URL this sandbox can't receive: a device or browser of the owner's catches it where one can (`connect.catchers`),
|
|
16
|
+
// otherwise `complete` takes the landing URL pasted back; either way it reaches the translator the same way. `connect.flow` tells the
|
|
16
17
|
// card which mechanic it received without inferring it from whether an optional device code happened to exist.
|
|
17
18
|
export const translatorContract = {
|
|
18
19
|
accounts: procedure
|
|
@@ -2,6 +2,8 @@ import { oc } from "@orpc/contract";
|
|
|
2
2
|
// Named imports rather than the `z` namespace: this module is bundled into the browser extension, where the
|
|
3
3
|
// namespace keeps zod's 60 locales (~250 kB) that esbuild can otherwise drop. _devices/webext/scripts/size-budget.mjs holds the ceiling.
|
|
4
4
|
import { unknown } from "zod";
|
|
5
|
+
import { streamOf } from "../protocol/stream-of.js";
|
|
6
|
+
import { LoopbackCatchEventSchema, LoopbackCatchSchema } from "../schemas/loopback-catch.js";
|
|
5
7
|
import { OkSchema } from "../schemas/shared.js";
|
|
6
8
|
import { WebExtFactsSchema, WebExtScopesSchema } from "../schemas/webext.js";
|
|
7
9
|
|
|
@@ -9,7 +11,8 @@ import { WebExtFactsSchema, WebExtScopesSchema } from "../schemas/webext.js";
|
|
|
9
11
|
// inverted from device.contract.ts, since a browser cannot be dialled.
|
|
10
12
|
// `mcp` stays one opaque procedure so a browser can gain a tool without a matching daemon release; the payload is
|
|
11
13
|
// validated in the extension against the tool's own schema.
|
|
12
|
-
// No `runSandboxFlow` twin: every browser operation is a click or read that either happened or did not.
|
|
14
|
+
// No `runSandboxFlow` twin: every browser operation is a click or read that either happened or did not. The one stream
|
|
15
|
+
// is `catchLoopback`, the device agent's own procedure answered the same way, so the daemon drives both alike.
|
|
13
16
|
export const webextContract = {
|
|
14
17
|
// Refetched on connect and each card read, never cached: the grant list changes in the browser, not here.
|
|
15
18
|
describe: oc.output(WebExtFactsSchema),
|
|
@@ -19,4 +22,7 @@ export const webextContract = {
|
|
|
19
22
|
ping: oc.output(OkSchema),
|
|
20
23
|
// One MCP JSON-RPC message forwarded verbatim in both directions; kept opaque, not typed per tool.
|
|
21
24
|
mcp: oc.input(unknown()).output(unknown()),
|
|
25
|
+
// Watches for a tab reaching one loopback address, a sign-in's redirect (schemas/loopback-catch.ts); armed by the
|
|
26
|
+
// daemon only, and sent only to a browser whose facts list `loopback-catch`.
|
|
27
|
+
catchLoopback: oc.input(LoopbackCatchSchema).output(streamOf(LoopbackCatchEventSchema)),
|
|
22
28
|
};
|
|
@@ -16,13 +16,6 @@ import {
|
|
|
16
16
|
WorkspaceGraphSchema,
|
|
17
17
|
WorkspaceSyncSchema,
|
|
18
18
|
} from "../schemas/workspace/workspace-repos.js";
|
|
19
|
-
import {
|
|
20
|
-
PushChecksSchema,
|
|
21
|
-
PushDismissResultSchema,
|
|
22
|
-
PushDismissSchema,
|
|
23
|
-
PushRecheckResultSchema,
|
|
24
|
-
PushRecheckSchema,
|
|
25
|
-
} from "../schemas/workspace/push-checks.js";
|
|
26
19
|
import { WorkspaceSearchQuerySchema, WorkspaceSearchResultSchema } from "../schemas/workspace/workspace-search.js";
|
|
27
20
|
import { WorkspaceInstallResultSchema, WorkspaceInstallSchema, WorkspaceSetupSchema } from "../schemas/workspace/workspace-setup.js";
|
|
28
21
|
import {
|
|
@@ -283,36 +276,6 @@ export const workspaceContract = {
|
|
|
283
276
|
})
|
|
284
277
|
.input(WorkspaceInstallSchema)
|
|
285
278
|
.output(WorkspaceInstallResultSchema),
|
|
286
|
-
// What the pre-push hook found and let through waits here until measured gone or dismissed; with the two hands on it.
|
|
287
|
-
pushChecks: procedure
|
|
288
|
-
.route({
|
|
289
|
-
method: "GET",
|
|
290
|
-
path: "/workspace/push-checks",
|
|
291
|
-
summary: "What pushes left behind",
|
|
292
|
-
description:
|
|
293
|
-
"Every push the pre-push hook measured, newest first, with what each brought in, and what is still owed per project. The hook never refuses a push, so this is where its findings wait. Nothing here is ever sent to an agent by itself.",
|
|
294
|
-
})
|
|
295
|
-
.output(PushChecksSchema),
|
|
296
|
-
pushDismiss: procedure
|
|
297
|
-
.route({
|
|
298
|
-
method: "POST",
|
|
299
|
-
path: "/workspace/push-checks/dismiss",
|
|
300
|
-
summary: "Set aside what a push left behind",
|
|
301
|
-
description:
|
|
302
|
-
"Marks findings a push check let through as not to be fixed, so they stop counting against the project, or opens dismissed ones again. Nothing is changed in the code.",
|
|
303
|
-
})
|
|
304
|
-
.input(PushDismissSchema)
|
|
305
|
-
.output(PushDismissResultSchema),
|
|
306
|
-
pushRecheck: procedure
|
|
307
|
-
.route({
|
|
308
|
-
method: "POST",
|
|
309
|
-
path: "/workspace/push-checks/recheck",
|
|
310
|
-
summary: "Measure what a push left behind again",
|
|
311
|
-
description:
|
|
312
|
-
"Runs the project's own push measurement over its main tree now and resolves every open finding it no longer prints. A few seconds; nothing is pushed.",
|
|
313
|
-
})
|
|
314
|
-
.input(PushRecheckSchema)
|
|
315
|
-
.output(PushRecheckResultSchema),
|
|
316
279
|
repos: procedure
|
|
317
280
|
.route({
|
|
318
281
|
method: "GET",
|
|
@@ -38,13 +38,16 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
38
38
|
remote: z.string().optional(),
|
|
39
39
|
}),
|
|
40
40
|
// After a clean isolated turn's delta lands or not: `landed` puts it uncommitted in the main tree, `conflicts`
|
|
41
|
-
// names paths that failed, `held` means nothing happened. `deps` covers undeclared dependencies.
|
|
41
|
+
// names paths that failed, `held` means nothing happened. `deps` covers undeclared dependencies. `into` names the
|
|
42
|
+
// parent conversation a spawned child's work went into instead of the main tree, as an in-process subagent's edits
|
|
43
|
+
// go into its parent's checkout.
|
|
42
44
|
z.object({
|
|
43
45
|
kind: z.literal("landed"),
|
|
44
46
|
landed: z.boolean(),
|
|
45
47
|
conflicts: z.array(LandConflictSchema).optional(),
|
|
46
48
|
held: z.boolean().optional(),
|
|
47
49
|
deps: z.object({ missing: z.number(), started: z.array(z.string()), deferred: z.boolean() }).optional(),
|
|
50
|
+
into: z.string().optional(),
|
|
48
51
|
}),
|
|
49
52
|
// Notes the daemon prepends to the user's message before the model reads it, verbatim, one per note. Serialized
|
|
50
53
|
// from the same typed notes the wire prompt uses, so disclosure cannot drift from what the model got.
|
|
@@ -180,6 +183,17 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
180
183
|
z.object({ kind: z.literal("account_usage"), account: z.string().optional(), windows: z.array(UsageWindowSchema) }),
|
|
181
184
|
ContextUsageSchema.extend({ kind: z.literal("context_usage") }),
|
|
182
185
|
z.object({ kind: z.literal("compact"), trigger: z.string(), preTokens: z.number().optional(), postTokens: z.number().optional() }),
|
|
186
|
+
// An agent's own project-dependency install was let through the command gate: where it writes, and which projects
|
|
187
|
+
// it works on, so the chat says so before its output arrives. Said by every runtime the gate stands in front of.
|
|
188
|
+
z.object({
|
|
189
|
+
kind: z.literal("install"),
|
|
190
|
+
reach: z
|
|
191
|
+
.enum(["own-copy", "main-tree"])
|
|
192
|
+
.describe("Where it writes: this conversation's own copy of the tree, or the main tree every conversation reads."),
|
|
193
|
+
projects: z
|
|
194
|
+
.array(z.string())
|
|
195
|
+
.describe("The projects it works on, workspace-relative, the workspace root as an empty string; empty when none could be named."),
|
|
196
|
+
}),
|
|
183
197
|
// The four interactive cards; each parks the turn until `POST /agent/reply` resolves its `requestId`.
|
|
184
198
|
PlanRequestSchema,
|
|
185
199
|
QuestionRequestSchema,
|
|
@@ -252,6 +266,9 @@ export const AgentEventSchema = z.discriminatedUnion("kind", [
|
|
|
252
266
|
// The model cannot hold a turn this size, refused before sending; retrying the same request never
|
|
253
267
|
// helps.
|
|
254
268
|
"context-window-too-small",
|
|
269
|
+
// The model can only write one-shot jobs (Model.helperOnly: its server says it cannot call tools, or
|
|
270
|
+
// it is the quick-jobs local model), refused before sending; the words wait for another model.
|
|
271
|
+
"model-helper-only",
|
|
255
272
|
// The session outgrew the model's context window mid-turn; resuming that session only overflows again,
|
|
256
273
|
// so the daemon re-runs the turn once in a fresh session carrying the hand-off.
|
|
257
274
|
"context-overflow",
|
|
@@ -44,6 +44,9 @@ export interface ChildReportFields {
|
|
|
44
44
|
readonly report: string;
|
|
45
45
|
// Undefined when nothing of the child's work was seen, which is not a verdict.
|
|
46
46
|
readonly verification: SubagentVerification | undefined;
|
|
47
|
+
// Where its work went, in the daemon's words: into the parent's own checkout, or held off it by a clash. Undefined
|
|
48
|
+
// for a child whose work lands as any conversation's does.
|
|
49
|
+
readonly landing?: string | undefined;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
// The wait tool's `verification` field, in words.
|
|
@@ -73,7 +76,7 @@ export const childReportPrompt = (fields: ChildReportFields): string => {
|
|
|
73
76
|
"",
|
|
74
77
|
fields.report.trim() === "" ? "(It ended without a closing report.)" : fields.report.trim(),
|
|
75
78
|
"",
|
|
76
|
-
"Its changes are in its own worktree and land the way any agent's do. Its account of its own work is a claim, not
|
|
79
|
+
`${fields.landing ?? "Its changes are in its own worktree and land the way any agent's do."} Its account of its own work is a claim, not ` +
|
|
77
80
|
"a result: check what matters before you build on it, and follow up with the subagents tools as you would mid-turn.",
|
|
78
81
|
].join("\n");
|
|
79
82
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
// The follow-ups the daemon USED to send when the check it ran after every land
|
|
1
|
+
// The follow-ups the daemon USED to send when the check it ran after every land failed: back to the conversation
|
|
2
2
|
// that landed the work, or to a fresh conversation started on it. Nothing sends either any more: nothing checks work
|
|
3
|
-
// after it lands, CI checks what the owner pushes (schemas/
|
|
4
|
-
//
|
|
5
|
-
// as their own words.
|
|
3
|
+
// after it lands, CI checks what the owner pushes (schemas/ci.ts). They stay on the wire because records already hold
|
|
4
|
+
// them, and the chat has to go on recognising them: a prompt nobody typed must not reach a reader as their own words.
|
|
6
5
|
|
|
7
6
|
// Anchored on by the chat, so it must stay unique and stable across releases.
|
|
8
7
|
export const LAND_BREAKAGE_OPENING =
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RESUME_NOTES, resumeDisclosure, withResumeNote, withoutResumeNote } from "./resume.js";
|
|
1
|
+
import { RESUME_NOTES, resumeDisclosure, resumeNoticeRow, withResumeNote, withoutResumeNote } from "./resume.js";
|
|
2
2
|
|
|
3
3
|
// Wrapping then unwrapping a resume note must return the exact original prompt; a mismatch leaks machine narration into
|
|
4
4
|
// the user's own words on screen.
|
|
@@ -46,7 +46,7 @@ test("the spent-allowance notes do not disclose as each other", () => {
|
|
|
46
46
|
test("a turn the door turned away discloses as its own notice, apart from the allowance's refusal", () => {
|
|
47
47
|
const door = resumeDisclosure(withResumeNote("ship the parser", RESUME_NOTES.door));
|
|
48
48
|
const refused = resumeDisclosure(withResumeNote("ship the parser", RESUME_NOTES.refused));
|
|
49
|
-
expect(door).toEqual({ kind: "notice", text: expect.stringContaining("turned away") });
|
|
49
|
+
expect(door).toEqual({ kind: "notice", text: expect.stringContaining("turned away"), reason: "door" });
|
|
50
50
|
expect(door).not.toEqual(refused);
|
|
51
51
|
});
|
|
52
52
|
|
|
@@ -60,5 +60,16 @@ test("a re-run after the window overflowed discloses as its own notice", () => {
|
|
|
60
60
|
expect(resumeDisclosure(withResumeNote("ship the parser", RESUME_NOTES.overflow))).toEqual({
|
|
61
61
|
kind: "notice",
|
|
62
62
|
text: "Sent again in a fresh session after the last one outgrew the model's context window.",
|
|
63
|
+
reason: "overflow",
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// The row keeps the English line, and names the re-run so an app can say it in its reader's language.
|
|
68
|
+
test("a re-run's notice row names its reason beside its words", () => {
|
|
69
|
+
const disclosure = resumeDisclosure(withResumeNote("ship the parser", RESUME_NOTES.restart));
|
|
70
|
+
expect(disclosure?.kind === "notice" ? resumeNoticeRow(disclosure) : undefined).toEqual({
|
|
71
|
+
role: "notice",
|
|
72
|
+
text: "The sandbox came back, this turn picked up where it left off.",
|
|
73
|
+
noticeCode: { code: "resumed", params: { reason: "restart" } },
|
|
63
74
|
});
|
|
64
75
|
});
|
package/src/events/resume.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { noticeCode, type ResumeNoticeReason } from "./sandbox-notice.js";
|
|
2
|
+
import type { TranscriptRow, TurnNote } from "./transcript.js";
|
|
2
3
|
|
|
3
4
|
// What a resumed turn's prompt says happened; lives on the wire since the client must recognise it too.
|
|
4
5
|
|
|
@@ -46,23 +47,35 @@ export type ResumeReason = keyof typeof RESUME_NOTES;
|
|
|
46
47
|
|
|
47
48
|
// How a resumed turn's interruption reads to a person: `notice` for the whole-turn re-runs, a muted line with the
|
|
48
49
|
// repeat dropped; `note` for the answered case, the user's real answer disclosed normally.
|
|
49
|
-
|
|
50
|
+
// A notice names its reason too, so the row it becomes can say it in the reader's language (sandbox-notice.ts).
|
|
51
|
+
export type ResumeDisclosure =
|
|
52
|
+
| { readonly kind: "notice"; readonly text: string; readonly reason: ResumeNoticeReason }
|
|
53
|
+
| { readonly kind: "note"; readonly note: TurnNote };
|
|
54
|
+
|
|
55
|
+
const notice = (reason: ResumeNoticeReason, text: string): ResumeDisclosure => ({ kind: "notice", text, reason });
|
|
50
56
|
|
|
51
57
|
const RESUME_DISCLOSURES: Record<ResumeReason, ResumeDisclosure> = {
|
|
52
|
-
auth:
|
|
53
|
-
outage:
|
|
54
|
-
restart:
|
|
55
|
-
stopped:
|
|
58
|
+
auth: notice("auth", "Claude sign-in renewed, this turn picked up where it left off."),
|
|
59
|
+
outage: notice("outage", "The model provider came back, this turn picked up where it left off."),
|
|
60
|
+
restart: notice("restart", "The sandbox came back, this turn picked up where it left off."),
|
|
61
|
+
stopped: notice("stopped", "Sent again after the turn stopped short, picking up where it left off."),
|
|
56
62
|
// None of these four auto-resumed, a person pressed Continue; `switched`/`carried` name the differing account.
|
|
57
|
-
limit:
|
|
58
|
-
switched:
|
|
59
|
-
carried:
|
|
60
|
-
refused:
|
|
61
|
-
door:
|
|
62
|
-
overflow:
|
|
63
|
+
limit: notice("limit", "Sent again after the allowance ran out mid-turn, picking up where it left off."),
|
|
64
|
+
switched: notice("switched", "Sent again on the switched account after the allowance ran out mid-turn, in a fresh session."),
|
|
65
|
+
carried: notice("carried", "Sent again on the switched account after the allowance ran out mid-turn, carrying the session with it."),
|
|
66
|
+
refused: notice("refused", "Sent again after the allowance refused it: nothing had run."),
|
|
67
|
+
door: notice("door", "Sent again: the first attempt was turned away before anything ran."),
|
|
68
|
+
overflow: notice("overflow", "Sent again in a fresh session after the last one outgrew the model's context window."),
|
|
63
69
|
answered: { kind: "note", note: { title: "Picked back up after a sandbox restart", text: RESUME_NOTES.answered } },
|
|
64
70
|
};
|
|
65
71
|
|
|
72
|
+
/** The row a whole-turn re-run stands in for its repeated words with, wherever a reader restores one. */
|
|
73
|
+
export const resumeNoticeRow = (resume: Extract<ResumeDisclosure, { kind: "notice" }>): TranscriptRow => ({
|
|
74
|
+
role: "notice",
|
|
75
|
+
text: resume.text,
|
|
76
|
+
noticeCode: noticeCode({ code: "resumed", params: { reason: resume.reason } }),
|
|
77
|
+
});
|
|
78
|
+
|
|
66
79
|
// What a stored prompt's resume note should be shown as; undefined when the prompt isn't a resume, so any reader can
|
|
67
80
|
// ask without checking first.
|
|
68
81
|
export const resumeDisclosure = (prompt: string): ResumeDisclosure | undefined => {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// The sandbox's own notice rows (a land, a hold, a renewal, a stop), as a code and the facts they were worded from. The
|
|
4
|
+
// row's `text` stays the English sentence, which older apps, stored transcripts and agents reading their own history
|
|
5
|
+
// go on reading; `noticeCode` beside it is what lets an app say the same thing in the reader's language and words.
|
|
6
|
+
|
|
7
|
+
// On the wire a code is any string and its facts a flat record: a transcript page carrying a code newer than its reader
|
|
8
|
+
// still parses, and that reader draws `text`. The codes this build writes, with their facts typed, are
|
|
9
|
+
// SandboxNoticeSchema below.
|
|
10
|
+
export const NoticeCodeSchema = z.object({
|
|
11
|
+
code: z.string().describe("Which of the sandbox's notices this row is, by name. A reader that does not know the name shows the row's text."),
|
|
12
|
+
params: z
|
|
13
|
+
.record(z.string(), z.union([z.string(), z.number(), z.boolean()]))
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("The facts the notice was worded from, by name: counts, names, and the provider's own sentence where the notice quotes one."),
|
|
16
|
+
});
|
|
17
|
+
export type NoticeCode = z.infer<typeof NoticeCodeSchema>;
|
|
18
|
+
|
|
19
|
+
const count = z.number().int().nonnegative();
|
|
20
|
+
|
|
21
|
+
// A failure's own sentence, which the notice's clause follows: the provider's words, or the sandbox's under `error`, its
|
|
22
|
+
// failure code, for a reader that words a failure it knows itself.
|
|
23
|
+
const failure = {
|
|
24
|
+
message: z.string(),
|
|
25
|
+
error: z.string().optional(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// The re-runs a resumed turn's row can name (events/resume.ts); a reason a reader does not know draws the row's text.
|
|
29
|
+
const ResumeNoticeReasonSchema = z.enum(["auth", "outage", "restart", "stopped", "limit", "switched", "carried", "refused", "door", "overflow"]);
|
|
30
|
+
export type ResumeNoticeReason = z.infer<typeof ResumeNoticeReasonSchema>;
|
|
31
|
+
|
|
32
|
+
// Every code this build writes, one per sentence shape, each with the facts that shape needs.
|
|
33
|
+
export const SandboxNoticeSchema = z.discriminatedUnion("code", [
|
|
34
|
+
z.object({ code: z.literal("compacted") }),
|
|
35
|
+
z.object({ code: z.literal("stopped") }),
|
|
36
|
+
// The branch was rebased onto `commits` new commits, and/or could not be in the repos named in `blocked`.
|
|
37
|
+
z.object({ code: z.literal("synced"), params: z.object({ commits: count, blocked: z.string().optional() }) }),
|
|
38
|
+
z.object({ code: z.literal("intoParent") }),
|
|
39
|
+
z.object({ code: z.literal("intoParentClash"), params: z.object({ files: count }) }),
|
|
40
|
+
z.object({ code: z.literal("landHeld") }),
|
|
41
|
+
z.object({ code: z.literal("landConflict"), params: z.object({ files: count, repos: z.string() }) }),
|
|
42
|
+
// `deps` dependencies the turn added or changed, installing now, or `queued` behind any other install.
|
|
43
|
+
z.object({ code: z.literal("landed"), params: z.object({ deps: count.optional(), queued: z.boolean().optional() }).optional() }),
|
|
44
|
+
z.object({ code: z.literal("retrying"), params: z.object({ ...failure, attempt: count, of: count }) }),
|
|
45
|
+
z.object({ code: z.literal("retried"), params: z.object({ ...failure, made: count, of: count }) }),
|
|
46
|
+
z.object({ code: z.literal("outageWaiting"), params: z.object(failure) }),
|
|
47
|
+
z.object({ code: z.literal("renewing"), params: z.object(failure) }),
|
|
48
|
+
z.object({ code: z.literal("renewalWithdrawn"), params: z.object(failure) }),
|
|
49
|
+
z.object({ code: z.literal("reconnect"), params: z.object(failure) }),
|
|
50
|
+
z.object({ code: z.literal("undelivered"), params: z.object({ ...failure, unattended: z.boolean().optional() }) }),
|
|
51
|
+
// A turn the sandbox kept whole, its message above; `memory` when a memory hold kept it.
|
|
52
|
+
z.object({ code: z.literal("kept"), params: z.object({ ...failure, memory: z.boolean().optional() }) }),
|
|
53
|
+
z.object({ code: z.literal("memoryHeld"), params: z.object(failure) }),
|
|
54
|
+
// A failure the sandbox names by code and adds nothing to.
|
|
55
|
+
z.object({ code: z.literal("failed"), params: z.object(failure) }),
|
|
56
|
+
z.object({ code: z.literal("questionDismissed") }),
|
|
57
|
+
z.object({ code: z.literal("planApproved") }),
|
|
58
|
+
z.object({ code: z.literal("keptPlanning") }),
|
|
59
|
+
// `note` is the agent's own words; `every` the interval, already worded ("5m").
|
|
60
|
+
z.object({ code: z.literal("watching"), params: z.object({ note: z.string(), every: z.string() }) }),
|
|
61
|
+
z.object({ code: z.literal("restartInterrupted") }),
|
|
62
|
+
// A turn that picked up a conversation the sandbox kept warm: `tokens` read from the cache ("305k"), or for
|
|
63
|
+
// keptCold sent again, after `span` ("2h 5m") and `refreshes` refreshes.
|
|
64
|
+
z.object({ code: z.literal("keptWarm"), params: z.object({ tokens: z.string(), span: z.string(), refreshes: count }) }),
|
|
65
|
+
z.object({ code: z.literal("keptCold"), params: z.object({ tokens: z.string(), span: z.string(), refreshes: count }) }),
|
|
66
|
+
// A turn sent thin for a small window ("16k"): what was left out, and whether the base instructions were swapped too.
|
|
67
|
+
z.object({ code: z.literal("contextTrim"), params: z.object({ window: z.string(), omitted: z.string().optional(), base: z.boolean() }) }),
|
|
68
|
+
z.object({ code: z.literal("resumed"), params: z.object({ reason: ResumeNoticeReasonSchema }) }),
|
|
69
|
+
// An agent's own dependency install starting: into its conversation's own copy (`ownCopy`) or the main tree; the
|
|
70
|
+
// workspace root (`root`) and up to three project folders named (`projects`, each with its slash, already joined),
|
|
71
|
+
// and how many `more` were not named.
|
|
72
|
+
z.object({
|
|
73
|
+
code: z.literal("installing"),
|
|
74
|
+
params: z.object({ ownCopy: z.boolean(), root: z.boolean().optional(), projects: z.string().optional(), more: count.optional() }),
|
|
75
|
+
}),
|
|
76
|
+
]);
|
|
77
|
+
export type SandboxNotice = z.infer<typeof SandboxNoticeSchema>;
|
|
78
|
+
|
|
79
|
+
/** The wire form of one of this build's notices, facts nobody gave left off rather than sent as nothing. */
|
|
80
|
+
export const noticeCode = (notice: SandboxNotice): NoticeCode => {
|
|
81
|
+
if (!("params" in notice) || notice.params === undefined) {
|
|
82
|
+
return { code: notice.code };
|
|
83
|
+
}
|
|
84
|
+
const params = Object.fromEntries(
|
|
85
|
+
Object.entries(notice.params).filter((entry): entry is [string, string | number | boolean] => entry[1] !== undefined),
|
|
86
|
+
);
|
|
87
|
+
return Object.keys(params).length === 0 ? { code: notice.code } : { code: notice.code, params };
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/** One of this build's notices, read off a row; undefined for a row without one, or with a code or facts this build does not know. */
|
|
91
|
+
export const sandboxNoticeOf = (row: { readonly noticeCode?: NoticeCode | undefined }): SandboxNotice | undefined =>
|
|
92
|
+
row.noticeCode === undefined ? undefined : SandboxNoticeSchema.safeParse(row.noticeCode).data;
|
|
@@ -53,6 +53,13 @@ export const HelloSchema = z.object({
|
|
|
53
53
|
shapes: z.record(z.string(), z.string()).optional(),
|
|
54
54
|
build: z.string().optional(),
|
|
55
55
|
boot: BootProgressSchema.optional(),
|
|
56
|
+
// A project sandbox's folder, workspace-relative (`my-app` for /work/my-app): the owner's own folder, synced live
|
|
57
|
+
// with their computer, which the browser scopes the workspace to on arrival. Absent on every other sandbox.
|
|
58
|
+
projectDir: z.string().optional(),
|
|
59
|
+
// What answers: a sandbox's daemon, or the desktop app's sidecar serving a folder on the user's own computer
|
|
60
|
+
// (_devices/local-files), whose `routes` are the few a folder has rather than a daemon's missing ones. Absent reads
|
|
61
|
+
// as a sandbox, which every daemon before this field was.
|
|
62
|
+
surface: z.enum(["sandbox", "folder"]).optional(),
|
|
56
63
|
});
|
|
57
64
|
export type Hello = z.infer<typeof HelloSchema>;
|
|
58
65
|
|
package/src/events/transcript.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { TurnErrandSchema, TurnSpeakerSchema } from "../schemas/speaker.js";
|
|
|
5
5
|
import { SubagentKindSchema, SubagentStatusSchema, SubagentVerificationSchema } from "../schemas/terminal.js";
|
|
6
6
|
import { NeedSchema } from "../schemas/needs.js";
|
|
7
7
|
import { RetryLadderSchema } from "../schemas/turn-break.js";
|
|
8
|
+
import { NoticeCodeSchema } from "./sandbox-notice.js";
|
|
8
9
|
import type { ToolCallContent, ToolCallLocation, ToolCallStatus, ToolKind} from "./requests.js";
|
|
9
10
|
import { browserHelpRequest, capabilityOfferRequest, CapabilityOutcomeSchema, credentialOfferRequest, CredentialReceiptSchema, paymentOfferRequest, PaymentReceiptSchema, PermissionAskSchema, permissionRequest, planRequest, questionRequest, terminalHelpRequest, TodoItemSchema, ToolCallContentSchema, ToolCallLocationSchema, ToolCallStatusSchema, ToolKindSchema } from "./requests.js";
|
|
10
11
|
|
|
@@ -105,7 +106,7 @@ export const TranscriptSubagentSchema = z.object({
|
|
|
105
106
|
.string()
|
|
106
107
|
.optional()
|
|
107
108
|
.describe(
|
|
108
|
-
"Its own id, where that is not the card's: a spawned subagent is named by its own conversation, which is what the roster, `wait` and its
|
|
109
|
+
"Its own id, where that is not the card's: a spawned subagent is named by its own conversation, which is what the roster, `wait` and its own chat call it. Absent, the card's id is its id, as it is for one the runtime started in-process.",
|
|
109
110
|
),
|
|
110
111
|
kind: SubagentKindSchema,
|
|
111
112
|
agentType: z.string().optional(),
|
|
@@ -300,6 +301,11 @@ export const TranscriptRowSchema = z.object({
|
|
|
300
301
|
.string()
|
|
301
302
|
.optional()
|
|
302
303
|
.describe("Which instance of the wait this notice names, for a kind that can have several running at once."),
|
|
304
|
+
// The sandbox's own notice by name, beside its English `text` (sandbox-notice.ts); absent on every other row, and
|
|
305
|
+
// on the notices written before rows carried it, which a reader draws from `text` as it always did.
|
|
306
|
+
noticeCode: NoticeCodeSchema.optional().describe(
|
|
307
|
+
"Which of the sandbox's own notices this row is, and the facts it was worded from, so a reader can say it in the reader's own language. The text stays the English sentence.",
|
|
308
|
+
),
|
|
303
309
|
// At most one card per row; a card closes its bubble. One field per kind, so a reader reaches it by name.
|
|
304
310
|
plan: TranscriptPlanSchema.optional().describe("The plan this row asked approval for, and the answer."),
|
|
305
311
|
question: TranscriptQuestionSchema.optional().describe("The questions this row asked, and the picks that answered them."),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// The follow-up the daemon USED to send when a turn ended with work it could not confirm. Nothing sends it any more:
|
|
2
|
-
// nothing checks inside a conversation, CI checks what the owner pushes (schemas/
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// nothing checks inside a conversation, CI checks what the owner pushes (schemas/ci.ts). It stays on the wire because
|
|
3
|
+
// records already hold it, and the chat has to go on recognising it: a prompt nobody typed must not reach a reader as
|
|
4
|
+
// their own words.
|
|
5
5
|
|
|
6
6
|
// Anchored on by the reader, so it must stay unique and stable across releases — a reworded opening un-recognises every
|
|
7
7
|
// nudge already in a record, and they read as the user's own typing again.
|