@dynamicagents/plugins 0.11.1 → 0.13.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 (134) hide show
  1. package/README.md +59 -79
  2. package/dist/browser/index.d.ts +0 -2
  3. package/dist/browser/index.js +21 -27
  4. package/dist/claude-code/cards.d.ts +53 -0
  5. package/dist/claude-code/cards.js +272 -0
  6. package/dist/claude-code/config.d.ts +73 -31
  7. package/dist/claude-code/config.js +0 -2
  8. package/dist/claude-code/credentials.d.ts +21 -9
  9. package/dist/claude-code/credentials.js +43 -9
  10. package/dist/claude-code/egress.d.ts +15 -14
  11. package/dist/claude-code/egress.js +51 -14
  12. package/dist/claude-code/events.d.ts +153 -9
  13. package/dist/claude-code/events.js +289 -58
  14. package/dist/claude-code/github.d.ts +39 -0
  15. package/dist/claude-code/github.js +82 -0
  16. package/dist/claude-code/index.d.ts +24 -80
  17. package/dist/claude-code/index.js +19 -234
  18. package/dist/claude-code/model.d.ts +152 -0
  19. package/dist/claude-code/model.js +342 -0
  20. package/dist/claude-code/run.d.ts +283 -92
  21. package/dist/claude-code/run.js +620 -114
  22. package/dist/claude-code/session.d.ts +131 -0
  23. package/dist/claude-code/session.js +285 -0
  24. package/dist/claude-code/spec.d.ts +46 -0
  25. package/dist/claude-code/spec.js +83 -0
  26. package/dist/claude-code/verified.d.ts +15 -0
  27. package/dist/claude-code/verified.js +15 -0
  28. package/dist/computer/context.d.ts +19 -0
  29. package/dist/computer/context.js +222 -0
  30. package/dist/computer/file-lock.d.ts +5 -0
  31. package/dist/computer/file-lock.js +40 -0
  32. package/dist/computer/gate.d.ts +12 -12
  33. package/dist/computer/gate.js +12 -12
  34. package/dist/computer/index.d.ts +57 -255
  35. package/dist/computer/index.js +98 -1039
  36. package/dist/computer/paths.d.ts +47 -22
  37. package/dist/computer/paths.js +64 -49
  38. package/dist/computer/proxy.d.ts +45 -0
  39. package/dist/computer/proxy.js +234 -0
  40. package/dist/computer/render.d.ts +27 -38
  41. package/dist/computer/render.js +32 -65
  42. package/dist/computer/tools-exec.d.ts +3 -0
  43. package/dist/computer/tools-exec.js +268 -0
  44. package/dist/computer/tools-file.d.ts +12 -0
  45. package/dist/computer/tools-file.js +64 -0
  46. package/dist/computer/tools-grep.d.ts +3 -0
  47. package/dist/computer/tools-grep.js +129 -0
  48. package/dist/repo/checkout.d.ts +35 -6
  49. package/dist/repo/checkout.js +64 -6
  50. package/dist/repo/context.d.ts +135 -0
  51. package/dist/repo/context.js +582 -0
  52. package/dist/repo/index.d.ts +79 -57
  53. package/dist/repo/index.js +118 -1112
  54. package/dist/repo/tools-checks.d.ts +3 -0
  55. package/dist/repo/tools-checks.js +112 -0
  56. package/dist/repo/tools-clone.d.ts +4 -0
  57. package/dist/repo/tools-clone.js +192 -0
  58. package/dist/repo/tools-pr.d.ts +14 -0
  59. package/dist/repo/tools-pr.js +196 -0
  60. package/dist/repo/tools-review.d.ts +12 -0
  61. package/dist/repo/tools-review.js +393 -0
  62. package/dist/repo/tools-worktree.d.ts +4 -0
  63. package/dist/repo/tools-worktree.js +305 -0
  64. package/dist/repo/tools-worktrees.d.ts +12 -0
  65. package/dist/repo/tools-worktrees.js +48 -0
  66. package/dist/repo/url.d.ts +2 -2
  67. package/dist/repo/url.js +7 -7
  68. package/dist/scratch/index.d.ts +4 -4
  69. package/dist/scratch/index.js +12 -11
  70. package/dist/{computer → workspace}/advisory.d.ts +33 -20
  71. package/dist/{computer → workspace}/advisory.js +32 -7
  72. package/dist/workspace/ca-trust.d.ts +95 -0
  73. package/dist/workspace/ca-trust.js +312 -0
  74. package/dist/workspace/container-deps.d.ts +54 -0
  75. package/dist/workspace/container-deps.js +224 -0
  76. package/dist/workspace/container-fault.d.ts +38 -0
  77. package/dist/workspace/container-fault.js +73 -0
  78. package/dist/workspace/exec.d.ts +94 -0
  79. package/dist/workspace/exec.js +153 -0
  80. package/dist/workspace/format.d.ts +36 -0
  81. package/dist/workspace/format.js +57 -0
  82. package/dist/workspace/git-host.d.ts +79 -0
  83. package/dist/workspace/git-host.js +226 -0
  84. package/dist/workspace/git-identity.d.ts +57 -0
  85. package/dist/workspace/git-identity.js +147 -0
  86. package/dist/workspace/index.d.ts +43 -47
  87. package/dist/workspace/index.js +52 -112
  88. package/dist/workspace/install-job.d.ts +121 -0
  89. package/dist/workspace/install-job.js +866 -0
  90. package/dist/{computer → workspace}/install.d.ts +15 -19
  91. package/dist/{computer → workspace}/install.js +8 -11
  92. package/dist/workspace/object.d.ts +502 -0
  93. package/dist/workspace/object.js +1427 -0
  94. package/dist/workspace/open.d.ts +95 -0
  95. package/dist/workspace/open.js +63 -0
  96. package/dist/workspace/read.d.ts +16 -0
  97. package/dist/workspace/read.js +22 -0
  98. package/dist/workspace/shell.d.ts +45 -0
  99. package/dist/workspace/shell.js +80 -0
  100. package/dist/workspace/sync.d.ts +111 -0
  101. package/dist/workspace/sync.js +124 -0
  102. package/dist/workspace/wake.d.ts +19 -0
  103. package/dist/workspace/wake.js +10 -0
  104. package/package.json +28 -42
  105. package/dist/arc-agi/analysis.d.ts +0 -336
  106. package/dist/arc-agi/analysis.js +0 -829
  107. package/dist/arc-agi/client.d.ts +0 -82
  108. package/dist/arc-agi/client.js +0 -113
  109. package/dist/arc-agi/game-tools.d.ts +0 -25
  110. package/dist/arc-agi/game-tools.js +0 -26
  111. package/dist/arc-agi/index.d.ts +0 -42
  112. package/dist/arc-agi/index.js +0 -175
  113. package/dist/arc-agi/main-agent.d.ts +0 -27
  114. package/dist/arc-agi/main-agent.js +0 -65
  115. package/dist/arc-agi/recipe.d.ts +0 -51
  116. package/dist/arc-agi/recipe.js +0 -100
  117. package/dist/arc-agi/scorecard.d.ts +0 -118
  118. package/dist/arc-agi/scorecard.js +0 -163
  119. package/dist/arc-agi/soul.d.ts +0 -40
  120. package/dist/arc-agi/soul.js +0 -90
  121. package/dist/arc-agi/store.d.ts +0 -154
  122. package/dist/arc-agi/store.js +0 -216
  123. package/dist/arc-agi/tools.d.ts +0 -36
  124. package/dist/arc-agi/tools.js +0 -576
  125. package/dist/arc-agi/types.d.ts +0 -212
  126. package/dist/arc-agi/types.js +0 -19
  127. package/dist/claude-code/recipe.d.ts +0 -53
  128. package/dist/claude-code/recipe.js +0 -100
  129. package/dist/computer/read.d.ts +0 -137
  130. package/dist/computer/read.js +0 -203
  131. package/dist/recall/index.d.ts +0 -99
  132. package/dist/recall/index.js +0 -171
  133. package/dist/triage/index.d.ts +0 -355
  134. package/dist/triage/index.js +0 -302
@@ -1,82 +0,0 @@
1
- import { type CookieJar, type FrameResponse, type GameInfo, type ScorecardSummary } from "./types.js";
2
- /**
3
- * Typed client for the ARC-AGI-3 REST API.
4
- *
5
- * Two Workers-specific concerns are handled explicitly, because `fetch` in a
6
- * Worker manages neither:
7
- *
8
- * - **Session affinity**: the API pins a game session to a load-balancer via
9
- * `AWSALB*` cookies returned on RESET/ACTION responses; they MUST be echoed on
10
- * every subsequent request. The jar is passed in and returned as plain data
11
- * (not a stateful client), so it checkpoints into the workspace and survives
12
- * isolate eviction between chunks.
13
- * - **Rate limiting**: 600 RPM → 429; we honor `Retry-After` with bounded
14
- * exponential backoff. Exhausted retries and 5xx throw (transient — the
15
- * Workflow step retries and the runner resumes from its checkpoint); a 401
16
- * throws a tagged deterministic error (bad key — a terminal failure).
17
- * - **Cancellation**: a client built with a `signal` stops at it — the `fetch` and
18
- * the backoff between retries alike. `Retry-After` is honoured up to
19
- * {@link MAX_RETRY_AFTER_MS} and no further: the header is the server's to set,
20
- * and an uncapped one parks a tool for as long as the server likes.
21
- */
22
- export interface ArcClient {
23
- listGames(cookies: CookieJar): Promise<{
24
- games: GameInfo[];
25
- cookies: CookieJar;
26
- }>;
27
- openScorecard(cookies: CookieJar): Promise<{
28
- cardId: string;
29
- cookies: CookieJar;
30
- }>;
31
- /**
32
- * The whole card, with one `environments` entry per game played on it.
33
- * Readable while the card is still open, which is what lets a result be
34
- * reported without anything closing a card.
35
- */
36
- getScorecard(cardId: string, cookies: CookieJar): Promise<{
37
- summary: ScorecardSummary;
38
- cookies: CookieJar;
39
- }>;
40
- reset(input: {
41
- gameId: string;
42
- cardId: string;
43
- guid?: string;
44
- }, cookies: CookieJar): Promise<{
45
- frame: FrameResponse;
46
- cookies: CookieJar;
47
- }>;
48
- act(input: {
49
- action: number;
50
- gameId: string;
51
- guid: string;
52
- x?: number;
53
- y?: number;
54
- note?: string;
55
- }, cookies: CookieJar): Promise<{
56
- frame: FrameResponse;
57
- cookies: CookieJar;
58
- }>;
59
- }
60
- /**
61
- * The longest a `Retry-After` is waited out. A minute covers the API's own
62
- * per-minute rate window; past that the header is either hostile or describing an
63
- * outage, and a retry loop is the wrong place to sit through either.
64
- */
65
- export declare const MAX_RETRY_AFTER_MS = 60000;
66
- /** Message prefix of the deterministic (non-retryable) auth error. */
67
- export declare const ARC_AUTH_ERROR = "arc-client: unauthorized";
68
- export interface ArcClientOptions {
69
- fetchFn?: typeof fetch;
70
- /** Injected for tests; defaults to a real timed sleep. */
71
- sleep?: (ms: number) => Promise<void>;
72
- /** Max attempts per request before a 429/5xx becomes a thrown transient fault. */
73
- maxAttempts?: number;
74
- /**
75
- * Stops every request this client makes, and every wait between them. Taken at
76
- * construction, so a client lives no longer than the signal it stops on: a tool
77
- * builds one per call, from that call's signal — see
78
- * {@link file://./tools.ts buildArcGameTools}.
79
- */
80
- signal?: AbortSignal;
81
- }
82
- export declare function makeArcClient(apiKey: string, options?: ArcClientOptions): ArcClient;
@@ -1,113 +0,0 @@
1
- import { withAbort } from "@dynamicagents/core";
2
- import { ARC_BASE_URL } from "./types.js";
3
- /**
4
- * The longest a `Retry-After` is waited out. A minute covers the API's own
5
- * per-minute rate window; past that the header is either hostile or describing an
6
- * outage, and a retry loop is the wrong place to sit through either.
7
- */
8
- export const MAX_RETRY_AFTER_MS = 60_000;
9
- /** Message prefix of the deterministic (non-retryable) auth error. */
10
- export const ARC_AUTH_ERROR = "arc-client: unauthorized";
11
- const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
12
- /** Merge `set-cookie` headers from a response into the jar (name=value pairs). */
13
- function mergeCookies(jar, res) {
14
- const next = { ...jar };
15
- for (const raw of res.headers.getSetCookie()) {
16
- const pair = raw.split(";", 1)[0];
17
- const eq = pair.indexOf("=");
18
- if (eq <= 0)
19
- continue;
20
- next[pair.slice(0, eq).trim()] = pair.slice(eq + 1).trim();
21
- }
22
- return next;
23
- }
24
- /** Serialize the jar to a `Cookie` request header, or undefined when empty. */
25
- function cookieHeader(jar) {
26
- const parts = Object.entries(jar).map(([k, v]) => `${k}=${v}`);
27
- return parts.length === 0 ? undefined : parts.join("; ");
28
- }
29
- export function makeArcClient(apiKey, options = {}) {
30
- const doFetch = options.fetchFn ?? fetch;
31
- const sleep = options.sleep ?? realSleep;
32
- const maxAttempts = options.maxAttempts ?? 4;
33
- const signal = options.signal;
34
- async function request(path, init, cookies) {
35
- const headers = {
36
- "X-API-Key": apiKey,
37
- accept: "application/json"
38
- };
39
- if (init.body !== undefined)
40
- headers["content-type"] = "application/json";
41
- const cookie = cookieHeader(cookies);
42
- if (cookie)
43
- headers["cookie"] = cookie;
44
- let attempt = 0;
45
- for (;;) {
46
- attempt++;
47
- const res = await doFetch(`${ARC_BASE_URL}${path}`, {
48
- method: init.method,
49
- headers,
50
- body: init.body === undefined ? undefined : JSON.stringify(init.body),
51
- ...(signal ? { signal } : {})
52
- });
53
- if (res.ok) {
54
- const nextCookies = mergeCookies(cookies, res);
55
- const data = (await res.json());
56
- return { data, cookies: nextCookies };
57
- }
58
- if (res.status === 401 || res.status === 403) {
59
- throw new Error(`${ARC_AUTH_ERROR} (HTTP ${res.status})`);
60
- }
61
- // 429 / 5xx: retry with backoff, honoring Retry-After when present.
62
- const retryable = res.status === 429 || res.status >= 500;
63
- if (!retryable || attempt >= maxAttempts) {
64
- throw new Error(`arc-client: ${init.method} ${path} failed (HTTP ${res.status})`);
65
- }
66
- const retryAfter = Number(res.headers.get("retry-after"));
67
- const backoffMs = Number.isFinite(retryAfter) && retryAfter > 0
68
- ? Math.min(retryAfter * 1000, MAX_RETRY_AFTER_MS)
69
- : Math.min(1000 * 2 ** (attempt - 1), 8000);
70
- // The wait between attempts is the longest thing this loop does, so it is
71
- // the part a cancel most needs to reach.
72
- await withAbort(signal, sleep(backoffMs));
73
- }
74
- }
75
- return {
76
- async listGames(cookies) {
77
- const { data, cookies: next } = await request("/api/games", { method: "GET" }, cookies);
78
- return { games: data, cookies: next };
79
- },
80
- async openScorecard(cookies) {
81
- const { data, cookies: next } = await request("/api/scorecard/open", { method: "POST", body: {} }, cookies);
82
- return { cardId: data.card_id, cookies: next };
83
- },
84
- async getScorecard(cardId, cookies) {
85
- const { data, cookies: next } = await request(`/api/scorecard/${encodeURIComponent(cardId)}`, { method: "GET" }, cookies);
86
- return { summary: data, cookies: next };
87
- },
88
- async reset(input, cookies) {
89
- const body = {
90
- game_id: input.gameId,
91
- card_id: input.cardId
92
- };
93
- if (input.guid !== undefined)
94
- body.guid = input.guid;
95
- const { data, cookies: next } = await request("/api/cmd/RESET", { method: "POST", body }, cookies);
96
- return { frame: data, cookies: next };
97
- },
98
- async act(input, cookies) {
99
- const body = {
100
- game_id: input.gameId,
101
- guid: input.guid
102
- };
103
- if (input.action === 6) {
104
- body.x = input.x;
105
- body.y = input.y;
106
- }
107
- if (input.note !== undefined)
108
- body.reasoning = { text: input.note };
109
- const { data, cookies: next } = await request(`/api/cmd/ACTION${input.action}`, { method: "POST", body }, cookies);
110
- return { frame: data, cookies: next };
111
- }
112
- };
113
- }
@@ -1,25 +0,0 @@
1
- import { type ToolSet } from "ai";
2
- import type { ArcClient } from "./client.js";
3
- /**
4
- * The **main agent's** ARC tool: the game catalogue, and nothing else.
5
- *
6
- * It used to also own the scorecard lifecycle — open a card, name it in each
7
- * play's params, close it for the score. That modelled a lifecycle the API
8
- * already manages (it auto-closes an idle card), and made every play depend on
9
- * the model getting the bookkeeping right. The card is now leased by the recipe
10
- * (see {@link file://./scorecard.ts}) and never named here, so the only thing the
11
- * main agent still needs from ARC is the exact game id to delegate a play with.
12
- *
13
- * Handlers are exported separately from the `tool()` wiring so they unit-test
14
- * without an LLM, and the client is closed over so it is never model input.
15
- */
16
- export interface ArcGamesDeps {
17
- client: ArcClient;
18
- }
19
- /** One line per game: id, title, and how it is played. */
20
- export declare function renderGames(games: {
21
- game_id: string;
22
- title?: string;
23
- tags?: string[];
24
- }[]): string;
25
- export declare function buildArcGamesTools(deps: ArcGamesDeps): ToolSet;
@@ -1,26 +0,0 @@
1
- import { tool } from "ai";
2
- import { z } from "zod";
3
- /** One line per game: id, title, and how it is played. */
4
- export function renderGames(games) {
5
- if (games.length === 0)
6
- return "(the API listed no games)";
7
- return games
8
- .map((g) => {
9
- const title = g.title ? ` (${g.title})` : "";
10
- const tags = g.tags?.length ? ` [${g.tags.join(", ")}]` : "";
11
- return `- ${g.game_id}${title}${tags}`;
12
- })
13
- .join("\n");
14
- }
15
- export function buildArcGamesTools(deps) {
16
- return {
17
- arc_list_games: tool({
18
- description: "List the ARC-AGI-3 games available to play, with their exact game ids and tags describing how each is played. Use this to find the full game id before delegating a play.",
19
- inputSchema: z.object({}),
20
- execute: async () => {
21
- const { games } = await deps.client.listGames({});
22
- return renderGames(games);
23
- }
24
- })
25
- };
26
- }
@@ -1,42 +0,0 @@
1
- import type { AgentPlugin } from "@dynamicagents/core";
2
- import { ARC_GAME_TYPE } from "./recipe.js";
3
- import { type ScorecardStore } from "./scorecard.js";
4
- import { ARC_GAME_FAMILY } from "./tools.js";
5
- import type { ArcRuntime } from "./types.js";
6
- /**
7
- * `@dynamicagents/plugins/arc-agi` — play ARC-AGI-3 games.
8
- *
9
- * The stress test for the whole plugin contract, and the reason three of its
10
- * hooks exist. In the predecessor these were four leaks in the agent's Durable
11
- * Object — `resolveRuntime`, `arcScorecardDeps`, `leaseScorecard`/`leasePlay`,
12
- * and `enrichResult` — each a piece of ARC-specific policy living in code that
13
- * had no other reason to know what a scorecard was. Inverted, they are this
14
- * file.
15
- *
16
- * What the split makes visible: the *only* thing the agent still knows is that
17
- * it installed a plugin. Nothing in a loop, a workflow, or a DO names a card, a
18
- * guid, or a game.
19
- */
20
- /** Everything this plugin needs from its host. */
21
- export interface ArcAgiConfig {
22
- /** `ARC_API_KEY` — a secret the host must set. */
23
- apiKey: string;
24
- /**
25
- * The Durable Object's storage, for the `arc_scorecards` ledger.
26
- *
27
- * `DurableObjectStorage` rather than the `SqlStorage` that `ensureTables`
28
- * receives, because the query side builds a drizzle handle over it. The host
29
- * has it as `this.ctx.storage`.
30
- */
31
- storage: DurableObjectStorage;
32
- /**
33
- * Test override: an in-memory {@link ScorecardStore}. Supplying this skips the
34
- * table entirely, which is what lets the policy specs run with no SQLite.
35
- */
36
- store?: ScorecardStore;
37
- }
38
- export declare function arcAgi(config: ArcAgiConfig): AgentPlugin<ArcRuntime>;
39
- export { ARC_GAME_FAMILY, ARC_GAME_TYPE };
40
- export type { ArcRuntime, ScorecardStore };
41
- export { arcScorecardStore, makeScorecardStore } from "./store.js";
42
- export { ARC_GAME_RECIPE, ARC_GAME_SPEC } from "./recipe.js";
@@ -1,175 +0,0 @@
1
- import { definePlugin } from "@dynamicagents/core";
2
- import { makeArcClient } from "./client.js";
3
- import { buildArcGamesTools } from "./game-tools.js";
4
- import { ARC_GAME_SPEC, ARC_GAME_TYPE } from "./recipe.js";
5
- import { gameScoreReport, resolvePlayOn, resolveScorecard } from "./scorecard.js";
6
- import { arcScorecardStore, makeScorecardStore } from "./store.js";
7
- import { ARC_GAME_FAMILY, buildArcGameTools } from "./tools.js";
8
- export function arcAgi(config) {
9
- const { apiKey, storage } = config;
10
- // Built once per DO instance, like the plugin itself. `makeScorecardStore`
11
- // only constructs a drizzle handle — it issues no query until something asks —
12
- // so this is safe before `AgentDB` has run the store's DDL.
13
- let store = config.store;
14
- const deps = () => ({
15
- store: (store ??= makeScorecardStore(storage)),
16
- client: makeArcClient(apiKey)
17
- });
18
- /**
19
- * In-flight leases, collapsed so concurrent branches share one call.
20
- *
21
- * These were DO instance fields in the predecessor, and the plugin is built
22
- * per DO instance, so this closure is the same scope — but it is now the scope
23
- * of the thing that *cares*, rather than of the agent that merely hosted it.
24
- *
25
- * Load-bearing, not an optimization. All of a round's ready Subtasks execute
26
- * concurrently, and opening a card is a `fetch`, which opens the DO's input
27
- * gate — so without this, two branches starting together each find no live
28
- * card and each open one. It matters more for a play: RESET is also a `fetch`,
29
- * so two Subtasks for one game would each find no recorded guid and each open
30
- * a play. The store settles that race anyway (first guid written wins), but
31
- * only after a wasted run is already recorded on the card, so collapsing is
32
- * what keeps the card's history honest rather than merely cheap.
33
- */
34
- let leasingCard;
35
- const leasingPlays = new Map();
36
- /**
37
- * The card each execution *first* resolved onto, so a later chunk's lease can
38
- * be recognised as a different one. See {@link ArcAgiConfig} and the note on
39
- * `enrichResult`.
40
- *
41
- * In memory, and that is the honest limit: an isolate evicted between the
42
- * final chunk and the result loses the entry and simply cannot tell. That is
43
- * no worse than not tracking at all, and the common case — the parent
44
- * resolving the last chunk and then handling its result — keeps it warm.
45
- */
46
- const firstCard = new Map();
47
- const executionKey = (taskId, subtaskId) => `${taskId}:${subtaskId}`;
48
- const leaseScorecard = () => (leasingCard ??= resolveScorecard(deps()).finally(() => {
49
- leasingCard = undefined;
50
- }));
51
- const leasePlay = (gameId) => {
52
- const inFlight = leasingPlays.get(gameId);
53
- if (inFlight)
54
- return inFlight;
55
- // Keyed per game: different games legitimately open different plays on the
56
- // same card — but they must all be on *the same card*, so the play resolves
57
- // onto the collapsed lease rather than looking one up for itself. Calling
58
- // `resolvePlay` here instead would re-enter `resolveScorecard` per game and
59
- // undo the collapse entirely: two games starting together would each find
60
- // an empty ledger and each open a card.
61
- const pending = leaseScorecard()
62
- .then((card) => resolvePlayOn(deps(), card, gameId))
63
- .finally(() => {
64
- leasingPlays.delete(gameId);
65
- });
66
- leasingPlays.set(gameId, pending);
67
- return pending;
68
- };
69
- return definePlugin({
70
- key: "arc-agi",
71
- subtaskType: ARC_GAME_SPEC,
72
- toolFamilies: {
73
- [ARC_GAME_FAMILY]: (ctx) => buildArcGameTools(apiKey, ctx)
74
- },
75
- /**
76
- * The **game catalogue only**. Playing is a subagent's job, and the card it
77
- * plays on is leased below and never reaches a model — so the only thing the
78
- * main agent needs from ARC is the exact id to delegate a play with.
79
- */
80
- mainAgentTools: () => buildArcGamesTools({ client: makeArcClient(apiKey) }),
81
- // No `capability` here: it is on the subtask type, with the delegation
82
- // guidance it has to agree with. See `ARC_GAME_SPEC`.
83
- /**
84
- * Resolve the session state an execution needs and no model can supply: the
85
- * card, and the play on it.
86
- *
87
- * Neither is a decision. Which card is live is a fact about the clock, and a
88
- * guid is mintable only by RESET — a call a subagent must never make, since a
89
- * second RESET is a second run on the card that discards whatever the first
90
- * reached. Both are settled here and handed down.
91
- *
92
- * Called once per **chunk**, not once per run, and the repetition is
93
- * load-bearing twice over: each call restarts the card's reuse clock (which
94
- * keeps a long play's card alive), and each call re-resolves the same guid
95
- * from the store rather than opening anything.
96
- */
97
- async resolveRuntime(ctx) {
98
- const gameId = ctx.params.game_id;
99
- // A Subtask whose params never validated still reaches here. Resolve the
100
- // card alone and let the recipe's own validation report the missing game,
101
- // rather than RESETting on it and turning a clean failure into an API error.
102
- const resolved = gameId
103
- ? await leasePlay(gameId)
104
- : await leaseScorecard();
105
- // Remember the first card only. A later chunk that lands on a different
106
- // one has rolled over, and the play it names is not the play running.
107
- const key = executionKey(ctx.taskId, ctx.subtaskId);
108
- if (!firstCard.has(key))
109
- firstCard.set(key, resolved.cardId);
110
- return resolved;
111
- },
112
- /**
113
- * Append what only the parent can know to a completed execution's report:
114
- * the score.
115
- *
116
- * Nothing closes a scorecard any more, so the score is *read* from the card
117
- * once the play that earned it is done — which only this side can do, since
118
- * it alone knows the leased card and holds the jar pinned to it. The score
119
- * lands as an extra text part, and result parts are joined on delivery, so it
120
- * reaches the user and any dependent Subtask with no other change.
121
- *
122
- * Never fails the execution: a play that succeeded is not retroactively
123
- * broken by a rate-limited score read, so `gameScoreReport` swallows its own
124
- * errors and a null leaves the report as the child wrote it. Safe to repeat
125
- * on a Workflow step replay — the read is a GET.
126
- */
127
- async enrichResult(ctx, result) {
128
- const gameId = ctx.request.params.game_id;
129
- const cardId = ctx.runtime.cardId;
130
- const key = executionKey(ctx.request.taskId, ctx.request.subtaskId);
131
- const opened = firstCard.get(key);
132
- firstCard.delete(key);
133
- if (result.status !== "completed" || !cardId || !gameId)
134
- return result;
135
- // A rollover means this runtime names a card the play never ran on, so
136
- // its score belongs to something else. The tool family keeps playing the
137
- // session it already has when the lease diverges — deliberately, because
138
- // joining the new play would throw away every level the real one reached
139
- // — so the report is right and only the score would be wrong.
140
- //
141
- // Nothing here can recover the real one: the parent cannot read the
142
- // child's workspace, which is the only place the play it actually ran is
143
- // recorded. And a rollover means over 14 minutes passed between two
144
- // chunks, so the old card is idle-closed and unreachable anyway. What is
145
- // fixable is the lie — an empty RESET on the fresh card renders as a
146
- // perfectly plausible "score 0, 0 levels", which reads as a play that
147
- // achieved nothing rather than as a score that could not be read. Omit it
148
- // instead; the main agent is told to report an absent score as
149
- // unavailable.
150
- if (opened !== undefined && opened !== cardId) {
151
- console.warn("[arc-agi] scorecard rolled over mid-execution", {
152
- gameId,
153
- played: opened,
154
- leased: cardId
155
- });
156
- return result;
157
- }
158
- const score = await gameScoreReport(deps(), cardId, gameId);
159
- if (!score)
160
- return result;
161
- return {
162
- ...result,
163
- resultParts: [...result.resultParts, { kind: "text", text: score }]
164
- };
165
- },
166
- // No `onAbort`. There is deliberately nothing to release: the ARC API
167
- // auto-closes an idle card, so an abandoned play needs no cleanup at all.
168
- // Declaring an empty hook would imply otherwise.
169
- store: arcScorecardStore,
170
- requires: { secrets: ["ARC_API_KEY"] }
171
- });
172
- }
173
- export { ARC_GAME_FAMILY, ARC_GAME_TYPE };
174
- export { arcScorecardStore, makeScorecardStore } from "./store.js";
175
- export { ARC_GAME_RECIPE, ARC_GAME_SPEC } from "./recipe.js";
@@ -1,27 +0,0 @@
1
- import type { DelegationNames } from "@dynamicagents/core";
2
- /**
3
- * Everything the **main agent** is told about ARC-AGI-3 — the counterpart to
4
- * {@link file://./soul.ts}, which is what the *subagent* playing a game is told.
5
- *
6
- * Both blocks used to be hand-written inside `agent/` (`prompt.ts`'s
7
- * `ARC_CAPABILITY` and a `## Playing an ARC-AGI-3 game` section of
8
- * `turn.ts`'s round contract). The main agent's system prompt is soul +
9
- * round contract concatenated, so it read ARC advice twice per round from two
10
- * files with no reason to agree — and they had stopped agreeing: one said to
11
- * delegate a subtask per game, the other said to delegate exactly one subtask and
12
- * nothing else. They are one file now, and the guidance below follows the
13
- * capability block.
14
- */
15
- /**
16
- * The capability block: what the agent can do, and what to do with a result that
17
- * comes back. Deliberately names no scorecard tool and no `card_id` — the card is
18
- * leased by the recipe per chunk and is not this model's to manage, so naming one
19
- * would only invite a call to a tool that does not exist.
20
- */
21
- export declare const ARC_CAPABILITY: string;
22
- /**
23
- * The delegation guidance: how to build the `delegate` payload for a play. What
24
- * the capability block already says is not repeated here, and neither is the
25
- * params schema — the `delegate` tool description renders that from the type.
26
- */
27
- export declare function arcDelegationGuidance(names: DelegationNames): string;
@@ -1,65 +0,0 @@
1
- /**
2
- * Everything the **main agent** is told about ARC-AGI-3 — the counterpart to
3
- * {@link file://./soul.ts}, which is what the *subagent* playing a game is told.
4
- *
5
- * Both blocks used to be hand-written inside `agent/` (`prompt.ts`'s
6
- * `ARC_CAPABILITY` and a `## Playing an ARC-AGI-3 game` section of
7
- * `turn.ts`'s round contract). The main agent's system prompt is soul +
8
- * round contract concatenated, so it read ARC advice twice per round from two
9
- * files with no reason to agree — and they had stopped agreeing: one said to
10
- * delegate a subtask per game, the other said to delegate exactly one subtask and
11
- * nothing else. They are one file now, and the guidance below follows the
12
- * capability block.
13
- */
14
- /**
15
- * The capability block: what the agent can do, and what to do with a result that
16
- * comes back. Deliberately names no scorecard tool and no `card_id` — the card is
17
- * leased by the recipe per chunk and is not this model's to manage, so naming one
18
- * would only invite a call to a tool that does not exist.
19
- */
20
- export const ARC_CAPABILITY = [
21
- "You can run ARC-AGI-3 games, played for you by subagents:",
22
- "- `arc_list_games` shows the available games with their exact ids and tags describing how each is played.",
23
- "- To have a game played, delegate a subtask of type `arc-game` with param `game_id` (an exact id from `arc_list_games`). That is the whole contract — there is no scorecard for you to open, choose, or close.",
24
- "- To have several games played, delegate one `arc-game` subtask per game; they run concurrently.",
25
- "- Each play's report ends with that game's score, read from the scorecard once the play finishes. Report that score rather than inventing one — and if a report carries no score line, say the score was unavailable.",
26
- "- A play's report also carries what it learned: the mechanics it confirmed, what it never got to test, and where the level's pieces are. That is the only record of it — the subagent keeps nothing between plays. Record what generalizes (mechanics, geography, what failed and why) so the next play starts from it, and keep it separate from what is merely suspected. Spent scorecard ids and other one-off residue are not worth keeping."
27
- ].join("\n");
28
- /**
29
- * The delegation guidance: how to build the `delegate` payload for a play. What
30
- * the capability block already says is not repeated here, and neither is the
31
- * params schema — the `delegate` tool description renders that from the type.
32
- */
33
- export function arcDelegationGuidance(names) {
34
- return `## Playing an ARC-AGI-3 game
35
-
36
- When the user asks for a game to be played (e.g. "play game ls20"), you can
37
- delegate in parallel subtasks of "type": "arc-game" per game they named.
38
-
39
- Each of those subtasks carries "params": { "game_id": "<id>" }, an exact id from
40
- \`arc_list_games\`. The param is what starts the play, and the "prompt" is never a
41
- substitute for it. Restate the request in the "prompt" as well (e.g. "Play the
42
- ARC-AGI-3 game ls20."), so the subagent knows what it was asked for.
43
-
44
- If the request does not name a game, or names it loosely — call \`arc_list_games\`
45
- first and delegate the id associated with "ls20". Never invent an id or pass through
46
- the user's wording as one. If nothing in the list matches well enough to choose,
47
- ask the user which game they mean with \`${names.finalReplyTool}\` rather than guessing.
48
-
49
- ### What to put in the prompt
50
-
51
- Give it the goal, and give it what earlier plays actually established — labeled as
52
- what it is. Write "an earlier play observed …" for something a play reported seeing,
53
- and "we suspect …" for a hypothesis, so it can tell what to verify from what to use.
54
- A route or a map you pass down is a guess about a level nobody has finished; stated
55
- as fact, it gets followed off a cliff.
56
-
57
- Do **not** state mechanics of the tools or the budget: how many actions it has, how
58
- many moves fit in one call, how many turns it may spend. It is told all of that
59
- directly, it is told correctly, and a number you supply that disagrees will be
60
- believed over the truth — a play once stopped early because its prompt said it had
61
- "20 actions total" when 20 was its turn budget.
62
-
63
- These subtasks take several minutes — acknowledge in your "reply" that you have started playing
64
- and will report back, without promising a time.`;
65
- }
@@ -1,51 +0,0 @@
1
- import type { ResolvedRecipe, SubtaskTypeSpec } from "@dynamicagents/core";
2
- /** Semantic Subtask type the decomposer emits for a "play this game" request. */
3
- export declare const ARC_GAME_TYPE = "arc-game";
4
- /**
5
- * Recipe for playing an ARC-AGI-3 game. Names no model, so it runs on whatever
6
- * pair its host agent is configured with; what distinguishes it is its tool
7
- * family, its soul, its context discipline, and
8
- * a turn budget twice the baseline — a play is a long sequence of cheap decisions,
9
- * and 20 turns bought roughly ten game actions once inspection was paid for.
10
- *
11
- * It used to be "the long recipe", budgeted at 1,000 turns on the reasoning that
12
- * 25 turns per chunk made 40 durable chunks. That arithmetic assumed a turn under
13
- * ten seconds. A turn here is a reasoning model plus an ARC HTTP round trip, so
14
- * real runs took 70-100 chunks, blew the per-branch cap, and were *failed* after
15
- * hours of unattended play rather than being asked to report. The budget is now
16
- * time and turns, both enforced directly, and a play ends through the graceful
17
- * summary — a terminal report with the metrics footer.
18
- *
19
- * - `historyWindow` bounds context, and it is now the model's *only* memory: the
20
- * workspace tools are gone (see below), so a plan that scrolls out of it is
21
- * gone. Note it counts *assistant messages* — one per tool call, not one per
22
- * game action — so a play spends it several times faster than the number
23
- * suggests.
24
- * - `reportMetrics` appends the turns/model-calls/wall-clock footer the user
25
- * asked to see.
26
- *
27
- * Tool family: `arc-game` alone (act/inspect against the ARC REST API, session
28
- * state kept in the workspace), code-validated by
29
- * `validateRecipe`/`buildRecipeTools`.
30
- *
31
- * It used to also carry `workspace`, on the theory that a small history window
32
- * needs a file store behind it. Two logged plays say otherwise: `ws_read` was
33
- * never called once, and the three `ws_write` calls between them were a
34
- * scratchpad for arithmetic — a use that costs a turn per note and now belongs in
35
- * `arc_act`'s `note` field, which costs none and stays in the model's own history.
36
- * The session file is unaffected: the family reaches the workspace through its
37
- * {@link file://../../agent/tools.ts ToolFamilyContext}, not through the tools the
38
- * model can see.
39
- */
40
- export declare const ARC_GAME_RECIPE: ResolvedRecipe;
41
- /**
42
- * The arc-game type. Its one param is an id the model quotes back from a tool
43
- * result it already saw, so the contract is checkable before anything runs: a
44
- * play with no game cannot succeed, and refusing it here costs no model call.
45
- *
46
- * There is deliberately no `card_id`. Which scorecard a play runs on is not a
47
- * choice — the API auto-closes an idle card, so the live card is whichever one
48
- * was used recently — and the parent leases it per chunk (see
49
- * {@link file://./scorecard.ts}), handing it to the execution as runtime state.
50
- */
51
- export declare const ARC_GAME_SPEC: SubtaskTypeSpec;