@intentic/sandbox-contract 1.343.0 → 1.345.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 +10 -0
- package/dist/contracts/accounts.contract.d.ts +24 -0
- package/dist/contracts/accounts.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.d.ts +214 -6
- package/dist/contracts/agent.contract.d.ts.map +1 -1
- package/dist/contracts/agent.contract.js +13 -2
- package/dist/contracts/agent.contract.js.map +1 -1
- package/dist/contracts/agents.contract.d.ts +656 -0
- package/dist/contracts/agents.contract.d.ts.map +1 -1
- package/dist/contracts/agents.contract.js +5 -3
- package/dist/contracts/agents.contract.js.map +1 -1
- package/dist/contracts/device.contract.d.ts +259 -0
- package/dist/contracts/device.contract.d.ts.map +1 -1
- package/dist/contracts/device.contract.js +5 -1
- package/dist/contracts/device.contract.js.map +1 -1
- package/dist/contracts/endpoints.contract.d.ts +2 -0
- package/dist/contracts/endpoints.contract.d.ts.map +1 -1
- package/dist/contracts/endpoints.contract.js +1 -0
- package/dist/contracts/endpoints.contract.js.map +1 -1
- package/dist/contracts/push.contract.d.ts +11 -0
- package/dist/contracts/push.contract.d.ts.map +1 -1
- package/dist/contracts/push.contract.js +10 -1
- package/dist/contracts/push.contract.js.map +1 -1
- package/dist/contracts/runner.contract.d.ts +18 -2
- package/dist/contracts/runner.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.d.ts +169 -0
- package/dist/contracts/secrets.contract.d.ts.map +1 -1
- package/dist/contracts/secrets.contract.js +35 -0
- package/dist/contracts/secrets.contract.js.map +1 -1
- package/dist/contracts/sessions.contract.d.ts +2 -0
- package/dist/contracts/sessions.contract.d.ts.map +1 -1
- package/dist/contracts/settings.contract.d.ts +37 -2
- package/dist/contracts/settings.contract.d.ts.map +1 -1
- package/dist/contracts/system.contract.d.ts +185 -35
- package/dist/contracts/system.contract.d.ts.map +1 -1
- package/dist/contracts/translator.contract.d.ts +24 -0
- package/dist/contracts/translator.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.d.ts +11 -0
- package/dist/contracts/workspace.contract.d.ts.map +1 -1
- package/dist/contracts/workspace.contract.js +11 -1
- package/dist/contracts/workspace.contract.js.map +1 -1
- package/dist/events/agent-events.d.ts +18 -0
- package/dist/events/agent-events.d.ts.map +1 -1
- package/dist/events/agent-events.js +3 -1
- package/dist/events/agent-events.js.map +1 -1
- package/dist/events/agent-transcript.d.ts +727 -0
- package/dist/events/agent-transcript.d.ts.map +1 -0
- package/dist/events/agent-transcript.js +34 -0
- package/dist/events/agent-transcript.js.map +1 -0
- package/dist/events/agent-words.d.ts +5 -0
- package/dist/events/agent-words.d.ts.map +1 -1
- package/dist/events/agent-words.js +9 -0
- package/dist/events/agent-words.js.map +1 -1
- package/dist/events/requests.d.ts +143 -0
- package/dist/events/requests.d.ts.map +1 -1
- package/dist/events/requests.js +35 -1
- package/dist/events/requests.js.map +1 -1
- package/dist/events/sandbox-notice.d.ts +7 -0
- package/dist/events/sandbox-notice.d.ts.map +1 -1
- package/dist/events/sandbox-notice.js +1 -0
- package/dist/events/sandbox-notice.js.map +1 -1
- package/dist/events/system-events.d.ts +88 -0
- package/dist/events/system-events.d.ts.map +1 -1
- package/dist/events/transcript.d.ts +20 -720
- package/dist/events/transcript.d.ts.map +1 -1
- package/dist/events/transcript.js +17 -19
- package/dist/events/transcript.js.map +1 -1
- package/dist/events/undelivered.d.ts +4 -0
- package/dist/events/undelivered.d.ts.map +1 -1
- package/dist/events/undelivered.js +13 -0
- package/dist/events/undelivered.js.map +1 -1
- package/dist/ids/conversation-ids.d.ts +2 -0
- package/dist/ids/conversation-ids.d.ts.map +1 -1
- package/dist/ids/conversation-ids.js +2 -0
- package/dist/ids/conversation-ids.js.map +1 -1
- package/dist/ids/row-ids.d.ts +3 -0
- package/dist/ids/row-ids.d.ts.map +1 -0
- package/dist/ids/row-ids.js +11 -0
- package/dist/ids/row-ids.js.map +1 -0
- package/dist/index.d.ts +1339 -48
- package/dist/index.d.ts.map +1 -1
- package/dist/models/agent-lanes.d.ts.map +1 -1
- package/dist/models/agent-lanes.js +3 -2
- package/dist/models/agent-lanes.js.map +1 -1
- package/dist/models/agent-standing.d.ts +4 -0
- package/dist/models/agent-standing.d.ts.map +1 -1
- package/dist/models/agent-standing.js +2 -1
- package/dist/models/agent-standing.js.map +1 -1
- package/dist/models/plan-pools.d.ts +5 -1
- package/dist/models/plan-pools.d.ts.map +1 -1
- package/dist/models/plan-pools.js +57 -21
- package/dist/models/plan-pools.js.map +1 -1
- package/dist/netd/generated/wire.d.ts +5 -0
- package/dist/netd/generated/wire.d.ts.map +1 -1
- package/dist/policy/command-classes.d.ts +1 -1
- package/dist/policy/command-classes.d.ts.map +1 -1
- package/dist/policy/command-classes.js +2 -2
- package/dist/policy/command-classes.js.map +1 -1
- package/dist/policy/keyring-origins.d.ts +27 -0
- package/dist/policy/keyring-origins.d.ts.map +1 -0
- package/dist/policy/keyring-origins.js +213 -0
- package/dist/policy/keyring-origins.js.map +1 -0
- package/dist/policy/keyring-seal.d.ts +9 -0
- package/dist/policy/keyring-seal.d.ts.map +1 -1
- package/dist/policy/keyring-seal.js +18 -6
- package/dist/policy/keyring-seal.js.map +1 -1
- package/dist/policy/safety-policy.d.ts +1 -1
- package/dist/policy/safety-policy.d.ts.map +1 -1
- package/dist/policy/safety-policy.js +1 -1
- package/dist/policy/safety-policy.js.map +1 -1
- package/dist/policy/turned-away.d.ts +1 -0
- package/dist/policy/turned-away.d.ts.map +1 -1
- package/dist/policy/turned-away.js +11 -0
- package/dist/policy/turned-away.js.map +1 -1
- package/dist/protocol/doors/host-protocol.d.ts +1 -0
- package/dist/protocol/doors/host-protocol.d.ts.map +1 -1
- package/dist/protocol/doors/host-protocol.js +1 -0
- package/dist/protocol/doors/host-protocol.js.map +1 -1
- package/dist/protocol/doors/webext-links.d.ts +1 -0
- package/dist/protocol/doors/webext-links.d.ts.map +1 -1
- package/dist/protocol/doors/webext-links.js +1 -0
- package/dist/protocol/doors/webext-links.js.map +1 -1
- package/dist/protocol/peer-dial.d.ts +2 -0
- package/dist/protocol/peer-dial.d.ts.map +1 -1
- package/dist/protocol/peer-dial.js +62 -29
- package/dist/protocol/peer-dial.js.map +1 -1
- package/dist/protocol/raw/raw-json-routes.d.ts +193 -0
- package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-json-routes.js +5 -0
- package/dist/protocol/raw/raw-json-routes.js.map +1 -1
- package/dist/protocol/raw/raw-routes.d.ts +31 -0
- package/dist/protocol/raw/raw-routes.d.ts.map +1 -1
- package/dist/protocol/raw/raw-routes.js +8 -0
- package/dist/protocol/raw/raw-routes.js.map +1 -1
- package/dist/schemas/agent-place.d.ts +10 -0
- package/dist/schemas/agent-place.d.ts.map +1 -0
- package/dist/schemas/agent-place.js +15 -0
- package/dist/schemas/agent-place.js.map +1 -0
- package/dist/schemas/agent.d.ts +116 -83
- package/dist/schemas/agent.d.ts.map +1 -1
- package/dist/schemas/agent.js +26 -39
- package/dist/schemas/agent.js.map +1 -1
- package/dist/schemas/agents-list.d.ts +38 -0
- package/dist/schemas/agents-list.d.ts.map +1 -1
- package/dist/schemas/agents.d.ts +117 -16
- package/dist/schemas/agents.d.ts.map +1 -1
- package/dist/schemas/agents.js +19 -21
- package/dist/schemas/agents.js.map +1 -1
- package/dist/schemas/attach.d.ts +8 -0
- package/dist/schemas/attach.d.ts.map +1 -0
- package/dist/schemas/attach.js +14 -0
- package/dist/schemas/attach.js.map +1 -0
- package/dist/schemas/command-admission.d.ts +71 -0
- package/dist/schemas/command-admission.d.ts.map +1 -0
- package/dist/schemas/command-admission.js +27 -0
- package/dist/schemas/command-admission.js.map +1 -0
- package/dist/schemas/conversation-links.d.ts +44 -0
- package/dist/schemas/conversation-links.d.ts.map +1 -0
- package/dist/schemas/conversation-links.js +35 -0
- package/dist/schemas/conversation-links.js.map +1 -0
- package/dist/schemas/data-protection.d.ts +5 -2
- package/dist/schemas/data-protection.d.ts.map +1 -1
- package/dist/schemas/data-protection.js +17 -1
- package/dist/schemas/data-protection.js.map +1 -1
- package/dist/schemas/device-folder.d.ts +61 -0
- package/dist/schemas/device-folder.d.ts.map +1 -0
- package/dist/schemas/device-folder.js +24 -0
- package/dist/schemas/device-folder.js.map +1 -0
- package/dist/schemas/devices.d.ts +112 -39
- package/dist/schemas/devices.d.ts.map +1 -1
- package/dist/schemas/devices.js +8 -10
- package/dist/schemas/devices.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 -0
- package/dist/schemas/hosts.js.map +1 -1
- package/dist/schemas/keyring-native.d.ts +137 -0
- package/dist/schemas/keyring-native.d.ts.map +1 -0
- package/dist/schemas/keyring-native.js +69 -0
- package/dist/schemas/keyring-native.js.map +1 -0
- package/dist/schemas/keyring.d.ts +413 -0
- package/dist/schemas/keyring.d.ts.map +1 -1
- package/dist/schemas/keyring.js +139 -4
- package/dist/schemas/keyring.js.map +1 -1
- package/dist/schemas/metrics.d.ts +11 -0
- package/dist/schemas/metrics.d.ts.map +1 -1
- package/dist/schemas/metrics.js +17 -0
- package/dist/schemas/metrics.js.map +1 -1
- package/dist/schemas/phone-passwords.d.ts +186 -0
- package/dist/schemas/phone-passwords.d.ts.map +1 -0
- package/dist/schemas/phone-passwords.js +25 -0
- package/dist/schemas/phone-passwords.js.map +1 -0
- package/dist/schemas/providers/plan-limits.d.ts +74 -0
- package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
- package/dist/schemas/providers/plan-limits.js +31 -0
- package/dist/schemas/providers/plan-limits.js.map +1 -1
- package/dist/schemas/providers/provider-oauth.d.ts +24 -0
- package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
- package/dist/schemas/providers/usage.d.ts +1 -0
- package/dist/schemas/providers/usage.d.ts.map +1 -1
- package/dist/schemas/providers/usage.js +1 -0
- package/dist/schemas/providers/usage.js.map +1 -1
- package/dist/schemas/push.d.ts +13 -0
- package/dist/schemas/push.d.ts.map +1 -1
- package/dist/schemas/push.js +11 -1
- package/dist/schemas/push.js.map +1 -1
- package/dist/schemas/sandbox-passwords.d.ts +288 -0
- package/dist/schemas/sandbox-passwords.d.ts.map +1 -0
- package/dist/schemas/sandbox-passwords.js +66 -0
- package/dist/schemas/sandbox-passwords.js.map +1 -0
- package/dist/schemas/secrets.d.ts +2 -0
- package/dist/schemas/secrets.d.ts.map +1 -1
- package/dist/schemas/secrets.js +4 -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 +15 -0
- package/dist/schemas/settings-history.js.map +1 -1
- package/dist/schemas/settings-savings.d.ts +709 -0
- package/dist/schemas/settings-savings.d.ts.map +1 -0
- package/dist/schemas/settings-savings.js +53 -0
- package/dist/schemas/settings-savings.js.map +1 -0
- package/dist/schemas/settings.d.ts +7 -673
- package/dist/schemas/settings.d.ts.map +1 -1
- package/dist/schemas/settings.js +7 -58
- package/dist/schemas/settings.js.map +1 -1
- package/dist/schemas/terminal.d.ts +5 -0
- package/dist/schemas/terminal.d.ts.map +1 -1
- package/dist/schemas/terminal.js +4 -0
- package/dist/schemas/terminal.js.map +1 -1
- package/dist/schemas/work-assurance.d.ts +24 -0
- package/dist/schemas/work-assurance.d.ts.map +1 -0
- package/dist/schemas/work-assurance.js +23 -0
- package/dist/schemas/work-assurance.js.map +1 -0
- package/dist/schemas/workspace/workspace-tree.d.ts +23 -0
- package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
- package/dist/schemas/workspace/workspace-tree.js +20 -0
- package/dist/schemas/workspace/workspace-tree.js.map +1 -1
- package/dist/state/auth-state.d.ts +4 -0
- package/dist/state/auth-state.d.ts.map +1 -0
- package/dist/state/auth-state.js +37 -0
- package/dist/state/auth-state.js.map +1 -0
- 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 +17 -1
- package/dist/state/history-state.js.map +1 -1
- package/dist/state/runtime-state.d.ts.map +1 -1
- package/dist/state/runtime-state.js.map +1 -1
- package/dist/text/transcript-fold.js +5 -5
- 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 +6 -5
- package/src/contracts/agent.contract.ts +13 -1
- package/src/contracts/agents.contract.ts +4 -3
- package/src/contracts/device.contract.ts +16 -0
- package/src/contracts/endpoints.contract.ts +3 -0
- package/src/contracts/push.contract.ts +23 -1
- package/src/contracts/secrets.contract.ts +39 -0
- package/src/contracts/workspace.contract.ts +16 -0
- package/src/events/agent-events.ts +6 -1
- package/src/events/agent-transcript.ts +48 -0
- package/src/events/agent-words.ts +13 -0
- package/src/events/requests.ts +41 -3
- package/src/events/sandbox-notice.ts +3 -0
- package/src/events/transcript.ts +30 -28
- package/src/events/undelivered.ts +18 -0
- package/src/ids/conversation-ids.ts +7 -0
- package/src/ids/row-ids.ts +20 -0
- package/src/models/agent-lanes.ts +9 -3
- package/src/models/agent-standing.ts +9 -1
- package/src/models/plan-pools.test.ts +128 -20
- package/src/models/plan-pools.ts +114 -31
- package/src/netd/generated/netd-wire.json +25 -0
- package/src/netd/generated/wire.ts +1 -1
- package/src/policy/command-classes.ts +2 -2
- package/src/policy/keyring-origins.test.ts +132 -0
- package/src/policy/keyring-origins.ts +287 -0
- package/src/policy/keyring-seal.test.ts +37 -2
- package/src/policy/keyring-seal.ts +33 -7
- package/src/policy/safety-policy.ts +1 -1
- package/src/policy/tests/safety-policy.test.ts +1 -1
- package/src/policy/turned-away.ts +16 -0
- package/src/protocol/doors/host-protocol.ts +3 -0
- package/src/protocol/doors/webext-links.ts +3 -0
- package/src/protocol/peer-dial.test.ts +90 -4
- package/src/protocol/peer-dial.ts +83 -39
- package/src/protocol/raw/raw-json-routes.ts +13 -0
- package/src/protocol/raw/raw-routes.ts +12 -1
- package/src/schemas/agent-place.ts +22 -0
- package/src/schemas/agent.ts +42 -78
- package/src/schemas/agents.ts +41 -46
- package/src/schemas/attach.ts +23 -0
- package/src/schemas/command-admission.ts +57 -0
- package/src/schemas/conversation-links.ts +62 -0
- package/src/schemas/data-protection.ts +36 -10
- package/src/schemas/device-folder.ts +59 -0
- package/src/schemas/devices.ts +17 -42
- package/src/schemas/hosts.ts +4 -0
- package/src/schemas/keyring-native.test.ts +13 -0
- package/src/schemas/keyring-native.ts +101 -0
- package/src/schemas/keyring.ts +202 -4
- package/src/schemas/metrics.ts +28 -3
- package/src/schemas/phone-passwords.ts +51 -0
- package/src/schemas/providers/plan-limits.ts +49 -2
- package/src/schemas/providers/usage.ts +2 -0
- package/src/schemas/push.ts +19 -3
- package/src/schemas/sandbox-passwords.ts +88 -0
- package/src/schemas/secrets.ts +4 -0
- package/src/schemas/settings-history.ts +20 -0
- package/src/schemas/settings-savings.ts +125 -0
- package/src/schemas/settings.test.ts +38 -0
- package/src/schemas/settings.ts +20 -128
- package/src/schemas/terminal.ts +8 -0
- package/src/schemas/work-assurance.ts +36 -0
- package/src/schemas/workspace/workspace-tree.ts +32 -0
- package/src/state/auth-state.ts +89 -0
- package/src/state/history-state.ts +44 -1
- package/src/state/runtime-state.ts +5 -4
- package/src/text/transcript-fold.test.ts +67 -0
- package/src/text/transcript-fold.ts +6 -6
- package/src/webext/index.ts +2 -0
|
@@ -58,8 +58,9 @@ export interface PeerDialSpec<S extends SocketLike> {
|
|
|
58
58
|
readonly hello: () => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
59
59
|
// Hand the open socket to the oRPC handler serving the door's contract.
|
|
60
60
|
readonly attach: (socket: S) => void;
|
|
61
|
-
// The retry ladder: how long to wait after a drop, given how long the socket had held
|
|
62
|
-
|
|
61
|
+
// The retry ladder: how long to wait after a drop, given how long the socket had held; `reset` puts it back on its
|
|
62
|
+
// floor (`retryNow`).
|
|
63
|
+
readonly backoff: { readonly next: (heldMs: number) => number; readonly reset: () => void };
|
|
63
64
|
/* How long this socket may hear nothing before the link is presumed dead: `peerLinkSilenceMs` of the heartbeat the door's own hub pings on. */
|
|
64
65
|
readonly silenceMs: number;
|
|
65
66
|
readonly log: (message: string) => void;
|
|
@@ -86,8 +87,71 @@ export interface PeerLink {
|
|
|
86
87
|
readonly stop: (reason?: string) => void;
|
|
87
88
|
readonly state: () => PeerLinkState;
|
|
88
89
|
readonly outage: () => PeerOutage | undefined;
|
|
90
|
+
/* SOMEBODY KNOWS THE FAR END IS BACK, so the link need not wait to find out (2026-10-19). A machine agent that has
|
|
91
|
+
just woken a sleeping sandbox knows it is starting, but the link to it had spent the sleep on the ladder: past
|
|
92
|
+
LONG_OUTAGE_ATTEMPTS each try rests a quarter of an hour, and on rog a sandbox woken at 16:48 had its link back at
|
|
93
|
+
17:12, 24 minutes with no device tools. This ends a wait on the ladder (the long rest included) and dials now,
|
|
94
|
+
and puts the outage behind it as an answer would (`failures`, the quiet rule, its `since`, the ladder's rung), so
|
|
95
|
+
a dial that finds the sandbox still booting retries on the fast floor. A dial in flight is left to finish and
|
|
96
|
+
only its ladder is reset, so a failure of it retries fast too; an open or stopped link is untouched. */
|
|
97
|
+
readonly retryNow: () => void;
|
|
89
98
|
}
|
|
90
99
|
|
|
100
|
+
/* ONE OUTAGE'S BOOKKEEPING: the attempts that have failed since the link was last open, when the first of them was, and
|
|
101
|
+
what each may say (the quiet rule above). An answer clears it, and so does `retryNow`. */
|
|
102
|
+
const failureRun = (log: (message: string) => void) => {
|
|
103
|
+
let failures = 0;
|
|
104
|
+
// When the loop last complained out loud, and when the CURRENT outage began.
|
|
105
|
+
let quietSince = 0;
|
|
106
|
+
let since: number | undefined;
|
|
107
|
+
return {
|
|
108
|
+
count: (): number => failures,
|
|
109
|
+
// One more failed attempt; answers how many that makes.
|
|
110
|
+
fail: (): number => {
|
|
111
|
+
failures += 1;
|
|
112
|
+
since ??= Date.now();
|
|
113
|
+
return failures;
|
|
114
|
+
},
|
|
115
|
+
/* What ONE failed attempt is allowed to say. */
|
|
116
|
+
complain: (said: string, delay: number): void => {
|
|
117
|
+
const every = `retrying every ${Math.round(delay / 1000)}s`;
|
|
118
|
+
if (failures <= LOUD_ATTEMPTS) {
|
|
119
|
+
log(`${said}; reconnecting in ${Math.round(delay / 1000)}s`);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (failures === LOUD_ATTEMPTS + 1) {
|
|
123
|
+
quietSince = Date.now();
|
|
124
|
+
log(`${said}; still nothing after ${failures} attempts — ${every}, and saying so at most every ${Math.round(QUIET_LOG_MS / 60_000)} minutes from here`);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (Date.now() - quietSince >= QUIET_LOG_MS) {
|
|
128
|
+
quietSince = Date.now();
|
|
129
|
+
log(`${said}; ${failures} failed attempts, ${every}`);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
clear: (): void => {
|
|
133
|
+
failures = 0;
|
|
134
|
+
quietSince = 0;
|
|
135
|
+
since = undefined;
|
|
136
|
+
},
|
|
137
|
+
reading: (): PeerOutage | undefined => (since === undefined ? undefined : { failures, since }),
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/* THE WAIT ON THE LADDER hangs off the loop's stop, so a link stopped during it is done at once and never dials again,
|
|
142
|
+
and off a controller of its own, which `retryNow` aborts to dial at once. Cutting a wait already over does nothing. */
|
|
143
|
+
const ladderWaits = (stopping: AbortSignal) => {
|
|
144
|
+
let resting: AbortController | undefined;
|
|
145
|
+
return {
|
|
146
|
+
wait: (delay: number, dial: () => Promise<void>): void => {
|
|
147
|
+
const rest = new AbortController();
|
|
148
|
+
resting = rest;
|
|
149
|
+
void sleep(delay, { signal: anySignal(stopping, rest.signal) }).then(() => (stopping.aborted ? undefined : dial()));
|
|
150
|
+
},
|
|
151
|
+
cut: (): void => resting?.abort(),
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
91
155
|
export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink => {
|
|
92
156
|
// The loop's whole life: every way it ends (a stop, a revocation, a pairing gone) aborts this, and everything the
|
|
93
157
|
// loop arms hangs off it, so nothing it left behind can dial, wait or fire once it is over. A stopped link that
|
|
@@ -96,32 +160,8 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
|
|
|
96
160
|
const done = new Promise<void>((resolve) => void whenAborted(stopping.signal, () => resolve()));
|
|
97
161
|
let socket: S | undefined;
|
|
98
162
|
let openedAt: number | undefined;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
let failures = 0;
|
|
102
|
-
let quietSince = 0;
|
|
103
|
-
// When the CURRENT outage began, as opposed to when this link was last complained about.
|
|
104
|
-
let failingSince: number | undefined;
|
|
105
|
-
|
|
106
|
-
/* What ONE failed attempt is allowed to say. */
|
|
107
|
-
const complain = (said: string, delay: number): void => {
|
|
108
|
-
const every = `retrying every ${Math.round(delay / 1000)}s`;
|
|
109
|
-
if (failures <= LOUD_ATTEMPTS) {
|
|
110
|
-
spec.log(`${said}; reconnecting in ${Math.round(delay / 1000)}s`);
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (failures === LOUD_ATTEMPTS + 1) {
|
|
114
|
-
quietSince = Date.now();
|
|
115
|
-
spec.log(
|
|
116
|
-
`${said}; still nothing after ${failures} attempts — ${every}, and saying so at most every ${Math.round(QUIET_LOG_MS / 60_000)} minutes from here`,
|
|
117
|
-
);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (Date.now() - quietSince >= QUIET_LOG_MS) {
|
|
121
|
-
quietSince = Date.now();
|
|
122
|
-
spec.log(`${said}; ${failures} failed attempts, ${every}`);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
163
|
+
const outage = failureRun(spec.log);
|
|
164
|
+
const ladder = ladderWaits(stopping.signal);
|
|
125
165
|
|
|
126
166
|
const open = async (): Promise<void> => {
|
|
127
167
|
const attempt = await spec.open(stopping.signal);
|
|
@@ -155,14 +195,11 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
|
|
|
155
195
|
}
|
|
156
196
|
const rung = spec.backoff.next(openedAt === undefined ? 0 : Date.now() - openedAt);
|
|
157
197
|
openedAt = undefined;
|
|
158
|
-
failures += 1;
|
|
159
|
-
failingSince ??= Date.now();
|
|
160
198
|
// The rest is added to the ladder's draw rather than replacing it: a flat fifteen minutes would bring back in
|
|
161
199
|
// lockstep every link that entered the long outage together.
|
|
162
|
-
const delay =
|
|
163
|
-
complain(said, delay);
|
|
164
|
-
|
|
165
|
-
void sleep(delay, { signal: stopping.signal }).then(() => (stopping.signal.aborted ? undefined : open()));
|
|
200
|
+
const delay = outage.fail() >= LONG_OUTAGE_ATTEMPTS ? LONG_OUTAGE_MS + rung : rung;
|
|
201
|
+
outage.complain(said, delay);
|
|
202
|
+
ladder.wait(delay, open);
|
|
166
203
|
};
|
|
167
204
|
|
|
168
205
|
const arm = (): void => {
|
|
@@ -189,9 +226,7 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
|
|
|
189
226
|
openedAt = Date.now();
|
|
190
227
|
// A link that is up owes nothing to the failures behind it: the next outage is news again, and the
|
|
191
228
|
// "connected to …" line this open is about to log is what reports the recovery.
|
|
192
|
-
|
|
193
|
-
quietSince = 0;
|
|
194
|
-
failingSince = undefined;
|
|
229
|
+
outage.clear();
|
|
195
230
|
arm();
|
|
196
231
|
spec.attach(ws);
|
|
197
232
|
const send = (hello: Record<string, unknown>): void => {
|
|
@@ -230,7 +265,7 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
|
|
|
230
265
|
|
|
231
266
|
/* Socket errors record a cause; the close event owns retry scheduling. */
|
|
232
267
|
ws.addEventListener("error", () => {
|
|
233
|
-
if (
|
|
268
|
+
if (outage.count() < LOUD_ATTEMPTS) {
|
|
234
269
|
spec.log("connection error");
|
|
235
270
|
}
|
|
236
271
|
});
|
|
@@ -251,6 +286,15 @@ export const dialPeer = <S extends SocketLike>(spec: PeerDialSpec<S>): PeerLink
|
|
|
251
286
|
// ladder) and a finished one is closed: read off the loop itself, not a flag kept beside it that a redial
|
|
252
287
|
// firing after the stop could set back.
|
|
253
288
|
state: () => (socket?.readyState === OPEN ? "open" : stopping.signal.aborted ? "closed" : "connecting"),
|
|
254
|
-
outage:
|
|
289
|
+
outage: outage.reading,
|
|
290
|
+
retryNow: () => {
|
|
291
|
+
if (stopping.signal.aborted || socket?.readyState === OPEN) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
outage.clear();
|
|
295
|
+
spec.backoff.reset();
|
|
296
|
+
// Waiting on the ladder: the wait ends now and its dial follows. A dial in flight has no wait to end.
|
|
297
|
+
ladder.cut();
|
|
298
|
+
},
|
|
255
299
|
};
|
|
256
300
|
};
|
|
@@ -17,6 +17,15 @@ import { HostsListSchema } from "../../schemas/hosts.js";
|
|
|
17
17
|
import { VoicesViewSchema } from "../../schemas/voice.js";
|
|
18
18
|
import { MemberEmailSchema, MemberGrantSchema, MemberSelfSchema, MembersListSchema, MembersRosterSchema } from "../../schemas/members.js";
|
|
19
19
|
import { PhonesListSchema, PhoneWakeRegistrationSchema } from "../../schemas/phone.js";
|
|
20
|
+
import {
|
|
21
|
+
PhoneKeyringsResultSchema,
|
|
22
|
+
PhonePasswordsCaptureResultSchema,
|
|
23
|
+
PhonePasswordsCaptureSchema,
|
|
24
|
+
PhonePasswordsFillResultSchema,
|
|
25
|
+
PhonePasswordsFillSchema,
|
|
26
|
+
PhonePasswordsPairResultSchema,
|
|
27
|
+
PhonePasswordsPairSchema,
|
|
28
|
+
} from "../../schemas/phone-passwords.js";
|
|
20
29
|
import { OkSchema } from "../../schemas/shared.js";
|
|
21
30
|
import { EnrollCodeAnswerSchema, EnrollCodeRequestSchema, PeerPairingAnswerSchema, SyncPairAnswerSchema, SyncPairRequestSchema } from "../../schemas/short-codes.js";
|
|
22
31
|
import { SpeechStatusSchema, SpeechTranscriptSchema, SpeechWakeClaimSchema, SpeechWakeGrantSchema } from "../../schemas/speech.js";
|
|
@@ -133,6 +142,10 @@ export const RAW_JSON_ROUTES = {
|
|
|
133
142
|
"POST /system/phones/pair": { output: PeerPairingAnswerSchema },
|
|
134
143
|
"DELETE /system/phones/{id}": { output: OkSchema },
|
|
135
144
|
"POST /system/phones/{id}/wake": { input: PhoneWakeRegistrationSchema, output: OkSchema },
|
|
145
|
+
"GET /system/phones/passwords/keyrings": { output: PhoneKeyringsResultSchema },
|
|
146
|
+
"POST /system/phones/passwords/pair": { input: PhonePasswordsPairSchema, output: PhonePasswordsPairResultSchema },
|
|
147
|
+
"POST /system/phones/passwords/capture": { input: PhonePasswordsCaptureSchema, output: PhonePasswordsCaptureResultSchema },
|
|
148
|
+
"POST /system/phones/passwords/fill": { input: PhonePasswordsFillSchema, output: PhonePasswordsFillResultSchema },
|
|
136
149
|
"GET /system/runners": { output: RunnersListSchema },
|
|
137
150
|
"DELETE /system/runners/{id}": { output: OkSchema },
|
|
138
151
|
"POST /system/runners/{id}/definition/sync": { output: RunnerDefinitionAppliedSchema },
|
|
@@ -13,6 +13,8 @@ export const RAW_ROUTES = {
|
|
|
13
13
|
// A person opening this sandbox's own address in a browser: sent to the app's /open on it, the address being what
|
|
14
14
|
// they may still hold when the platform has lost the rest. Anything else gets the same 401 as before it existed.
|
|
15
15
|
"GET /": { auth: "door", beforeBoot: true },
|
|
16
|
+
// The tab icon a browser asks for on that address: the lotus in the sandbox green, the same bytes for everyone.
|
|
17
|
+
"GET /favicon.ico": { auth: "door", beforeBoot: true },
|
|
16
18
|
"GET /diff/raw": { lane: "bulk" },
|
|
17
19
|
// Arming the dictation model is a read any tier makes; dictating is writing a message, the collaborator's grant.
|
|
18
20
|
"GET /speech/status": { guest: true },
|
|
@@ -149,9 +151,11 @@ export const RAW_ROUTES = {
|
|
|
149
151
|
"POST /children/delegate": { agent: true, control: "never" },
|
|
150
152
|
"GET /children/links": { agent: true, control: "never" },
|
|
151
153
|
"GET /children": { agent: true, control: "never" },
|
|
152
|
-
// The fleet reads, and
|
|
154
|
+
// The fleet reads, and its two writes: words in front of another conversation, which a person can do by typing, and
|
|
155
|
+
// the Continue a person can press on one a spent allowance or a stop held (`agents resume`).
|
|
153
156
|
"GET /fleet": { agent: true },
|
|
154
157
|
"POST /fleet/message": { agent: true },
|
|
158
|
+
"POST /fleet/resume": { agent: true },
|
|
155
159
|
"GET /fleet/{handle}": { agent: true },
|
|
156
160
|
// The `devices push` CLI: a program the agent built, carried to one of the owner's computers in chunks; held to the
|
|
157
161
|
// devices the calling conversation's turn mounts, and refused by the machine itself unless "Run programs" is on.
|
|
@@ -192,6 +196,7 @@ export const RAW_ROUTES = {
|
|
|
192
196
|
"DELETE /system/hosts/{id}": { control: "never" },
|
|
193
197
|
// A peer's socket reconnects on its own backoff, so it answers before boot.
|
|
194
198
|
"GET /system/hosts/connect": { auth: "door", beforeBoot: true, control: "never" },
|
|
199
|
+
"POST /system/hosts/keyring-changed": { auth: "door", control: "never" },
|
|
195
200
|
"POST /system/webext/pair": { control: "never" },
|
|
196
201
|
"POST /system/webext/enroll": { auth: "door", control: "never" },
|
|
197
202
|
"GET /system/webext": { control: "never" },
|
|
@@ -204,6 +209,11 @@ export const RAW_ROUTES = {
|
|
|
204
209
|
"GET /system/phones/connect": { auth: "door", beforeBoot: true, control: "never" },
|
|
205
210
|
// The editor hands over the push-relay channel it registered for a phone, so the sandbox can wake it.
|
|
206
211
|
"POST /system/phones/{id}/wake": { control: "never" },
|
|
212
|
+
// The phone as Android's autofill service (schemas/phone-passwords.ts): each checks the phone's enrollment token itself.
|
|
213
|
+
"GET /system/phones/passwords/keyrings": { auth: "door", control: "never" },
|
|
214
|
+
"POST /system/phones/passwords/pair": { auth: "door", control: "never" },
|
|
215
|
+
"POST /system/phones/passwords/capture": { auth: "door", control: "never" },
|
|
216
|
+
"POST /system/phones/passwords/fill": { auth: "door", control: "never" },
|
|
207
217
|
"POST /system/runners/pair": { control: "never" },
|
|
208
218
|
"POST /system/runners/enroll": { auth: "door", control: "never" },
|
|
209
219
|
"GET /system/runners": { control: "never" },
|
|
@@ -219,6 +229,7 @@ export const RAW_ROUTES = {
|
|
|
219
229
|
// A secret the browser types for the agent (`type_secret` aimed at it): one value for one ticket the daemon minted
|
|
220
230
|
// for this browser and one host, handed back on the browser's own request rather than over the tool socket.
|
|
221
231
|
"POST /system/webext/secret": { auth: "door", control: "never" },
|
|
232
|
+
"POST /system/webext/grants-changed": { auth: "door", control: "never" },
|
|
222
233
|
// This sandbox's keyring keys (schemas/keyring.ts), public halves only: a keyring fetches them here over TLS, from the
|
|
223
234
|
// sandbox's own address, before it shares anything with it, rather than take them from whoever relays the share.
|
|
224
235
|
"GET /keyring/keys": { auth: "door", control: "never" },
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
// Words put in an agent's mouth (`agents.place`): what is asked, and what the record answers.
|
|
4
|
+
|
|
5
|
+
// Bounded just above the handoff's per-message render cap, so a line too long to carry whole doesn't reach the agent
|
|
6
|
+
// truncated.
|
|
7
|
+
export const AgentPlaceSchema = z.object({
|
|
8
|
+
id: z.string().min(1).describe("Which conversation."),
|
|
9
|
+
text: z
|
|
10
|
+
.string()
|
|
11
|
+
.trim()
|
|
12
|
+
.min(1)
|
|
13
|
+
.max(8_000)
|
|
14
|
+
.describe(
|
|
15
|
+
"The words to put in the agent's mouth. Bounded just above what the next turn can carry whole, because a line too long to be handed over intact would reach the agent truncated and quietly break the very thing this is for.",
|
|
16
|
+
),
|
|
17
|
+
});
|
|
18
|
+
// The placed line's own id, so the window that placed it holds the same row its next read of the record brings.
|
|
19
|
+
export const AgentPlacedSchema = z.object({
|
|
20
|
+
ok: z.literal(true).describe("Always true: the line is on the record."),
|
|
21
|
+
rowId: z.string().optional().describe("The `rowId` the line was recorded under. Absent from a sandbox older than row ids."),
|
|
22
|
+
});
|
package/src/schemas/agent.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { TurnErrandSchema } from "./speaker.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { CONVERSATION_ID } from "../ids/conversation-ids.js";
|
|
3
|
+
import { CONVERSATION_ID, CONVERSATION_TITLE_MAX } from "../ids/conversation-ids.js";
|
|
4
4
|
import { canonicalHarness } from "../models/agent-catalog.js";
|
|
5
5
|
import { ModelRoleSchema } from "../models/model-roles.js";
|
|
6
6
|
import { NATIVE_PROVIDERS } from "../models/provider-specs.js";
|
|
7
7
|
import { AgentPlacementSchema } from "../protocol/doors/runner-protocol.js";
|
|
8
8
|
import { MENTION_LIMIT } from "../text/mentions.js";
|
|
9
9
|
import { entryId } from "./internal.js";
|
|
10
|
+
import { FRESH_OF_DESCRIPTION, FreshOfSchema, freshOfIssues } from "./conversation-links.js";
|
|
10
11
|
// Agent runtimes the daemon can serve: native providers have dedicated adapters, `endpoint/<id>` names an installed
|
|
11
12
|
// endpoint capability, anything else is an ACP agent capability id. A bare string, not an enum, so an unknown id is a
|
|
12
13
|
// clean error, not a contract change.
|
|
@@ -66,76 +67,14 @@ export const AgentOriginSchema = z.object({
|
|
|
66
67
|
author: z.string().optional(),
|
|
67
68
|
});
|
|
68
69
|
export type AgentOrigin = z.infer<typeof AgentOriginSchema>;
|
|
69
|
-
// The class of thing asking to start a session, the admission policy's key space; derived daemon-side, never sent by a
|
|
70
|
-
// client. Chat and loops are absent since both begin with the owner's own click.
|
|
71
|
-
export const WakeSourceSchema = z.enum(["schedule", "event", "listener", "webchat", "issues", "workspace", "workflow"]);
|
|
72
|
-
export type WakeSource = z.infer<typeof WakeSourceSchema>;
|
|
73
|
-
// One admission verdict the owner can configure: let it run, hold it for approval, or refuse it outright.
|
|
74
|
-
export const AdmissionRuleSchema = z.enum(["allow", "hold", "deny"]);
|
|
75
|
-
export type AdmissionRule = z.infer<typeof AdmissionRuleSchema>;
|
|
76
|
-
// Where a command would run; the same string means different things on each machine (rm -rf /usr is recoverable here,
|
|
77
|
-
// fatal on a laptop). Read with a locus (command-classes.ts CommandContext); callers must state one rather than
|
|
78
|
-
// default.
|
|
79
|
-
export const CommandLocusSchema = z.enum([
|
|
80
|
-
// This sandbox's own shell: a disposable container, /work a git worktree, /history every other agent's.
|
|
81
|
-
"sandbox",
|
|
82
|
-
// One of the owner's own computers, reached through the machine agent. Nothing here is disposable.
|
|
83
|
-
"device",
|
|
84
|
-
]);
|
|
85
|
-
export type CommandLocus = z.infer<typeof CommandLocusSchema>;
|
|
86
|
-
// What kind of thing a shell command is, the command gate's key space under the admission floor; gates one command
|
|
87
|
-
// inside an already-running session. Six classes, chosen because each is hard or impossible to undo somewhere.
|
|
88
|
-
export const CommandClassSchema = z.enum([
|
|
89
|
-
// Rewrites or discards committed work: force-push, hard reset, force-delete a branch, clean -f, filter-branch.
|
|
90
|
-
"git.destructive",
|
|
91
|
-
// Moves a checkout to another branch. Only ever matches in a tree the conversation SHARES with its owner: inside
|
|
92
|
-
// its own copy a conversation may stand where it likes, and the drift that causes is reported, not refused.
|
|
93
|
-
"git.branch-switch",
|
|
94
|
-
// Recursive-force deletion (`rm -rf`), and its spelling in a script (`fs.rm(p, { recursive: true })`).
|
|
95
|
-
"files.destructive",
|
|
96
|
-
// State nothing recovers at this locus; which roots count (/, /history in the sandbox) depends on the locus.
|
|
97
|
-
"system.destructive",
|
|
98
|
-
// A container volume or its data; the sandbox's blast radius (nested engine) differs sharply from a device's.
|
|
99
|
-
"container.state",
|
|
100
|
-
// Reads credential material: a secret reference, or a file confirmed to actually hold one.
|
|
101
|
-
"secrets.access",
|
|
102
|
-
// Publishes outward and irreversibly: npm/pnpm/yarn/cargo publish, gh release create, docker push.
|
|
103
|
-
"package.publish",
|
|
104
|
-
// A network program (curl, nc, ssh, scp, …) or interpreter one-liner aimed at a non-loopback or run-time-built
|
|
105
|
-
// destination, the general exfiltration channel under the per-provider actionRules.
|
|
106
|
-
"network.outbound",
|
|
107
|
-
]);
|
|
108
|
-
export type CommandClass = z.infer<typeof CommandClassSchema>;
|
|
109
|
-
// Workspace-wide admission floor per wake source, consulted on every outside-driven wake; composes with per-automation
|
|
110
|
-
// overrides most-restrictive-wins. `workflow` is allow|deny only, since a hold there is indistinguishable from a CI
|
|
111
|
-
// runner's timeout.
|
|
112
|
-
export const AdmissionPolicySchema = z.object({
|
|
113
|
-
schedule: AdmissionRuleSchema.default("allow"),
|
|
114
|
-
event: AdmissionRuleSchema.default("allow"),
|
|
115
|
-
listener: AdmissionRuleSchema.default("allow"),
|
|
116
|
-
webchat: AdmissionRuleSchema.default("allow"),
|
|
117
|
-
// Defaults to hold, unlike the others: a bug-report wake has full repo powers and a stranger's stack trace as its
|
|
118
|
-
// brief.
|
|
119
|
-
issues: AdmissionRuleSchema.default("hold"),
|
|
120
|
-
workspace: AdmissionRuleSchema.default("allow"),
|
|
121
|
-
workflow: z.enum(["allow", "deny"]).default("allow"),
|
|
122
|
-
});
|
|
123
|
-
export type AdmissionPolicy = z.infer<typeof AdmissionPolicySchema>;
|
|
124
70
|
// How tool calls are gated, the Claude Agent SDK's PermissionMode narrowed to the three the composer offers. Both a
|
|
125
71
|
// turn input and the payload of the `mode` frame, since the agent can move itself between them mid-turn. The SDK's
|
|
126
72
|
// acceptEdits is not one of them: only `default` asks a person here, so it would differ from bypassPermissions in name
|
|
127
73
|
// alone.
|
|
128
74
|
export const PermissionModeSchema = z.enum(["default", "plan", "bypassPermissions"]);
|
|
129
75
|
export type PermissionMode = z.infer<typeof PermissionModeSchema>;
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
export const ForkedFromSchema = z.object({
|
|
133
|
-
conversationId: ConversationIdSchema,
|
|
134
|
-
index: z.number().int().nonnegative(),
|
|
135
|
-
// Which files this fork opened on; kept so the fork can still say it later, not only right after the click.
|
|
136
|
-
files: z.enum(["then", "now"]),
|
|
137
|
-
});
|
|
138
|
-
export type ForkedFrom = z.infer<typeof ForkedFromSchema>;
|
|
76
|
+
// How one conversation relates to another (a fork's cut, a fresh session's origin): conversation-links.ts.
|
|
77
|
+
export * from "./conversation-links.js";
|
|
139
78
|
// The turn's fields before the cross-field refinements below, so a subset (TurnProfileSchema) can be picked from them.
|
|
140
79
|
// How many files one turn may carry. A batch of a person's queued messages joins their files, so the admission splits a
|
|
141
80
|
// batch rather than build a turn past this (turn-admission.ts, together): a turn the daemon makes must parse back.
|
|
@@ -158,7 +97,7 @@ const AgentTurnFieldsSchema = z.object({
|
|
|
158
97
|
// Seeds a fresh registry entry's title; an existing entry's title always wins over this.
|
|
159
98
|
title: z
|
|
160
99
|
.string()
|
|
161
|
-
.max(
|
|
100
|
+
.max(CONVERSATION_TITLE_MAX)
|
|
162
101
|
.optional()
|
|
163
102
|
.describe("A title for a conversation this turn is opening. Ignored for a conversation that already has one."),
|
|
164
103
|
// Already uploaded via /workspace/upload; Claude reads them via Read, Codex gets images as native input.
|
|
@@ -262,6 +201,8 @@ const AgentTurnFieldsSchema = z.object({
|
|
|
262
201
|
})
|
|
263
202
|
.optional()
|
|
264
203
|
.describe("Where this conversation was cut from, on its first turn only. Only the client knows this, so only the client can say it."),
|
|
204
|
+
// A fresh session's origin, on its first turn only; requires an isolated conversationId the registry has never seen.
|
|
205
|
+
freshOf: FreshOfSchema.optional().describe(FRESH_OF_DESCRIPTION),
|
|
265
206
|
// The browser sends the chosen model per turn; the provider token is the sandbox's own stored credential.
|
|
266
207
|
model: z.string().optional().describe("Which model to use. Leave it out for the provider's default."),
|
|
267
208
|
// Audience only, never model routing: `runRole` is what fills a model in. A run somebody pressed and is
|
|
@@ -327,6 +268,15 @@ const AgentTurnFieldsSchema = z.object({
|
|
|
327
268
|
.describe(
|
|
328
269
|
"Hold this message until then (epoch milliseconds) instead of starting a turn now: a time you chose, or the reopen of an allowance you know is spent. It waits in the conversation's queue, where it can be sent early, reworded, rescheduled or removed, and goes by itself at that instant, even for a conversation this message opens or one whose turn is running now. Ignored when already past; at most a month ahead.",
|
|
329
270
|
),
|
|
271
|
+
// Why `sendAt` is the instant it is, when it is not a time somebody chose: the composer booked the message for the
|
|
272
|
+
// spent allowance's reopen. Kept with the booking (`reopenOf` on the queue), so every window can tell an allowance
|
|
273
|
+
// wait from an appointment without matching instants against whatever the usage feed says now.
|
|
274
|
+
sendAtReopen: z
|
|
275
|
+
.literal(true)
|
|
276
|
+
.optional()
|
|
277
|
+
.describe(
|
|
278
|
+
"Says `sendAt` is the reopen of the allowance this message would be refused by, not a time you chose. Recorded with the booking (the queue's `reopenOf` names the account it waits for), so every window can say the message waits on an allowance, and see when the conversation has moved somewhere with room. Only with `sendAt`.",
|
|
279
|
+
),
|
|
330
280
|
// The other scheduled send: work that builds on another agent's, held until that agent's work is in the workspace.
|
|
331
281
|
// Held in the queue like `sendAt`; the queue's `after` is this. Never both: a hold waits on exactly one thing.
|
|
332
282
|
sendAfter: ConversationIdSchema.optional().describe(
|
|
@@ -362,6 +312,7 @@ export const AgentTurnSchema = AgentTurnFieldsSchema
|
|
|
362
312
|
.refine((turn) => turn.forkOf?.files !== "then" || turn.isolated === true, {
|
|
363
313
|
message: 'forkOf.files "then" requires isolated',
|
|
364
314
|
})
|
|
315
|
+
.superRefine(freshOfIssues)
|
|
365
316
|
.refine((turn) => turn.sendAt === undefined || turn.sendAfter === undefined, {
|
|
366
317
|
message: "sendAt and sendAfter are two different holds: name one",
|
|
367
318
|
})
|
|
@@ -514,6 +465,25 @@ export type MessageReceipt = z.infer<typeof MessageReceiptSchema>;
|
|
|
514
465
|
// a job that ended, a land that broke something), or another agent (a child reporting back).
|
|
515
466
|
export const MessageVoiceSchema = z.enum(["person", "sandbox", "agent"]);
|
|
516
467
|
export type MessageVoice = z.infer<typeof MessageVoiceSchema>;
|
|
468
|
+
// The account a message booked for an allowance's reopen waits on: what it waits out, which the booking's instant alone
|
|
469
|
+
// cannot say once the chat has moved somewhere with room.
|
|
470
|
+
export const QueuedReopenSchema = z.object({
|
|
471
|
+
agent: AgentProviderSchema.describe("The provider whose allowance it waits out."),
|
|
472
|
+
account: z
|
|
473
|
+
.string()
|
|
474
|
+
.optional()
|
|
475
|
+
.describe("Which of its accounts. Absent when none was named, and every account of the provider read spent."),
|
|
476
|
+
});
|
|
477
|
+
export type QueuedReopen = z.infer<typeof QueuedReopenSchema>;
|
|
478
|
+
// Who a person's waiting message goes on, as its request names it now.
|
|
479
|
+
export const QueuedServingSchema = z.object({
|
|
480
|
+
agent: AgentProviderSchema.describe("The provider."),
|
|
481
|
+
harness: AgentHarnessSchema.describe("The agentic loop."),
|
|
482
|
+
model: z.string().optional().describe("The model. Absent when it named none, and takes the conversation's own."),
|
|
483
|
+
effort: z.string().optional().describe("How hard it thinks, where the model offers a choice."),
|
|
484
|
+
account: z.string().optional().describe("The account that pays for it. Absent when it named none, and goes on the conversation's own."),
|
|
485
|
+
});
|
|
486
|
+
export type QueuedServing = z.infer<typeof QueuedServingSchema>;
|
|
517
487
|
// One message waiting for the conversation's next turn, as every window shows it.
|
|
518
488
|
export const QueuedMessageSchema = z.object({
|
|
519
489
|
id: z.string().describe("The message's id: what its sender named it, or what the sandbox did."),
|
|
@@ -533,6 +503,12 @@ export const QueuedMessageSchema = z.object({
|
|
|
533
503
|
after: ConversationIdSchema.optional().describe(
|
|
534
504
|
"The conversation whose finished work must land before this message goes out by itself, in place of `until`.",
|
|
535
505
|
),
|
|
506
|
+
reopenOf: QueuedReopenSchema.optional().describe(
|
|
507
|
+
"The allowance this message's `until` waits out: it was booked for that account's reopen, by the composer or by the sandbox holding words it would not send into a spent allowance, rather than for a time somebody chose. Absent on any other booking, and from sandboxes older than the field.",
|
|
508
|
+
),
|
|
509
|
+
serves: QueuedServingSchema.optional().describe(
|
|
510
|
+
"Who serves the turn this message starts: the provider, loop, model, effort and account it was sent under, or was moved to since (`agent.queueReroute`, an account switch). Only on a person's words; the sandbox's and an agent's own go on wherever the conversation runs when they go. Absent from sandboxes older than the field.",
|
|
511
|
+
),
|
|
536
512
|
continues: z
|
|
537
513
|
.literal(true)
|
|
538
514
|
.optional()
|
|
@@ -586,15 +562,3 @@ export const QueueResumedSchema = z.object({
|
|
|
586
562
|
),
|
|
587
563
|
});
|
|
588
564
|
export type QueueResumed = z.infer<typeof QueueResumedSchema>;
|
|
589
|
-
// Attaches to a conversation's newest run (live, or finished within retention); no cursor to resume from, the head
|
|
590
|
-
// carries all rows. `run` names what the client was watching, so a newer run's head id tells it to catch up.
|
|
591
|
-
export const AttachTurnSchema = z.object({
|
|
592
|
-
conversationId: ConversationIdSchema.describe("Which conversation to watch."),
|
|
593
|
-
run: z
|
|
594
|
-
.string()
|
|
595
|
-
.optional()
|
|
596
|
-
.describe(
|
|
597
|
-
"The run you were watching. The stream opens on the conversation's newest run whatever you name: if a newer turn has started since, the head names that one instead, and its rows are that turn's.",
|
|
598
|
-
),
|
|
599
|
-
});
|
|
600
|
-
export type AttachTurn = z.infer<typeof AttachTurnSchema>;
|