@odla-ai/cli 0.37.1 → 0.38.1
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/bin.cjs +199 -62
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-XFIFFYNH.js → chunk-HETCZVFB.js} +183 -56
- package/dist/chunk-HETCZVFB.js.map +1 -0
- package/dist/{cli-OH6PCYZ3.js → cli-LGYDXY5R.js} +2 -2
- package/dist/index.cjs +182 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-XFIFFYNH.js.map +0 -1
- /package/dist/{cli-OH6PCYZ3.js.map → cli-LGYDXY5R.js.map} +0 -0
package/dist/bin.cjs
CHANGED
|
@@ -1322,6 +1322,74 @@ var init_argv = __esm({
|
|
|
1322
1322
|
}
|
|
1323
1323
|
});
|
|
1324
1324
|
|
|
1325
|
+
// src/admin-spend.ts
|
|
1326
|
+
async function call(ctx, method, scope) {
|
|
1327
|
+
const url = `${ctx.platformUrl.replace(/\/$/, "")}/registry/platform/spend?scope=${encodeURIComponent(scope)}`;
|
|
1328
|
+
const response2 = await ctx.doFetch(url, {
|
|
1329
|
+
method,
|
|
1330
|
+
headers: { authorization: `Bearer ${ctx.token}` }
|
|
1331
|
+
});
|
|
1332
|
+
const body = await response2.json().catch(() => ({}));
|
|
1333
|
+
if (!response2.ok) {
|
|
1334
|
+
const detail = body.error?.message ?? body.error?.code ?? `registry returned ${response2.status}`;
|
|
1335
|
+
throw new Error(`spend ${method} failed: ${detail} (${response2.status})`);
|
|
1336
|
+
}
|
|
1337
|
+
return body;
|
|
1338
|
+
}
|
|
1339
|
+
async function spendShow(ctx, scope) {
|
|
1340
|
+
const view = await call(ctx, "GET", scope);
|
|
1341
|
+
if (ctx.json) return ctx.out.log(JSON.stringify(view, null, 2));
|
|
1342
|
+
ctx.out.log(`scope: ${view.scope}`);
|
|
1343
|
+
ctx.out.log(`day: ${view.day} (UTC)`);
|
|
1344
|
+
ctx.out.log(
|
|
1345
|
+
`spent: ${money(view.spentUsd)} of ${view.capUsd > 0 ? money(view.capUsd) : "(no cap set)"}`
|
|
1346
|
+
);
|
|
1347
|
+
ctx.out.log(`calls: ${view.calls}`);
|
|
1348
|
+
if (view.unpricedCalls > 0) {
|
|
1349
|
+
ctx.out.log(
|
|
1350
|
+
`unpriced: ${view.unpricedCalls} call(s) had no price, so "spent" is a floor, not the total.`
|
|
1351
|
+
);
|
|
1352
|
+
}
|
|
1353
|
+
if (!view.latched) return ctx.out.log("status: running");
|
|
1354
|
+
ctx.out.log(
|
|
1355
|
+
`status: HALTED \u2014 reached ${money(view.latched.capUsd)} on ${view.latched.day} (${view.latched.reason}), at ${money(view.latched.costUsd)}.`
|
|
1356
|
+
);
|
|
1357
|
+
ctx.out.log("A new day does not clear this. Resume with:");
|
|
1358
|
+
ctx.out.log(` odla-ai admin spend reset ${view.scope}`);
|
|
1359
|
+
}
|
|
1360
|
+
async function spendReset(ctx, scope) {
|
|
1361
|
+
const result = await call(ctx, "DELETE", scope);
|
|
1362
|
+
if (ctx.json) return ctx.out.log(JSON.stringify(result, null, 2));
|
|
1363
|
+
ctx.out.log(result.message);
|
|
1364
|
+
if (result.stillOverCap) {
|
|
1365
|
+
ctx.out.log(
|
|
1366
|
+
` today: ${money(result.spentUsd)} against a ${money(result.capUsd)} cap.`
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
async function adminSpend(parsed, ctx) {
|
|
1371
|
+
const action2 = parsed.positionals[2];
|
|
1372
|
+
const scope = parsed.positionals[3] ?? stringOpt(parsed.options.scope);
|
|
1373
|
+
if (action2 !== "show" && action2 !== "reset") {
|
|
1374
|
+
throw new Error('unknown spend command. Try "odla-ai admin spend show <scope>".');
|
|
1375
|
+
}
|
|
1376
|
+
if (!scope) {
|
|
1377
|
+
throw new Error(
|
|
1378
|
+
`"admin spend ${action2}" needs a scope, e.g. odla-ai admin spend ${action2} app:my-app:<incarnation>`
|
|
1379
|
+
);
|
|
1380
|
+
}
|
|
1381
|
+
return action2 === "show" ? spendShow(ctx, scope) : spendReset(ctx, scope);
|
|
1382
|
+
}
|
|
1383
|
+
var money;
|
|
1384
|
+
var init_admin_spend = __esm({
|
|
1385
|
+
"src/admin-spend.ts"() {
|
|
1386
|
+
"use strict";
|
|
1387
|
+
init_cjs_shims();
|
|
1388
|
+
init_argv();
|
|
1389
|
+
money = (value2) => `$${value2.toFixed(2)}`;
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
|
|
1325
1393
|
// src/ai-config-validation.ts
|
|
1326
1394
|
function validateAiConfig(cfg, path) {
|
|
1327
1395
|
if (cfg.ai === void 0) return;
|
|
@@ -2050,7 +2118,11 @@ async function resolveOperatorContext(parsed, options = {}) {
|
|
|
2050
2118
|
const appEnvironment = clean2(import_node_process10.default.env.ODLA_APP_ID);
|
|
2051
2119
|
const appValue = appFlag ?? appEnvironment ?? profile.value?.app ?? loaded?.app.id ?? null;
|
|
2052
2120
|
const appSource = appFlag ? "flag" : appEnvironment ? "environment" : profile.value?.app ? "profile" : loaded ? "config" : "unresolved";
|
|
2053
|
-
if (appValue)
|
|
2121
|
+
if (appValue) {
|
|
2122
|
+
for (const id2 of options.allowAppList ? appValue.split(",") : [appValue]) {
|
|
2123
|
+
assertOperatorName(id2.trim(), "app");
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2054
2126
|
if (options.requireApp && !appValue) {
|
|
2055
2127
|
throw new Error(
|
|
2056
2128
|
"app context is unresolved; pass --app <id>, set ODLA_APP_ID, select --context <name>, or run inside a project with odla.config.mjs"
|
|
@@ -2141,6 +2213,31 @@ var init_operator_context = __esm({
|
|
|
2141
2213
|
async function adminCommand(parsed, deps = {}) {
|
|
2142
2214
|
const area = parsed.positionals[1];
|
|
2143
2215
|
const action2 = parsed.positionals[2];
|
|
2216
|
+
if (area === "spend") {
|
|
2217
|
+
assertArgs(parsed, JSON_OPTIONS, 4);
|
|
2218
|
+
const context2 = await resolveOperatorContext(parsed, { allowMissingConfig: true });
|
|
2219
|
+
const out = deps.stdout ?? console;
|
|
2220
|
+
const doFetch = deps.fetch ?? fetch;
|
|
2221
|
+
const token = await getDeveloperToken(
|
|
2222
|
+
context2.cfg,
|
|
2223
|
+
{
|
|
2224
|
+
configPath: context2.cfg.configPath,
|
|
2225
|
+
token: stringOpt(parsed.options.token),
|
|
2226
|
+
email: stringOpt(parsed.options.email),
|
|
2227
|
+
open: parsed.options.open === false ? false : parsed.options.open === true ? true : void 0,
|
|
2228
|
+
openApprovalUrl: deps.openUrl
|
|
2229
|
+
},
|
|
2230
|
+
doFetch,
|
|
2231
|
+
out
|
|
2232
|
+
);
|
|
2233
|
+
return adminSpend(parsed, {
|
|
2234
|
+
platformUrl: context2.platform.value,
|
|
2235
|
+
token,
|
|
2236
|
+
doFetch,
|
|
2237
|
+
json: parsed.options.json === true,
|
|
2238
|
+
out
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2144
2241
|
const credentialSet = action2 === "credential" && parsed.positionals[3] === "set";
|
|
2145
2242
|
const credentials = action2 === "credentials";
|
|
2146
2243
|
const models = action2 === "models";
|
|
@@ -2190,6 +2287,8 @@ var init_admin_command = __esm({
|
|
|
2190
2287
|
"use strict";
|
|
2191
2288
|
init_cjs_shims();
|
|
2192
2289
|
init_admin_ai();
|
|
2290
|
+
init_admin_spend();
|
|
2291
|
+
init_token();
|
|
2193
2292
|
init_argv();
|
|
2194
2293
|
init_operator_context();
|
|
2195
2294
|
CONTEXT_OPTIONS = ["platform", "config", "context", "token", "open", "email"];
|
|
@@ -2265,7 +2364,8 @@ async function fetchIdentity(platformUrl, token, doFetch) {
|
|
|
2265
2364
|
email,
|
|
2266
2365
|
admin: body.admin === true,
|
|
2267
2366
|
machine,
|
|
2268
|
-
scopes
|
|
2367
|
+
scopes,
|
|
2368
|
+
projects: Array.isArray(body.projects) ? body.projects.map(String) : null
|
|
2269
2369
|
};
|
|
2270
2370
|
}
|
|
2271
2371
|
function credentialLabel(identity) {
|
|
@@ -2335,6 +2435,13 @@ async function whoamiCommand(parsed, deps = {}) {
|
|
|
2335
2435
|
out.log(`credential id: ${identity.credential.id}`);
|
|
2336
2436
|
out.log(`admin: ${identity.admin ? "yes" : "no"}`);
|
|
2337
2437
|
if (identity.scopes.length) out.log(`scopes: ${identity.scopes.join(", ")}`);
|
|
2438
|
+
if (identity.projects === null) {
|
|
2439
|
+
out.log("projects: (this registry does not report project grants)");
|
|
2440
|
+
} else if (identity.projects.length) {
|
|
2441
|
+
out.log(`projects: ${identity.projects.join(", ")}`);
|
|
2442
|
+
} else {
|
|
2443
|
+
out.log("projects: (none \u2014 every pm and discuss call will be refused)");
|
|
2444
|
+
}
|
|
2338
2445
|
if (!identity.admin) {
|
|
2339
2446
|
if (identity.scopes.includes("platform:runbook:write")) {
|
|
2340
2447
|
out.log("\nThis exact scope can read and edit all platform runbook content.");
|
|
@@ -6211,17 +6318,17 @@ var init_cli_project = __esm({
|
|
|
6211
6318
|
}
|
|
6212
6319
|
});
|
|
6213
6320
|
|
|
6214
|
-
// ../harness/dist/chunk-
|
|
6321
|
+
// ../harness/dist/chunk-LNQNFGQC.js
|
|
6215
6322
|
var HARNESS_PROTOCOL_VERSION;
|
|
6216
|
-
var
|
|
6217
|
-
"../harness/dist/chunk-
|
|
6323
|
+
var init_chunk_LNQNFGQC = __esm({
|
|
6324
|
+
"../harness/dist/chunk-LNQNFGQC.js"() {
|
|
6218
6325
|
"use strict";
|
|
6219
6326
|
init_cjs_shims();
|
|
6220
6327
|
HARNESS_PROTOCOL_VERSION = 1;
|
|
6221
6328
|
}
|
|
6222
6329
|
});
|
|
6223
6330
|
|
|
6224
|
-
// ../harness/dist/chunk-
|
|
6331
|
+
// ../harness/dist/chunk-K76I2TCQ.js
|
|
6225
6332
|
function assertPinnedImage(image) {
|
|
6226
6333
|
if (!DIGEST_IMAGE.test(image)) throw new TypeError("container image must be pinned by sha256 digest");
|
|
6227
6334
|
}
|
|
@@ -6570,8 +6677,8 @@ async function stageWorkspacePair(baselineSource, workspaceSource, options = {})
|
|
|
6570
6677
|
}
|
|
6571
6678
|
}
|
|
6572
6679
|
var import_child_process, import_fs, import_promises2, import_path, import_process, import_promises3, import_os, import_path2, import_child_process2, import_path3, import_promises4, import_os2, import_path4, import_child_process3, DIGEST_IMAGE, SKIP_WORKSPACE_DIRS, SECRET_WORKSPACE_FILE;
|
|
6573
|
-
var
|
|
6574
|
-
"../harness/dist/chunk-
|
|
6680
|
+
var init_chunk_K76I2TCQ = __esm({
|
|
6681
|
+
"../harness/dist/chunk-K76I2TCQ.js"() {
|
|
6575
6682
|
"use strict";
|
|
6576
6683
|
init_cjs_shims();
|
|
6577
6684
|
import_child_process = require("child_process");
|
|
@@ -7569,7 +7676,7 @@ var init_code2 = __esm({
|
|
|
7569
7676
|
}
|
|
7570
7677
|
});
|
|
7571
7678
|
|
|
7572
|
-
// ../harness/dist/chunk-
|
|
7679
|
+
// ../harness/dist/chunk-UVGZHNLW.js
|
|
7573
7680
|
async function digestStagedWorkspace(root, limits) {
|
|
7574
7681
|
const files = [];
|
|
7575
7682
|
const walk = async (directory) => {
|
|
@@ -7647,7 +7754,7 @@ function createCodeRuntimeControlClient(options) {
|
|
|
7647
7754
|
throw new TypeError("modelRequestTimeoutMs must be an integer from 30000 to 1800000");
|
|
7648
7755
|
}
|
|
7649
7756
|
const request3 = options.fetch ?? fetch;
|
|
7650
|
-
const
|
|
7757
|
+
const call4 = async (path, body, timeoutMs = requestTimeoutMs) => {
|
|
7651
7758
|
const timeout = AbortSignal.timeout(timeoutMs);
|
|
7652
7759
|
const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
|
|
7653
7760
|
let response2;
|
|
@@ -7677,17 +7784,17 @@ function createCodeRuntimeControlClient(options) {
|
|
|
7677
7784
|
return {
|
|
7678
7785
|
heartbeat: async (version, capabilities) => {
|
|
7679
7786
|
validateHeartbeat(version, capabilities);
|
|
7680
|
-
return parseSnapshot(await
|
|
7787
|
+
return parseSnapshot(await call4("/registry/code/runtime/heartbeat", { runtimeVersion: version, capabilities }));
|
|
7681
7788
|
},
|
|
7682
7789
|
acknowledge: async (commandId, result) => {
|
|
7683
7790
|
if (!/^ccmd_[0-9a-f]{32}$/.test(commandId)) throw new TypeError("invalid Code runtime command id");
|
|
7684
|
-
await
|
|
7791
|
+
await call4(`/registry/code/runtime/commands/${commandId}/ack`, result);
|
|
7685
7792
|
},
|
|
7686
7793
|
source: async (sessionId) => parseSource(
|
|
7687
|
-
await
|
|
7794
|
+
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
|
|
7688
7795
|
),
|
|
7689
7796
|
infer: async (sessionId, inference) => {
|
|
7690
|
-
const value2 = record5(await
|
|
7797
|
+
const value2 = record5(await call4(
|
|
7691
7798
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
|
|
7692
7799
|
inference,
|
|
7693
7800
|
modelRequestTimeoutMs
|
|
@@ -7698,11 +7805,11 @@ function createCodeRuntimeControlClient(options) {
|
|
|
7698
7805
|
return value2;
|
|
7699
7806
|
},
|
|
7700
7807
|
review: async (sessionId, review) => parseReview(
|
|
7701
|
-
await
|
|
7808
|
+
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
|
|
7702
7809
|
),
|
|
7703
7810
|
submitCandidate: async (sessionId, checkpointId, verification) => {
|
|
7704
7811
|
if (!/^cpoint_[0-9a-f]{32}$/.test(checkpointId)) throw new TypeError("invalid Code checkpoint id");
|
|
7705
|
-
return parseCandidate(await
|
|
7812
|
+
return parseCandidate(await call4(
|
|
7706
7813
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/candidates`,
|
|
7707
7814
|
{ checkpointId, verification }
|
|
7708
7815
|
));
|
|
@@ -7712,21 +7819,21 @@ function createCodeRuntimeControlClient(options) {
|
|
|
7712
7819
|
if (!/^[A-Za-z0-9._:-]{1,120}$/.test(eventId) || !event || typeof event !== "object" || new TextEncoder().encode(serialized).byteLength > 24e3) {
|
|
7713
7820
|
throw new TypeError("invalid Code session event");
|
|
7714
7821
|
}
|
|
7715
|
-
await
|
|
7822
|
+
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/chat/events`, { eventId, event });
|
|
7716
7823
|
},
|
|
7717
7824
|
recallMemories: async (sessionId, subjects, limit) => {
|
|
7718
|
-
const response2 = await
|
|
7825
|
+
const response2 = await call4(
|
|
7719
7826
|
`/registry/code/runtime/sessions/${validSessionId(sessionId)}/recall`,
|
|
7720
7827
|
{ subjects: [...subjects], limit }
|
|
7721
7828
|
);
|
|
7722
7829
|
return Array.isArray(response2.memories) ? response2.memories : [];
|
|
7723
7830
|
},
|
|
7724
7831
|
rememberMemory: async (sessionId, memory) => {
|
|
7725
|
-
await
|
|
7832
|
+
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/remember`, memory);
|
|
7726
7833
|
},
|
|
7727
7834
|
reportSessionFailure: async (sessionId, message2) => {
|
|
7728
7835
|
if (!message2.trim() || message2.length > 2e3) throw new TypeError("invalid Code session failure");
|
|
7729
|
-
await
|
|
7836
|
+
await call4(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/failure`, { message: message2 });
|
|
7730
7837
|
}
|
|
7731
7838
|
};
|
|
7732
7839
|
}
|
|
@@ -8512,7 +8619,7 @@ async function materializeCommandWorkspace(input) {
|
|
|
8512
8619
|
}
|
|
8513
8620
|
function codeSkill(opts) {
|
|
8514
8621
|
let seq = 0;
|
|
8515
|
-
const
|
|
8622
|
+
const call4 = async (tool, input, signal) => {
|
|
8516
8623
|
const startedAt = Date.now();
|
|
8517
8624
|
const response2 = await opts.broker.execute(
|
|
8518
8625
|
{ lease: opts.lease, workspaceDir: opts.workspaceDir, signal },
|
|
@@ -8534,7 +8641,7 @@ function codeSkill(opts) {
|
|
|
8534
8641
|
},
|
|
8535
8642
|
additionalProperties: false
|
|
8536
8643
|
},
|
|
8537
|
-
handler: (input, ctx) =>
|
|
8644
|
+
handler: (input, ctx) => call4("sandbox.read", input, ctx.signal)
|
|
8538
8645
|
};
|
|
8539
8646
|
const applyPatch = {
|
|
8540
8647
|
name: "odla_apply_git_diff",
|
|
@@ -8545,7 +8652,7 @@ function codeSkill(opts) {
|
|
|
8545
8652
|
properties: { patch: { type: "string", minLength: 1, maxLength: 262144 } },
|
|
8546
8653
|
additionalProperties: false
|
|
8547
8654
|
},
|
|
8548
|
-
handler: (input, ctx) =>
|
|
8655
|
+
handler: (input, ctx) => call4("sandbox.apply_patch", input, ctx.signal)
|
|
8549
8656
|
};
|
|
8550
8657
|
const runRecipe = {
|
|
8551
8658
|
name: "odla_run_recipe",
|
|
@@ -8556,7 +8663,7 @@ function codeSkill(opts) {
|
|
|
8556
8663
|
properties: { recipeId: { type: "string", minLength: 1, maxLength: 120, pattern: "^[a-zA-Z0-9._:-]+$" } },
|
|
8557
8664
|
additionalProperties: false
|
|
8558
8665
|
},
|
|
8559
|
-
handler: (input, ctx) =>
|
|
8666
|
+
handler: (input, ctx) => call4("sandbox.run_recipe", input, ctx.signal)
|
|
8560
8667
|
};
|
|
8561
8668
|
const listFiles2 = {
|
|
8562
8669
|
name: "odla_list",
|
|
@@ -8569,7 +8676,7 @@ function codeSkill(opts) {
|
|
|
8569
8676
|
},
|
|
8570
8677
|
additionalProperties: false
|
|
8571
8678
|
},
|
|
8572
|
-
handler: (input, ctx) =>
|
|
8679
|
+
handler: (input, ctx) => call4("sandbox.list", input, ctx.signal)
|
|
8573
8680
|
};
|
|
8574
8681
|
const searchFiles = {
|
|
8575
8682
|
name: "odla_search",
|
|
@@ -8585,7 +8692,7 @@ function codeSkill(opts) {
|
|
|
8585
8692
|
},
|
|
8586
8693
|
additionalProperties: false
|
|
8587
8694
|
},
|
|
8588
|
-
handler: (input, ctx) =>
|
|
8695
|
+
handler: (input, ctx) => call4("sandbox.search", input, ctx.signal)
|
|
8589
8696
|
};
|
|
8590
8697
|
const graphTool = (name, tool, description, required) => ({
|
|
8591
8698
|
name,
|
|
@@ -8596,7 +8703,7 @@ function codeSkill(opts) {
|
|
|
8596
8703
|
properties: { query: { type: "string", maxLength: 512 } },
|
|
8597
8704
|
additionalProperties: false
|
|
8598
8705
|
},
|
|
8599
|
-
handler: (input, ctx) =>
|
|
8706
|
+
handler: (input, ctx) => call4(tool, input, ctx.signal)
|
|
8600
8707
|
});
|
|
8601
8708
|
const orientation = [
|
|
8602
8709
|
graphTool(
|
|
@@ -8635,9 +8742,9 @@ async function runCodeAgent(options) {
|
|
|
8635
8742
|
lease: options.lease,
|
|
8636
8743
|
workspaceDir: options.workspaceDir,
|
|
8637
8744
|
surface,
|
|
8638
|
-
onToolCall: (
|
|
8639
|
-
toolCalls.push(
|
|
8640
|
-
options.onToolCall?.(
|
|
8745
|
+
onToolCall: (call4) => {
|
|
8746
|
+
toolCalls.push(call4);
|
|
8747
|
+
options.onToolCall?.(call4);
|
|
8641
8748
|
}
|
|
8642
8749
|
});
|
|
8643
8750
|
const compaction = options.compaction === void 0 ? (0, import_ai4.keepRecentExchanges)({ whenInputTokensExceed: 12e4, keep: 3 }) : options.compaction;
|
|
@@ -8722,6 +8829,9 @@ async function handleCodeRuntimeInference(input) {
|
|
|
8722
8829
|
call: request3.call
|
|
8723
8830
|
});
|
|
8724
8831
|
state2.tokens += response2.receipt.inputTokens + response2.receipt.outputTokens;
|
|
8832
|
+
const { costUsd } = response2.receipt;
|
|
8833
|
+
if (costUsd === void 0) state2.costKnown = false;
|
|
8834
|
+
else state2.costUsd += costUsd;
|
|
8725
8835
|
await input.event({
|
|
8726
8836
|
type: "usage",
|
|
8727
8837
|
provider: response2.receipt.provider,
|
|
@@ -8731,7 +8841,9 @@ async function handleCodeRuntimeInference(input) {
|
|
|
8731
8841
|
durationMs: Date.now() - startedAt,
|
|
8732
8842
|
interactionId: command.commandId,
|
|
8733
8843
|
interactionTokens: state2.tokens,
|
|
8734
|
-
interactionMaxTokens: metadata2.maxTokensPerInteraction
|
|
8844
|
+
interactionMaxTokens: metadata2.maxTokensPerInteraction,
|
|
8845
|
+
...costUsd === void 0 ? {} : { costUsd },
|
|
8846
|
+
...state2.costKnown ? { interactionCostUsd: state2.costUsd } : {}
|
|
8735
8847
|
}).catch(() => void 0);
|
|
8736
8848
|
return {
|
|
8737
8849
|
protocolVersion: HARNESS_PROTOCOL_VERSION,
|
|
@@ -9522,10 +9634,16 @@ async function startGoalPursuit(input) {
|
|
|
9522
9634
|
attempt: async ({ prompt }) => {
|
|
9523
9635
|
const result = await input.attempt(prompt);
|
|
9524
9636
|
return {
|
|
9525
|
-
//
|
|
9526
|
-
//
|
|
9527
|
-
//
|
|
9528
|
-
|
|
9637
|
+
// What the attempt actually spent, so the runner's token_budget and
|
|
9638
|
+
// cost_budget checks can be reached. This used to be a hardcoded 0 with
|
|
9639
|
+
// no cost at all, which made maxTokens and maxUsd unreachable while
|
|
9640
|
+
// callers reasonably read them as hard ceilings.
|
|
9641
|
+
//
|
|
9642
|
+
// costUsd is omitted rather than zeroed when any call in the attempt
|
|
9643
|
+
// was unpriced: the runner only enforces a cost budget while the cost
|
|
9644
|
+
// is known, and a zero would make it enforce against a lie.
|
|
9645
|
+
tokens: result.tokens ?? 0,
|
|
9646
|
+
...result.costUsd === void 0 ? {} : { costUsd: result.costUsd },
|
|
9529
9647
|
...result.status === "failed" ? { error: result.error ?? "attempt failed" } : {}
|
|
9530
9648
|
};
|
|
9531
9649
|
},
|
|
@@ -9554,12 +9672,12 @@ async function appendCodeRuntimeEvent(control, command, event, refs) {
|
|
|
9554
9672
|
await control.appendSessionEvent(command.sessionId, eventId, bounded);
|
|
9555
9673
|
}
|
|
9556
9674
|
var import_crypto, import_promises5, import_path5, import_child_process4, import_promises6, import_path6, import_child_process5, import_process2, import_crypto2, import_crypto3, import_fs2, import_promises7, import_path7, import_promises8, import_os3, import_path8, import_ai4, import_promises9, import_path9, import_promises10, import_promises11, import_path10, import_crypto4, CODE_RUNTIME_PROTOCOL_VERSION, CodeRuntimeReconciler, CodeRuntimeControlError, record5, invalid, RESERVED, SECRET, PATH, FORBIDDEN, ARTIFACT_PATH, PRIVATE_ARTIFACT_PART, SHA3, DIGEST3, ID3, RULE, DEFAULT_PREFIXES, DEFAULT_SUFFIXES, message, CodeRuntimeCheckpointManager, record22, SOURCE_LIMITS, RESERVED2, SECRET2, V1_SYSTEM_PROMPT, V2_SYSTEM_PROMPT, V3_SYSTEM_PROMPT, SYSTEM_PROMPT_FOR, DEFAULT_MAX_FILES, DEFAULT_MAX_RESULTS, DEFAULT_MAX_FILE_BYTES, DESTINATIONS, READ, LIST, SEARCH, GRAPH, PATCH, RECIPE, cache, shortId, GRAPH_TOOLS, MAX_MEMORY_BODY, POSITIVE, digestRuntimeValue, runtimeErrorMessage, CodePiRuntimeEngine;
|
|
9557
|
-
var
|
|
9558
|
-
"../harness/dist/chunk-
|
|
9675
|
+
var init_chunk_UVGZHNLW = __esm({
|
|
9676
|
+
"../harness/dist/chunk-UVGZHNLW.js"() {
|
|
9559
9677
|
"use strict";
|
|
9560
9678
|
init_cjs_shims();
|
|
9561
|
-
|
|
9562
|
-
|
|
9679
|
+
init_chunk_K76I2TCQ();
|
|
9680
|
+
init_chunk_LNQNFGQC();
|
|
9563
9681
|
import_crypto = require("crypto");
|
|
9564
9682
|
import_promises5 = require("fs/promises");
|
|
9565
9683
|
import_path5 = require("path");
|
|
@@ -9973,7 +10091,7 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
9973
10091
|
recipeAuthorization: this.options.recipeAuthorization
|
|
9974
10092
|
}, lease, metadata2.role));
|
|
9975
10093
|
const startedAt = Date.now();
|
|
9976
|
-
const interaction = { tokens: 0, noticeEmitted: false };
|
|
10094
|
+
const interaction = { tokens: 0, noticeEmitted: false, costUsd: 0, costKnown: true };
|
|
9977
10095
|
const inference = createCodeRuntimeInference({
|
|
9978
10096
|
command,
|
|
9979
10097
|
metadata: metadata2,
|
|
@@ -10011,7 +10129,11 @@ Never claim a build or test passed unless odla_run_recipe returned that result.`
|
|
|
10011
10129
|
await this.#diagnostic(command, active, detail);
|
|
10012
10130
|
await this.#failure(command, active, detail);
|
|
10013
10131
|
}
|
|
10014
|
-
return
|
|
10132
|
+
return {
|
|
10133
|
+
...result,
|
|
10134
|
+
tokens: interaction.tokens,
|
|
10135
|
+
...interaction.costKnown ? { costUsd: interaction.costUsd } : {}
|
|
10136
|
+
};
|
|
10015
10137
|
}
|
|
10016
10138
|
/** Report every brokered effect as it starts and finishes. */
|
|
10017
10139
|
#observed(command, active, broker) {
|
|
@@ -10070,8 +10192,8 @@ var init_node = __esm({
|
|
|
10070
10192
|
"../harness/dist/node.js"() {
|
|
10071
10193
|
"use strict";
|
|
10072
10194
|
init_cjs_shims();
|
|
10073
|
-
|
|
10074
|
-
|
|
10195
|
+
init_chunk_UVGZHNLW();
|
|
10196
|
+
init_chunk_K76I2TCQ();
|
|
10075
10197
|
MEASURED_PREMIUM = Object.freeze({
|
|
10076
10198
|
/** 3 racers vs pure depth at equal budget: 21,044 / 7,936. */
|
|
10077
10199
|
racePerRacer: 0.55,
|
|
@@ -11175,6 +11297,8 @@ Usage:
|
|
|
11175
11297
|
odla-ai admin ai credential set <provider> [--context <name>] (--from-env <NAME>|--stdin)
|
|
11176
11298
|
odla-ai admin ai usage [--context <name>] [--app-id <id>] [--env <env>] [--run-id <id>] [--limit <1-500>] [--json]
|
|
11177
11299
|
odla-ai admin ai audit [--context <name>] [--limit <1-200>] [--json]
|
|
11300
|
+
odla-ai admin spend show <app:<id>:<incarnation>> [--context <name>] [--json]
|
|
11301
|
+
odla-ai admin spend reset <app:<id>:<incarnation>> [--context <name>] [--json]
|
|
11178
11302
|
odla-ai security github connect [--repo owner/name] [--env dev] [continue in Studio; human session required]
|
|
11179
11303
|
odla-ai security github disconnect --source <id> [--env dev] [continue in Studio; human session required]
|
|
11180
11304
|
odla-ai security plan [--env dev] [--json]
|
|
@@ -11269,6 +11393,9 @@ Commands:
|
|
|
11269
11393
|
human session connects one); "code grant request|list|approve|revoke" then
|
|
11270
11394
|
governs unattended access: an agent may request, only a human may approve.
|
|
11271
11395
|
admin Manage platform-funded AI routing/credentials/usage with narrow device grants.
|
|
11396
|
+
"admin spend" reads one app's daily inference spend and resumes it
|
|
11397
|
+
after a cap halts it. The cap is per UTC day; exhausting it LATCHES,
|
|
11398
|
+
and a new day does not clear the latch \u2014 resuming is deliberate.
|
|
11272
11399
|
security Connect GitHub sources and run commit-pinned hosted reviews, or scan a local snapshot.
|
|
11273
11400
|
pm Project management (via @odla-ai/pm): Products contain Projects;
|
|
11274
11401
|
projects contain goals, kanban tasks, decisions, and bugs. Use
|
|
@@ -11276,6 +11403,12 @@ Commands:
|
|
|
11276
11403
|
pass --app/--project explicitly. Same device-grant auth as "app".
|
|
11277
11404
|
Status changes and comments post to each item's @odla-ai/chat
|
|
11278
11405
|
discussion thread.
|
|
11406
|
+
NOTE: "--column ready" is OWNER-ONLY. Creating a task in Ready
|
|
11407
|
+
approves its complete execution contract, so it needs pm.plan,
|
|
11408
|
+
which no device enrollment or handshake approval can grant. An
|
|
11409
|
+
agent proposes in Backlog (the default); a human owner or a
|
|
11410
|
+
pm.plan agent promotes. This is deliberate, not a permission
|
|
11411
|
+
gap \u2014 it was reported as one.
|
|
11279
11412
|
bug Intent-first alias for PM bugs. "bug report" writes to
|
|
11280
11413
|
odla PM; odla product defects do not belong in GitHub Issues.
|
|
11281
11414
|
discuss Group discussions (via @odla-ai/chat) for the apps you co-own:
|
|
@@ -14663,7 +14796,11 @@ async function revoke(parsed, deps, cfg, doFetch, out, json) {
|
|
|
14663
14796
|
if (json) out.log(JSON.stringify({ deviceId, revoked: true }, null, 2));
|
|
14664
14797
|
}
|
|
14665
14798
|
async function scopedToken2(parsed, deps, cfg, doFetch, out, label, scope = "app:device:enroll") {
|
|
14666
|
-
const { credentials } = await resolveOperatorContext(parsed, {
|
|
14799
|
+
const { credentials } = await resolveOperatorContext(parsed, {
|
|
14800
|
+
allowMissingConfig: true,
|
|
14801
|
+
// A device is granted the apps named in ONE approval, so --app is a list here.
|
|
14802
|
+
allowAppList: true
|
|
14803
|
+
});
|
|
14667
14804
|
const scopedTokenFile = credentials.scopedTokenFile;
|
|
14668
14805
|
return getScopedPlatformToken({
|
|
14669
14806
|
platform: cfg.platformUrl,
|
|
@@ -14700,7 +14837,7 @@ var init_device_command = __esm({
|
|
|
14700
14837
|
});
|
|
14701
14838
|
|
|
14702
14839
|
// src/runbook-actions.ts
|
|
14703
|
-
async function
|
|
14840
|
+
async function call2(ctx, method, path, body) {
|
|
14704
14841
|
const res = await ctx.doFetch(`${ctx.platformUrl.replace(/\/$/, "")}/registry/pm${path}`, {
|
|
14705
14842
|
method,
|
|
14706
14843
|
headers: {
|
|
@@ -14722,7 +14859,7 @@ async function call(ctx, method, path, body) {
|
|
|
14722
14859
|
throw new Error(message2);
|
|
14723
14860
|
}
|
|
14724
14861
|
async function bySlug(ctx, slug) {
|
|
14725
|
-
const page2 = await
|
|
14862
|
+
const page2 = await call2(
|
|
14726
14863
|
ctx,
|
|
14727
14864
|
"GET",
|
|
14728
14865
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&slug=${encodeURIComponent(slug)}&limit=1`
|
|
@@ -14731,7 +14868,7 @@ async function bySlug(ctx, slug) {
|
|
|
14731
14868
|
if (filtered) return filtered;
|
|
14732
14869
|
const limit = 100;
|
|
14733
14870
|
for (let offset = 0; ; offset += limit) {
|
|
14734
|
-
const fallback = await
|
|
14871
|
+
const fallback = await call2(
|
|
14735
14872
|
ctx,
|
|
14736
14873
|
"GET",
|
|
14737
14874
|
`/runbook?app=${encodeURIComponent(ctx.appId)}&limit=${limit}&offset=${offset}`
|
|
@@ -14751,7 +14888,7 @@ async function runbookList(ctx, all, query) {
|
|
|
14751
14888
|
const params = new URLSearchParams();
|
|
14752
14889
|
if (!all) params.set("app", ctx.appId);
|
|
14753
14890
|
if (query) params.set("q", query);
|
|
14754
|
-
const page2 = await
|
|
14891
|
+
const page2 = await call2(ctx, "GET", `/runbook${params.size ? `?${params}` : ""}`);
|
|
14755
14892
|
if (ctx.json) return ctx.out.log(JSON.stringify(page2, null, 2));
|
|
14756
14893
|
if (!page2.records.length) return ctx.out.log("(no runbooks)");
|
|
14757
14894
|
ctx.out.log(["SLUG", "STATUS", "V", "SCOPE", "UPDATED", "TITLE"].join(" "));
|
|
@@ -14768,7 +14905,7 @@ async function runbookGet(ctx, slug) {
|
|
|
14768
14905
|
ctx.out.log(runbook.body);
|
|
14769
14906
|
}
|
|
14770
14907
|
async function runbookNew(ctx, slug, title, body, summary, requires) {
|
|
14771
|
-
const created = await
|
|
14908
|
+
const created = await call2(ctx, "POST", "/runbook", {
|
|
14772
14909
|
appId: ctx.appId,
|
|
14773
14910
|
input: { slug, title, body, ...summary ? { summary } : {}, ...requires ? { requires } : {} }
|
|
14774
14911
|
});
|
|
@@ -14776,7 +14913,7 @@ async function runbookNew(ctx, slug, title, body, summary, requires) {
|
|
|
14776
14913
|
}
|
|
14777
14914
|
async function runbookEdit(ctx, slug, body, note, requires, expectedVersion) {
|
|
14778
14915
|
const runbook = await bySlug(ctx, slug);
|
|
14779
|
-
const result = await
|
|
14916
|
+
const result = await call2(ctx, "PATCH", `/runbook/${encodeURIComponent(runbook.id)}`, {
|
|
14780
14917
|
// An empty --requires clears the declaration; omitting the flag leaves
|
|
14781
14918
|
// whatever is there, so an ordinary body edit never drops it.
|
|
14782
14919
|
patch: {
|
|
@@ -14791,7 +14928,7 @@ async function runbookEdit(ctx, slug, body, note, requires, expectedVersion) {
|
|
|
14791
14928
|
}
|
|
14792
14929
|
async function runbookStatus(ctx, slug, status) {
|
|
14793
14930
|
const runbook = await bySlug(ctx, slug);
|
|
14794
|
-
const result = await
|
|
14931
|
+
const result = await call2(ctx, "PATCH", `/runbook/${encodeURIComponent(runbook.id)}`, {
|
|
14795
14932
|
patch: { status }
|
|
14796
14933
|
});
|
|
14797
14934
|
ctx.out.log(ctx.json ? JSON.stringify(result, null, 2) : `${slug} \u2192 ${status}`);
|
|
@@ -14800,7 +14937,7 @@ async function runbookVisibility(ctx, slug, visibility) {
|
|
|
14800
14937
|
if (visibility !== "operator" && visibility !== "admin")
|
|
14801
14938
|
throw new Error(`visibility must be "operator" or "admin", got "${visibility}"`);
|
|
14802
14939
|
const runbook = await bySlug(ctx, slug);
|
|
14803
|
-
const result = await
|
|
14940
|
+
const result = await call2(ctx, "PATCH", `/runbook/${encodeURIComponent(runbook.id)}`, {
|
|
14804
14941
|
patch: { visibility }
|
|
14805
14942
|
});
|
|
14806
14943
|
if (ctx.json) return ctx.out.log(JSON.stringify(result, null, 2));
|
|
@@ -14810,7 +14947,7 @@ async function runbookVisibility(ctx, slug, visibility) {
|
|
|
14810
14947
|
}
|
|
14811
14948
|
async function runbookHistory(ctx, slug) {
|
|
14812
14949
|
const runbook = await bySlug(ctx, slug);
|
|
14813
|
-
const page2 = await
|
|
14950
|
+
const page2 = await call2(ctx, "GET", `/runbook/${encodeURIComponent(runbook.id)}/revisions`);
|
|
14814
14951
|
if (ctx.json) return ctx.out.log(JSON.stringify(page2, null, 2));
|
|
14815
14952
|
ctx.out.log(`${slug} is at v${runbook.version}`);
|
|
14816
14953
|
if (!page2.records.length) return ctx.out.log("(no earlier versions)");
|
|
@@ -14820,7 +14957,7 @@ async function runbookHistory(ctx, slug) {
|
|
|
14820
14957
|
}
|
|
14821
14958
|
async function runbookRevert(ctx, slug, version) {
|
|
14822
14959
|
const runbook = await bySlug(ctx, slug);
|
|
14823
|
-
const result = await
|
|
14960
|
+
const result = await call2(
|
|
14824
14961
|
ctx,
|
|
14825
14962
|
"POST",
|
|
14826
14963
|
`/runbook/${encodeURIComponent(runbook.id)}/revert`,
|
|
@@ -14831,7 +14968,7 @@ async function runbookRevert(ctx, slug, version) {
|
|
|
14831
14968
|
}
|
|
14832
14969
|
async function runbookRemove(ctx, slug) {
|
|
14833
14970
|
const runbook = await bySlug(ctx, slug);
|
|
14834
|
-
await
|
|
14971
|
+
await call2(ctx, "DELETE", `/runbook/${encodeURIComponent(runbook.id)}`);
|
|
14835
14972
|
ctx.out.log(`removed ${slug}`);
|
|
14836
14973
|
}
|
|
14837
14974
|
var import_node_fs21, PLATFORM_SCOPE, stamp;
|
|
@@ -14902,7 +15039,7 @@ ${counts.created} created, ${counts.updated} updated, ${counts.unchanged} unchan
|
|
|
14902
15039
|
async function upsert(ctx, r, visibility) {
|
|
14903
15040
|
const found = await bySlug(ctx, r.slug).catch(() => null);
|
|
14904
15041
|
if (!found) {
|
|
14905
|
-
await
|
|
15042
|
+
await call2(ctx, "POST", "/runbook", {
|
|
14906
15043
|
appId: ctx.appId,
|
|
14907
15044
|
input: {
|
|
14908
15045
|
slug: r.slug,
|
|
@@ -14921,7 +15058,7 @@ async function upsert(ctx, r, visibility) {
|
|
|
14921
15058
|
ctx.out.log(` = ${r.slug} (already current at v${found.version})`);
|
|
14922
15059
|
return "unchanged";
|
|
14923
15060
|
}
|
|
14924
|
-
const result = await
|
|
15061
|
+
const result = await call2(
|
|
14925
15062
|
ctx,
|
|
14926
15063
|
"PATCH",
|
|
14927
15064
|
`/runbook/${encodeURIComponent(found.id)}`,
|
|
@@ -15160,7 +15297,7 @@ async function assessImpact(ctx, surfaces, all, limit) {
|
|
|
15160
15297
|
for (const surface of surfaces) {
|
|
15161
15298
|
const params = new URLSearchParams({ q: surface.query, limit: String(limit) });
|
|
15162
15299
|
if (!all) params.set("app", ctx.appId);
|
|
15163
|
-
const result = await
|
|
15300
|
+
const result = await call2(ctx, "GET", `/runbook/search?${params}`);
|
|
15164
15301
|
const runbooks = result.outcome === "ranked" ? foldHits(result.hits) : result.candidates.map((c) => ({ ...c, version: 0, sections: [] }));
|
|
15165
15302
|
out.push({ surface, runbooks });
|
|
15166
15303
|
}
|
|
@@ -15256,7 +15393,7 @@ function lintRunbook(runbook, installed) {
|
|
|
15256
15393
|
async function runbookLint(ctx, all) {
|
|
15257
15394
|
const params = new URLSearchParams();
|
|
15258
15395
|
if (!all) params.set("app", ctx.appId);
|
|
15259
|
-
const page2 = await
|
|
15396
|
+
const page2 = await call2(ctx, "GET", `/runbook${params.size ? `?${params}` : ""}`);
|
|
15260
15397
|
const installed = { "@odla-ai/cli": cliVersion() };
|
|
15261
15398
|
const findings = page2.records.flatMap((runbook) => lintRunbook(runbook, installed));
|
|
15262
15399
|
if (ctx.json) return ctx.out.log(JSON.stringify({ checked: page2.records.length, findings }, null, 2));
|
|
@@ -15291,7 +15428,7 @@ async function runbookSearch(ctx, query, all, limit) {
|
|
|
15291
15428
|
const params = new URLSearchParams({ q: query });
|
|
15292
15429
|
if (!all) params.set("app", ctx.appId);
|
|
15293
15430
|
if (limit) params.set("limit", String(limit));
|
|
15294
|
-
const result = await
|
|
15431
|
+
const result = await call2(ctx, "GET", `/runbook/search?${params}`);
|
|
15295
15432
|
if (ctx.json) return ctx.out.log(JSON.stringify(result, null, 2));
|
|
15296
15433
|
if (result.outcome === "empty-corpus") return ctx.out.log("no runbooks are available to search");
|
|
15297
15434
|
if (result.outcome === "no-match") return ctx.out.log(`no runbook mentions "${query}"`);
|
|
@@ -15309,7 +15446,7 @@ async function runbookSearch(ctx, query, all, limit) {
|
|
|
15309
15446
|
}
|
|
15310
15447
|
}
|
|
15311
15448
|
async function runbookAsk(ctx, question, all) {
|
|
15312
|
-
const result = await
|
|
15449
|
+
const result = await call2(ctx, "POST", "/runbook/ask", {
|
|
15313
15450
|
question,
|
|
15314
15451
|
...all ? {} : { app: ctx.appId }
|
|
15315
15452
|
});
|
|
@@ -15339,7 +15476,7 @@ async function runbookAsk(ctx, question, all) {
|
|
|
15339
15476
|
}
|
|
15340
15477
|
async function runbookComment(ctx, slug, body) {
|
|
15341
15478
|
const found = await bySlug(ctx, slug);
|
|
15342
|
-
await
|
|
15479
|
+
await call2(ctx, "POST", `/runbook/${encodeURIComponent(found.id)}/comments`, { body });
|
|
15343
15480
|
ctx.out.log(`commented on ${slug} (v${found.version})`);
|
|
15344
15481
|
}
|
|
15345
15482
|
var JSDOC_POINTER;
|