@addai/node 0.30.13 → 0.30.15
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/auto-update.d.ts +3 -0
- package/dist/auto-update.js +15 -0
- package/dist/capabilities.d.ts +17 -3
- package/dist/capabilities.js +18 -8
- package/dist/claude-models.d.ts +4 -12
- package/dist/claude-models.js +12 -88
- package/dist/claude-print.d.ts +15 -0
- package/dist/claude-print.js +16 -0
- package/dist/codex-models.d.ts +81 -0
- package/dist/codex-models.js +385 -0
- package/dist/codex-spawn.d.ts +19 -8
- package/dist/codex-spawn.js +68 -16
- package/dist/command-runner.js +31 -9
- package/dist/desktop/docker.js +2 -0
- package/dist/desktop/manager.d.ts +2 -1
- package/dist/desktop/manager.js +51 -1
- package/dist/desktop/provider.d.ts +1 -1
- package/dist/desktop/provider.js +2 -0
- package/dist/desktop/relay-client.js +7 -0
- package/dist/desktop/spec.d.ts +2 -0
- package/dist/direct/aios-bridge.d.ts +13 -0
- package/dist/direct/aios-bridge.js +177 -0
- package/dist/direct/aios-mcp.d.ts +2 -0
- package/dist/direct/aios-mcp.js +132 -0
- package/dist/direct/aios-tools.d.ts +351 -0
- package/dist/direct/aios-tools.js +120 -0
- package/dist/direct/board-chat-provider.d.ts +64 -0
- package/dist/direct/board-chat-provider.js +154 -0
- package/dist/direct/board-chat.d.ts +40 -0
- package/dist/direct/board-chat.js +414 -0
- package/dist/direct/config.d.ts +2 -0
- package/dist/direct/config.js +60 -0
- package/dist/direct/launch.d.ts +14 -0
- package/dist/direct/launch.js +121 -0
- package/dist/direct/protocol.d.ts +46 -0
- package/dist/direct/protocol.js +84 -0
- package/dist/direct/relay-main.d.ts +1 -0
- package/dist/direct/relay-main.js +21 -0
- package/dist/direct/relay.d.ts +26 -0
- package/dist/direct/relay.js +334 -0
- package/dist/direct/sessions.d.ts +61 -0
- package/dist/direct/sessions.js +368 -0
- package/dist/direct/supervisor.d.ts +9 -0
- package/dist/direct/supervisor.js +137 -0
- package/dist/direct/terminal.d.ts +1 -0
- package/dist/direct/terminal.js +106 -0
- package/dist/direct/worker.d.ts +1 -0
- package/dist/direct/worker.js +278 -0
- package/dist/entitybox/container-action.cjs +85 -0
- package/dist/entitybox/container-watchdog.cjs +70 -0
- package/dist/entitybox/model-entry.d.ts +3 -0
- package/dist/entitybox/model-entry.js +233 -0
- package/dist/entitybox/model-mcp-proxy.d.ts +3 -0
- package/dist/entitybox/model-mcp-proxy.js +85 -0
- package/dist/entitybox-application-boundary.d.ts +59 -0
- package/dist/entitybox-application-boundary.js +161 -0
- package/dist/entitybox-application-guard-core.d.ts +44 -0
- package/dist/entitybox-application-guard-core.js +164 -0
- package/dist/entitybox-application-guard-process.d.ts +1 -0
- package/dist/entitybox-application-guard-process.js +83 -0
- package/dist/entitybox-application-guard.d.ts +46 -0
- package/dist/entitybox-application-guard.js +239 -0
- package/dist/entitybox-capacity-health-host.d.ts +12 -0
- package/dist/entitybox-capacity-health-host.js +80 -0
- package/dist/entitybox-capacity-health-worker.d.ts +22 -0
- package/dist/entitybox-capacity-health-worker.js +168 -0
- package/dist/entitybox-capacity-host.d.ts +17 -0
- package/dist/entitybox-capacity-host.js +155 -0
- package/dist/entitybox-capacity-owner-process.d.ts +1 -0
- package/dist/entitybox-capacity-owner-process.js +32 -0
- package/dist/entitybox-capacity-owner.d.ts +16 -0
- package/dist/entitybox-capacity-owner.js +90 -0
- package/dist/entitybox-capacity-programs.d.ts +7 -0
- package/dist/entitybox-capacity-programs.js +49 -0
- package/dist/entitybox-capacity-provisioner.d.ts +82 -0
- package/dist/entitybox-capacity-provisioner.js +404 -0
- package/dist/entitybox-capacity-publication.d.ts +29 -0
- package/dist/entitybox-capacity-publication.js +199 -0
- package/dist/entitybox-capacity-registration.d.ts +36 -0
- package/dist/entitybox-capacity-registration.js +75 -0
- package/dist/entitybox-capacity-worker.d.ts +29 -0
- package/dist/entitybox-capacity-worker.js +113 -0
- package/dist/entitybox-computer-task.d.ts +69 -0
- package/dist/entitybox-computer-task.js +176 -0
- package/dist/entitybox-controller-recovery.d.ts +40 -0
- package/dist/entitybox-controller-recovery.js +156 -0
- package/dist/entitybox-desktop-action-server.d.ts +34 -0
- package/dist/entitybox-desktop-action-server.js +176 -0
- package/dist/entitybox-desktop-admission.d.ts +32 -0
- package/dist/entitybox-desktop-admission.js +79 -0
- package/dist/entitybox-display-binding.d.ts +13 -0
- package/dist/entitybox-display-binding.js +31 -0
- package/dist/entitybox-execution-container.d.ts +82 -0
- package/dist/entitybox-execution-container.js +450 -0
- package/dist/entitybox-execution-host.d.ts +40 -0
- package/dist/entitybox-execution-host.js +168 -0
- package/dist/entitybox-execution-lease.d.ts +81 -0
- package/dist/entitybox-execution-lease.js +332 -0
- package/dist/entitybox-file-inputs.d.ts +51 -0
- package/dist/entitybox-file-inputs.js +182 -0
- package/dist/entitybox-file-session.d.ts +38 -0
- package/dist/entitybox-file-session.js +82 -0
- package/dist/entitybox-host-process.d.ts +12 -0
- package/dist/entitybox-host-process.js +120 -0
- package/dist/entitybox-install.d.ts +10 -0
- package/dist/entitybox-install.js +40 -0
- package/dist/entitybox-mcp-broker.d.ts +77 -0
- package/dist/entitybox-mcp-broker.js +420 -0
- package/dist/entitybox-mcp-contract.d.ts +10 -0
- package/dist/entitybox-mcp-contract.js +24 -0
- package/dist/entitybox-mcp-guard.d.ts +3 -0
- package/dist/entitybox-mcp-guard.js +167 -0
- package/dist/entitybox-model-artifact.d.ts +9 -0
- package/dist/entitybox-model-artifact.js +83 -0
- package/dist/entitybox-native-services.d.ts +33 -0
- package/dist/entitybox-native-services.js +172 -0
- package/dist/entitybox-operation.d.ts +4 -0
- package/dist/entitybox-operation.js +34 -0
- package/dist/entitybox-provider-broker.d.ts +41 -0
- package/dist/entitybox-provider-broker.js +149 -0
- package/dist/entitybox-queue-request.d.ts +32 -0
- package/dist/entitybox-queue-request.js +141 -0
- package/dist/entitybox-recovery-host.d.ts +12 -0
- package/dist/entitybox-recovery-host.js +80 -0
- package/dist/entitybox-recovery-store.d.ts +33 -0
- package/dist/entitybox-recovery-store.js +150 -0
- package/dist/entitybox-recovery-worker.d.ts +30 -0
- package/dist/entitybox-recovery-worker.js +134 -0
- package/dist/entitybox-vault-provider.d.ts +27 -0
- package/dist/entitybox-vault-provider.js +127 -0
- package/dist/harness-registry.js +3 -1
- package/dist/index.js +72 -38
- package/dist/install.d.ts +14 -2
- package/dist/install.js +115 -10
- package/dist/model-cache.d.ts +38 -0
- package/dist/model-cache.js +137 -0
- package/dist/request-pump.d.ts +3 -0
- package/dist/request-pump.js +21 -7
- package/dist/session-runner.d.ts +8 -1
- package/dist/session-runner.js +56 -3
- package/dist/supabase-client.js +4 -1
- package/package.json +5 -1
- package/scripts/copy-assets.js +4 -2
package/dist/auto-update.d.ts
CHANGED
|
@@ -103,6 +103,9 @@ type ProbeShape = Partial<Record<HarnessId, {
|
|
|
103
103
|
available?: boolean;
|
|
104
104
|
}>>;
|
|
105
105
|
export interface AutoUpdateDeps {
|
|
106
|
+
/** Optional admission gate for direct sessions. Legacy callers keep the existing update path. */
|
|
107
|
+
quiesceDirect?: () => Promise<boolean>;
|
|
108
|
+
releaseDirect?: () => void;
|
|
106
109
|
/** The daemon token — only used to derive this node's slot. */
|
|
107
110
|
token: () => string | null;
|
|
108
111
|
/** True while this node holds a child process for a live run. */
|
package/dist/auto-update.js
CHANGED
|
@@ -143,6 +143,21 @@ function installedHarnesses(probe) {
|
|
|
143
143
|
/** One pass. Exported so `ainode` can be made to do it on demand later, and
|
|
144
144
|
* so a test can drive it without waiting an hour. */
|
|
145
145
|
async function runOnce(d) {
|
|
146
|
+
if (!d.quiesceDirect || shouldRun({ enabled: d.enabled(), busy: d.isBusy(), breakerOpen: d.breakerOpen() })) {
|
|
147
|
+
return runUpdate(d);
|
|
148
|
+
}
|
|
149
|
+
if (!await d.quiesceDirect()) {
|
|
150
|
+
state = { ...state, last_result: 'skipped', skipped_reason: 'busy' };
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
await runUpdate(d);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
d.releaseDirect?.();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function runUpdate(d) {
|
|
146
161
|
const skip = shouldRun({ enabled: d.enabled(), busy: d.isBusy(), breakerOpen: d.breakerOpen() });
|
|
147
162
|
if (skip) {
|
|
148
163
|
state = { ...state, last_checked_at: new Date().toISOString(), last_result: 'skipped', skipped_reason: skip };
|
package/dist/capabilities.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { entityboxFileCapabilities } from './entitybox-file-session';
|
|
1
2
|
import type { EngineInfo } from './desktop/provider';
|
|
2
3
|
import { type ClaudeModelEntry } from './claude-models';
|
|
4
|
+
import { type CodexModelEntry } from './codex-models';
|
|
3
5
|
import { type AutostartState } from './autostart';
|
|
4
6
|
import { type AutoUpdateState } from './auto-update';
|
|
5
7
|
import { type MachineSample } from './machine-metrics';
|
|
@@ -39,14 +41,15 @@ interface FlowsCapability {
|
|
|
39
41
|
max_concurrent: number;
|
|
40
42
|
}
|
|
41
43
|
interface CapabilitiesShape {
|
|
44
|
+
entitybox?: {
|
|
45
|
+
files: NonNullable<ReturnType<typeof entityboxFileCapabilities>>;
|
|
46
|
+
};
|
|
42
47
|
/** Version of @addai/node running. Lets the studio / CodeFlows
|
|
43
48
|
* UIs show "outdated daemon" hints and helps us debug field issues
|
|
44
49
|
* ("which version was this row produced by?"). */
|
|
45
50
|
daemon_version?: string;
|
|
46
51
|
claude: BinaryProbe & ClaudeModelFields;
|
|
47
|
-
codex: BinaryProbe &
|
|
48
|
-
models?: string[];
|
|
49
|
-
};
|
|
52
|
+
codex: BinaryProbe & CodexModelFields;
|
|
50
53
|
kimi: BinaryProbe & {
|
|
51
54
|
models?: string[];
|
|
52
55
|
};
|
|
@@ -91,6 +94,17 @@ interface ClaudeModelFields {
|
|
|
91
94
|
* fallback above — so a stale picker can be told apart from a live one. */
|
|
92
95
|
models_source?: 'cli' | 'builtin';
|
|
93
96
|
}
|
|
97
|
+
interface CodexModelFields {
|
|
98
|
+
/** Asked of codex's app-server (codex-models.ts); empty until it answers.
|
|
99
|
+
* There is no built-in list: a blank model — codex's own default — is the
|
|
100
|
+
* one choice that always runs. */
|
|
101
|
+
models?: string[];
|
|
102
|
+
model_catalog?: CodexModelEntry[];
|
|
103
|
+
models_source?: 'cli' | 'builtin';
|
|
104
|
+
/** 'account' when the list is what this node's login can run, 'bundled'
|
|
105
|
+
* when the login was left alone and it is what the CLI ships with. */
|
|
106
|
+
models_scope?: 'account' | 'bundled';
|
|
107
|
+
}
|
|
94
108
|
/** Codex's credential store: $CODEX_HOME (or ~/.codex) + /auth.json. */
|
|
95
109
|
export declare function codexHome(): string;
|
|
96
110
|
/**
|
package/dist/capabilities.js
CHANGED
|
@@ -42,12 +42,14 @@ exports.codexHome = codexHome;
|
|
|
42
42
|
exports.codexAuthFromStore = codexAuthFromStore;
|
|
43
43
|
exports.probeCapabilities = probeCapabilities;
|
|
44
44
|
const engine_1 = require("./desktop/engine");
|
|
45
|
+
const entitybox_file_session_1 = require("./entitybox-file-session");
|
|
45
46
|
const child_process_1 = require("child_process");
|
|
46
47
|
const fs = __importStar(require("fs"));
|
|
47
48
|
const path = __importStar(require("path"));
|
|
48
49
|
const os = __importStar(require("os"));
|
|
49
50
|
const claude_binary_1 = require("./claude-binary");
|
|
50
51
|
const claude_models_1 = require("./claude-models");
|
|
52
|
+
const codex_models_1 = require("./codex-models");
|
|
51
53
|
const kimi_binary_1 = require("./kimi-binary");
|
|
52
54
|
const gemini_binary_1 = require("./gemini-binary");
|
|
53
55
|
const grok_binary_1 = require("./grok-binary");
|
|
@@ -132,12 +134,6 @@ const CLAUDE_MODELS = [
|
|
|
132
134
|
'claude-sonnet-4-6',
|
|
133
135
|
'claude-haiku-4-5',
|
|
134
136
|
];
|
|
135
|
-
const CODEX_MODELS = [
|
|
136
|
-
'gpt-5',
|
|
137
|
-
'gpt-5-mini',
|
|
138
|
-
'o4',
|
|
139
|
-
'o4-mini',
|
|
140
|
-
];
|
|
141
137
|
const KIMI_MODELS = [
|
|
142
138
|
'kimi-k2-instruct',
|
|
143
139
|
'kimi-k2-base',
|
|
@@ -257,7 +253,18 @@ async function probeCodex() {
|
|
|
257
253
|
else {
|
|
258
254
|
authShape = codexAuthFromStore(codexHome());
|
|
259
255
|
}
|
|
260
|
-
|
|
256
|
+
// Asked once per binary and version, in the background; see codex-models.ts.
|
|
257
|
+
// Its efforts replace the registry's when it answers — they are per model,
|
|
258
|
+
// and newer codex takes xhigh and max.
|
|
259
|
+
const live = (0, codex_models_1.codexModelsFor)(bin, `${bin}|${ver.stdout}`);
|
|
260
|
+
return {
|
|
261
|
+
available: true,
|
|
262
|
+
version: ver.stdout,
|
|
263
|
+
models: live?.models ?? [],
|
|
264
|
+
...(live ? { model_catalog: live.catalog, models_scope: live.scope, efforts: (0, codex_models_1.offeredEfforts)(live) } : {}),
|
|
265
|
+
models_source: live ? 'cli' : 'builtin',
|
|
266
|
+
...authShape,
|
|
267
|
+
};
|
|
261
268
|
}
|
|
262
269
|
async function probeKimi() {
|
|
263
270
|
const bin = (0, kimi_binary_1.findKimiBinary)();
|
|
@@ -487,7 +494,8 @@ async function probeCapabilities() {
|
|
|
487
494
|
// login strategy) so Studio and the TUI render from one source of truth.
|
|
488
495
|
const deco = (id, probe) => ({
|
|
489
496
|
...probe,
|
|
490
|
-
|
|
497
|
+
// A list the CLI gave itself (codex) beats the registry's.
|
|
498
|
+
efforts: probe.efforts?.length ? probe.efforts : harness_registry_1.HARNESSES[id].efforts,
|
|
491
499
|
installable: (0, harness_registry_1.isInstallable)(id),
|
|
492
500
|
login_strategy: harness_registry_1.HARNESSES[id].login.strategy,
|
|
493
501
|
login_methods: [
|
|
@@ -495,7 +503,9 @@ async function probeCapabilities() {
|
|
|
495
503
|
...(harness_registry_1.HARNESSES[id].extraLogins ?? []).map(m => m.method),
|
|
496
504
|
],
|
|
497
505
|
});
|
|
506
|
+
const fileCapability = (0, entitybox_file_session_1.entityboxFileCapabilities)(claude);
|
|
498
507
|
return {
|
|
508
|
+
...(fileCapability ? { entitybox: { files: fileCapability } } : {}),
|
|
499
509
|
daemon_version: readDaemonVersion(),
|
|
500
510
|
autostart: (0, autostart_1.status)(),
|
|
501
511
|
container_engine: containerEngine,
|
package/dist/claude-models.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ModelProbeResult } from './model-cache';
|
|
1
2
|
import { type CliInvocation } from './win';
|
|
2
3
|
export interface ClaudeModelEntry {
|
|
3
4
|
/** What goes to `--model`: an alias ('opus') or a full id. */
|
|
@@ -21,13 +22,7 @@ export interface ClaudeModelReport {
|
|
|
21
22
|
* the probe ever sees, so it is not reported as this node's default. */
|
|
22
23
|
defaultModel?: string;
|
|
23
24
|
}
|
|
24
|
-
export type ProbeResult =
|
|
25
|
-
ok: true;
|
|
26
|
-
report: ClaudeModelReport;
|
|
27
|
-
} | {
|
|
28
|
-
ok: false;
|
|
29
|
-
reason: string;
|
|
30
|
-
};
|
|
25
|
+
export type ProbeResult = ModelProbeResult<ClaudeModelReport>;
|
|
31
26
|
/**
|
|
32
27
|
* Turn the `models` array of an initialize response into a report.
|
|
33
28
|
*
|
|
@@ -67,13 +62,10 @@ export interface ModelCacheDeps {
|
|
|
67
62
|
now: () => number;
|
|
68
63
|
log: (line: string) => void;
|
|
69
64
|
}
|
|
65
|
+
/** Refreshed every 6h, retried 30 min after a failure — see model-cache.ts. */
|
|
70
66
|
export declare function createClaudeModelCache(deps: ModelCacheDeps): {
|
|
71
|
-
/**
|
|
72
|
-
* The models for this binary state, or null to mean "use the built-in
|
|
73
|
-
* list". Never waits: a missing or stale answer is fetched in the
|
|
74
|
-
* background and arrives on a later call.
|
|
75
|
-
*/
|
|
76
67
|
get(bin: string, key: string): ClaudeModelReport | null;
|
|
68
|
+
last(): ClaudeModelReport | null;
|
|
77
69
|
};
|
|
78
70
|
/** What capabilities.ts reports for claude's models. */
|
|
79
71
|
export declare function claudeModelsFor(bin: string, key: string): ClaudeModelReport | null;
|
package/dist/claude-models.js
CHANGED
|
@@ -77,9 +77,7 @@ exports.createClaudeModelCache = createClaudeModelCache;
|
|
|
77
77
|
exports.claudeModelsFor = claudeModelsFor;
|
|
78
78
|
const child_process_1 = require("child_process");
|
|
79
79
|
const fs = __importStar(require("fs"));
|
|
80
|
-
const
|
|
81
|
-
const path = __importStar(require("path"));
|
|
82
|
-
const paths_1 = require("./paths");
|
|
80
|
+
const model_cache_1 = require("./model-cache");
|
|
83
81
|
const win_1 = require("./win");
|
|
84
82
|
// What a model id may look like before it is passed on: `claude-opus-5-5`,
|
|
85
83
|
// `opus[1m]`, `claude-haiku-4-5-20251001`. Anything else is dropped rather
|
|
@@ -164,34 +162,6 @@ const CREDENTIAL_ENV = [
|
|
|
164
162
|
'ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'CLAUDE_CODE_OAUTH_TOKEN',
|
|
165
163
|
'CLAUDE_CODE_OAUTH_REFRESH_TOKEN', 'CLAUDE_CONFIG_DIR',
|
|
166
164
|
];
|
|
167
|
-
/** A throwaway folder that is both the probe's cwd and its CLAUDE_CONFIG_DIR,
|
|
168
|
-
* so no project's settings or CLAUDE.md are read and nothing the CLI writes
|
|
169
|
-
* lands in the real ~/.claude. Folders older than a day are swept — a
|
|
170
|
-
* probe's own cleanup can lose a race with Windows releasing the cwd. */
|
|
171
|
-
function makeProbeDir() {
|
|
172
|
-
const root = path.join(paths_1.RUNTIME_HOME, 'model-probe');
|
|
173
|
-
try {
|
|
174
|
-
fs.mkdirSync(root, { recursive: true });
|
|
175
|
-
const cutoff = Date.now() - 24 * 60 * 60 * 1000;
|
|
176
|
-
for (const name of fs.readdirSync(root)) {
|
|
177
|
-
const p = path.join(root, name);
|
|
178
|
-
try {
|
|
179
|
-
if (fs.statSync(p).mtimeMs < cutoff)
|
|
180
|
-
fs.rmSync(p, { recursive: true, force: true });
|
|
181
|
-
}
|
|
182
|
-
catch { /* next time */ }
|
|
183
|
-
}
|
|
184
|
-
return fs.mkdtempSync(path.join(root, 'p-'));
|
|
185
|
-
}
|
|
186
|
-
catch {
|
|
187
|
-
try {
|
|
188
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), 'ainode-model-probe-'));
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
return null;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
165
|
const PROBE_ARGS = [
|
|
196
166
|
'--print', '--input-format', 'stream-json', '--output-format', 'stream-json', '--verbose',
|
|
197
167
|
// No keychain reads (the macOS login), no hooks, no plugin sync, no
|
|
@@ -223,7 +193,10 @@ function probeClaudeModels(bin, opts = {}) {
|
|
|
223
193
|
done({ ok: false, reason: err.message || String(err) });
|
|
224
194
|
return;
|
|
225
195
|
}
|
|
226
|
-
|
|
196
|
+
// Both the probe's cwd and its CLAUDE_CONFIG_DIR, so no project's
|
|
197
|
+
// settings or CLAUDE.md are read and nothing the CLI writes lands in the
|
|
198
|
+
// real ~/.claude.
|
|
199
|
+
const dir = opts.dir ?? (0, model_cache_1.makeProbeDir)();
|
|
227
200
|
if (!dir) {
|
|
228
201
|
done({ ok: false, reason: 'no folder to probe from' });
|
|
229
202
|
return;
|
|
@@ -337,63 +310,14 @@ function probeClaudeModels(bin, opts = {}) {
|
|
|
337
310
|
}
|
|
338
311
|
/** Tests only. */
|
|
339
312
|
function __resetIsolationForTests() { isolationBroken = false; }
|
|
340
|
-
|
|
341
|
-
/** Re-ask now and then even when nothing changed: the CLI's list can move
|
|
342
|
-
* without a CLI update. */
|
|
343
|
-
const REFRESH_MS = 6 * 60 * 60 * 1000;
|
|
344
|
-
const RETRY_AFTER_FAIL_MS = 30 * 60 * 1000;
|
|
313
|
+
/** Refreshed every 6h, retried 30 min after a failure — see model-cache.ts. */
|
|
345
314
|
function createClaudeModelCache(deps) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
inflight = deps.probe(bin).then(result => {
|
|
353
|
-
if (result.ok) {
|
|
354
|
-
const changed = !good || good.report.models.join() !== result.report.models.join();
|
|
355
|
-
good = { key, report: result.report, at: deps.now() };
|
|
356
|
-
if (failed?.key === key)
|
|
357
|
-
failed = null;
|
|
358
|
-
if (changed) {
|
|
359
|
-
const head = result.report.catalog.filter(e => e.alias && e.resolved !== e.id)
|
|
360
|
-
.map(e => `${e.id} → ${e.resolved}`).join(', ');
|
|
361
|
-
deps.log(`[models] claude: ${result.report.models.length} models from the CLI${head ? ` (${head})` : ''}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
// An answer this exact binary already gave stays good: a refresh
|
|
366
|
-
// that fails is a reason to retry, not to forget it.
|
|
367
|
-
failed = { key, at: deps.now() };
|
|
368
|
-
const kept = good?.key === key;
|
|
369
|
-
deps.log(`[models] could not read claude's model list (${result.reason}) — ${kept ? 'keeping the last answer' : 'offering the built-in list'}; next try in ${RETRY_AFTER_FAIL_MS / 60000} min`);
|
|
370
|
-
}
|
|
371
|
-
}).catch(() => { failed = { key, at: deps.now() }; })
|
|
372
|
-
.finally(() => { inflight = null; });
|
|
373
|
-
};
|
|
374
|
-
return {
|
|
375
|
-
/**
|
|
376
|
-
* The models for this binary state, or null to mean "use the built-in
|
|
377
|
-
* list". Never waits: a missing or stale answer is fetched in the
|
|
378
|
-
* background and arrives on a later call.
|
|
379
|
-
*/
|
|
380
|
-
get(bin, key) {
|
|
381
|
-
const now = deps.now();
|
|
382
|
-
const recentlyFailed = failed?.key === key && now - failed.at < RETRY_AFTER_FAIL_MS;
|
|
383
|
-
if (good?.key === key) {
|
|
384
|
-
if (now - good.at > REFRESH_MS && !recentlyFailed)
|
|
385
|
-
start(bin, key);
|
|
386
|
-
return good.report;
|
|
387
|
-
}
|
|
388
|
-
if (!recentlyFailed)
|
|
389
|
-
start(bin, key);
|
|
390
|
-
// A new CLI version that has not answered yet: keep showing the last
|
|
391
|
-
// real list — closer to the truth than the constant, and it stops the
|
|
392
|
-
// pickers flickering to the built-in list across an upgrade. Once the
|
|
393
|
-
// new version has actually failed, the built-in list it is.
|
|
394
|
-
return failed?.key === key ? null : (good?.report ?? null);
|
|
395
|
-
},
|
|
396
|
-
};
|
|
315
|
+
return (0, model_cache_1.createModelCache)({
|
|
316
|
+
...deps,
|
|
317
|
+
agent: 'claude',
|
|
318
|
+
describe: report => report.catalog.filter(e => e.alias && e.resolved !== e.id)
|
|
319
|
+
.map(e => `${e.id} → ${e.resolved}`).join(', '),
|
|
320
|
+
});
|
|
397
321
|
}
|
|
398
322
|
const sharedCache = createClaudeModelCache({
|
|
399
323
|
probe: bin => probeClaudeModels(bin),
|
package/dist/claude-print.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { RuntimeEvent, RuntimePermissionMode, RuntimeEffortLevel } from './
|
|
|
2
2
|
export interface ClaudePrintInput {
|
|
3
3
|
workingDirectory: string;
|
|
4
4
|
prompt: string;
|
|
5
|
+
/** Verified original file blocks for explicitly marked EntityBox chat. */
|
|
6
|
+
inputBlocks?: readonly ClaudePrintInputBlock[];
|
|
5
7
|
permissionMode?: RuntimePermissionMode;
|
|
6
8
|
effortLevel?: RuntimeEffortLevel;
|
|
7
9
|
model?: string;
|
|
@@ -13,6 +15,19 @@ export interface ClaudePrintInput {
|
|
|
13
15
|
/** Restrict to a specific set of tools (claude only). null/undefined = inherit. */
|
|
14
16
|
allowedTools?: string[];
|
|
15
17
|
}
|
|
18
|
+
export type ClaudePrintInputBlock = {
|
|
19
|
+
type: 'text';
|
|
20
|
+
text: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'image' | 'document';
|
|
23
|
+
source: {
|
|
24
|
+
type: 'base64';
|
|
25
|
+
media_type: string;
|
|
26
|
+
data: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** Stream JSON reaches stdin only; files never become command-line arguments. */
|
|
30
|
+
export declare function claudePrintInputMessage(prompt: string, blocks: readonly ClaudePrintInputBlock[]): string;
|
|
16
31
|
/**
|
|
17
32
|
* The text to emit for one flushed block, given what came before.
|
|
18
33
|
*
|
package/dist/claude-print.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
// our normalised RuntimeEvent shape, and resolves when the process exits.
|
|
6
6
|
// No PTY needed — Claude detects non-TTY and runs headless.
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.claudePrintInputMessage = claudePrintInputMessage;
|
|
8
9
|
exports.blockDelta = blockDelta;
|
|
9
10
|
exports.lineToEvents = lineToEvents;
|
|
10
11
|
exports.spawnClaudePrint = spawnClaudePrint;
|
|
@@ -13,6 +14,16 @@ const claude_binary_1 = require("./claude-binary");
|
|
|
13
14
|
const win_1 = require("./win");
|
|
14
15
|
const claude_system_prompt_1 = require("./claude-system-prompt");
|
|
15
16
|
const prompt_transport_1 = require("./prompt-transport");
|
|
17
|
+
/** Stream JSON reaches stdin only; files never become command-line arguments. */
|
|
18
|
+
function claudePrintInputMessage(prompt, blocks) {
|
|
19
|
+
if (!Array.isArray(blocks) || blocks.length < 1 || blocks.length > 12 || !blocks.every(b => b && (b.type === 'text' && typeof b.text === 'string' || ['image', 'document'].includes(b.type) && 'source' in b && b.source?.type === 'base64' && typeof b.source.data === 'string' && /^[A-Za-z0-9+/]*={0,2}$/.test(b.source.data)
|
|
20
|
+
&& (b.type === 'document' ? b.source.media_type === 'application/pdf' : ['image/png', 'image/jpeg', 'image/webp', 'image/gif'].includes(b.source.media_type)))))
|
|
21
|
+
throw new Error('Invalid file input');
|
|
22
|
+
const message = JSON.stringify({ type: 'user', session_id: '', parent_tool_use_id: null, message: { role: 'user', content: [...blocks, { type: 'text', text: prompt }] } }) + '\n';
|
|
23
|
+
if (Buffer.byteLength(message) > 30 * 1024 * 1024)
|
|
24
|
+
throw new Error('File input is too large');
|
|
25
|
+
return message;
|
|
26
|
+
}
|
|
16
27
|
/**
|
|
17
28
|
* The text to emit for one flushed block, given what came before.
|
|
18
29
|
*
|
|
@@ -113,6 +124,7 @@ function lineToEvents(line, suppressText = false) {
|
|
|
113
124
|
return [{ type: `claude:${type || 'unknown'}`, raw: line }];
|
|
114
125
|
}
|
|
115
126
|
function spawnClaudePrint(input) {
|
|
127
|
+
const inputMessage = input.inputBlocks ? claudePrintInputMessage(input.prompt, input.inputBlocks) : undefined;
|
|
116
128
|
const bin = (0, claude_binary_1.findClaudeBinary)();
|
|
117
129
|
// No claude on this runtime — fail THIS request cleanly rather than
|
|
118
130
|
// spawning a bare 'claude' that ENOENTs and crashes the daemon. Both
|
|
@@ -138,6 +150,8 @@ function spawnClaudePrint(input) {
|
|
|
138
150
|
];
|
|
139
151
|
if (partialStream)
|
|
140
152
|
args.push('--include-partial-messages');
|
|
153
|
+
if (input.inputBlocks)
|
|
154
|
+
args.push('--input-format', 'stream-json');
|
|
141
155
|
if (input.permissionMode === 'bypassPermissions') {
|
|
142
156
|
args.push('--dangerously-skip-permissions');
|
|
143
157
|
}
|
|
@@ -183,6 +197,8 @@ function spawnClaudePrint(input) {
|
|
|
183
197
|
const isWindows = process.platform === 'win32';
|
|
184
198
|
const sysPrompt = (0, claude_system_prompt_1.offloadLongSystemPrompt)(bin, args, isWindows, (0, claude_system_prompt_1.claudeSupportsPromptFile)(bin));
|
|
185
199
|
const transport = (0, prompt_transport_1.offloadLongPrompt)(bin, sysPrompt.args, sysPrompt.args.length - 1, null, isWindows, true);
|
|
200
|
+
if (inputMessage !== undefined)
|
|
201
|
+
transport.stdin = inputMessage;
|
|
186
202
|
let proc;
|
|
187
203
|
try {
|
|
188
204
|
const inv = (0, win_1.resolveCliInvocation)(bin, transport.args);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type ModelProbeResult } from './model-cache';
|
|
2
|
+
import type { RuntimeEffortLevel } from './types';
|
|
3
|
+
import { type CliInvocation } from './win';
|
|
4
|
+
export interface CodexModelEntry {
|
|
5
|
+
/** What goes to `--model`. */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Always `id` — codex has no aliases. Here so Studio reads both CLIs alike. */
|
|
8
|
+
resolved: string;
|
|
9
|
+
/** Codex's own label, e.g. 'GPT-6-Astra'. */
|
|
10
|
+
name: string;
|
|
11
|
+
alias: false;
|
|
12
|
+
/** Effort levels this model takes, in codex's spelling. */
|
|
13
|
+
efforts?: string[];
|
|
14
|
+
/** What a run with no model set gets. */
|
|
15
|
+
default?: true;
|
|
16
|
+
}
|
|
17
|
+
export interface CodexModelReport {
|
|
18
|
+
/** Plain ids, the default first — the shape `capabilities.codex.models`
|
|
19
|
+
* has always had. */
|
|
20
|
+
models: string[];
|
|
21
|
+
catalog: CodexModelEntry[];
|
|
22
|
+
defaultModel?: string;
|
|
23
|
+
/** 'account': what this node's login can run. 'bundled': what the CLI
|
|
24
|
+
* ships with, read without the login. */
|
|
25
|
+
scope: 'account' | 'bundled';
|
|
26
|
+
}
|
|
27
|
+
export type ProbeResult = ModelProbeResult<CodexModelReport>;
|
|
28
|
+
/**
|
|
29
|
+
* Turn the `data` of a `model/list` answer into a report. Hidden models
|
|
30
|
+
* (codex's internal reviewers and the like) are left out. Returns null when
|
|
31
|
+
* nothing usable is in there.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseModelList(raw: unknown, scope: CodexModelReport['scope']): CodexModelReport | null;
|
|
34
|
+
/** What a picker can offer: every level some listed model takes, in order. */
|
|
35
|
+
export declare function offeredEfforts(report: CodexModelReport): RuntimeEffortLevel[];
|
|
36
|
+
export type ProbeLogin = {
|
|
37
|
+
use: true;
|
|
38
|
+
file: string;
|
|
39
|
+
} | {
|
|
40
|
+
use: false;
|
|
41
|
+
why: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* May the probe use this login? Only if nothing about it can change while the
|
|
45
|
+
* probe runs: an API key never does, and a ChatGPT login only while its token
|
|
46
|
+
* is fresh. Never throws.
|
|
47
|
+
*/
|
|
48
|
+
export declare function loginForProbe(codexHome: string, now?: number): ProbeLogin;
|
|
49
|
+
/**
|
|
50
|
+
* Ask one codex binary for its models. Never throws; resolves within
|
|
51
|
+
* `timeoutMs` however the CLI behaves, and leaves no process behind.
|
|
52
|
+
*/
|
|
53
|
+
export declare function probeCodexModels(bin: string, opts?: {
|
|
54
|
+
timeoutMs?: number;
|
|
55
|
+
/** Where the login lives. Runs link it from ~/.codex (writeCodexHome), so
|
|
56
|
+
* the probe does too. */
|
|
57
|
+
codexHome?: string;
|
|
58
|
+
now?: number;
|
|
59
|
+
/** Tests only: run something else in place of the CLI. */
|
|
60
|
+
resolve?: (bin: string, args: string[]) => CliInvocation;
|
|
61
|
+
/** Tests only: where the throwaway CODEX_HOME goes. */
|
|
62
|
+
dir?: string;
|
|
63
|
+
}): Promise<ProbeResult>;
|
|
64
|
+
export interface CodexModelCacheDeps {
|
|
65
|
+
probe: (bin: string) => Promise<ProbeResult>;
|
|
66
|
+
now: () => number;
|
|
67
|
+
log: (line: string) => void;
|
|
68
|
+
}
|
|
69
|
+
/** Refreshed every 6h, retried 30 min after a failure — see model-cache.ts. */
|
|
70
|
+
export declare function createCodexModelCache(deps: CodexModelCacheDeps): {
|
|
71
|
+
get(bin: string, key: string): CodexModelReport | null;
|
|
72
|
+
last(): CodexModelReport | null;
|
|
73
|
+
};
|
|
74
|
+
/** What capabilities.ts reports for codex's models. */
|
|
75
|
+
export declare function codexModelsFor(bin: string, key: string): CodexModelReport | null;
|
|
76
|
+
/**
|
|
77
|
+
* The effort levels a model takes, from the last list codex gave: the
|
|
78
|
+
* default model's when none is named. Null when codex never said, or the
|
|
79
|
+
* model is not in its list.
|
|
80
|
+
*/
|
|
81
|
+
export declare function codexModelEfforts(model?: string | null, report?: CodexModelReport | null): string[] | null;
|