withruntime 0.23.0 → 0.33.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/COMPATIBILITY.md +66 -5
- package/E2B.md +1 -1
- package/README.md +36 -2
- package/README.src.md +35 -1
- package/compatibility-lock.json +3 -3
- package/dist/agents/browser.d.ts +12 -0
- package/dist/agents/browser.js +12 -0
- package/dist/agents/index.d.ts +7 -7
- package/dist/agents/index.js +7 -8
- package/dist/agents-cli.d.ts +1 -1
- package/dist/agents-cli.js +250 -3
- package/dist/agents-deploy.d.ts +186 -0
- package/dist/agents-deploy.js +752 -0
- package/dist/agents-file.d.ts +19 -0
- package/dist/agents-file.js +135 -0
- package/dist/apps/index.d.ts +10 -0
- package/dist/apps/index.js +11 -0
- package/dist/apps-cli.d.ts +3 -1
- package/dist/apps-cli.js +285 -38
- package/dist/blaxel/errors.js +2 -1
- package/dist/ci/index.d.ts +13 -0
- package/dist/ci/index.js +14 -0
- package/dist/ci-cli.d.ts +10 -0
- package/dist/ci-cli.js +402 -0
- package/dist/ci-import.d.ts +23 -0
- package/dist/ci-import.js +565 -0
- package/dist/cli.d.ts +18 -7
- package/dist/cli.js +775 -85
- package/dist/daytona/errors.js +2 -1
- package/dist/e2b/errors.js +2 -1
- package/dist/e2b/filesystem.d.ts +1 -0
- package/dist/e2b/filesystem.js +1 -1
- package/dist/e2b/sandbox.d.ts +11 -2
- package/dist/e2b/sandbox.js +22 -6
- package/dist/errors.d.ts +11 -4
- package/dist/errors.js +27 -4
- package/dist/fly/index.d.ts +102 -0
- package/dist/fly/index.js +930 -0
- package/dist/index.d.ts +7 -3
- package/dist/machine.d.ts +10 -6
- package/dist/machine.js +14 -6
- package/dist/modal/index.d.ts +34 -0
- package/dist/modal/index.js +128 -22
- package/dist/products/agents.d.ts +101 -3
- package/dist/products/agents.js +49 -0
- package/dist/products/apps.d.ts +206 -10
- package/dist/products/apps.js +172 -1
- package/dist/products/ci.d.ts +335 -0
- package/dist/products/ci.js +108 -0
- package/dist/products/index.d.ts +8 -0
- package/dist/products/index.js +15 -0
- package/dist/products/jobs.d.ts +105 -5
- package/dist/products/jobs.js +47 -3
- package/dist/products/network.d.ts +13 -0
- package/dist/products/observability.d.ts +1 -1
- package/dist/products/plans.d.ts +131 -0
- package/dist/products/plans.js +24 -0
- package/dist/products/reservations.d.ts +108 -0
- package/dist/products/reservations.js +41 -0
- package/dist/products/resources.d.ts +2 -1
- package/dist/products/secrets.d.ts +90 -6
- package/dist/products/secrets.js +8 -2
- package/dist/proxy.d.ts +3 -3
- package/dist/proxy.js +20 -0
- package/dist/sandbox.d.ts +29 -1
- package/dist/sandbox.js +56 -3
- package/dist/snapshots.d.ts +1 -1
- package/dist/switched-off.d.ts +5 -0
- package/dist/switched-off.js +8 -0
- package/dist/tar.d.ts +1 -1
- package/dist/tar.js +19 -1
- package/dist/transport.d.ts +1 -1
- package/dist/transport.js +48 -9
- package/dist/types.d.ts +35 -4
- package/dist/vercel/errors.d.ts +1 -1
- package/dist/vercel/errors.js +2 -1
- package/dist/vercel/snapshot.js +4 -2
- package/package.json +23 -6
package/dist/agents-cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
2
3
|
import { me, named } from "./cli-name.js";
|
|
3
|
-
import { AGENT_TEMPLATES, AGENT_USES, agents, } from "./products/agents.js";
|
|
4
|
+
import { AGENT_TEMPLATES, agentTemplate, AGENT_USES, agents, } from "./products/agents.js";
|
|
4
5
|
export const AGENT_HELP = `runtime agents <command>
|
|
5
6
|
|
|
6
7
|
An agent runs a harness (Claude Code, Codex, Gemini CLI, or your own code on
|
|
@@ -8,6 +9,15 @@ export const AGENT_HELP = `runtime agents <command>
|
|
|
8
9
|
In a private beta: outside it, each command says how to ask to join.
|
|
9
10
|
|
|
10
11
|
templates The harnesses and uses to start from
|
|
12
|
+
init [name] [--template <harness>] [--use support|team] [--file runtime.yml]
|
|
13
|
+
Write a starter agents: section into runtime.yml
|
|
14
|
+
deploy [--file runtime.yml] [--dry-run] [--prune [--prune-memory]]
|
|
15
|
+
Make your agents match runtime.yml: create, update
|
|
16
|
+
(a new version only when it changed) and set
|
|
17
|
+
triggers; one line per change. --prune deletes the
|
|
18
|
+
agents a deploy made that the file no longer names,
|
|
19
|
+
with their triggers; one holding memory files only
|
|
20
|
+
with --prune-memory too, which deletes them for good
|
|
11
21
|
create <name> (--template <harness> | --command "<cmd>") [--use support|team]
|
|
12
22
|
[--instructions <text> | --instructions-file <path>] [--secret NAME]...
|
|
13
23
|
[--env KEY=VALUE]... [--image <image> | --snapshot <id>] [--vcpu n] [--memory n]
|
|
@@ -34,6 +44,16 @@ export const AGENT_HELP = `runtime agents <command>
|
|
|
34
44
|
triggers pause <triggerId> --why <words> Refuse its events, saying why; nothing else is held
|
|
35
45
|
triggers resume <triggerId>
|
|
36
46
|
triggers rm <triggerId>
|
|
47
|
+
memory ls <agent> [--scope <key>] [--prefix <path>]
|
|
48
|
+
Its memory files, with their scope (shared or a key)
|
|
49
|
+
memory search <agent> <words...> [--scope <key>] [--limit n]
|
|
50
|
+
Files whose words match, best first
|
|
51
|
+
memory cat <agent> <path> [--scope <key>] A file's text
|
|
52
|
+
memory put <agent> <path> [<file> | - | --content <text>] [--scope <key>]
|
|
53
|
+
Seed or replace a file (from a file, or - for stdin)
|
|
54
|
+
memory rm <agent> <path> [--scope <key>] Delete a file
|
|
55
|
+
Without --scope: the shared memory, which every
|
|
56
|
+
session reads and only a shared agent's write
|
|
37
57
|
|
|
38
58
|
A subscription is for your own team's agents; an agent that serves your
|
|
39
59
|
customers uses an API key.
|
|
@@ -42,6 +62,8 @@ Examples
|
|
|
42
62
|
printf %s "$ANTHROPIC_API_KEY" | runtime secrets set ANTHROPIC_API_KEY --host api.anthropic.com
|
|
43
63
|
runtime agents create helper --template claude-code --use support --instructions "Answer briefly."
|
|
44
64
|
runtime agents start helper "How do I reset my password?" --key customer:42 --follow
|
|
65
|
+
runtime agents memory put helper faq/refunds.md refunds.md
|
|
66
|
+
runtime agents init --template claude-code && runtime agents deploy --dry-run
|
|
45
67
|
`;
|
|
46
68
|
const when = (iso) => iso ?? "-";
|
|
47
69
|
const OPTIONS = [
|
|
@@ -89,7 +111,7 @@ function definitionOf(args, kit, env, base) {
|
|
|
89
111
|
const secrets = args.flags.get("secret");
|
|
90
112
|
const definition = {
|
|
91
113
|
...(base ?? {}),
|
|
92
|
-
...(template ?
|
|
114
|
+
...(template ? agentTemplate(template).definition : {}),
|
|
93
115
|
...(use ? AGENT_USES[use].definition : {}),
|
|
94
116
|
};
|
|
95
117
|
const set = (field, value) => {
|
|
@@ -149,6 +171,10 @@ export async function agentsCommand(argv, env, out, client, kit) {
|
|
|
149
171
|
].join("\n"), value);
|
|
150
172
|
return 0;
|
|
151
173
|
}
|
|
174
|
+
if (verb === "init")
|
|
175
|
+
return initFile(rest, out, kit);
|
|
176
|
+
if (verb === "deploy")
|
|
177
|
+
return deploy(rest, out, client, kit);
|
|
152
178
|
const transport = (await client()).transport;
|
|
153
179
|
const api = agents(transport);
|
|
154
180
|
const follow = async (sessionId, after) => {
|
|
@@ -343,9 +369,13 @@ export async function agentsCommand(argv, env, out, client, kit) {
|
|
|
343
369
|
: "No triggers.", all);
|
|
344
370
|
return 0;
|
|
345
371
|
}
|
|
372
|
+
case "memory":
|
|
373
|
+
return memoryCommand(rest, api, out, kit, print);
|
|
346
374
|
default:
|
|
347
375
|
throw unknown("agents command", verb, [
|
|
348
376
|
"templates",
|
|
377
|
+
"init",
|
|
378
|
+
"deploy",
|
|
349
379
|
"create",
|
|
350
380
|
"ls",
|
|
351
381
|
"get",
|
|
@@ -357,6 +387,223 @@ export async function agentsCommand(argv, env, out, client, kit) {
|
|
|
357
387
|
"sessions",
|
|
358
388
|
"stop",
|
|
359
389
|
"triggers",
|
|
390
|
+
"memory",
|
|
360
391
|
]);
|
|
361
392
|
}
|
|
362
393
|
}
|
|
394
|
+
const scopeName = (scope) => scope || "(shared)";
|
|
395
|
+
/** `runtime agents memory`: an agent's built-in memory, by scope and path.
|
|
396
|
+
* Without --scope, cat, put and rm mean the shared memory, which every
|
|
397
|
+
* session reads (a per-key session read-only, what you put there alone);
|
|
398
|
+
* ls and search mean every scope. */
|
|
399
|
+
async function memoryCommand(argv, api, out, kit, print) {
|
|
400
|
+
const { parse, flag, need, table, usage, unknown } = kit;
|
|
401
|
+
const [sub, ...rest] = argv;
|
|
402
|
+
switch (sub) {
|
|
403
|
+
case "ls":
|
|
404
|
+
case "list": {
|
|
405
|
+
const args = parse(rest, [], ["scope", "prefix"]);
|
|
406
|
+
const agent = need(args.positional[0], "an agent's id or name");
|
|
407
|
+
const scope = flag(args, "scope");
|
|
408
|
+
const prefix = flag(args, "prefix");
|
|
409
|
+
const first = await api.memory.list(agent, {
|
|
410
|
+
limit: 1000,
|
|
411
|
+
...(scope === undefined ? {} : { scope }),
|
|
412
|
+
...(prefix === undefined ? {} : { prefix }),
|
|
413
|
+
});
|
|
414
|
+
const all = await first.toArray(Infinity);
|
|
415
|
+
const { usage: used } = first;
|
|
416
|
+
print([
|
|
417
|
+
all.length
|
|
418
|
+
? table([
|
|
419
|
+
["SCOPE", "PATH", "BYTES", "UPDATED"],
|
|
420
|
+
...all.map((f) => [scopeName(f.scope), f.path, String(f.bytes), f.updatedAt]),
|
|
421
|
+
])
|
|
422
|
+
: "No memory files.",
|
|
423
|
+
`${used.files} files, ${used.bytes} bytes in all (at most ${used.limitFiles} files, ${used.limitBytes} bytes).`,
|
|
424
|
+
].join("\n"), { data: all, usage: used });
|
|
425
|
+
return 0;
|
|
426
|
+
}
|
|
427
|
+
case "search": {
|
|
428
|
+
const args = parse(rest, [], ["scope", "limit"]);
|
|
429
|
+
const agent = need(args.positional[0], "an agent's id or name");
|
|
430
|
+
const words = args.positional.slice(1).join(" ");
|
|
431
|
+
if (!words)
|
|
432
|
+
throw usage(`Give the words: ${me} agents memory search ${agent} "refund policy"`);
|
|
433
|
+
const scope = flag(args, "scope");
|
|
434
|
+
const limit = kit.integer(args, "limit");
|
|
435
|
+
const hits = await api.memory.search(agent, words, {
|
|
436
|
+
...(scope === undefined ? {} : { scope }),
|
|
437
|
+
...(limit === undefined ? {} : { limit }),
|
|
438
|
+
});
|
|
439
|
+
print(hits.length
|
|
440
|
+
? table([
|
|
441
|
+
["SCOPE", "PATH", "SNIPPET"],
|
|
442
|
+
...hits.map((h) => [scopeName(h.scope), h.path, h.snippet.replace(/\s+/g, " ")]),
|
|
443
|
+
])
|
|
444
|
+
: "Nothing matches.", hits);
|
|
445
|
+
return 0;
|
|
446
|
+
}
|
|
447
|
+
case "cat":
|
|
448
|
+
case "read": {
|
|
449
|
+
const args = parse(rest, [], ["scope"]);
|
|
450
|
+
const agent = need(args.positional[0], "an agent's id or name");
|
|
451
|
+
const file = await api.memory.read(agent, need(args.positional[1], "a file's path"), {
|
|
452
|
+
scope: flag(args, "scope") ?? "",
|
|
453
|
+
});
|
|
454
|
+
print(file.content, file);
|
|
455
|
+
return 0;
|
|
456
|
+
}
|
|
457
|
+
case "put":
|
|
458
|
+
case "write": {
|
|
459
|
+
const args = parse(rest, [], ["scope", "content"]);
|
|
460
|
+
const agent = need(args.positional[0], "an agent's id or name");
|
|
461
|
+
const path = need(args.positional[1], "a file's path");
|
|
462
|
+
const source = args.positional[2];
|
|
463
|
+
const given = flag(args, "content");
|
|
464
|
+
if (given !== undefined && source !== undefined)
|
|
465
|
+
throw usage("Give a file or --content, not both.");
|
|
466
|
+
let content = given;
|
|
467
|
+
if (content === undefined) {
|
|
468
|
+
if (source !== undefined && source !== "-")
|
|
469
|
+
content = readFileSync(source, "utf8");
|
|
470
|
+
// stdin only when named: a CI step with nothing piped in would
|
|
471
|
+
// otherwise replace the file with nothing.
|
|
472
|
+
else if (source === "-") {
|
|
473
|
+
const chunks = [];
|
|
474
|
+
for await (const chunk of process.stdin)
|
|
475
|
+
chunks.push(chunk);
|
|
476
|
+
content = Buffer.concat(chunks).toString("utf8");
|
|
477
|
+
}
|
|
478
|
+
else
|
|
479
|
+
throw usage(`Give the text: a file (${me} agents memory put ${agent} ${path} notes.md), - for stdin, or --content.`);
|
|
480
|
+
}
|
|
481
|
+
const written = await api.memory.write(agent, path, content, {
|
|
482
|
+
scope: flag(args, "scope") ?? "",
|
|
483
|
+
});
|
|
484
|
+
print(`${written.created ? "Wrote" : "Replaced"} ${path} in ${scopeName(written.scope)}: ${written.bytes} bytes.`, written);
|
|
485
|
+
return 0;
|
|
486
|
+
}
|
|
487
|
+
case "rm":
|
|
488
|
+
case "delete": {
|
|
489
|
+
const args = parse(rest, [], ["scope"]);
|
|
490
|
+
const agent = need(args.positional[0], "an agent's id or name");
|
|
491
|
+
const path = need(args.positional[1], "a file's path");
|
|
492
|
+
const scope = flag(args, "scope") ?? "";
|
|
493
|
+
const deleted = await api.memory.delete(agent, path, { scope });
|
|
494
|
+
print(deleted
|
|
495
|
+
? `${path} deleted from ${scopeName(scope)}.`
|
|
496
|
+
: `No ${path} in ${scopeName(scope)}.`, { deleted });
|
|
497
|
+
return 0;
|
|
498
|
+
}
|
|
499
|
+
default:
|
|
500
|
+
if (!sub)
|
|
501
|
+
throw usage("agents memory takes ls, search, cat, put or rm.");
|
|
502
|
+
throw unknown("agents memory command", sub, ["ls", "search", "cat", "put", "rm"]);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/** `runtime agents init`: a starter agents: section, into a new runtime.yml
|
|
506
|
+
* or added to one that has none yet. The YAML parser loads only here and in
|
|
507
|
+
* deploy. */
|
|
508
|
+
async function initFile(argv, out, kit) {
|
|
509
|
+
const { parse, flag, usage } = kit;
|
|
510
|
+
const { AGENTS_FILE, parseAgentsFile, starterAgents } = await import("./agents-file.js");
|
|
511
|
+
const args = parse(argv, [], ["template", "use", "file"]);
|
|
512
|
+
const template = flag(args, "template") ?? "claude-code";
|
|
513
|
+
if (!(template in AGENT_TEMPLATES))
|
|
514
|
+
throw usage(`--template takes ${Object.keys(AGENT_TEMPLATES).join(", ")}.`);
|
|
515
|
+
const use = flag(args, "use");
|
|
516
|
+
if (use !== undefined && use !== "support" && use !== "team")
|
|
517
|
+
throw usage("--use takes support or team.");
|
|
518
|
+
const name = args.positional[0] ?? template;
|
|
519
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/.test(name))
|
|
520
|
+
throw usage("An agent's name is letters, digits, '.', '_' and '-', starting with a letter or digit.");
|
|
521
|
+
const file = flag(args, "file") ?? AGENTS_FILE;
|
|
522
|
+
const folder = dirname(resolve(file));
|
|
523
|
+
const instructionsFile = ["AGENTS.md", "CLAUDE.md"].find((f) => existsSync(join(folder, f)));
|
|
524
|
+
const text = starterAgents({
|
|
525
|
+
name,
|
|
526
|
+
template,
|
|
527
|
+
...(use ? { use } : {}),
|
|
528
|
+
...(instructionsFile ? { instructionsFile } : {}),
|
|
529
|
+
});
|
|
530
|
+
if (existsSync(file)) {
|
|
531
|
+
const existing = readFileSync(file, "utf8");
|
|
532
|
+
const config = parseAgentsFile(existing, file).config;
|
|
533
|
+
if (typeof config === "object" && config !== null && "agents" in config)
|
|
534
|
+
throw usage(`${file} already has an agents: section. Add ${name} under it by hand, or run \`${me} agents deploy\`.`);
|
|
535
|
+
writeFileSync(file, `${existing}${existing.endsWith("\n") || !existing ? "" : "\n"}\n${text}`);
|
|
536
|
+
}
|
|
537
|
+
else
|
|
538
|
+
writeFileSync(file, text);
|
|
539
|
+
const t = agentTemplate(template);
|
|
540
|
+
say(out, [
|
|
541
|
+
`Wrote agent ${name} (${t.title}) to ${file}${instructionsFile ? `, with ${instructionsFile} as its instructions` : ""}.`,
|
|
542
|
+
"Next:",
|
|
543
|
+
` printf %s "$${t.apiKeySecret}" | ${me} secrets set ${t.apiKeySecret} --host ${t.apiKeyHost}`,
|
|
544
|
+
` ${me} agents deploy --dry-run`,
|
|
545
|
+
` ${me} agents deploy`,
|
|
546
|
+
].join("\n"), { file, name, template, text });
|
|
547
|
+
return 0;
|
|
548
|
+
}
|
|
549
|
+
/** `runtime agents deploy`: the file is read and checked before any key is
|
|
550
|
+
* needed, then the plan is made against the account and each change made in
|
|
551
|
+
* turn, printed as it is made with its idempotency key. */
|
|
552
|
+
async function deploy(argv, out, client, kit) {
|
|
553
|
+
const { parse, flag, has } = kit;
|
|
554
|
+
const { AGENTS_FILE, loadAgentsFile } = await import("./agents-file.js");
|
|
555
|
+
const { checkAgentsFile, withDeploy } = await import("./agents-deploy.js");
|
|
556
|
+
const args = parse(argv, ["dry-run", "prune", "prune-memory"], ["file"]);
|
|
557
|
+
if (has(args, "prune-memory") && !has(args, "prune"))
|
|
558
|
+
throw kit.usage("--prune-memory goes with --prune.");
|
|
559
|
+
const dryRun = has(args, "dry-run");
|
|
560
|
+
const source = loadAgentsFile(flag(args, "file") ?? AGENTS_FILE);
|
|
561
|
+
const count = checkAgentsFile(source).length;
|
|
562
|
+
const api = withDeploy(agents((await client()).transport));
|
|
563
|
+
const shown = (c) => `${dryRun ? "would " : ""}${c.text} (key ${c.key})`;
|
|
564
|
+
if (!out.json)
|
|
565
|
+
out.write(`${source.file}: ${count} agent${count === 1 ? "" : "s"}${dryRun ? ". Dry run: nothing is changed." : "."}`);
|
|
566
|
+
let made = 0;
|
|
567
|
+
let result;
|
|
568
|
+
try {
|
|
569
|
+
result = await api.deploy(source, {
|
|
570
|
+
dryRun,
|
|
571
|
+
prune: has(args, "prune"),
|
|
572
|
+
pruneMemory: has(args, "prune-memory"),
|
|
573
|
+
onChange: (change) => {
|
|
574
|
+
made++;
|
|
575
|
+
if (out.json)
|
|
576
|
+
return;
|
|
577
|
+
out.write(shown(change));
|
|
578
|
+
if (change.action === "add-trigger" && change.secret)
|
|
579
|
+
out.write(` secret ${change.secret} (shown this once: each of its calls carries it; keep it now)`);
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
catch (error) {
|
|
584
|
+
if (made && !out.json)
|
|
585
|
+
out.error(`Stopped after ${made} change${made === 1 ? "" : "s"}. Run \`${me} agents deploy\` again to make the rest: each change's key makes a rerun safe.`);
|
|
586
|
+
throw error;
|
|
587
|
+
}
|
|
588
|
+
if (out.json) {
|
|
589
|
+
out.write(JSON.stringify(result));
|
|
590
|
+
return 0;
|
|
591
|
+
}
|
|
592
|
+
if (dryRun)
|
|
593
|
+
for (const change of result.changes)
|
|
594
|
+
out.write(shown(change));
|
|
595
|
+
if (result.unchanged.length)
|
|
596
|
+
out.write(`unchanged: ${result.unchanged.join(", ")}`);
|
|
597
|
+
for (const kept of result.leftAlone)
|
|
598
|
+
out.write(`left alone: ${kept.agent} (${kept.why})`);
|
|
599
|
+
const n = result.changes.length;
|
|
600
|
+
out.write(n === 0
|
|
601
|
+
? `Nothing to change: your agents match ${source.file}.`
|
|
602
|
+
: dryRun
|
|
603
|
+
? `${n} change${n === 1 ? "" : "s"} planned. Run \`${me} agents deploy\` to make ${n === 1 ? "it" : "them"}.`
|
|
604
|
+
: `Done: ${n} change${n === 1 ? "" : "s"}.`);
|
|
605
|
+
return 0;
|
|
606
|
+
}
|
|
607
|
+
function say(out, human, value) {
|
|
608
|
+
out.write(out.json ? JSON.stringify(value) : human);
|
|
609
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { Runtime } from "./client.js";
|
|
2
|
+
import { type Agent, type AgentDefinition, type AgentTrigger, type AgentTriggerKind, type CreateAgentTrigger } from "./products/agents.js";
|
|
3
|
+
/** One trigger as the file writes it. `paused` holds it, saying why. */
|
|
4
|
+
export type AgentsFileTrigger = {
|
|
5
|
+
kind: AgentTriggerKind;
|
|
6
|
+
config: Record<string, unknown>;
|
|
7
|
+
paused?: string;
|
|
8
|
+
};
|
|
9
|
+
/** One agent as the file writes it: a harness template and a use fill in
|
|
10
|
+
* what it leaves out, then each definition field it sets. */
|
|
11
|
+
export type AgentsFileAgent = Omit<Partial<AgentDefinition>, "template"> & {
|
|
12
|
+
/** A harness: claude-code, codex, gemini-cli, claude-agent-sdk,
|
|
13
|
+
* openai-agents-sdk. Fills in `command` and `secrets`. */
|
|
14
|
+
template?: string;
|
|
15
|
+
/** support or team: a size and bounds for that use (`agents.uses`). */
|
|
16
|
+
use?: "support" | "team";
|
|
17
|
+
/** A file of the repo, relative to runtime.yml, read as `instructions`. */
|
|
18
|
+
instructionsFile?: string;
|
|
19
|
+
/** Absent: none. A deploy removes the triggers the file does not name. */
|
|
20
|
+
triggers?: AgentsFileTrigger[];
|
|
21
|
+
};
|
|
22
|
+
/** runtime.yml, as parsed. */
|
|
23
|
+
export type AgentsFile = {
|
|
24
|
+
agents: Record<string, AgentsFileAgent>;
|
|
25
|
+
};
|
|
26
|
+
/** A file read from disk (`loadAgentsFile`): its parsed text, its name for
|
|
27
|
+
* messages, a reader for `instructionsFile`, and the line of a field. */
|
|
28
|
+
export type AgentsSource = {
|
|
29
|
+
file: string;
|
|
30
|
+
config: unknown;
|
|
31
|
+
readFile?: (path: string) => string;
|
|
32
|
+
line?: (path: readonly (string | number)[]) => number | undefined;
|
|
33
|
+
};
|
|
34
|
+
/** One agent as a deploy wants it. */
|
|
35
|
+
export type DesiredAgent = {
|
|
36
|
+
name: string;
|
|
37
|
+
definition: AgentDefinition;
|
|
38
|
+
triggers: AgentsFileTrigger[];
|
|
39
|
+
};
|
|
40
|
+
/** What a deploy reads and changes, by the SDK over HTTP or by the API's
|
|
41
|
+
* own store. Each change gets its idempotency key. */
|
|
42
|
+
export type AgentsDeployPort = {
|
|
43
|
+
list(): Promise<Agent[]>;
|
|
44
|
+
create(input: {
|
|
45
|
+
name: string;
|
|
46
|
+
definition: AgentDefinition;
|
|
47
|
+
labels: Record<string, string>;
|
|
48
|
+
}, key: string): Promise<Agent>;
|
|
49
|
+
update(agentId: string, definition: AgentDefinition, key: string): Promise<Agent>;
|
|
50
|
+
delete(agentId: string, key: string): Promise<void>;
|
|
51
|
+
triggers(agentId: string): Promise<AgentTrigger[]>;
|
|
52
|
+
addTrigger(agentId: string, input: CreateAgentTrigger, key: string): Promise<AgentTrigger>;
|
|
53
|
+
pauseTrigger(triggerId: string, why: string, key: string): Promise<AgentTrigger>;
|
|
54
|
+
resumeTrigger(triggerId: string, key: string): Promise<AgentTrigger>;
|
|
55
|
+
removeTrigger(triggerId: string, key: string): Promise<void>;
|
|
56
|
+
/** How many memory files the agent holds: deleting it deletes them. */
|
|
57
|
+
memoryFiles(agentId: string): Promise<number>;
|
|
58
|
+
};
|
|
59
|
+
export type AgentsDeployChange = {
|
|
60
|
+
action: "create";
|
|
61
|
+
agent: string;
|
|
62
|
+
definition: AgentDefinition;
|
|
63
|
+
key: string;
|
|
64
|
+
text: string;
|
|
65
|
+
} | {
|
|
66
|
+
action: "update";
|
|
67
|
+
agent: string;
|
|
68
|
+
agentId: string;
|
|
69
|
+
fromVersion: number;
|
|
70
|
+
fields: string[];
|
|
71
|
+
definition: AgentDefinition;
|
|
72
|
+
key: string;
|
|
73
|
+
text: string;
|
|
74
|
+
} | {
|
|
75
|
+
action: "delete";
|
|
76
|
+
agent: string;
|
|
77
|
+
agentId: string;
|
|
78
|
+
key: string;
|
|
79
|
+
text: string;
|
|
80
|
+
} | {
|
|
81
|
+
action: "add-trigger";
|
|
82
|
+
agent: string;
|
|
83
|
+
agentId: string | null;
|
|
84
|
+
trigger: AgentsFileTrigger;
|
|
85
|
+
key: string;
|
|
86
|
+
text: string;
|
|
87
|
+
/** Once made: its id, and a webhook's secret, which the API answers
|
|
88
|
+
* this once and never again (a dry run has neither). */
|
|
89
|
+
triggerId?: string;
|
|
90
|
+
secret?: string;
|
|
91
|
+
} | {
|
|
92
|
+
action: "pause-trigger";
|
|
93
|
+
agent: string;
|
|
94
|
+
triggerId: string;
|
|
95
|
+
why: string;
|
|
96
|
+
key: string;
|
|
97
|
+
text: string;
|
|
98
|
+
} | {
|
|
99
|
+
action: "resume-trigger";
|
|
100
|
+
agent: string;
|
|
101
|
+
triggerId: string;
|
|
102
|
+
key: string;
|
|
103
|
+
text: string;
|
|
104
|
+
} | {
|
|
105
|
+
action: "remove-trigger";
|
|
106
|
+
agent: string;
|
|
107
|
+
triggerId: string;
|
|
108
|
+
key: string;
|
|
109
|
+
text: string;
|
|
110
|
+
};
|
|
111
|
+
export type AgentsDeployResult = {
|
|
112
|
+
file: string;
|
|
113
|
+
dryRun: boolean;
|
|
114
|
+
/** In order; applied unless dryRun. */
|
|
115
|
+
changes: AgentsDeployChange[];
|
|
116
|
+
/** Agents the file names whose definition and triggers already match. */
|
|
117
|
+
unchanged: string[];
|
|
118
|
+
/** Agents of the account the file does not name, kept, and why. */
|
|
119
|
+
leftAlone: {
|
|
120
|
+
agent: string;
|
|
121
|
+
why: string;
|
|
122
|
+
}[];
|
|
123
|
+
};
|
|
124
|
+
export type AgentsDeployOptions = {
|
|
125
|
+
/** Plan only: read the account, change nothing. */
|
|
126
|
+
dryRun?: boolean;
|
|
127
|
+
/** Delete the agents an earlier deploy made that the file no longer names.
|
|
128
|
+
* One that still holds memory files is kept (leftAlone) unless pruneMemory. */
|
|
129
|
+
prune?: boolean;
|
|
130
|
+
/** With prune: delete such an agent even when it holds memory files, and
|
|
131
|
+
* the files with it, for good. */
|
|
132
|
+
pruneMemory?: boolean;
|
|
133
|
+
/** The file's name in messages; runtime.yml by default. */
|
|
134
|
+
file?: string;
|
|
135
|
+
/** Reads `instructionsFile`, relative to the file. */
|
|
136
|
+
readFile?: (path: string) => string;
|
|
137
|
+
/** Called as each change is made. */
|
|
138
|
+
onChange?: (change: AgentsDeployChange) => void;
|
|
139
|
+
};
|
|
140
|
+
/** The label a deploy puts on the agents it makes; prune deletes only these. */
|
|
141
|
+
export declare const MANAGED_LABEL: {
|
|
142
|
+
readonly "managed-by": "runtime.yml";
|
|
143
|
+
};
|
|
144
|
+
/** The file's agents, checked as the API checks them, with every mistake
|
|
145
|
+
* named by file, agent and field (and line, when the source knows it).
|
|
146
|
+
* Throws a RuntimeError `invalid_file` listing them all. */
|
|
147
|
+
export declare function checkAgentsFile(input: AgentsFile | AgentsSource, options?: AgentsDeployOptions): DesiredAgent[];
|
|
148
|
+
/** Makes the account's agents match the file: the plan, then (unless
|
|
149
|
+
* dryRun) each change in order. A failed change stops the deploy; what was
|
|
150
|
+
* done stays done, and running it again finishes the rest. */
|
|
151
|
+
export declare function deployAgents(port: AgentsDeployPort, input: AgentsFile | AgentsSource, options?: AgentsDeployOptions): Promise<AgentsDeployResult>;
|
|
152
|
+
/** What a deploy would change, reading the account through `port`. */
|
|
153
|
+
export declare function planAgents(port: AgentsDeployPort, desired: DesiredAgent[], options?: {
|
|
154
|
+
prune?: boolean;
|
|
155
|
+
pruneMemory?: boolean;
|
|
156
|
+
}): Promise<Pick<AgentsDeployResult, "changes" | "unchanged" | "leftAlone">>;
|
|
157
|
+
/** The fields whose value differs. A field the file leaves out matches the
|
|
158
|
+
* API's default for it, and a snapshot's size is the snapshot's. */
|
|
159
|
+
export declare function changedFields(current: AgentDefinition, desired: AgentDefinition): string[];
|
|
160
|
+
/** JSON with every map's keys sorted, so equal values read equal. */
|
|
161
|
+
export declare function canonical(value: unknown): string;
|
|
162
|
+
/** Whether `value`, as JSON, is at most about `limit` bytes. Walks with a
|
|
163
|
+
* budget and stops when it is spent, so a value of shared parts (each part
|
|
164
|
+
* counted every time it is reached) or a cycle is refused at once, never
|
|
165
|
+
* expanded. */
|
|
166
|
+
export declare function within(value: unknown, limit: number): boolean;
|
|
167
|
+
/** The agents client with `deploy`. It lives here, not on `runtime.agents`,
|
|
168
|
+
* so code that loads only the main client (Runtime's own hub among it) never
|
|
169
|
+
* loads the deploy (agents/hub-loads.ts). */
|
|
170
|
+
export type AgentsClient = Runtime["agents"] & {
|
|
171
|
+
/** Makes your agents match a runtime.yml's `agents:` section: creates
|
|
172
|
+
* the missing, makes a new version of a changed one (an unchanged one
|
|
173
|
+
* gets none), and adds, pauses, resumes or removes triggers. Deletes an
|
|
174
|
+
* agent only with `prune`, and only one a deploy made, and one holding
|
|
175
|
+
* memory files only with `pruneMemory` as well. `dryRun` reads
|
|
176
|
+
* and plans, changing nothing. Every change has an idempotency key, so a
|
|
177
|
+
* rerun is safe. The same plan as `runtime agents deploy`.
|
|
178
|
+
*
|
|
179
|
+
* import { agents, loadAgentsFile } from "withruntime/agents";
|
|
180
|
+
* const plan = await agents().deploy(loadAgentsFile("runtime.yml"), { dryRun: true });
|
|
181
|
+
* for (const change of plan.changes) console.log(change.text);
|
|
182
|
+
*/
|
|
183
|
+
deploy(file: AgentsFile | AgentsSource, options?: AgentsDeployOptions): Promise<AgentsDeployResult>;
|
|
184
|
+
};
|
|
185
|
+
/** `api` with `deploy`. */
|
|
186
|
+
export declare function withDeploy(api: Runtime["agents"]): AgentsClient;
|