@jini-ai/daemon 0.6.8 → 0.6.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +148 -0
- package/dist/agent-executor/antigravity-permissions.d.ts +11 -0
- package/dist/agent-executor/antigravity-permissions.js +64 -0
- package/dist/agent-executor/contracts.d.ts +37 -6
- package/dist/agent-executor/event-translation.d.ts +6 -1
- package/dist/agent-executor/event-translation.js +3 -1
- package/dist/agent-executor/events.d.ts +5 -0
- package/dist/agent-executor/events.js +143 -87
- package/dist/agent-executor/launch.d.ts +5 -3
- package/dist/agent-executor/launch.js +315 -217
- package/dist/agent-executor/mcp-bridge-probe.js +51 -35
- package/dist/agent-executor/mcp-bridge.d.ts +18 -8
- package/dist/agent-executor/mcp-bridge.js +105 -65
- package/dist/agent-executor/run-output.d.ts +20 -0
- package/dist/agent-executor/run-output.js +80 -0
- package/dist/attachment-content.js +18 -15
- package/dist/core/read-only-tools.d.ts +15 -0
- package/dist/core/read-only-tools.js +29 -1
- package/dist/core/tool-audit.d.ts +3 -1
- package/dist/core/tool-audit.js +35 -22
- package/dist/core/tool-gaps.d.ts +60 -0
- package/dist/core/tool-gaps.js +199 -0
- package/dist/delegated-result-correlation.d.ts +26 -0
- package/dist/delegated-result-correlation.js +68 -0
- package/dist/delegated-tool-bridge.d.ts +6 -14
- package/dist/delegated-tool-bridge.js +155 -155
- package/dist/event-log.d.ts +45 -2
- package/dist/event-log.js +83 -4
- package/dist/http/attachments.d.ts +26 -1
- package/dist/http/attachments.js +129 -65
- package/dist/http/connectors.d.ts +1 -32
- package/dist/http/connectors.js +13 -68
- package/dist/http/delegated-tools.d.ts +8 -1
- package/dist/http/delegated-tools.js +30 -30
- package/dist/http/host-tools.d.ts +1 -0
- package/dist/http/host-tools.js +64 -59
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.js +1 -1
- package/dist/http/media.js +48 -69
- package/dist/http/memory.js +45 -36
- package/dist/http/model-proxy-fields.d.ts +23 -0
- package/dist/http/model-proxy-fields.js +29 -0
- package/dist/http/model-proxy.js +193 -395
- package/dist/http/research-tavily.adapter.js +72 -49
- package/dist/http/research.js +33 -23
- package/dist/http/resource-request.d.ts +37 -0
- package/dist/http/resource-request.js +59 -0
- package/dist/http/routines.js +49 -90
- package/dist/http/runs.d.ts +7 -5
- package/dist/http/runs.js +21 -7
- package/dist/http/terminals.js +23 -48
- package/dist/http/tool-catalog.d.ts +5 -0
- package/dist/http/xai.d.ts +11 -1
- package/dist/http/xai.js +125 -124
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/legacy-data-migration.js +41 -24
- package/dist/run/core/retry.js +51 -35
- package/dist/run/diagnostics/diagnostics.js +5 -17
- package/dist/run-credentials.js +49 -27
- package/dist/run-lifecycle.d.ts +31 -2
- package/dist/run-lifecycle.js +49 -42
- package/dist/store/agent-sessions/sqlite.d.ts +6 -0
- package/dist/store/agent-sessions/sqlite.js +6 -4
- package/dist/surface-exchanges.js +2 -1
- package/dist/terminal-session.d.ts +1 -1
- package/dist/terminal-session.js +26 -33
- package/dist/tool-audit.d.ts +1 -0
- package/dist/tool-audit.js +1 -0
- package/dist/tool-executor.d.ts +24 -3
- package/dist/tool-executor.js +276 -139
- package/dist/tool-recovery/recovery.js +64 -35
- package/dist/tool-recovery/stack.d.ts +2 -1
- package/dist/tool-recovery/stack.js +1 -1
- package/dist/tool-result-diagnostics.d.ts +27 -0
- package/dist/tool-result-diagnostics.js +77 -0
- package/dist/tool-result-media.d.ts +27 -14
- package/dist/tool-result-media.js +51 -38
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,151 @@
|
|
|
1
|
+
## 0.6.10
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- 4f52784: Stop advertising agents `AgentExecutor` cannot run.
|
|
6
|
+
|
|
7
|
+
The built-in `agents` feature scanned every runtime definition, but `AgentExecutor` rejects some of
|
|
8
|
+
them (`antigravity`, whose deferral is documented in that module). A consumer could therefore offer a
|
|
9
|
+
user an agent that failed the instant it was selected, with the mismatch visible nowhere.
|
|
10
|
+
|
|
11
|
+
- `@jini-ai/daemon` exports `isAgentExecutorSupported(def)` and `assessAgentExecutorCompatibility(def)`.
|
|
12
|
+
`run()` now consumes the latter instead of re-checking the conditions itself, so the discovery-time
|
|
13
|
+
answer and the run-time guards cannot drift apart. Error messages are unchanged.
|
|
14
|
+
- `@jini-ai/server`'s `agents` feature applies the predicate by default, and exports
|
|
15
|
+
`isExecutableDetectedAgent` for hosts that want it directly.
|
|
16
|
+
|
|
17
|
+
`antigravity`'s definition remains in `@jini-ai/agent-runtime` — the predicate is advisory, and a
|
|
18
|
+
non-`AgentExecutor` launch path can ignore it. An id with no registered def is kept rather than
|
|
19
|
+
dropped, so a host supplying its own `detector` is unaffected.
|
|
20
|
+
|
|
21
|
+
Note for anyone implementing something similar: the predicate deliberately takes the full
|
|
22
|
+
`RuntimeAgentDef`, not a projected `DetectedAgent`. That projection omits `maxPromptArgBytes`, and the
|
|
23
|
+
argv-bound defs (`aider`, `deepseek`) qualify solely through it — judging the projection would have
|
|
24
|
+
dropped two working agents while fixing one broken one.
|
|
25
|
+
|
|
26
|
+
- 8ff5653: Drive Antigravity (`agy`) — the 24th and last agent definition `AgentExecutor` rejected.
|
|
27
|
+
|
|
28
|
+
`AgentExecutor` drove 23 of 24 registered definitions. Antigravity was rejected by an explicit
|
|
29
|
+
`def.id === 'antigravity'` guard, for two reasons that are real but narrow:
|
|
30
|
+
|
|
31
|
+
- **`agy` can print an OAuth sign-in URL to stdout and still exit 0.** Streaming stdout live shows
|
|
32
|
+
that URL to the user as if it were the model's reply — a URL that carries the daemon operator's
|
|
33
|
+
`client_id`/`redirect_uri` into a chat transcript, and that is useless to click anyway (`agy -p`
|
|
34
|
+
print mode has no field to paste the resulting auth code into).
|
|
35
|
+
- **`agy` has no `--model` flag.** The model choice is written into one process-global
|
|
36
|
+
`~/.gemini/antigravity-cli/settings.json` that `agy` reads on its own startup, so two concurrent
|
|
37
|
+
runs race: run A writes model A, A spawns, B writes model B, and only _then_ does A's `agy` read
|
|
38
|
+
the file — so A silently executes on B's model.
|
|
39
|
+
|
|
40
|
+
Both are now met by **declarative `RuntimeAgentDef` fields the executor reads generically**, joining
|
|
41
|
+
the 14 optional behavior flags (`promptViaFile`, `authProbe`, …) that already work this way. There is
|
|
42
|
+
no agent-id branch anywhere in the dispatch path — a deliberate divergence from Open Design's own
|
|
43
|
+
daemon, which hardcodes the id twice.
|
|
44
|
+
|
|
45
|
+
New on `@jini-ai/agent-runtime`'s `RuntimeAgentDef`:
|
|
46
|
+
|
|
47
|
+
- `needsAgentLogFile?: boolean` — asks the caller to stage a temp path and pass it as
|
|
48
|
+
`RuntimeContext.agentLogFilePath` before `buildArgs` runs, mirroring `promptViaFile`. Staged by the
|
|
49
|
+
new `prepareAgentLogFile(def, label)` (the sibling of `preparePromptFileForAgent`; it creates only
|
|
50
|
+
the `0o700` containing directory, since the log file is output the CLI authors, not input we do).
|
|
51
|
+
- `stdoutPolicy?: RuntimeStdoutPolicy` — `{buffering: 'live'}` (the default, and every other
|
|
52
|
+
definition's behavior) or `{buffering: 'until-close', sanitize?}`. A discriminated union rather
|
|
53
|
+
than two flat fields on purpose: a sanitizer is only meaningful on the buffered path, because the
|
|
54
|
+
pattern to redact can straddle two `'data'` chunks. Two independent flags would let a definition
|
|
55
|
+
declare a sanitizer the caller could not honor — a confidentiality gap that _looks_ closed.
|
|
56
|
+
- `runtimeLock?: RuntimeLock` — a mutex around a process-global side effect `buildArgs` performs.
|
|
57
|
+
Acquired before `buildArgs`, released on whichever of `waitForHandoff` settling or process exit
|
|
58
|
+
comes first. Releasing on exit is load-bearing, not a fallback: a watcher that stops polling means
|
|
59
|
+
"I stopped watching", never "the child definitely didn't read the file".
|
|
60
|
+
|
|
61
|
+
All three are stripped from the `DetectedAgent` registry projection. They instruct whoever _spawns_
|
|
62
|
+
the CLI, not whoever lists agents — and two carry closures, which `JSON.stringify` would flatten into
|
|
63
|
+
a misleading `{"buffering":"until-close"}` / `{}` rather than omit.
|
|
64
|
+
|
|
65
|
+
In `@jini-ai/daemon`, `AgentExecutor` now stages a log file when `needsAgentLogFile` is set (released
|
|
66
|
+
on every pre-spawn, spawn-failure, and close path alongside the prompt file, through one composed
|
|
67
|
+
`cleanupStagedFiles` closure), calls `runtimeLock.acquire()` before `buildArgs`, and branches its
|
|
68
|
+
`streamFormat: 'plain'` stdout handling on `stdoutPolicy`. `assessAgentExecutorCompatibility` no
|
|
69
|
+
longer rejects anything by id, and `isAgentExecutorSupported` now accepts all 24 definitions.
|
|
70
|
+
|
|
71
|
+
**No behavior change for any other agent.** Antigravity is the only definition declaring any of the
|
|
72
|
+
three fields; the other four `streamFormat: 'plain'` definitions (`grok-build`, `aider`, `deepseek`,
|
|
73
|
+
`qwen`) keep streaming live, per chunk, which `aider`'s and `deepseek`'s own comments call out as
|
|
74
|
+
deliberate. That is pinned by an explicit regression test rather than left implied.
|
|
75
|
+
|
|
76
|
+
One thing worth knowing if you consume the run event stream: on the buffered path the raw `'stdout'`
|
|
77
|
+
echo is held back and sanitized too, not just the `'agent'`/`text_delta` copy. Emitting an
|
|
78
|
+
unsanitized raw echo while withholding the chat copy would leak the exact string the sanitizer exists
|
|
79
|
+
to remove to any subscriber. The opt-in byte journal still records raw bytes per chunk — that is its
|
|
80
|
+
documented contract, and it deliberately lives in a separate `EventLog` instance that is never
|
|
81
|
+
replayed to run-event subscribers.
|
|
82
|
+
|
|
83
|
+
- 3fe4d14: Store tool-result images once in media, preserve model-facing pixels, and provide opt-in digest-verified echo summaries and bounded image-safe diagnostics. Hosts with exact-byte journaling must inject a separate stdout blob/reference writer.
|
|
84
|
+
|
|
85
|
+
Preserve conflicting image representations during digest verification, and keep the required bridge executor authoritative when route dependencies supply optional settings.
|
|
86
|
+
|
|
87
|
+
- e16a907: Choose reported-cost semantics from agent definition metadata rather than a vendor id; absent metadata retains per-run behavior.
|
|
88
|
+
- 4f52784: Add `createRunScopedContextStore` and widen `ResolvedRunInput` with the executor's optional inputs.
|
|
89
|
+
|
|
90
|
+
**`createRunScopedContextStore<T>({ lifecycle })`** — bind/resolve/auto-evict keyed by run id, for
|
|
91
|
+
host-owned context that must survive the gap between starting a run and a later delegated call that
|
|
92
|
+
carries only that run's id. `resolve` fails closed (`RunContextNotBoundError`) rather than fabricating a
|
|
93
|
+
default, and bindings are evicted when the run reaches a terminal state.
|
|
94
|
+
|
|
95
|
+
`resolveRunInput` could already decode and stash such context, but it is handed no lifecycle and so
|
|
96
|
+
cannot register the eviction half — leaving a map that only grows and keeps stale authority resolvable.
|
|
97
|
+
Owning both halves together is the point. `T` is fully generic: this helper does not decode
|
|
98
|
+
`contextRef`, does not sign or verify anything, and has no notion of a principal. It is in-memory only,
|
|
99
|
+
and says so — after a restart every `resolve` fails, which is the correct posture rather than a gap.
|
|
100
|
+
|
|
101
|
+
**`ResolvedRunInput` now carries `permissionMode`, `model`, `reasoning`, and `credentialEnv`**, each
|
|
102
|
+
forwarded to `AgentExecutor.run()` only when present.
|
|
103
|
+
|
|
104
|
+
`permissionMode` is the load-bearing one and closes a real trap: every def with an auto-approve flag
|
|
105
|
+
(`bypassPermissions` / `--yolo` / `--dangerously-skip-permissions`) applies it by default when the field
|
|
106
|
+
is absent. A host that had been passing `'restricted'` to `AgentExecutor.run()` by hand and then adopted
|
|
107
|
+
`createDefaultRunStartHandler` would silently have started auto-approving every action — a security
|
|
108
|
+
regression wearing the clothes of a refactor. Existing behavior is unchanged: omitted fields are omitted
|
|
109
|
+
from the executor call, never passed as an explicit `undefined`.
|
|
110
|
+
|
|
111
|
+
- 4f52784: Add a `sidecar-strict` security mode and per-run MCP credential propagation.
|
|
112
|
+
|
|
113
|
+
For a daemon whose threat model is **another process running as the same OS user** rather than a
|
|
114
|
+
remote attacker, the existing `jini-local` mode is a no-op: `registerApiBearerAuthMiddleware`
|
|
115
|
+
short-circuits for any loopback peer before it reads the `Authorization` header, and a `127.0.0.1`
|
|
116
|
+
bind keeps remote hosts out while doing nothing about a co-resident process. A consumer that spawns a
|
|
117
|
+
Jini daemon holding real authority — starting agent runs, executing tools against a real database —
|
|
118
|
+
previously had to write its own middleware.
|
|
119
|
+
|
|
120
|
+
- `@jini-ai/http-kit` gains `requireStrictBearerToken`: fail-closed 503 when the named token env var
|
|
121
|
+
is unset, 401 on mismatch, **no loopback exemption and no disable flag**. Its `tokenEnvVar` is
|
|
122
|
+
required with no default, so this package never names a host's secret.
|
|
123
|
+
- `composeJiniKernel` gains `security: { mode: 'sidecar-strict', host, tokenEnvVar, exemptPaths? }`.
|
|
124
|
+
Purely additive — `host` and `jini-local` are unchanged by construction, since the modes are arms of
|
|
125
|
+
a discriminated union. The strict gate mounts ahead of the JSON body parser, so a caller it rejects
|
|
126
|
+
never has its body parsed.
|
|
127
|
+
- `@jini-ai/daemon`'s `McpJsonInjectionOptions` gains `credential?: (runId) => string | Promise<string>`
|
|
128
|
+
— a **resolver, not a string**, because injection options are built once before any run exists and a
|
|
129
|
+
boot-wide shared secret would defeat the point of scoping a credential to a run. It is delivered to
|
|
130
|
+
the child as `JINI_DAEMON_TOKEN`.
|
|
131
|
+
- `@jini-ai/mcp`'s `jini-mcp` reads that variable and attaches `Authorization` to every daemon call.
|
|
132
|
+
Optional throughout: with no credential, request headers and `.mcp.json` output are byte-identical
|
|
133
|
+
to before.
|
|
134
|
+
|
|
135
|
+
Also generalized: both existing bearer gates now compare tokens in constant time (`timingSafeEqual`)
|
|
136
|
+
and share one header-parsing helper, closing a timing side channel and removing a duplicated regex.
|
|
137
|
+
|
|
138
|
+
- Updated dependencies [22f0619]
|
|
139
|
+
- Updated dependencies [82ed2d3]
|
|
140
|
+
- Updated dependencies [3fe4d14]
|
|
141
|
+
- Updated dependencies [5a3de86]
|
|
142
|
+
- @jini-ai/core@0.6.10
|
|
143
|
+
- @jini-ai/protocol@0.6.10
|
|
144
|
+
|
|
145
|
+
## 0.6.9 — 2026-10-22
|
|
146
|
+
|
|
147
|
+
- 2026-10-22: Memory fixes (bounded event log and tool-executor audit), chromeIntegration option, provider-plugin registration, coverage.
|
|
148
|
+
|
|
1
149
|
## 0.6.8 — 2026-10-16
|
|
2
150
|
|
|
3
151
|
- An unknown tool on the read-only gateway points to discovery, never a mutation 409 (75d37c32).
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persist one server's MCP grant for agy, which has no run-scoped settings override.
|
|
3
|
+
* Reuses the platform lock and atomic writer; keeps the first existing file as a backup.
|
|
4
|
+
* Invalid settings and I/O failures reject before spawn rather than widening permissions.
|
|
5
|
+
* @complexity O(settings bytes), including the allow-list scan; bounded by the settings file.
|
|
6
|
+
*/
|
|
7
|
+
export declare function ensureAntigravityMcpPermission({ settingsPath, serverName }: {
|
|
8
|
+
settingsPath: string;
|
|
9
|
+
serverName: string;
|
|
10
|
+
}, _options?: Record<string, never>): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=antigravity-permissions.d.ts.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { constants, promises as fs } from 'node:fs';
|
|
2
|
+
import { withFileLock, writeFileAtomicAsync } from '@jini-ai/platform/fs';
|
|
3
|
+
import { isRecord } from './values.js';
|
|
4
|
+
/** Read the current settings text; a missing file is undefined, every other failure rejects. */
|
|
5
|
+
async function readSettingsText(settingsPath) {
|
|
6
|
+
try {
|
|
7
|
+
return await fs.readFile(settingsPath, 'utf8');
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (error.code !== 'ENOENT')
|
|
11
|
+
throw error;
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Parse and validate the settings shape; anything unexpected rejects rather than widening permissions. */
|
|
16
|
+
function parseSettings(raw) {
|
|
17
|
+
const settings = raw === undefined ? {} : JSON.parse(raw);
|
|
18
|
+
if (!isRecord(settings))
|
|
19
|
+
throw new Error('Antigravity settings must be an object');
|
|
20
|
+
const permissions = settings.permissions === undefined ? {} : settings.permissions;
|
|
21
|
+
if (!isRecord(permissions) || (permissions.allow !== undefined && !Array.isArray(permissions.allow))) {
|
|
22
|
+
throw new Error('Antigravity permissions.allow must be an array');
|
|
23
|
+
}
|
|
24
|
+
return { settings, permissions, allow: permissions.allow ?? [] };
|
|
25
|
+
}
|
|
26
|
+
/** The allow list holding exactly one copy of rule (first occurrence kept, order otherwise
|
|
27
|
+
* unchanged), or null when it already holds exactly one and nothing needs writing. */
|
|
28
|
+
function grantedAllowList(allow, rule) {
|
|
29
|
+
const first = allow.indexOf(rule);
|
|
30
|
+
if (first < 0)
|
|
31
|
+
return [...allow, rule];
|
|
32
|
+
const deduped = allow.filter((entry, index) => entry !== rule || index === first);
|
|
33
|
+
return deduped.length === allow.length ? null : deduped;
|
|
34
|
+
}
|
|
35
|
+
async function backupOriginalOnce(settingsPath) {
|
|
36
|
+
// Never replace the first backup, including on subsequent launches after operator edits.
|
|
37
|
+
await fs.copyFile(settingsPath, `${settingsPath}.jini-backup`, constants.COPYFILE_EXCL)
|
|
38
|
+
.catch((error) => { if (error.code !== 'EEXIST')
|
|
39
|
+
throw error; });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Persist one server's MCP grant for agy, which has no run-scoped settings override.
|
|
43
|
+
* Reuses the platform lock and atomic writer; keeps the first existing file as a backup.
|
|
44
|
+
* Invalid settings and I/O failures reject before spawn rather than widening permissions.
|
|
45
|
+
* @complexity O(settings bytes), including the allow-list scan; bounded by the settings file.
|
|
46
|
+
*/
|
|
47
|
+
export async function ensureAntigravityMcpPermission({ settingsPath, serverName }, _options = {}) {
|
|
48
|
+
if (!/^[\w.-]+$/.test(serverName))
|
|
49
|
+
throw new Error('Invalid MCP server name');
|
|
50
|
+
const rule = `mcp(${serverName}/*)`;
|
|
51
|
+
await withFileLock({ lockPath: `${settingsPath}.jini-lock`, run: async () => {
|
|
52
|
+
const raw = await readSettingsText(settingsPath);
|
|
53
|
+
const { settings, permissions, allow } = parseSettings(raw);
|
|
54
|
+
const nextAllow = grantedAllowList(allow, rule);
|
|
55
|
+
if (nextAllow === null)
|
|
56
|
+
return;
|
|
57
|
+
if (raw !== undefined)
|
|
58
|
+
await backupOriginalOnce(settingsPath);
|
|
59
|
+
await writeFileAtomicAsync({ filePath: settingsPath, content: `${JSON.stringify({
|
|
60
|
+
...settings, permissions: { ...permissions, allow: nextAllow },
|
|
61
|
+
}, null, 2)}\n` }, { refuseSymlink: true });
|
|
62
|
+
} }, { createParent: true, timeoutMs: 5000 });
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=antigravity-permissions.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { DelegatedResultCorrelation } from '../delegated-result-correlation.js';
|
|
2
|
+
import type { StdoutJournalBlobPort } from '../tool-result-diagnostics.js';
|
|
1
3
|
import type { MessageAttachmentImage } from '../attachment-content.js';
|
|
2
4
|
import type { probeMcpBridge } from './mcp-bridge-probe.js';
|
|
3
5
|
import type { spawn as nodeSpawn, ChildProcess } from 'node:child_process';
|
|
@@ -92,7 +94,7 @@ export type AgentRuntimeEventTranslation = {
|
|
|
92
94
|
readonly kind: 'ignored';
|
|
93
95
|
};
|
|
94
96
|
/** Machine-readable failure reasons `run()` can reject with — every one is preceded by a `lifecycle.finish({status:'failed'})` call (see index.ts module doc's Invariant section). */
|
|
95
|
-
export type AgentExecutorErrorCode = 'AGENT_MODEL_UNRESOLVED' | 'AGENT_PERMISSION_MODE_INVALID' | 'AGENT_NOT_FOUND' | 'AGENT_RUNTIME_UNSUPPORTED' | 'AGENT_BINARY_NOT_RESOLVED' | 'AGENT_SPAWN_FAILED' | 'AGENT_PROMPT_TOO_LARGE';
|
|
97
|
+
export type AgentExecutorErrorCode = 'NATIVE_TOOL_POLICY_UNSUPPORTED' | 'AGENT_MODEL_UNRESOLVED' | 'AGENT_PERMISSION_MODE_INVALID' | 'AGENT_NOT_FOUND' | 'AGENT_RUNTIME_UNSUPPORTED' | 'AGENT_BINARY_NOT_RESOLVED' | 'AGENT_SPAWN_FAILED' | 'AGENT_PROMPT_TOO_LARGE';
|
|
96
98
|
/** Thrown by `AgentExecutor.run()` on every failure path — never a bare `Error`, so callers can branch on `.code` instead of parsing `.message`. */
|
|
97
99
|
export declare class AgentExecutorError extends Error {
|
|
98
100
|
readonly code: AgentExecutorErrorCode;
|
|
@@ -119,6 +121,12 @@ export interface AgentExecutorRunInput {
|
|
|
119
121
|
* delegate auto-approval, and any unknown mode is rejected before launching a process.
|
|
120
122
|
*/
|
|
121
123
|
readonly permissionMode?: 'bypass' | 'restricted';
|
|
124
|
+
/** Host-authorized native shell/edit grant; unsupported restricted providers fail before spawn. */
|
|
125
|
+
readonly nativeToolAccess?: boolean;
|
|
126
|
+
/** Independent host-verified permissions, snapshotted for this run. */
|
|
127
|
+
readonly nativeCapabilities?: Partial<import('@jini-ai/agent-runtime').NativeCapabilities>;
|
|
128
|
+
/** Trusted-host CLI parity; never derived from prompt/context fields. */
|
|
129
|
+
readonly cliParity?: boolean;
|
|
122
130
|
/**
|
|
123
131
|
* Host-validated image files. How each one actually reaches the model
|
|
124
132
|
* depends on `def.imageDelivery` (see `@jini-ai/agent-runtime`'s `types.ts`):
|
|
@@ -184,6 +192,8 @@ export interface AgentExecutorRunInput {
|
|
|
184
192
|
readonly settingSources?: readonly string[];
|
|
185
193
|
/** Forwarded verbatim to `RuntimeBuildOptions.settings` (extra settings JSON or file path for this run). */
|
|
186
194
|
readonly settings?: string;
|
|
195
|
+
/** Forwarded verbatim to `RuntimeBuildOptions.chromeIntegration`; `undefined` = no browser-integration flag. */
|
|
196
|
+
readonly chromeIntegration?: boolean;
|
|
187
197
|
}
|
|
188
198
|
export interface AgentExecutor {
|
|
189
199
|
/**
|
|
@@ -195,16 +205,19 @@ export interface AgentExecutor {
|
|
|
195
205
|
* underlying run is always already transitioned to `'failed'` via
|
|
196
206
|
* `lifecycle.finish()` before this rejects (see index.ts module doc's Invariant).
|
|
197
207
|
*/
|
|
198
|
-
run(requiredArgs: Pick<AgentExecutorRunInput, "runId" | "agentId" | "prompt" | "cwd">, optionalArgs?: Pick<AgentExecutorRunInput, "model" | "reasoning" | "permissionMode" | "imagePaths" | "imageContents" | "extraAllowedDirs" | "uploadRoot" | "credentialEnv" | "env" | "resumeSessionId" | "newSessionId" | "disallowedTools" | "allowedTools" | "settingSources" | "settings">): Promise<void>;
|
|
208
|
+
run(requiredArgs: Pick<AgentExecutorRunInput, "runId" | "agentId" | "prompt" | "cwd">, optionalArgs?: Pick<AgentExecutorRunInput, "model" | "reasoning" | "nativeToolAccess" | "nativeCapabilities" | "cliParity" | "permissionMode" | "imagePaths" | "imageContents" | "extraAllowedDirs" | "uploadRoot" | "credentialEnv" | "env" | "resumeSessionId" | "newSessionId" | "disallowedTools" | "allowedTools" | "settingSources" | "settings" | "chromeIntegration">): Promise<void>;
|
|
199
209
|
/**
|
|
200
210
|
* Delivers a message the human sent while `runId` is going straight into its live agent process
|
|
201
211
|
* (see {@link UserMessageDelivery} for each outcome). A stream-json agent is interrupted first and
|
|
202
212
|
* gets the message once the CLI acknowledges the interrupt, so this settles in milliseconds (at
|
|
203
213
|
* most `INTERRUPT_ACK_TIMEOUT_MS`); it never waits on the agent's reply.
|
|
214
|
+
* Optional `imageContents` contains host-authorized pixels, encoded exactly as in an idle send.
|
|
204
215
|
*/
|
|
205
216
|
sendUserMessage(requiredArgs: {
|
|
206
217
|
readonly runId: string;
|
|
207
218
|
readonly text: string;
|
|
219
|
+
}, optionalArgs?: {
|
|
220
|
+
readonly imageContents?: readonly MessageAttachmentImage[];
|
|
208
221
|
}): Promise<UserMessageDelivery>;
|
|
209
222
|
}
|
|
210
223
|
/**
|
|
@@ -212,7 +225,8 @@ export interface AgentExecutor {
|
|
|
212
225
|
* - `'delivered'` — the running turn was interrupted and the message written into the live
|
|
213
226
|
* session; the agent answers it next, in the same process and session.
|
|
214
227
|
* - `'unsupported'` — the run is live, but its agent has no way to take input mid-run (its prompt
|
|
215
|
-
* is plain text or an RPC request).
|
|
228
|
+
* is plain text or an RPC request). Queue attachment turns intact after the reply; text-only
|
|
229
|
+
* turns may retain the interrupt-and-resume fallback.
|
|
216
230
|
* - `'not-running'` — no live process will accept it: an unknown run, a finished one, or one whose
|
|
217
231
|
* last turn already ended and closed stdin. The run is ending; the host should send it next.
|
|
218
232
|
*/
|
|
@@ -260,7 +274,7 @@ export interface StdinCloseHandle {
|
|
|
260
274
|
/** Journals a sent-to-stdin byte chunk, queued through the same FIFO {@link wireChildLifecycle} already uses for emitted events. No-op when no journal was configured (see `CreateAgentExecutorOptions.journal`). */
|
|
261
275
|
recordSentBytes(content: string): void;
|
|
262
276
|
/** Interrupts this child's turn, then writes a mid-run user message into its open stdin — see {@link AgentExecutor.sendUserMessage}. */
|
|
263
|
-
sendUserMessage(text: string): Promise<UserMessageDelivery>;
|
|
277
|
+
sendUserMessage(text: string, imageContents?: readonly MessageAttachmentImage[]): Promise<UserMessageDelivery>;
|
|
264
278
|
}
|
|
265
279
|
/**
|
|
266
280
|
* Gap 3 (capability-routed continuation transport) — host-owned config for the
|
|
@@ -313,6 +327,17 @@ export interface ContinuationOptions {
|
|
|
313
327
|
* interface that defaults to *nothing* rather than a real implementation).
|
|
314
328
|
*/
|
|
315
329
|
export interface McpJsonInjectionOptions {
|
|
330
|
+
/** Read current host-registered tool IDs at launch, outside model-controlled input. */
|
|
331
|
+
readonly diagnosticToolIds?: () => readonly string[];
|
|
332
|
+
/**
|
|
333
|
+
* Visible registry IDs to resolve before the bridge's first tools/list, including for clients
|
|
334
|
+
* whose mid-run refresh is unverified. Independent of diagnostic/redaction IDs; this grants
|
|
335
|
+
* no execution permission. The bridge fetches authoritative descriptors using the run credential.
|
|
336
|
+
* @example startupToolIds: ({ runId }) => visibleToolsForRun(runId).map(tool => tool.id)
|
|
337
|
+
*/
|
|
338
|
+
readonly startupToolIds?: (requiredArgs: {
|
|
339
|
+
readonly runId: string;
|
|
340
|
+
}, optionalArgs?: Record<string, never>) => readonly string[];
|
|
316
341
|
/** Probe a reported bridge failure before emitting its error. @default true when injection is configured. */
|
|
317
342
|
readonly probeOnFailure?: boolean;
|
|
318
343
|
/** Absolute path (or PATH-resolvable name) to the `jini-mcp` bin entry (`packages/mcp/src/bin/serve.ts`) this driver tells the spawned CLI to launch as its own MCP server subprocess. */
|
|
@@ -401,12 +426,14 @@ export interface McpJsonInjectionOptions {
|
|
|
401
426
|
readonly path: string;
|
|
402
427
|
}) => Promise<void>;
|
|
403
428
|
/** `'codex-toml'` only. Links the run home's sessions/archived_sessions to the operator's
|
|
404
|
-
* persistent rollout store.
|
|
429
|
+
* persistent rollout store and authentication. Parity also links user home entries; config alone stays isolated.
|
|
405
430
|
* @default Native mkdir (0700) and directory symlinks; errors fail staging before spawn. */
|
|
406
431
|
readonly linkSessionStore?: (required: {
|
|
407
432
|
runHome: string;
|
|
408
433
|
sourceHome: string;
|
|
409
|
-
}, optional?: {
|
|
434
|
+
}, optional?: {
|
|
435
|
+
inheritUserConfig?: boolean;
|
|
436
|
+
}) => Promise<void>;
|
|
410
437
|
}
|
|
411
438
|
/** One `.mcp.json` `mcpServers` entry — the shape Claude Code's own config schema expects. */
|
|
412
439
|
export interface McpJsonServerEntry {
|
|
@@ -575,6 +602,10 @@ export interface FailureClassificationContext {
|
|
|
575
602
|
*/
|
|
576
603
|
export type ClassifyFailure = (context: FailureClassificationContext) => boolean | Promise<boolean>;
|
|
577
604
|
export interface CreateAgentExecutorOptions {
|
|
605
|
+
/** Negotiated v1 only; share with bridge/lifecycle. Absent preserves legacy diagnostics/echoes. */
|
|
606
|
+
readonly delegatedResultCorrelation?: DelegatedResultCorrelation;
|
|
607
|
+
/** Required with correlation + byte journal: exact stdout blobs and durable reference records. */
|
|
608
|
+
readonly stdoutJournalBlobs?: StdoutJournalBlobPort;
|
|
578
609
|
/** Host environment snapshot; baseline spawn keys and source config paths are allowlisted. */
|
|
579
610
|
readonly hostEnv?: NodeJS.ProcessEnv;
|
|
580
611
|
readonly runtimeState?: AgentRuntimeState;
|
|
@@ -63,7 +63,12 @@ interface AgentTranslationSideEffectSink {
|
|
|
63
63
|
readonly onSessionId: (args: {
|
|
64
64
|
readonly sessionId: string;
|
|
65
65
|
}) => void;
|
|
66
|
-
|
|
66
|
+
/** Receives the already-narrowed `tool_use` payload, so a caller never re-checks its variant. */
|
|
67
|
+
readonly onToolCall: (args: {
|
|
68
|
+
readonly toolUse: Extract<RunAgentPayload, {
|
|
69
|
+
type: 'tool_use';
|
|
70
|
+
}>;
|
|
71
|
+
}) => void;
|
|
67
72
|
readonly onUserVisibleOutput: () => void;
|
|
68
73
|
}
|
|
69
74
|
/**
|
|
@@ -101,6 +101,7 @@ function translateToolInputDeltaEvent(rawEvent) {
|
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
103
|
export function translateToolResultEvent({ rawEvent }) {
|
|
104
|
+
const delegatedToolUseId = asOptionalString(rawEvent.delegatedToolUseId);
|
|
104
105
|
const isError = typeof rawEvent.isError === 'boolean' ? rawEvent.isError : undefined;
|
|
105
106
|
return {
|
|
106
107
|
kind: 'agent',
|
|
@@ -108,6 +109,7 @@ export function translateToolResultEvent({ rawEvent }) {
|
|
|
108
109
|
type: 'tool_result',
|
|
109
110
|
toolUseId: asString(rawEvent.toolUseId),
|
|
110
111
|
content: asString(rawEvent.content),
|
|
112
|
+
...(delegatedToolUseId !== undefined ? { delegatedToolUseId } : {}),
|
|
111
113
|
...(isError !== undefined ? { isError } : {}),
|
|
112
114
|
},
|
|
113
115
|
};
|
|
@@ -224,7 +226,7 @@ export function applyAgentTranslationSideEffects({ payload, sessionId, sink }) {
|
|
|
224
226
|
if (sessionId !== undefined)
|
|
225
227
|
sink.onSessionId({ sessionId });
|
|
226
228
|
if (payload.type === 'tool_use') {
|
|
227
|
-
sink.onToolCall();
|
|
229
|
+
sink.onToolCall({ toolUse: payload });
|
|
228
230
|
}
|
|
229
231
|
else if ((payload.type === 'text_delta' || payload.type === 'thinking_delta') && payload.delta.length > 0) {
|
|
230
232
|
sink.onUserVisibleOutput();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { DelegatedResultCorrelation } from '../delegated-result-correlation.js';
|
|
2
|
+
import type { StdoutJournalBlobPort } from '../tool-result-diagnostics.js';
|
|
1
3
|
import type { probeMcpBridge } from './mcp-bridge-probe.js';
|
|
2
4
|
import type { ModelCatalogSnapshot } from '@jini-ai/agent-runtime';
|
|
3
5
|
import type { ChildProcess } from 'node:child_process';
|
|
@@ -24,6 +26,8 @@ export declare function defaultCleanupFailureSink(context: AgentCleanupFailureCo
|
|
|
24
26
|
*/
|
|
25
27
|
export declare const DEFAULT_BUFFERED_STDOUT_MAX_BYTES: number;
|
|
26
28
|
interface WireChildLifecycleContext extends TerminateChildTreeDeps {
|
|
29
|
+
readonly delegatedResultCorrelation?: DelegatedResultCorrelation;
|
|
30
|
+
readonly stdoutJournalBlobs?: StdoutJournalBlobPort;
|
|
27
31
|
readonly startingModel?: string;
|
|
28
32
|
readonly modelCatalog?: ModelCatalogSnapshot;
|
|
29
33
|
readonly runId: string;
|
|
@@ -162,6 +166,7 @@ interface RunAcpDispatchInput {
|
|
|
162
166
|
readonly prompt: string;
|
|
163
167
|
readonly cwd: string;
|
|
164
168
|
readonly permissionMode: 'bypass' | 'restricted' | undefined;
|
|
169
|
+
readonly cliParity?: boolean | undefined;
|
|
165
170
|
readonly model: string | undefined;
|
|
166
171
|
readonly modelCatalog?: ModelCatalogSnapshot;
|
|
167
172
|
readonly imagePaths: readonly string[];
|