withruntime 0.23.0 → 0.33.0

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.
Files changed (76) hide show
  1. package/COMPATIBILITY.md +64 -3
  2. package/E2B.md +1 -1
  3. package/README.md +36 -2
  4. package/README.src.md +35 -1
  5. package/compatibility-lock.json +3 -3
  6. package/dist/agents/browser.d.ts +12 -0
  7. package/dist/agents/browser.js +12 -0
  8. package/dist/agents/index.d.ts +7 -7
  9. package/dist/agents/index.js +7 -8
  10. package/dist/agents-cli.d.ts +1 -1
  11. package/dist/agents-cli.js +250 -3
  12. package/dist/agents-deploy.d.ts +186 -0
  13. package/dist/agents-deploy.js +752 -0
  14. package/dist/agents-file.d.ts +19 -0
  15. package/dist/agents-file.js +135 -0
  16. package/dist/apps/index.d.ts +10 -0
  17. package/dist/apps/index.js +11 -0
  18. package/dist/apps-cli.d.ts +3 -1
  19. package/dist/apps-cli.js +285 -38
  20. package/dist/blaxel/errors.js +2 -1
  21. package/dist/ci/index.d.ts +10 -0
  22. package/dist/ci/index.js +11 -0
  23. package/dist/ci-cli.d.ts +10 -0
  24. package/dist/ci-cli.js +343 -0
  25. package/dist/cli.d.ts +18 -7
  26. package/dist/cli.js +775 -85
  27. package/dist/daytona/errors.js +2 -1
  28. package/dist/e2b/errors.js +2 -1
  29. package/dist/e2b/filesystem.d.ts +1 -0
  30. package/dist/e2b/filesystem.js +1 -1
  31. package/dist/e2b/sandbox.d.ts +11 -2
  32. package/dist/e2b/sandbox.js +22 -6
  33. package/dist/errors.d.ts +11 -4
  34. package/dist/errors.js +27 -4
  35. package/dist/fly/index.d.ts +102 -0
  36. package/dist/fly/index.js +930 -0
  37. package/dist/index.d.ts +7 -3
  38. package/dist/machine.d.ts +10 -6
  39. package/dist/machine.js +14 -6
  40. package/dist/modal/index.d.ts +34 -0
  41. package/dist/modal/index.js +128 -22
  42. package/dist/products/agents.d.ts +101 -3
  43. package/dist/products/agents.js +49 -0
  44. package/dist/products/apps.d.ts +206 -10
  45. package/dist/products/apps.js +172 -1
  46. package/dist/products/ci.d.ts +332 -0
  47. package/dist/products/ci.js +101 -0
  48. package/dist/products/index.d.ts +8 -0
  49. package/dist/products/index.js +15 -0
  50. package/dist/products/jobs.d.ts +105 -5
  51. package/dist/products/jobs.js +47 -3
  52. package/dist/products/network.d.ts +13 -0
  53. package/dist/products/observability.d.ts +1 -1
  54. package/dist/products/plans.d.ts +131 -0
  55. package/dist/products/plans.js +24 -0
  56. package/dist/products/reservations.d.ts +108 -0
  57. package/dist/products/reservations.js +41 -0
  58. package/dist/products/resources.d.ts +2 -1
  59. package/dist/products/secrets.d.ts +90 -6
  60. package/dist/products/secrets.js +8 -2
  61. package/dist/proxy.d.ts +3 -3
  62. package/dist/proxy.js +20 -0
  63. package/dist/sandbox.d.ts +29 -1
  64. package/dist/sandbox.js +56 -3
  65. package/dist/snapshots.d.ts +1 -1
  66. package/dist/switched-off.d.ts +5 -0
  67. package/dist/switched-off.js +8 -0
  68. package/dist/tar.d.ts +1 -1
  69. package/dist/tar.js +19 -1
  70. package/dist/transport.d.ts +1 -1
  71. package/dist/transport.js +48 -9
  72. package/dist/types.d.ts +35 -4
  73. package/dist/vercel/errors.d.ts +1 -1
  74. package/dist/vercel/errors.js +2 -1
  75. package/dist/vercel/snapshot.js +4 -2
  76. package/package.json +23 -6
@@ -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 ? AGENT_TEMPLATES[template].definition : {}),
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;