@platless/axom-cli 0.3.13 → 0.5.9
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/dist/axom-patch/cli/README.md +30 -8
- package/dist/axom-patch/cli/account-limits/README.md +27 -0
- package/dist/axom-patch/cli/account-limits/antigravity-proxy.mjs +47 -0
- package/dist/axom-patch/cli/account-limits/antigravity-read.mjs +90 -0
- package/dist/axom-patch/cli/account-limits/antigravity.mjs +46 -0
- package/dist/axom-patch/cli/account-limits/generate.py +120 -0
- package/dist/axom-patch/cli/account-limits/kimi-proxy.mjs +64 -0
- package/dist/axom-patch/cli/account-limits/normalize.mjs +151 -0
- package/dist/axom-patch/cli/claude-account-limits.json +37 -0
- package/dist/axom-patch/cli/codex-account-limits.json +37 -0
- package/dist/axom-patch/cli/commandcode-account-limits.json +30 -0
- package/dist/axom-patch/cli/nightly-task.md +152 -0
- package/dist/axom-patch/cli/pi-subagent-subwork.json +23 -0
- package/dist/axom-patch/cli/probes/claude-late-async-terminal.mjs +5 -1
- package/dist/axom-patch/cli/probes/pi-subagent-subwork.mjs +211 -0
- package/dist/axom-patch/cli/probes/qoder-steering.mjs +1 -1
- package/dist/axom-patch/cli/probes/qoder-subagent-origin.mjs +20 -8
- package/dist/axom-patch/cli/probes/zcode-subagent-subwork.mjs +257 -0
- package/dist/axom-patch/cli/qoder-background-terminal.md +2 -1
- package/dist/axom-patch/cli/qoder-foreground-output.md +4 -3
- package/dist/axom-patch/cli/qoder-steering.json +15 -15
- package/dist/axom-patch/cli/qoder-subagent-origin.json +21 -21
- package/dist/axom-patch/cli/runtime.json +34 -8
- package/dist/axom-patch/cli/zcode-account-limits.json +31 -0
- package/dist/axom-patch/cli/zcode-models.json +38 -0
- package/dist/axom-patch/cli/zcode-subagent-subwork.json +73 -0
- package/dist/cli.js +33 -6
- package/dist/keepers/acp/keeper.mjs +3083 -0
- package/dist/keepers/acp/manifest.json +9 -0
- package/dist/keepers/terminal/keeper.mjs +8469 -0
- package/dist/keepers/terminal/manifest.json +9 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/conpty_console_list_agent.js +25 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/eventEmitter2.js +47 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/index.js +52 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/interfaces.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/shared/conout.js +10 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/terminal.js +190 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/types.js +7 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/unixTerminal.js +351 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/utils.js +38 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsConoutConnection.js +131 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsPtyAgent.js +344 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/windowsTerminal.js +209 -0
- package/dist/keepers/terminal/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/dist/keepers/terminal/node_modules/node-pty/package.json +66 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-arm64/pty.node +0 -0
- package/dist/keepers/terminal/node_modules/node-pty/prebuilds/linux-x64/pty.node +0 -0
- package/dist/runtime-deps/qoder-sdk/package-lock.json +1189 -0
- package/dist/runtime-deps/qoder-sdk/package.json +8 -0
- package/dist/test/keeperKit.js +67 -0
- package/dist/workstation/acp/acpAgents.js +2163 -611
- package/dist/workstation/acp/acpClient.js +60 -497
- package/dist/workstation/acp/adoption.js +10 -396
- package/dist/workstation/acp/binaryInstall.js +100 -27
- package/dist/workstation/acp/builds/gc.js +245 -0
- package/dist/workstation/acp/builds/install/binary.js +28 -0
- package/dist/workstation/acp/builds/install/npm.js +235 -0
- package/dist/workstation/acp/builds/install/uv.js +254 -0
- package/dist/workstation/acp/builds/migrate.js +195 -0
- package/dist/workstation/acp/builds/model.js +128 -0
- package/dist/workstation/acp/builds/nodeGate.js +100 -0
- package/dist/workstation/acp/builds/store.js +352 -0
- package/dist/workstation/acp/commandTableProbe.js +68 -0
- package/dist/workstation/acp/configOptions.js +103 -1
- package/dist/workstation/acp/envSecrets.js +27 -0
- package/dist/workstation/acp/initializeResponse.js +285 -0
- package/dist/workstation/acp/installErrors.js +12 -2
- package/dist/workstation/acp/installProbe.js +1 -1
- package/dist/workstation/acp/managedPatches.js +76 -160
- package/dist/workstation/acp/outbox.js +330 -0
- package/dist/workstation/acp/patchAssets.js +20 -3
- package/dist/workstation/acp/permission.js +42 -10
- package/dist/workstation/acp/processor/checkpoint.js +87 -0
- package/dist/workstation/acp/processor/commands.js +35 -0
- package/dist/workstation/acp/processor/control.js +355 -0
- package/dist/workstation/acp/processor/emit.js +26 -0
- package/dist/workstation/acp/processor/jsonrpc.js +172 -0
- package/dist/workstation/acp/processor/memoryLog.js +49 -0
- package/dist/workstation/acp/processor/origins.js +48 -0
- package/dist/workstation/acp/processor/output.js +67 -0
- package/dist/workstation/acp/processor/projection.js +42 -0
- package/dist/workstation/acp/processor/record.js +128 -0
- package/dist/workstation/acp/processor/runtime.js +181 -0
- package/dist/workstation/acp/processor/sdkSchemas.js +61 -0
- package/dist/workstation/acp/processor/session.js +525 -0
- package/dist/workstation/acp/processor/sideChannel.js +80 -0
- package/dist/workstation/acp/processor/state.js +74 -0
- package/dist/workstation/acp/processor/step.js +459 -0
- package/dist/workstation/acp/processor/test/fixtureLog.js +65 -0
- package/dist/workstation/acp/processor/test/harness.js +120 -0
- package/dist/workstation/acp/processor/test/largeIdEcho.js +50 -0
- package/dist/workstation/acp/processor/test/rawAgent.js +70 -0
- package/dist/workstation/acp/processor/transport/generations.js +76 -0
- package/dist/workstation/acp/processor/transport/keeper.js +130 -0
- package/dist/workstation/acp/processor/transport/local.js +269 -0
- package/dist/workstation/acp/processor/transport/types.js +78 -0
- package/dist/workstation/acp/processor/updates.js +364 -0
- package/dist/workstation/acp/processorSession.js +1512 -0
- package/dist/workstation/acp/qoderStartup.js +1 -1
- package/dist/workstation/acp/registry/catalog.js +154 -32
- package/dist/workstation/acp/registry/launch.js +61 -119
- package/dist/workstation/acp/sessionUpdateMapper.js +18 -7
- package/dist/workstation/acp/steering.js +58 -0
- package/dist/workstation/acp/switching.js +114 -0
- package/dist/workstation/acp/terminalLogin.js +16 -42
- package/dist/workstation/acp/terminalLoginSpec.js +41 -0
- package/dist/workstation/acp/test/adapterFixtures.js +256 -0
- package/dist/workstation/acp/test/daemonLife.js +106 -0
- package/dist/workstation/acp/test/keeperWorld.js +267 -0
- package/dist/workstation/acp/test/memoryOutbox.js +55 -0
- package/dist/workstation/acp/test/raw/fixtures.js +196 -0
- package/dist/workstation/acp/test/raw/qoderCaptures.js +125 -0
- package/dist/workstation/acp/test/raw/sanitize.js +344 -0
- package/dist/workstation/acp/test/raw/sources.js +249 -0
- package/dist/workstation/acp/test/realAdapter.js +377 -0
- package/dist/workstation/acp/test/scriptAgent.js +206 -0
- package/dist/workstation/acp/test/sessionFrames.js +42 -0
- package/dist/workstation/acp/timedCommand.js +4 -2
- package/dist/workstation/acp/uvxInstall.js +72 -122
- package/dist/workstation/agentFlow.js +103 -0
- package/dist/workstation/agentSessions.js +1324 -474
- package/dist/workstation/channels/agent.js +7 -5
- package/dist/workstation/channels/computer.js +69 -21
- package/dist/workstation/channels/computerExecs.js +200 -0
- package/dist/workstation/channels/management.js +84 -4
- package/dist/workstation/daemon.js +288 -7
- package/dist/workstation/daemonctl.js +28 -2
- package/dist/workstation/exec/attach.js +126 -0
- package/dist/workstation/exec/command.js +40 -0
- package/dist/workstation/exec/durable.js +517 -0
- package/dist/workstation/exec/fallback.js +106 -0
- package/dist/workstation/exec/policy.js +837 -0
- package/dist/workstation/exec/shaping.js +211 -0
- package/dist/workstation/exec.js +3 -112
- package/dist/workstation/files/adapters/computerFileFrames.js +51 -0
- package/dist/workstation/files/adapters/toolRequests.js +121 -0
- package/dist/workstation/files/client.js +455 -0
- package/dist/workstation/files/errors.js +28 -0
- package/dist/workstation/files/fence.js +350 -0
- package/dist/workstation/files/find/fileIndex.js +153 -0
- package/dist/workstation/files/find/fuzzy.js +155 -0
- package/dist/workstation/files/host.js +122 -0
- package/dist/workstation/files/hostProtocol.js +2 -0
- package/dist/workstation/files/media/cache.js +620 -0
- package/dist/workstation/files/media/encoding.js +308 -0
- package/dist/workstation/files/media/estimator.js +100 -0
- package/dist/workstation/files/media/media.js +325 -0
- package/dist/workstation/files/media/packedAudio.js +23 -0
- package/dist/workstation/files/media/scheduler.js +551 -0
- package/dist/workstation/files/media/types.js +5 -0
- package/dist/workstation/files/scope.js +45 -0
- package/dist/workstation/files/structured.js +284 -0
- package/dist/workstation/{fileOps.js → files/text.js} +117 -38
- package/dist/workstation/files/uploads.js +351 -0
- package/dist/workstation/journal.js +65 -236
- package/dist/workstation/keepers/acp/client.js +101 -0
- package/dist/workstation/keepers/acp/envelope.js +62 -0
- package/dist/workstation/keepers/acp/host.js +419 -0
- package/dist/workstation/keepers/acp/main.js +18 -0
- package/dist/workstation/keepers/acp/memoryStream.js +121 -0
- package/dist/workstation/keepers/acp/params.js +137 -0
- package/dist/workstation/keepers/acp/protocol.js +66 -0
- package/dist/workstation/keepers/acp/recover.js +120 -0
- package/dist/workstation/keepers/acp/session.js +584 -0
- package/dist/workstation/keepers/acp/stderr.js +154 -0
- package/dist/workstation/keepers/kit/activity.js +103 -0
- package/dist/workstation/keepers/kit/bootstrap.js +164 -0
- package/dist/workstation/keepers/kit/buildVersion.js +51 -0
- package/dist/workstation/keepers/kit/bundle.js +120 -0
- package/dist/workstation/keepers/kit/client.js +432 -0
- package/dist/workstation/keepers/kit/identity.js +21 -0
- package/dist/workstation/keepers/kit/ipc.js +112 -0
- package/dist/workstation/keepers/kit/launchConfig.js +8 -0
- package/dist/workstation/keepers/kit/launcher.js +249 -0
- package/dist/workstation/keepers/kit/lock.js +123 -0
- package/dist/workstation/keepers/kit/orphanSweep.js +86 -0
- package/dist/workstation/keepers/kit/paths.js +75 -0
- package/dist/workstation/keepers/kit/protocol.js +43 -0
- package/dist/workstation/keepers/kit/server.js +518 -0
- package/dist/workstation/keepers/kit/streamLog.js +697 -0
- package/dist/workstation/keepers/legacy.js +296 -0
- package/dist/workstation/keepers/policy.js +576 -0
- package/dist/workstation/keepers/stop.js +34 -0
- package/dist/workstation/keepers/terminal/client.js +213 -0
- package/dist/workstation/keepers/terminal/exec.js +981 -0
- package/dist/workstation/keepers/terminal/generations.js +129 -0
- package/dist/workstation/keepers/terminal/keeper.js +62 -0
- package/dist/workstation/keepers/terminal/main.js +43 -0
- package/dist/workstation/keepers/terminal/orphanSweep.js +3 -0
- package/dist/workstation/keepers/terminal/params.js +27 -0
- package/dist/workstation/keepers/terminal/protocol.js +56 -0
- package/dist/workstation/keepers/terminal/pty.js +330 -0
- package/dist/workstation/protocol/accountLimits.js +47 -0
- package/dist/workstation/protocol/agent.js +48 -4
- package/dist/workstation/protocol/common.js +30 -0
- package/dist/workstation/protocol/computer.js +15 -4
- package/dist/workstation/protocol/management.js +50 -2
- package/dist/workstation/qoderAdapter/backgroundProcess.js +18 -6
- package/dist/workstation/qoderAdapter/backgroundTerminal.js +78 -147
- package/dist/workstation/qoderAdapter/backgroundTerminalFold.js +372 -0
- package/dist/workstation/qoderAdapter/callbackContext.js +76 -0
- package/dist/workstation/qoderAdapter/foregroundOutput.js +15 -9
- package/dist/workstation/qoderAdapter/history.js +1 -3
- package/dist/workstation/qoderAdapter/main.js +4 -2
- package/dist/workstation/qoderAdapter/sdkDriver.js +1 -2
- package/dist/workstation/qoderAdapter/sdkRuntime.js +93 -0
- package/dist/workstation/qoderAdapter/sdkRuntimeInstall.js +145 -0
- package/dist/workstation/qoderAdapter/session.js +1 -1
- package/dist/workstation/qoderAdapter/subwork.js +15 -7
- package/dist/workstation/systemMetrics.js +110 -1
- package/dist/workstation/tools/client.js +9 -1
- package/dist/workstation/tools/info.js +50 -0
- package/dist/workstation/tools/keeperProcess.js +15 -5
- package/dist/workstation/tools/router.js +55 -0
- package/dist/workstation/tools/terminalRouter.js +222 -0
- package/dist/workstation/tools/validation.js +37 -1
- package/dist/workstation/update/coordinator.js +3 -0
- package/dist/workstation/update/ptyPreflight.js +21 -0
- package/dist/workstation/update/taskRegistry.js +105 -11
- package/package.json +10 -7
- package/dist/workstation/acp/acpSession.js +0 -1475
- package/dist/workstation/acp/contract.js +0 -499
- package/dist/workstation/acp/draftInterceptor.js +0 -163
- package/dist/workstation/acp/sessionScope.js +0 -19
- package/dist/workstation/filePaths.js +0 -174
- package/dist/workstation/fileWorker.js +0 -81
- package/dist/workstation/fileWorkerClient.js +0 -121
- package/dist/workstation/qoderAdapter/taskEvent.js +0 -26
- package/dist/workstation/tools/core.js +0 -50
- package/dist/workstation/tools/files.js +0 -525
- package/dist/workstation/tools/terminal.js +0 -214
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Bounded, plain-JS wire validation: usable inside the deterministic ACP processor. */
|
|
2
|
+
export const ACCOUNT_LIMITS_READ_TIMEOUT_MS = 180_000;
|
|
3
|
+
const object = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
4
|
+
const text = (v, min = 0, max = 160) => typeof v === 'string' && v.length >= min && v.length <= max;
|
|
5
|
+
const time = (v) => typeof v === 'string' && /^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(v) && Number.isFinite(new Date(v).getTime());
|
|
6
|
+
const oneOf = (v, values) => typeof v === 'string' && values.includes(v);
|
|
7
|
+
function parse(value) {
|
|
8
|
+
const valid = object(value) && value.schemaVersion === 1 && text(value.provider, 1, 64)
|
|
9
|
+
&& (value.updateMode === undefined || oneOf(value.updateMode, ['snapshot', 'delta']))
|
|
10
|
+
&& oneOf(value.billingMode, ['subscription', 'non_subscription', 'unknown'])
|
|
11
|
+
&& oneOf(value.availability, ['available', 'unavailable', 'unknown', 'not_applicable']) && time(value.observedAt)
|
|
12
|
+
&& (value.plan === null || object(value.plan) && text(value.plan.id) && text(value.plan.label))
|
|
13
|
+
&& (value.accountKey === undefined || text(value.accountKey, 0, 128))
|
|
14
|
+
&& Array.isArray(value.limits) && value.limits.length <= 32 && value.limits.every(row => object(row)
|
|
15
|
+
&& text(row.id, 1) && text(row.label) && oneOf(row.kind, ['subscription', 'spend', 'rate'])
|
|
16
|
+
&& (row.windowSeconds === null || typeof row.windowSeconds === 'number' && Number.isInteger(row.windowSeconds) && row.windowSeconds > 0)
|
|
17
|
+
&& (row.period == null || text(row.period))
|
|
18
|
+
&& (row.key === undefined || row.key === null || text(row.key, 1, 64))
|
|
19
|
+
&& (row.usedPercent === null || typeof row.usedPercent === 'number' && Number.isFinite(row.usedPercent) && row.usedPercent >= 0 && row.usedPercent <= 100)
|
|
20
|
+
&& (row.resetsAt === null || time(row.resetsAt)) && oneOf(row.status, ['allowed', 'warning', 'blocked', 'unknown'])
|
|
21
|
+
&& (row.active == null || typeof row.active === 'boolean') && (row.scope == null || object(row.scope))
|
|
22
|
+
&& ['used', 'limit', 'unit', 'currency'].every(key => row[key] === undefined || text(row[key]))
|
|
23
|
+
&& (row.exponent === undefined || typeof row.exponent === 'number' && Number.isInteger(row.exponent) && row.exponent >= 0 && row.exponent <= 12))
|
|
24
|
+
&& new Set(value.limits.map(row => row.id)).size === value.limits.length
|
|
25
|
+
&& Array.isArray(value.balances) && value.balances.length <= 16 && value.balances.every(row => object(row)
|
|
26
|
+
&& text(row.id, 1) && text(row.label) && text(row.unit) && (row.remaining === null || text(row.remaining))
|
|
27
|
+
&& (row.currency === undefined || text(row.currency)) && (row.unlimited === undefined || typeof row.unlimited === 'boolean')
|
|
28
|
+
&& (row.exponent === undefined || typeof row.exponent === 'number' && Number.isInteger(row.exponent) && row.exponent >= 0 && row.exponent <= 12))
|
|
29
|
+
&& new Set(value.balances.map(row => row.id)).size === value.balances.length
|
|
30
|
+
&& (value._meta === undefined || object(value._meta)) && JSON.stringify(value).length <= 65_536;
|
|
31
|
+
if (!valid)
|
|
32
|
+
throw new Error('Invalid account quota snapshot');
|
|
33
|
+
return { ...value, _meta: value._meta ?? {} };
|
|
34
|
+
}
|
|
35
|
+
export const accountLimitsSchema = {
|
|
36
|
+
parse,
|
|
37
|
+
safeParse(value) {
|
|
38
|
+
try {
|
|
39
|
+
return { success: true, data: parse(value) };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return { success: false, error: new Error('Invalid account quota snapshot') };
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
export const ACCOUNT_LIMITS_READ = '_axom/account/rateLimits/read';
|
|
47
|
+
export const ACCOUNT_LIMITS_UPDATED = '_axom/account/rateLimits/updated';
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { accountLimitsSchema } from './accountLimits.js';
|
|
1
2
|
import { isRuntimeDiagnostics } from '../qoderAdapter/profile.js';
|
|
2
3
|
import { decodeChannelFrame, hasOptional, hasRequired, isBoolean, isBridgeInfoArray, isNullableAuthMethodInfoArray, isNullableString, isNumber, isObject, isString, isStringArray, isStringRecord, } from './common.js';
|
|
3
4
|
/** Current version and feature floors for the independently negotiated agent protocol. */
|
|
4
|
-
export const AGENT_WIRE_VERSION =
|
|
5
|
+
export const AGENT_WIRE_VERSION = 27;
|
|
6
|
+
/**
|
|
7
|
+
* `agent_switch_idle` / `agent_switch_idle_result` (spec 2026-10-11 §6.4, Task 25): "move idle sessions" of one agent to another
|
|
8
|
+
* adapter build. A server-to-client request: the server sends it only to a client advertising this version (an older one has no
|
|
9
|
+
* case for it and the request would only die at its timeout).
|
|
10
|
+
*/
|
|
11
|
+
export const AGENT_WIRE_ACCOUNT_LIMITS_VERSION = 27;
|
|
12
|
+
export const AGENT_WIRE_SWITCH_IDLE_VERSION = 26;
|
|
5
13
|
/** `agent_delete_native` / `agent_native_deleted`: purge a session Axom created on an external agent. */
|
|
6
14
|
export const AGENT_WIRE_NATIVE_DELETE_VERSION = 24;
|
|
7
15
|
export const AGENT_WIRE_PROVIDER_TASK_VERSION = 23;
|
|
@@ -207,7 +215,7 @@ export const AGENT_WIRE_ELICITATION_VERSION = 16;
|
|
|
207
215
|
*
|
|
208
216
|
* Declarative on purpose: the required-field half of this table is the *only* statement anywhere of
|
|
209
217
|
* which fields the Kotlin twin will refuse to decode without, and the contract suite
|
|
210
|
-
* (`
|
|
218
|
+
* (`protocol/agentRequiredFields.test.ts`'s `assertRequiredFieldsEnforced`) reads it directly to prove each one is really
|
|
211
219
|
* enforced. Left as inline `hasRequired({...})` calls inside a `switch`, that list is unreadable from
|
|
212
220
|
* a test, so the only way to check it would be a hand-maintained copy in the test file — which is
|
|
213
221
|
* precisely how `agent_authenticate.methodId` came to have no guard at all while a report still
|
|
@@ -229,6 +237,7 @@ export const AGENT_FRAME_SHAPES = {
|
|
|
229
237
|
optional: { sessions: (sessions) => Array.isArray(sessions) && sessions.every(isAgentResumeSession) },
|
|
230
238
|
},
|
|
231
239
|
heartbeat_ack: { required: { seq: isNumber } },
|
|
240
|
+
agent_reopen_request: { required: { sessionRef: isString, reason: isString } },
|
|
232
241
|
agent_open: {
|
|
233
242
|
required: {
|
|
234
243
|
id: isString, sessionRef: isString, agentKey: isString, bridge: isString, cwd: isString, shell: isString,
|
|
@@ -272,6 +281,8 @@ export const AGENT_FRAME_SHAPES = {
|
|
|
272
281
|
// Vendor-verbatim and uninterpreted here (decision L1) -- any object shape is accepted, the
|
|
273
282
|
// same lenience `agent_event.payload` gets via `isRecord`.
|
|
274
283
|
activityRaw: isRecord,
|
|
284
|
+
// Task 21 (spec §5.5.4): `true`-or-absent, and the two id lists.
|
|
285
|
+
durable: isVerifiedTrue, pendingRequestIds: isStringArray, steeredIds: isStringArray,
|
|
275
286
|
},
|
|
276
287
|
},
|
|
277
288
|
agent_prompt: { required: { sessionRef: isString, text: isString }, optional: { images: isImageBlockArray, platformTurnId: isString } },
|
|
@@ -319,6 +330,9 @@ export const AGENT_FRAME_SHAPES = {
|
|
|
319
330
|
},
|
|
320
331
|
// Same lenience as `agent_list_native` above, for the same reason: the session manager wants to
|
|
321
332
|
// answer a malformed query with its own `ok: false` rather than have the transport drop it.
|
|
333
|
+
agent_account_read: { required: { id: isString, bridge: isString, agentKey: isString, query: () => true } },
|
|
334
|
+
agent_account_read_result: { required: { id: isString, ok: isBoolean }, optional: { snapshot: (value) => accountLimitsSchema.safeParse(value).success, error: isString } },
|
|
335
|
+
agent_account_update: { required: { agentKey: isString, snapshot: (value) => accountLimitsSchema.safeParse(value).success } },
|
|
322
336
|
agent_verify: {
|
|
323
337
|
required: { id: isString, bridge: isString, query: () => true },
|
|
324
338
|
// 与 `query` 那条**刻意的宽松**相反,这里是严格的:一份畸形的 query 还有个能回
|
|
@@ -398,8 +412,35 @@ export const AGENT_FRAME_SHAPES = {
|
|
|
398
412
|
agent_provider_task_stopped: { required: { id: isTaskId, state: isProviderStopState },
|
|
399
413
|
optional: { error: isTaskSummary } },
|
|
400
414
|
agent_async_task_stop: { required: { sessionRef: isString, asyncTaskId: isString } },
|
|
415
|
+
agent_switch_idle: { required: { id: isString, bridge: isString }, optional: { toBuild: isString } },
|
|
416
|
+
agent_switch_idle_result: {
|
|
417
|
+
required: { id: isString, ok: isBoolean },
|
|
418
|
+
optional: { registered: isCount, immediate: isCount, unmovable: isSwitchIdleUnmovableArray, error: isNullableString },
|
|
419
|
+
},
|
|
401
420
|
};
|
|
402
421
|
const DISCRIMINATORS = new Set(Object.keys(AGENT_FRAME_SHAPES));
|
|
422
|
+
/**
|
|
423
|
+
* `agent_reopen_request{sessionRef, reason}` (spec 2026-10-11 §6.3, C→S): a session that is idle and has a pending switch (an adapter
|
|
424
|
+
* update, a keeper-acp generation change) asks the server to send `agent_open{requireSessionLoad:true}` with the session's fresh
|
|
425
|
+
* environment — a switch needs the spawn secrets only an `agent_open` carries. Task 24 decides when; the manager's
|
|
426
|
+
* `requestReopen` sends it, and only to a server advertising {@link AGENT_WIRE_REOPEN_REQUEST_VERSION}: an older server cannot
|
|
427
|
+
* decode it, and eight undecodable frames in a row close the agent channel (spec §10: there the switch waits for a natural reopen).
|
|
428
|
+
*/
|
|
429
|
+
export const AGENT_WIRE_REOPEN_REQUEST_VERSION = 25;
|
|
430
|
+
/**
|
|
431
|
+
* The same version (Task 22): the server acknowledges as soon as a subagent relation releases the watermark it capped, and stops
|
|
432
|
+
* wasting its 32-event ack count on capped attempts — so a sent relation-pinned outbox entry may count against the sending
|
|
433
|
+
* window again (`SessionOutbox.inflight`). Below it the entries keep not counting once sent (fix round 1 of Task 20).
|
|
434
|
+
*/
|
|
435
|
+
export const AGENT_WIRE_RELATION_ACK_VERSION = 25;
|
|
436
|
+
export const AGENT_REOPEN_REQUEST_SHAPE = AGENT_FRAME_SHAPES.agent_reopen_request;
|
|
437
|
+
export function agentReopenRequest(sessionRef, reason) {
|
|
438
|
+
return { t: 'agent_reopen_request', sessionRef, reason };
|
|
439
|
+
}
|
|
440
|
+
function isCount(value) { return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0; }
|
|
441
|
+
function isSwitchIdleUnmovableArray(value) {
|
|
442
|
+
return Array.isArray(value) && value.every((entry) => isObject(entry) && isString(entry.sessionRef) && isString(entry.reason));
|
|
443
|
+
}
|
|
403
444
|
function isRecord(value) { return isObject(value); }
|
|
404
445
|
function isTaskId(value) {
|
|
405
446
|
return typeof value === 'string' && value.length > 0 &&
|
|
@@ -422,12 +463,13 @@ function isProviderStopState(value) {
|
|
|
422
463
|
}
|
|
423
464
|
function isAgentResumeSession(value) {
|
|
424
465
|
return isObject(value)
|
|
425
|
-
&& hasRequired(value, { sessionRef: isString, journalMaxSeq: isNumber, agentAlive: isBoolean })
|
|
466
|
+
&& hasRequired(value, { sessionRef: isString, journalMaxSeq: isNumber, agentAlive: isBoolean })
|
|
467
|
+
&& (value.pendingRequestIds === undefined || isStringArray(value.pendingRequestIds));
|
|
426
468
|
}
|
|
427
469
|
/**
|
|
428
470
|
* Accepts only the two outcomes this client can produce. `startedNewTurn` is refused on purpose: it
|
|
429
471
|
* is the extension's third outcome, and receiving one means a peer invented a disposition for a
|
|
430
|
-
* message the server has already put on its timeline — see `
|
|
472
|
+
* message the server has already put on its timeline — see `acp/steering.ts`'s `mapSteerOutcome`.
|
|
431
473
|
*/
|
|
432
474
|
function isSteerOutcome(value) { return value === 'injected' || value === 'promptRequired'; }
|
|
433
475
|
/** Accepts `true` and nothing else — the whole point of `authenticated` having no `false`. */
|
|
@@ -729,8 +771,10 @@ export function outboundFailureReply(frame, reason) {
|
|
|
729
771
|
case 'agent_authenticated': return { t: 'agent_authenticated', id, ok: false, error };
|
|
730
772
|
case 'agent_installed': return { t: 'agent_installed', id, ok: false, error };
|
|
731
773
|
case 'agent_steered': return { t: 'agent_steered', id, ok: false, error };
|
|
774
|
+
case 'agent_account_read_result': return { t: 'agent_account_read_result', id, ok: false, error };
|
|
732
775
|
case 'agent_config_option_set': return { t: 'agent_config_option_set', id, ok: false, error };
|
|
733
776
|
case 'agent_delegation_renewed': return { t: 'agent_delegation_renewed', id, ok: false, error };
|
|
777
|
+
case 'agent_switch_idle_result': return { t: 'agent_switch_idle_result', id, ok: false, error };
|
|
734
778
|
case 'agent_provider_task_stopped': return { t: 'agent_provider_task_stopped', id, state: 'unknown', error };
|
|
735
779
|
case 'agent_backfill_done':
|
|
736
780
|
case 'agent_backfill_events': return { t: 'agent_backfill_done', id, ok: false, count: 0, error };
|
|
@@ -26,6 +26,18 @@ export const isNullableAuthMethodInfoArray = (value) => value === null || (Array
|
|
|
26
26
|
export function isMissingPrerequisite(value) {
|
|
27
27
|
return isObject(value) && hasRequired(value, { label: isString }) && hasOptional(value, { hint: isString });
|
|
28
28
|
}
|
|
29
|
+
const isCount = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
30
|
+
export function isBridgeCurrentBuild(value) {
|
|
31
|
+
return isObject(value) && hasRequired(value, { id: isString, version: isString }) && hasOptional(value, { patched: isTrueOnly });
|
|
32
|
+
}
|
|
33
|
+
export function isBridgeBuild(value) {
|
|
34
|
+
return isObject(value)
|
|
35
|
+
&& hasRequired(value, { id: isString, version: isString, sessions: isCount, idle: isCount, busy: isCount, unmovable: isCount })
|
|
36
|
+
&& hasOptional(value, { patched: isTrueOnly, current: isTrueOnly, busyReasons: isStringArray, unmovableReasons: isStringArray });
|
|
37
|
+
}
|
|
38
|
+
export function isBridgeSwitchPending(value) {
|
|
39
|
+
return isObject(value) && hasRequired(value, { remaining: isCount }) && hasOptional(value, { toBuild: isString });
|
|
40
|
+
}
|
|
29
41
|
export function isBridgeInfo(value) {
|
|
30
42
|
return isObject(value)
|
|
31
43
|
&& hasRequired(value, { type: isString })
|
|
@@ -66,6 +78,11 @@ export function isBridgeInfo(value) {
|
|
|
66
78
|
// A peer that sent one would be publishing "we looked and it cannot steer" through a key
|
|
67
79
|
// whose absence already says exactly that, so refusing it keeps one spelling per fact.
|
|
68
80
|
supportsSteering: isTrueOnly,
|
|
81
|
+
supportsAccountLimits: isTrueOnly,
|
|
82
|
+
// Task 25 (spec §6.4): scan-time build data. Optional: absent is "not looked at".
|
|
83
|
+
currentBuild: isBridgeCurrentBuild,
|
|
84
|
+
builds: (value) => Array.isArray(value) && value.every(isBridgeBuild),
|
|
85
|
+
switchPending: isBridgeSwitchPending,
|
|
69
86
|
});
|
|
70
87
|
}
|
|
71
88
|
export function isBridgeInfoArray(value) {
|
|
@@ -103,6 +120,19 @@ export function bridgesForWire(bridges, frame) {
|
|
|
103
120
|
}
|
|
104
121
|
return kept;
|
|
105
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* The roster as a hello carries it: without the scan-only build fields (`currentBuild`/`builds`/`switchPending`, spec §6.4). The
|
|
125
|
+
* daemon keeps one cached roster, which a scan refreshes with those fields; a later reconnect's hello would otherwise carry a
|
|
126
|
+
* snapshot of sessions and pending moves that is stale by then. Only the scan answers them, fresh.
|
|
127
|
+
*/
|
|
128
|
+
export function helloRoster(bridges) {
|
|
129
|
+
return bridges.map((bridge) => {
|
|
130
|
+
if (bridge.currentBuild === undefined && bridge.builds === undefined && bridge.switchPending === undefined)
|
|
131
|
+
return bridge;
|
|
132
|
+
const { currentBuild: _current, builds: _builds, switchPending: _pending, ...rest } = bridge;
|
|
133
|
+
return rest;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
106
136
|
function partitionWireSafeBridges(bridges) {
|
|
107
137
|
let parsed;
|
|
108
138
|
try {
|
|
@@ -6,6 +6,7 @@ const DISCRIMINATORS = new Set([
|
|
|
6
6
|
'desktop_capability', 'desktop_open', 'desktop_opened', 'desktop_data', 'desktop_credit', 'desktop_close',
|
|
7
7
|
'computer_hello', 'computer_ready', 'heartbeat', 'heartbeat_ack',
|
|
8
8
|
'exec_request', 'exec_output', 'exec_exit', 'exec_cancel', 'tool_request', 'tool_result',
|
|
9
|
+
'exec_started', 'exec_ack', 'exec_attach', 'exec_status',
|
|
9
10
|
'file_read_request', 'file_read_result', 'file_write_request', 'file_write_result',
|
|
10
11
|
'file_ls_request', 'file_ls_result', 'file_mkdir_request', 'file_mkdir_result',
|
|
11
12
|
]);
|
|
@@ -16,6 +17,9 @@ const fileErrorCodes = new Set([
|
|
|
16
17
|
]);
|
|
17
18
|
const isNonnegativeInteger = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
18
19
|
const isPositiveInteger = (value) => Number.isSafeInteger(value) && value >= 1;
|
|
20
|
+
/** A record offset, or -1 for "none" (exec_status / exec_ack). */
|
|
21
|
+
const isOffsetOrNone = (value) => Number.isSafeInteger(value) && value >= -1;
|
|
22
|
+
const EXEC_STATES = new Set(['running', 'exited', 'unknown']);
|
|
19
23
|
const isSha256 = (value) => typeof value === 'string' && /^[0-9a-f]{64}$/.test(value);
|
|
20
24
|
const onlyKeys = (value, keys) => Object.keys(value).every(key => keys.includes(key));
|
|
21
25
|
function isFileError(value) {
|
|
@@ -66,12 +70,19 @@ function isComputerFrame(value) {
|
|
|
66
70
|
case 'exec_request': return hasRequired(value, {
|
|
67
71
|
id: isString, command: isString, shell: isString, cwd: isString, env: isStringRecord,
|
|
68
72
|
pathPrepend: isStringArray, streaming: isBoolean,
|
|
69
|
-
}) && hasOptional(value, { timeoutSeconds: isNullableNumber });
|
|
70
|
-
case '
|
|
73
|
+
}) && hasOptional(value, { timeoutSeconds: isNullableNumber, label: isString, jobId: isString });
|
|
74
|
+
case 'exec_started': return hasRequired(value, { id: isString, durable: isBoolean, startedAtMs: isNumber })
|
|
75
|
+
&& hasOptional(value, { pid: isNonnegativeInteger });
|
|
76
|
+
case 'exec_output': return hasRequired(value, { id: isString, stream: isString, chunk: isString })
|
|
77
|
+
&& hasOptional(value, { offset: isNonnegativeInteger, recvAtMs: isNumber });
|
|
78
|
+
case 'exec_ack': return hasRequired(value, { id: isString, throughOffset: isOffsetOrNone });
|
|
71
79
|
case 'exec_exit': return hasRequired(value, {
|
|
72
80
|
id: isString, exitCode: isNullableNumber, stdout: isString, stderr: isString,
|
|
73
81
|
timedOut: isBoolean, truncated: isBoolean,
|
|
74
|
-
});
|
|
82
|
+
}) && hasOptional(value, { signal: isString, cancelled: isBoolean, gaps: isNonnegativeInteger });
|
|
83
|
+
case 'exec_attach': return hasRequired(value, { id: isString, fromOffset: isNonnegativeInteger });
|
|
84
|
+
case 'exec_status': return hasRequired(value, { id: isString, state: isString, headOffset: isOffsetOrNone, committedOffset: isOffsetOrNone })
|
|
85
|
+
&& EXEC_STATES.has(value.state);
|
|
75
86
|
case 'tool_request': return hasRequired(value, { id: isString, method: isString, params: isObject })
|
|
76
87
|
&& value.id.length > 0 && value.id.length <= 128
|
|
77
88
|
&& value.method.length > 0 && value.method.length <= 64
|
|
@@ -82,7 +93,7 @@ function isComputerFrame(value) {
|
|
|
82
93
|
&& (value.ok ? value.error === null : typeof value.error === 'string' && value.error.length > 0)
|
|
83
94
|
&& Buffer.byteLength(JSON.stringify(value)) <= TOOL_RESULT_BYTES
|
|
84
95
|
&& onlyKeys(value, ['t', 'id', 'ok', 'result', 'error']);
|
|
85
|
-
case 'exec_cancel': return hasRequired(value, { id: isString });
|
|
96
|
+
case 'exec_cancel': return hasRequired(value, { id: isString }) && hasOptional(value, { signal: isString });
|
|
86
97
|
case 'file_read_request': return hasRequired(value, {
|
|
87
98
|
id: isString, root: isString, path: isString, startLine: isPositiveInteger, maxLines: isPositiveInteger,
|
|
88
99
|
}) && value.maxLines <= 2000 && onlyKeys(value, ['t', 'id', 'root', 'path', 'startLine', 'maxLines']);
|
|
@@ -8,11 +8,20 @@ export const MANAGEMENT_WIRE_METRICS_VERSION = 4;
|
|
|
8
8
|
export const MANAGEMENT_WIRE_PRESSURE_VERSION = 5;
|
|
9
9
|
/** Replaces normalized CPU load with raw 1/5/15-minute load averages and CPU capacity. */
|
|
10
10
|
export const MANAGEMENT_WIRE_LOAD_AVERAGES_VERSION = 6;
|
|
11
|
-
|
|
11
|
+
/** Adds per-GPU utilization and GPU memory to heartbeat metrics. */
|
|
12
|
+
export const MANAGEMENT_WIRE_GPU_VERSION = 7;
|
|
13
|
+
/** Adds `keepers` to heartbeats and the `keeper_control` / `keeper_control_result` pair (spec §8.1, Task 26). */
|
|
14
|
+
export const MANAGEMENT_WIRE_KEEPERS_VERSION = 8;
|
|
15
|
+
export const MANAGEMENT_WIRE_VERSION = MANAGEMENT_WIRE_KEEPERS_VERSION;
|
|
16
|
+
/** Bounds of one heartbeat's `keepers` (spec §8.1). */
|
|
17
|
+
export const KEEPER_STATUS_MAX_ITEMS = 32;
|
|
18
|
+
export const KEEPER_LABEL_MAX_CHARS = 64;
|
|
19
|
+
export const KEEPER_STATUS_MAX_ENTRIES = 16;
|
|
20
|
+
export const KEEPER_AFFECTED_MAX_ITEMS = 256;
|
|
12
21
|
const DISCRIMINATORS = new Set([
|
|
13
22
|
'management_hello', 'management_ready', 'heartbeat', 'heartbeat_ack',
|
|
14
23
|
'channel_ticket_request', 'channel_ticket', 'client_update', 'client_update_status',
|
|
15
|
-
'external_agents_scan', 'external_agents_scan_result',
|
|
24
|
+
'external_agents_scan', 'external_agents_scan_result', 'keeper_control', 'keeper_control_result',
|
|
16
25
|
]);
|
|
17
26
|
const CHANNEL_KINDS = new Set(['MANAGEMENT', 'COMPUTER', 'AGENT']);
|
|
18
27
|
const CHANNEL_STATES = new Set(['DISCONNECTED', 'CONNECTING', 'CONNECTED', 'RECONNECTING']);
|
|
@@ -63,6 +72,15 @@ function isStoragePoolMetrics(value) {
|
|
|
63
72
|
availableBytes: isNumber,
|
|
64
73
|
});
|
|
65
74
|
}
|
|
75
|
+
function isGpuMetrics(value) {
|
|
76
|
+
return isObject(value) && hasRequired(value, { id: isString, name: isString })
|
|
77
|
+
&& hasOptional(value, {
|
|
78
|
+
utilization: isNullable(isNumber),
|
|
79
|
+
memoryTotalBytes: isNullable(isNumber),
|
|
80
|
+
memoryUsedBytes: isNullable(isNumber),
|
|
81
|
+
coreCount: isNullable(isNumber),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
66
84
|
function isWorkstationMetrics(value) {
|
|
67
85
|
return isObject(value) && hasRequired(value, {
|
|
68
86
|
cpuUtilization: isNullable(isNumber),
|
|
@@ -76,8 +94,31 @@ function isWorkstationMetrics(value) {
|
|
|
76
94
|
cpuLoad15: isNullable(isNumber),
|
|
77
95
|
cpuLogicalCount: isNullable(isNumber),
|
|
78
96
|
memoryPressure: isNullable(isNumber),
|
|
97
|
+
gpus: isNullable((gpus) => Array.isArray(gpus) && gpus.every(isGpuMetrics)),
|
|
79
98
|
});
|
|
80
99
|
}
|
|
100
|
+
const KEEPER_KINDS = new Set(['terminal', 'acp']);
|
|
101
|
+
const KEEPER_STATES = new Set(['running', 'starting', 'stopped', 'unavailable']);
|
|
102
|
+
const KEEPER_REPLACEMENTS = new Set(['none', 'available', 'required', 'mandatory']);
|
|
103
|
+
const KEEPER_ITEM_TYPES = new Set(['pty', 'exec', 'session']);
|
|
104
|
+
const KEEPER_ACTIONS = new Set(['replace-when-idle', 'replace-now', 'cancel']);
|
|
105
|
+
const oneOf = (set) => (value) => typeof value === 'string' && set.has(value);
|
|
106
|
+
const isPending = (value) => value === null || value === 'when-idle';
|
|
107
|
+
function isKeeperItem(value) {
|
|
108
|
+
return isObject(value) && hasRequired(value, { type: oneOf(KEEPER_ITEM_TYPES), id: isString, label: isString, state: isString, sinceEpochMs: isNumber })
|
|
109
|
+
&& hasOptional(value, { jobId: isString });
|
|
110
|
+
}
|
|
111
|
+
function isKeeperStatus(value) {
|
|
112
|
+
return isObject(value) && hasRequired(value, {
|
|
113
|
+
kind: oneOf(KEEPER_KINDS), gen: isString, state: oneOf(KEEPER_STATES), protocolVersion: isNumber, buildVersion: isString,
|
|
114
|
+
replacement: oneOf(KEEPER_REPLACEMENTS),
|
|
115
|
+
metrics: (metrics) => isObject(metrics) && Object.values(metrics).every(isNumber),
|
|
116
|
+
items: (items) => Array.isArray(items) && items.length <= KEEPER_STATUS_MAX_ITEMS && items.every(isKeeperItem),
|
|
117
|
+
}) && hasOptional(value, { legacy: isBoolean, pending: isPending });
|
|
118
|
+
}
|
|
119
|
+
function isKeeperAffected(value) {
|
|
120
|
+
return isObject(value) && hasRequired(value, { type: oneOf(KEEPER_ITEM_TYPES), id: isString, label: isString, gen: isString });
|
|
121
|
+
}
|
|
81
122
|
function isManagementFrame(value) {
|
|
82
123
|
switch (value.t) {
|
|
83
124
|
case 'management_hello': return hasRequired(value, {
|
|
@@ -93,10 +134,12 @@ function isManagementFrame(value) {
|
|
|
93
134
|
channels: (channels) => isObject(channels) && Object.entries(channels).every(([kind, state]) => CHANNEL_KINDS.has(kind) && isChannelState(state)),
|
|
94
135
|
activeShellTasks: isNumber, activeAgentTasks: isNumber,
|
|
95
136
|
}) && hasOptional(value, {
|
|
137
|
+
playgroundCwd: isString,
|
|
96
138
|
protocols: (protocols) => isProtocolRangeMap(protocols, false),
|
|
97
139
|
os: isNullable(isOsInfo),
|
|
98
140
|
update: isNullable(isUpdateStatus),
|
|
99
141
|
metrics: isNullable(isWorkstationMetrics),
|
|
142
|
+
keepers: isNullable((keepers) => Array.isArray(keepers) && keepers.every(isKeeperStatus)),
|
|
100
143
|
});
|
|
101
144
|
case 'heartbeat_ack': return hasRequired(value, { seq: isNumber });
|
|
102
145
|
case 'channel_ticket_request': return hasRequired(value, { channel: isChannelKind });
|
|
@@ -105,6 +148,11 @@ function isManagementFrame(value) {
|
|
|
105
148
|
case 'client_update_status': return hasRequired(value, { status: isUpdateStatus });
|
|
106
149
|
case 'external_agents_scan': return hasRequired(value, { commandId: isString });
|
|
107
150
|
case 'external_agents_scan_result': return hasRequired(value, { commandId: isString, bridges: isBridgeInfoArray });
|
|
151
|
+
case 'keeper_control': return hasRequired(value, { commandId: isString, kind: oneOf(KEEPER_KINDS), action: oneOf(KEEPER_ACTIONS) });
|
|
152
|
+
case 'keeper_control_result': return hasRequired(value, {
|
|
153
|
+
commandId: isString, kind: oneOf(KEEPER_KINDS), action: oneOf(KEEPER_ACTIONS), ok: isBoolean,
|
|
154
|
+
affected: (affected) => Array.isArray(affected) && affected.every(isKeeperAffected),
|
|
155
|
+
}) && hasOptional(value, { pending: isPending, error: isString, affectedIncomplete: (flag) => flag === true });
|
|
108
156
|
default: return false;
|
|
109
157
|
}
|
|
110
158
|
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/** Native Qoder does not forward background child SDK messages through ACP. Read only the
|
|
2
|
-
* exact transcript named by a validated root launch receipt; never scan or infer ownership.
|
|
2
|
+
* exact transcript named by a validated root launch receipt; never scan or infer ownership.
|
|
3
|
+
*
|
|
4
|
+
* Each accepted row's derived events go to `onRow` (with the row's `uuid`) when it is given — the
|
|
5
|
+
* side-file reader records them as one `child` fact (`backgroundTerminalFold.ts`) — and otherwise one
|
|
6
|
+
* by one to `emit`. */
|
|
3
7
|
import { constants } from 'node:fs';
|
|
4
8
|
import { open } from 'node:fs/promises';
|
|
5
9
|
const object = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
@@ -73,13 +77,14 @@ export class BackgroundProcess {
|
|
|
73
77
|
const content = object(row.message).content;
|
|
74
78
|
if (!Array.isArray(content))
|
|
75
79
|
return;
|
|
80
|
+
const events = [];
|
|
76
81
|
for (const block of content.map(object)) {
|
|
77
82
|
if (row.type === 'assistant' && block.type === 'tool_use' && id(block.id) && typeof block.name === 'string') {
|
|
78
83
|
if (this.tools.has(block.id) || this.tools.size >= 4096)
|
|
79
84
|
continue;
|
|
80
85
|
const input = object(block.input);
|
|
81
86
|
this.tools.set(block.id, { name: block.name, input });
|
|
82
|
-
this.
|
|
87
|
+
this.derive(events, 'tool_call', { toolCallId: block.id, name: block.name, title: block.name,
|
|
83
88
|
kind: block.name === 'Read' ? 'read' : block.name === 'Bash' ? 'execute' : block.name === 'Agent' ? 'think' : 'other',
|
|
84
89
|
rawInput: input, status: 'pending' }, block.name);
|
|
85
90
|
}
|
|
@@ -89,18 +94,25 @@ export class BackgroundProcess {
|
|
|
89
94
|
continue;
|
|
90
95
|
const raw = row.toolUseResult ?? block.content;
|
|
91
96
|
const text = typeof block.content === 'string' ? block.content : JSON.stringify(block.content ?? '');
|
|
92
|
-
this.
|
|
97
|
+
this.derive(events, 'tool_call_update', { toolCallId: block.tool_use_id, name: tool.name,
|
|
93
98
|
status: block.is_error === true ? 'failed' : 'completed', rawOutput: raw,
|
|
94
99
|
content: [{ type: 'content', content: { type: 'text', text } }] }, tool.name);
|
|
95
100
|
}
|
|
96
101
|
else if (row.type === 'assistant' && ((block.type === 'text' && typeof block.text === 'string') ||
|
|
97
102
|
(block.type === 'thinking' && typeof block.thinking === 'string'))) {
|
|
98
|
-
this.
|
|
103
|
+
this.derive(events, block.type === 'text' ? 'agent_message_chunk' : 'agent_thought_chunk', { content: { type: 'text', text: block.type === 'text' ? block.text : block.thinking } });
|
|
99
104
|
}
|
|
100
105
|
}
|
|
106
|
+
if (this.options.onRow) {
|
|
107
|
+
if (events.length > 0)
|
|
108
|
+
this.options.onRow(row.uuid, events);
|
|
109
|
+
}
|
|
110
|
+
else
|
|
111
|
+
for (const event of events)
|
|
112
|
+
this.options.emit(event);
|
|
101
113
|
}
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
derive(events, eventName, payload, toolName) {
|
|
115
|
+
events.push({ eventName, payload: { ...payload, _meta: { qoder: { version: 1, source: 'correction',
|
|
104
116
|
parentToolUseId: this.options.parentToolUseId, route: 'child', ...(toolName ? { toolName } : {}) } } } });
|
|
105
117
|
}
|
|
106
118
|
}
|