@github/copilot-sdk 1.0.15-unstable.35395657398.gad69ee1 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,255 @@
1
+ # Dynamic Workflows
2
+
3
+ Dynamic Workflows are extension-authored, session-scoped workflows that coordinate subagents and durable steps. The API is experimental.
4
+
5
+ ## Define and register a workflow
6
+
7
+ Use `defineWorkflow` and pass the returned handle to `joinSession`:
8
+
9
+ ```js
10
+ import { defineWorkflow, joinSession } from "@github/copilot-sdk/extension";
11
+
12
+ const reviewChanged = defineWorkflow({
13
+ meta: {
14
+ name: "review-changed",
15
+ description:
16
+ "Review changed files and verify the findings. " +
17
+ "args: { files: string[] } — the paths to review.",
18
+ phases: [{ title: "Review" }, { title: "Verify" }],
19
+ argsSchema: {
20
+ type: "object",
21
+ required: ["files"],
22
+ properties: {
23
+ files: { type: "array", items: { type: "string" } },
24
+ },
25
+ },
26
+ },
27
+ run: async (ctx) => {
28
+ ctx.phase("Review");
29
+ const reviews = await ctx.parallel(
30
+ ctx.args.files.map(
31
+ (file) => () => ctx.agent(`Review ${file}`, { label: `Review ${file}` })
32
+ )
33
+ );
34
+
35
+ ctx.phase("Verify");
36
+ const report = await ctx.step("report", () => ({ reviews }));
37
+ ctx.log(`Completed workflow run ${ctx.runId}`);
38
+ return report;
39
+ },
40
+ });
41
+
42
+ const session = await joinSession({ workflows: [reviewChanged] });
43
+ ```
44
+
45
+ Workflow metadata contains a stable `name`, a human-readable `description`, declared `phases`, an optional `argsSchema`, and optional `limits`. Phase entries contain a `title` and optional `detail`.
46
+
47
+ ## Declaring an argument shape
48
+
49
+ A workflow that reads `ctx.args` should declare `meta.argsSchema`, as the example above does. The schema records the workflow's expected input contract alongside its registration metadata.
50
+
51
+ Enforcement covers structure — types, required properties, and enum or const values. Finer constraints such as `minLength`, `pattern`, or `additionalProperties` are recorded in the declaration but not enforced. The accepted vocabulary is the `WorkflowJsonSchema` subset also used for subagent structured output: `type`, `required`, `enum`, `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf`. A `type` is one of `null`, `boolean`, `integer`, `number`, `string`, `array`, or `object`, or a non-empty array of those such as `["object", "null"]`. A declaration outside that subset is rejected at registration.
52
+
53
+ `argsSchema` is optional and backward compatible. A workflow that omits it behaves exactly as before, so state the expected shape in its `description`.
54
+
55
+ An extension calling `session.workflow.run(...)` is not validated against `argsSchema`; those arguments are typed through `defineWorkflow<TArgs>` instead. A workflow that reads `ctx.args` should still validate it rather than assume a shape because the declared subset does not enforce every constraint and JavaScript callers are not statically typed.
56
+
57
+ `defineWorkflow<TArgs, TResult>` accepts a `run(context)` function returning `Promise<TResult>`, where `TResult` is `JsonValue | void`. Objects, arrays, strings, numbers, booleans, and `null` are valid results. Returning `undefined` completes the workflow with no result. Other non-JSON values are rejected.
58
+
59
+ ## Workflow context
60
+
61
+ The `run()` context provides:
62
+
63
+ * `ctx.runId`: Stable ID reused across resumed attempts.
64
+ * `ctx.args`: Invocation arguments, forwarded verbatim. When the caller omits `args`, this is `{}` rather than `undefined`.
65
+ * `ctx.agent(prompt, options?)`: Runs one workflow-owned subagent. Options are exactly `label`, `schema`, `model`, `agent`, `reasoningEffort`, and `contextTier`. See [Subagent calls](#subagent-calls).
66
+ * `ctx.parallel(thunks)`: Runs thunks concurrently and awaits all of them (a barrier). A thunk that throws becomes `null` in the result array, so one failed item does not lose the rest. Cancellation and hard runtime failures (`ResponseError`, `ConnectionError`) are the exception — those propagate and reject the whole call, because they mean the run itself is in trouble rather than one item having failed. Handle them at run level; do not assume every failure arrives as a `null`. Rejects above 4096 items.
67
+ * `ctx.pipeline(items, ...stages)`: Flows each item through every stage without a barrier between stages, so one item can be in a later stage while another is still in an earlier one. Each stage is called as `(previous, item, index)`, where `previous` is the prior stage's result and `item` is the original input. A stage that throws drops that item to `null` and skips its remaining stages, with the same exception for cancellation and hard runtime failures. Rejects above 4096 items.
68
+ * `ctx.phase(title)`: Starts a named progress phase. This sets a single run-global value, so calling it from inside concurrent `parallel`/`pipeline` stages races. Call it at run-level transitions and distinguish concurrent work by `label` instead.
69
+ * `ctx.log(message)`: Appends a progress line. When a workflow bounds its own coverage (top-N, sampling), log what was dropped.
70
+ * `ctx.step(key, producer, options?)`: Journals the producer's JSON result under a stable key so a resume replays it without re-running the producer. A journaled (default) producer must return a JSON-serializable value; `undefined` or a non-JSON value is rejected. Pass `{ volatile: true }` to bypass the journal and run the producer every time.
71
+
72
+ The key is the *sole* identity: neither the producer body nor its inputs contribute to it. A resume replays the cached value for a matching key even if the producer has since changed, so version the key (`"scan-v2"`) whenever its inputs or meaning change. Journaled producers are best-effort at-least-once and may run again across crashes or concurrent same-key callers, so keep side effects idempotent.
73
+ * `ctx.pause(key)`: Pauses at a durable, one-shot checkpoint. The first attempt records the checkpoint, pauses, and throws `AbortError` after cooperative cancellation. When the run resumes, the workflow starts again and the same checkpoint returns so execution can continue. Call it only from the main workflow flow, not inside `ctx.parallel()` or `ctx.pipeline()`.
74
+ * `ctx.session`: The session returned by `joinSession`. It refuses calls that start, resume, or pause a workflow run. Call `extensions_manage` with `operation: "guide"` to read more about the session APIs.
75
+ * `ctx.signal`: Cooperative cancellation signal for extension work and subprocesses.
76
+ * `ctx.workflow(...)`: Always rejects because nested workflows are not supported.
77
+
78
+ Workflow-owned subagents are intentionally hidden from `read_agent` and `write_agent`. Use the workflow observability APIs instead.
79
+
80
+ ### Subagent calls
81
+
82
+ `ctx.agent(prompt, options?)` spawns one workflow-scoped subagent and awaits it. Without a schema it resolves to the subagent's final text. With `options.schema` it resolves to the parsed JSON value.
83
+
84
+ **Identical calls are memoized into one subagent.** Each call is journaled by its canonical prompt and options, including `label`. Two calls with the same prompt and the same options return one shared result — even when issued concurrently. To spawn N *independent* subagents, give each a unique `label` or vary the prompt:
85
+
86
+ ```js
87
+ // One subagent, awaited five times — almost certainly not what you want.
88
+ await ctx.parallel([1, 2, 3, 4, 5].map(() => () => ctx.agent("Find a bug")));
89
+
90
+ // Five independent subagents.
91
+ await ctx.parallel(
92
+ [1, 2, 3, 4, 5].map((i) => () => ctx.agent("Find a bug", { label: `finder:${i}` }))
93
+ );
94
+ ```
95
+
96
+ **An ordinary failure resolves to `null` — it does not throw.** A subagent that errors, returns nothing, or (with a schema) produces output that still fails to parse or match after its one retry resolves `null`. Always guard the result before using it, including a bare `await ctx.agent(...)`:
97
+
98
+ ```js
99
+ const finding = await ctx.agent(prompt, { label: "inspector" });
100
+ if (!finding) return { finding: null };
101
+ ```
102
+
103
+ Cancellation and hard runtime failures — a reached limit, a durable-state failure — reject instead, aborting the run. When filtering results, prefer `v => v !== null` over `Boolean`, which also discards a valid `false`, `0`, or `""`.
104
+
105
+ **`schema` is a structural subset of JSON Schema, not a validator.** Honored: `type`, `required`, `enum`, `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf` — where `oneOf` is treated as `anyOf`, meaning at least one branch matches rather than exactly one. Ignored and *not* enforced: `additionalProperties`, `pattern`, `minLength`/`maxLength`, `format`, numeric ranges, and boolean schemas. Do not rely on an ignored keyword to constrain a result. A schema call retries once on a parse or match failure, so it may spawn twice, and both spawns count toward `maxTotalSubagents`.
106
+
107
+ ### Choosing between pipeline and parallel
108
+
109
+ Prefer `pipeline` for multi-stage work. It has no barrier between stages, so each item advances as soon as its own prior stage finishes.
110
+
111
+ Reach for a barrier — `parallel` between stages — only when a stage genuinely needs every prior result at once: deduplicating or merging across the full set, an early exit based on the total, or a prompt that compares one result against the others. Needing to map, filter, or flatten is not a reason to use a barrier; do that inside a pipeline stage. Barrier latency is real: if the slowest of N subagents takes three times the fastest, a barrier wastes the rest of the pool's time.
112
+
113
+ ## Resource limits
114
+
115
+ Limits may be declared in `meta.limits` and overridden per invocation. Every limit is optional and must be positive when present; an omitted limit leaves that dimension unbounded, except that an omitted `maxConcurrentSubagents` falls back to `maxTotalSubagents`, so a declared total cap also bounds concurrency.
116
+
117
+ Set a ceiling only from real knowledge of what the workflow costs, or because the user named one. A guessed ceiling does not make a run safer: it stops a healthy run partway with `workflow_limit_reached`, after that run has already spent credits. SDK-initiated `run` and `resume` do not request permission, so a caller that wants a ceiling must set it deliberately from a cost it already knows.
118
+
119
+ ```js
120
+ // Only when the cost profile is known, or the user asked for this ceiling.
121
+ limits: { maxTotalSubagents: 10 },
122
+ ```
123
+
124
+ - `maxConcurrentSubagents`: Positive integer concurrent-subagent cap. Additional subagents wait in a queue. Queueing applies backpressure and does not fail the run.
125
+ - `maxTotalSubagents`: Positive integer cumulative admission cap. An attempted subagent beyond the cap ends the attempt with failure kind `maxTotalSubagents`.
126
+ - `timeoutSeconds`: Positive finite number of seconds, including positive fractions, capped at `2_147_483.647`. It measures accumulated active-execution time across attempts, including the extension body, subprocess waits, queued-agent waits, and sleeps. Time between attempts is excluded. The timeout is soft because already-running work may take time to stop. Its failure kind is `timeoutSeconds`.
127
+ - `maxAiCredits`: Positive finite AI-credit budget for the whole run's workflow subagent subtree, including descendants. AI credits are GitHub Copilot's universal usage metric. This is a soft, post-paid ceiling, so completed or parallel turns can settle above it before the run stops. Accounting is fail-closed: an accounting failure stops a budgeted run rather than allowing untracked use. Its failure kind is `maxAiCredits`.
128
+
129
+ `maxTotalSubagents`, `timeoutSeconds`, and `maxAiCredits` use reject-and-retry semantics. A rejected attempt ends with run status `error` and `failure.type` set to `workflow_limit_reached`. The failed run keeps its ID, arguments, journal, and accounting. Resume the run with a raised limit when additional work is approved. Previously consumed resources still count.
130
+
131
+ ## Run and resume
132
+
133
+ Run by registered name or handle:
134
+
135
+ ```ts
136
+ const run = await session.workflow.run("review-changed", {
137
+ args: { files: ["src/a.ts"] },
138
+ limits: { maxAiCredits: 3 },
139
+ notifyOnComplete: true,
140
+ logPhaseNames: true,
141
+ });
142
+
143
+ if (run.status === "completed") {
144
+ console.log(run.result);
145
+ } else {
146
+ console.error(`run ${run.runId} ended as ${run.status}`, run.failure ?? run.error);
147
+ }
148
+ ```
149
+
150
+ The name overload is:
151
+
152
+ ```ts
153
+ session.workflow.run(
154
+ name: string,
155
+ options?: {
156
+ args?: JsonValue;
157
+ limits?: WorkflowLimitOverrides;
158
+ notifyOnComplete?: boolean;
159
+ logPhaseNames?: boolean;
160
+ },
161
+ ): Promise<WorkflowRunResult>;
162
+ ```
163
+
164
+ Resume by run ID without resending the name or arguments:
165
+
166
+ ```ts
167
+ const run = await session.workflow.resume(runId, {
168
+ limits: { maxAiCredits: 6 },
169
+ notifyOnComplete: true,
170
+ logPhaseNames: true,
171
+ });
172
+ ```
173
+
174
+ The signature is:
175
+
176
+ ```ts
177
+ session.workflow.resume(
178
+ runId: string,
179
+ options?: {
180
+ limits?: WorkflowLimitOverrides;
181
+ notifyOnComplete?: boolean;
182
+ logPhaseNames?: boolean;
183
+ },
184
+ ): Promise<WorkflowRunResult>;
185
+ ```
186
+
187
+ Set `notifyOnComplete` to `true` for workflows that are likely to be invoked by an agent, so the originating session is notified when the workflow completes. Set it to `false` for workflows intended to be invoked programmatically, where the caller awaits the result directly. Set `logPhaseNames` to emit workflow phase names to the session transcript. Both options apply to new and resumed runs.
188
+
189
+ Both resolve with the run envelope (`WorkflowRunResult`) for **every** outcome—`completed`, `error`, `halted`, `paused`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`. A `paused` envelope means that the current attempt settled, not that the durable run is permanently finished. Resume the same run ID to start another attempt with its journal and accounting intact. SDK-initiated `run` and `resume` do not request permission, so they have no declined outcome. An SDK-initiated run is refused only when the session already has its maximum number of active top-level runs. Pre-execution resume failures throw `WorkflowResumeError`, whose `code` is one of `not_found`, `non_resumable`, `workflow_run_not_resumable`, `already_active`, `workflow_already_running`, `workflow_limits_invalid`, `workflow_session_disposed`, `workflow_storage_unavailable`, or `workflow_storage_corrupt`.
190
+
191
+ Pause a running attempt from outside its workflow body:
192
+
193
+ ```ts
194
+ const paused = await session.workflow.pause(runId);
195
+ ```
196
+
197
+ Inside a workflow body, use a durable checkpoint instead:
198
+
199
+ ```ts
200
+ await ctx.step("prepare", prepareInput);
201
+ await ctx.pause("review-ready");
202
+ await ctx.agent("Review the prepared input");
203
+ ```
204
+
205
+ The first attempt pauses at `"review-ready"` and ends through cooperative cancellation. On resume, the workflow starts from the beginning, reuses the journaled step, returns from the checkpoint, and continues.
206
+
207
+ ## Observe a run
208
+
209
+ The calling session can inspect its own workflow runs:
210
+
211
+ ```ts
212
+ const runs = await session.workflow.listRuns();
213
+ const runsPage = await session.workflow.listRuns({
214
+ afterSeq,
215
+ beforeSeq,
216
+ limit,
217
+ });
218
+ const detail = await session.workflow.getRunDetail(runId);
219
+ const progressPage = await session.workflow.getRunProgress(runId, {
220
+ phaseId,
221
+ afterSeq,
222
+ beforeSeq,
223
+ limit,
224
+ });
225
+ ```
226
+
227
+ - `listRuns()` returns only the runs array from the newest default page of this session's durable workflow runs. This overload preserves the original convenience API.
228
+ - `listRuns({ afterSeq, beforeSeq, limit })` returns the full page. Its `oldestSeq`, `newestSeq`, `hasMoreNewer`, and `omittedOlder` fields let callers continue paging without raw RPC calls.
229
+ - `getRunDetail(runId)` returns phases, prompt-safe agent summaries, and the latest progress page.
230
+ - `getRunProgress(runId, options?)` pages progress forward, backward, by phase, or from the latest tail.
231
+
232
+ `getRun(runId)` reads the latest run envelope. `pause(runId)` pauses a running attempt and returns its `paused` envelope. `cancel(runId)` cancels a run and returns its terminal envelope.
233
+
234
+ `waitForRun(runId, options?)` resolves with the current attempt's envelope once it settles into `completed`, `error`, `halted`, `paused`, or `cancelled`. It resolves immediately when the current attempt has already settled:
235
+
236
+ ```ts
237
+ const settled = await session.workflow.waitForRun(runId);
238
+ if (settled.status === "completed") {
239
+ console.log(settled.result);
240
+ }
241
+ ```
242
+
243
+ It watches `workflow.run_updated` and re-reads the durable envelope on each invalidation, collapsing a burst of events into a single in-flight read. A low-frequency periodic re-read runs alongside the subscription, so a dropped or missing invalidation degrades into a slightly late resolution rather than an unbounded wait. Pass a `signal` to stop waiting:
244
+
245
+ ```ts
246
+ const controller = new AbortController();
247
+ setTimeout(() => controller.abort(), 30_000);
248
+ const settled = await session.workflow.waitForRun(runId, { signal: controller.signal });
249
+ ```
250
+
251
+ Aborting rejects the wait and has no effect on the run, which keeps executing—use `pause(runId)` or `cancel(runId)` to stop it. The resolved object is a snapshot of that settled attempt. If its status is `paused`, a later resume updates the durable envelope under the same run ID. Call `getRun(runId)` to read the latest envelope. `isWorkflowRunTerminal(status)` exposes the same current-attempt settlement test for callers driving their own loop.
252
+
253
+ Listen for the ephemeral `workflow.run_updated` event. Its `{ runId, revision }` payload is an invalidation signal. Re-read the desired API when a newer monotonic revision arrives.
254
+
255
+ Revisions cover durable lifecycle, accounting, phase, agent, and progress changes. Continuous read-time fields can change without a new revision. These include `observedAt`, active-time calculations, live counts, and a live agent's status or prompt-safe activity text. Workflow prompts are never exposed by these APIs. A run is visible only through the session that owns it.
package/package.json CHANGED
@@ -4,8 +4,8 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/github/copilot-sdk.git"
6
6
  },
7
- "version": "1.0.15-unstable.35395657398.gad69ee1",
8
- "copilotCliVersion": "1.0.86-unstable.r35389812552.g657d1e5",
7
+ "version": "1.0.15",
8
+ "copilotCliVersion": "1.0.89",
9
9
  "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
10
10
  "main": "./dist/cjs/index.js",
11
11
  "types": "./dist/index.d.ts",
@@ -43,6 +43,7 @@
43
43
  "release:manifest": "tsx scripts/release-manifest.ts",
44
44
  "prepare:runtime": "tsx scripts/prepare-runtime.ts",
45
45
  "test": "vitest run",
46
+ "test:unit": "vitest run --exclude=\"test/e2e/**\"",
46
47
  "test:watch": "vitest",
47
48
  "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" --ignore-path .prettierignore",
48
49
  "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" --ignore-path .prettierignore",
@@ -100,13 +101,13 @@
100
101
  "README.md"
101
102
  ],
102
103
  "optionalDependencies": {
103
- "@github/copilot-sdk-darwin-arm64": "1.0.15-unstable.35395657398.gad69ee1",
104
- "@github/copilot-sdk-darwin-x64": "1.0.15-unstable.35395657398.gad69ee1",
105
- "@github/copilot-sdk-linux-arm64": "1.0.15-unstable.35395657398.gad69ee1",
106
- "@github/copilot-sdk-linux-x64": "1.0.15-unstable.35395657398.gad69ee1",
107
- "@github/copilot-sdk-linuxmusl-arm64": "1.0.15-unstable.35395657398.gad69ee1",
108
- "@github/copilot-sdk-linuxmusl-x64": "1.0.15-unstable.35395657398.gad69ee1",
109
- "@github/copilot-sdk-win32-arm64": "1.0.15-unstable.35395657398.gad69ee1",
110
- "@github/copilot-sdk-win32-x64": "1.0.15-unstable.35395657398.gad69ee1"
104
+ "@github/copilot-sdk-darwin-arm64": "1.0.15",
105
+ "@github/copilot-sdk-darwin-x64": "1.0.15",
106
+ "@github/copilot-sdk-linux-arm64": "1.0.15",
107
+ "@github/copilot-sdk-linux-x64": "1.0.15",
108
+ "@github/copilot-sdk-linuxmusl-arm64": "1.0.15",
109
+ "@github/copilot-sdk-linuxmusl-x64": "1.0.15",
110
+ "@github/copilot-sdk-win32-arm64": "1.0.15",
111
+ "@github/copilot-sdk-win32-x64": "1.0.15"
111
112
  }
112
113
  }
package/dist/factory.d.ts DELETED
@@ -1,327 +0,0 @@
1
- import type { FactoryGetRunProgressRequest, FactoryListRunsRequest, FactoryListRunsResult, FactoryProgressPage, FactoryRunDetail, FactoryRunResult, FactoryRunStatus, FactoryRunSummary } from "./generated/rpc.js";
2
- import type { ContextTier } from "./generated/session-events.js";
3
- import type { CopilotSession } from "./session.js";
4
- import type { FactoryMeta } from "./types.js";
5
- export type { FactoryRunResult };
6
- export type { FactoryAgentSummary, FactoryPhaseStatus, FactoryPhaseObservation, FactoryProgressLine, FactoryProgressPage, FactoryRunDetail, FactoryRunStatus, FactoryRunSummary, } from "./generated/rpc.js";
7
- /**
8
- * Options for paging durable factory runs.
9
- *
10
- * @experimental Part of the experimental Agent Factories surface and may
11
- * change or be removed in future SDK or CLI releases.
12
- */
13
- export type FactoryListRunsOptions = FactoryListRunsRequest;
14
- /**
15
- * A page of durable factory runs and its paging metadata.
16
- *
17
- * @experimental Part of the experimental Agent Factories surface and may
18
- * change or be removed in future SDK or CLI releases.
19
- */
20
- export type FactoryRunsPage = FactoryListRunsResult;
21
- /**
22
- * Whether a factory run status is terminal.
23
- *
24
- * @experimental Part of the experimental Agent Factories surface and may
25
- * change or be removed in future SDK or CLI releases.
26
- */
27
- export declare function isFactoryRunTerminal(status: FactoryRunStatus): boolean;
28
- declare const factoryHandleBrand: unique symbol;
29
- /** A value that can be represented losslessly on the SDK JSON wire. */
30
- export type JsonValue = null | boolean | number | string | JsonValue[] | {
31
- [key: string]: JsonValue;
32
- };
33
- /**
34
- * Conservative JSON shape language accepted by the Agent Factories surface, for
35
- * both structured factory agent output and a factory's declared `argsSchema`.
36
- *
37
- * This is a best-effort structural guard — used to decide whether a subagent's
38
- * structured output should be accepted or retried, and whether a caller's
39
- * factory `args` match the declared shape — **not** a full JSON Schema
40
- * validator. Only these keywords are honored: `type`, `required`, `enum`,
41
- * `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf`. A `type`
42
- * is one of `null`, `boolean`, `integer`, `number`, `string`, `array`, or
43
- * `object`, or a non-empty array of those (for example `["object", "null"]`).
44
- *
45
- * Everything else is **ignored, not enforced**. In particular, string
46
- * constraints (`pattern`, `minLength`, `maxLength`, `format`), numeric ranges
47
- * (`minimum`, `maximum`), `additionalProperties`, and boolean (`true`/`false`)
48
- * schemas do not reject non-conforming output. `oneOf` is treated like `anyOf`
49
- * (at least one branch must match) rather than strict exactly-one. Author
50
- * schemas within this subset; do not rely on unsupported constraints for
51
- * correctness.
52
- *
53
- * @experimental Part of the experimental Agent Factories surface and may
54
- * change or be removed in future SDK or CLI releases.
55
- */
56
- export type FactoryJsonSchema = {
57
- [key: string]: JsonValue;
58
- };
59
- /**
60
- * Options for one factory-scoped subagent call.
61
- *
62
- * @experimental Part of the experimental Agent Factories surface and may
63
- * change or be removed in future SDK or CLI releases.
64
- */
65
- export interface FactoryAgentOptions {
66
- label?: string;
67
- schema?: FactoryJsonSchema;
68
- model?: string;
69
- reasoningEffort?: string;
70
- contextTier?: ContextTier;
71
- agent?: string;
72
- }
73
- export declare const FACTORY_AGENT_OPTION_KEYS: readonly ["label", "schema", "model", "reasoningEffort", "contextTier", "agent"];
74
- /**
75
- * Options for a durable factory step.
76
- *
77
- * @experimental Part of the experimental Agent Factories surface and may
78
- * change or be removed in future SDK or CLI releases.
79
- */
80
- export interface FactoryStepOptions {
81
- /** Skip the journal and always invoke the producer. */
82
- volatile?: boolean;
83
- }
84
- /**
85
- * Per-invocation factory resource ceiling overrides.
86
- *
87
- * An omitted field preserves the existing/default ceiling, a number replaces
88
- * it, and `null` explicitly makes that dimension unlimited.
89
- *
90
- * @experimental Part of the experimental Agent Factories surface and may
91
- * change or be removed in future SDK or CLI releases.
92
- */
93
- export interface FactoryLimitOverrides {
94
- maxConcurrentSubagents?: number | null;
95
- maxTotalSubagents?: number | null;
96
- maxAiCredits?: number | null;
97
- timeoutSeconds?: number | null;
98
- }
99
- /**
100
- * One stage in a per-item factory pipeline.
101
- *
102
- * @experimental Part of the experimental Agent Factories surface and may
103
- * change or be removed in future SDK or CLI releases.
104
- */
105
- export type FactoryPipelineStage<TInput = unknown, TResult = unknown> = (previous: TInput, item: unknown, index: number) => Promise<TResult> | TResult;
106
- /**
107
- * Context passed to an extension-authored factory body.
108
- *
109
- * @experimental Part of the experimental Agent Factories surface and may
110
- * change or be removed in future SDK or CLI releases.
111
- */
112
- export interface FactoryContext<TArgs extends JsonValue = JsonValue> {
113
- /** Stable identifier for the current factory run. */
114
- readonly runId: string;
115
- /** Spawn and await one factory-scoped subagent. */
116
- agent(prompt: string, options?: FactoryAgentOptions): Promise<unknown>;
117
- /** Memoize an arbitrary producer under a stable author-supplied key. */
118
- step(key: string, producer: () => Promise<JsonValue> | JsonValue, options?: FactoryStepOptions): Promise<JsonValue>;
119
- /**
120
- * Pause this run at a durable, one-shot checkpoint.
121
- *
122
- * The first attempt to reach a key pauses and aborts cooperatively. A
123
- * resumed attempt returns from the same key and continues.
124
- */
125
- pause(key: string): Promise<void>;
126
- /**
127
- * Run thunks concurrently and await all of them.
128
- *
129
- * A thunk that throws becomes `null` in the result array, so one failed
130
- * item does not lose the rest. Cancellation and hard runtime failures
131
- * (`ResponseError`, `ConnectionError`) are the exception: those propagate
132
- * and reject the whole call, because they mean the run itself is in
133
- * trouble rather than one item having failed.
134
- */
135
- parallel<TResult>(thunks: Array<() => Promise<TResult> | TResult>): Promise<Array<TResult | null>>;
136
- /**
137
- * Run each item through every stage without barriers between stages.
138
- *
139
- * A stage that throws drops that item to `null` and skips its remaining
140
- * stages. As with {@link FactoryContext.parallel}, cancellation and hard
141
- * runtime failures propagate instead of being recorded per item.
142
- */
143
- pipeline(items: unknown[], ...stages: FactoryPipelineStage[]): Promise<unknown[]>;
144
- /** Start a named factory progress phase. */
145
- phase(title: string): void;
146
- /** Emit a factory progress line. */
147
- log(message: string): void;
148
- /** Reject because nested factories are not supported. */
149
- factory(name: string, args?: JsonValue): Promise<JsonValue | void>;
150
- /** Caller-supplied input, forwarded verbatim. */
151
- args: TArgs;
152
- /**
153
- * The session instance returned by `joinSession`. It refuses calls that
154
- * start, resume, or pause a factory run.
155
- */
156
- session: CopilotSession;
157
- /** Cooperative cancellation signal for the current factory run. */
158
- signal: AbortSignal;
159
- }
160
- /**
161
- * Definition accepted by {@link defineFactory}.
162
- *
163
- * @experimental Part of the experimental Agent Factories surface and may
164
- * change or be removed in future SDK or CLI releases.
165
- */
166
- export interface FactoryDefinition<TArgs extends JsonValue = JsonValue, TResult extends JsonValue | void = JsonValue | void> {
167
- meta: FactoryMeta;
168
- run(context: FactoryContext<TArgs>): Promise<TResult>;
169
- }
170
- /**
171
- * A deeply immutable view of a value.
172
- *
173
- * `defineFactory` deep-freezes the metadata it stores, so the handle's view of
174
- * it has to be readonly all the way down or `handle.meta.name = "..."` and
175
- * `handle.meta.phases.push(...)` would compile and then throw at runtime.
176
- */
177
- type DeepReadonly<T> = T extends (infer U)[] ? readonly DeepReadonly<U>[] : T extends object ? {
178
- readonly [K in keyof T]: DeepReadonly<T[K]>;
179
- } : T;
180
- /**
181
- * Opaque reusable reference to a defined factory.
182
- *
183
- * @experimental Part of the experimental Agent Factories surface and may
184
- * change or be removed in future SDK or CLI releases.
185
- */
186
- export interface FactoryHandle<TArgs extends JsonValue = JsonValue, TResult extends JsonValue | void = JsonValue | void> {
187
- readonly meta: DeepReadonly<FactoryMeta>;
188
- readonly [factoryHandleBrand]: {
189
- readonly args: TArgs;
190
- readonly result: TResult;
191
- };
192
- }
193
- /**
194
- * Options for invoking a factory.
195
- *
196
- * @experimental Part of the experimental Agent Factories surface and may
197
- * change or be removed in future SDK or CLI releases.
198
- */
199
- export interface RunOptions<TArgs extends JsonValue = JsonValue> {
200
- /** Input surfaced as `context.args`. */
201
- args?: TArgs;
202
- /** Optional per-invocation resource ceiling overrides. */
203
- limits?: FactoryLimitOverrides;
204
- /** Whether to notify the originating session when the factory completes. */
205
- notifyOnComplete?: boolean;
206
- /** Whether to emit factory phase names to the session transcript. */
207
- logPhaseNames?: boolean;
208
- /**
209
- * Prior run whose persisted identity, arguments, journal, and accounting should be resumed.
210
- *
211
- * @deprecated Use {@link SessionFactoryApi.resume} instead.
212
- */
213
- resumeFromRunId?: string;
214
- }
215
- /**
216
- * Options for resuming a factory run by ID.
217
- *
218
- * @experimental Part of the experimental Agent Factories surface and may
219
- * change or be removed in future SDK or CLI releases.
220
- */
221
- export interface ResumeOptions {
222
- /** Optional per-invocation resource ceiling overrides. */
223
- limits?: FactoryLimitOverrides;
224
- /** Whether to notify the originating session when the factory completes. */
225
- notifyOnComplete?: boolean;
226
- /** Whether to emit factory phase names to the session transcript. */
227
- logPhaseNames?: boolean;
228
- }
229
- /**
230
- * Machine-readable pre-execution factory resume failure.
231
- *
232
- * @experimental Part of the experimental Agent Factories surface and may
233
- * change or be removed in future SDK or CLI releases.
234
- */
235
- export type FactoryResumeErrorCode = "not_found" | "non_resumable" | "already_active" | "factory_already_running" | "factory_limits_invalid" | "factory_session_disposed" | "factory_storage_unavailable" | "factory_storage_corrupt";
236
- /**
237
- * Friendly factory API exposed on a session.
238
- *
239
- * @experimental Part of the experimental Agent Factories surface and may
240
- * change or be removed in future SDK or CLI releases.
241
- */
242
- export interface SessionFactoryApi {
243
- /**
244
- * Run a registered factory and resolve with its run envelope.
245
- *
246
- * The envelope is returned for every outcome, including `error`, `halted`,
247
- * `paused`, and `cancelled` — inspect `status` and read `result` only when
248
- * the run completed. `paused` settles the current attempt, but the same
249
- * durable run can later resume under its existing run ID. SDK-initiated
250
- * runs do not request permission, so they have no declined outcome. The
251
- * model's `run_factory` tool requests permission before a durable row
252
- * exists; declining it creates no run row. Failures that occur before a run
253
- * exists (such as an unknown factory or attempting to start a run while the
254
- * session is at its active top-level run limit) still reject.
255
- */
256
- run(name: string, options?: RunOptions): Promise<FactoryRunResult>;
257
- run<TArgs extends JsonValue>(factory: FactoryHandle<TArgs, JsonValue | void>, options?: RunOptions<TArgs>): Promise<FactoryRunResult>;
258
- /**
259
- * Resume a run from its persisted factory name, arguments, journal, and accounting.
260
- *
261
- * Resolves with the run envelope like {@link SessionFactoryApi.run}.
262
- * SDK-initiated resumes do not request permission. A pre-execution failure
263
- * with a documented resume code rejects with {@link FactoryResumeError}.
264
- */
265
- resume(runId: string, options?: ResumeOptions): Promise<FactoryRunResult>;
266
- /** Read the latest durable envelope for a factory run. */
267
- getRun(runId: string): Promise<FactoryRunResult>;
268
- /**
269
- * Wait for the current attempt to settle and resolve with its envelope.
270
- *
271
- * Resolves as soon as the run reaches `completed`, `error`, `halted`,
272
- * `paused`, or `cancelled`, and resolves immediately when the current
273
- * attempt has already settled. A `paused` envelope is an attempt-level
274
- * snapshot: resuming the same durable run can later change the envelope
275
- * returned by {@link SessionFactoryApi.getRun}.
276
- *
277
- * This watches the run's `factory.run_updated` invalidation events and
278
- * periodically re-reads the durable envelope so a missed event cannot
279
- * leave the wait hanging. Pass a `signal` to stop waiting; aborting rejects
280
- * and has no effect on the run itself, which keeps executing. Use
281
- * {@link SessionFactoryApi.cancel} to actually stop it.
282
- */
283
- waitForRun(runId: string, options?: {
284
- signal?: AbortSignal;
285
- }): Promise<FactoryRunResult>;
286
- /**
287
- * List the newest default page of this session's durable factory runs.
288
- *
289
- * This backwards-compatible overload returns only the runs array. Pass
290
- * paging options to receive the full page, including its cursors and
291
- * truncation metadata.
292
- */
293
- listRuns(): Promise<FactoryRunSummary[]>;
294
- /**
295
- * Page this session's durable factory runs.
296
- *
297
- * `afterSeq` and `beforeSeq` are exclusive cursors. The result includes
298
- * `oldestSeq`, `newestSeq`, `hasMoreNewer`, and `omittedOlder` so callers
299
- * can continue paging without using the raw RPC client.
300
- */
301
- listRuns(options: FactoryListRunsOptions): Promise<FactoryRunsPage>;
302
- /** Read durable phases, direct agents, and the latest progress tail for a run. */
303
- getRunDetail(runId: string): Promise<FactoryRunDetail>;
304
- /** Page durable progress forward, backward, or from the latest tail. */
305
- getRunProgress(runId: string, options?: Omit<FactoryGetRunProgressRequest, "runId">): Promise<FactoryProgressPage>;
306
- /** Pause a running factory attempt and return its `paused` envelope. */
307
- pause(runId: string): Promise<FactoryRunResult>;
308
- /** Cancel a factory run and return its terminal envelope. */
309
- cancel(runId: string): Promise<FactoryRunResult>;
310
- }
311
- /**
312
- * Error thrown when a factory cannot be resumed before execution begins.
313
- *
314
- * @experimental Part of the experimental Agent Factories surface and may
315
- * change or be removed in future SDK or CLI releases.
316
- */
317
- export declare class FactoryResumeError extends Error {
318
- readonly code: FactoryResumeErrorCode;
319
- constructor(code: FactoryResumeErrorCode, message: string);
320
- }
321
- /**
322
- * Defines an extension-authored factory and returns an opaque registration handle.
323
- *
324
- * @experimental Part of the experimental Agent Factories surface and may
325
- * change or be removed in future SDK or CLI releases.
326
- */
327
- export declare function defineFactory<TArgs extends JsonValue = JsonValue, TResult extends JsonValue | void = JsonValue | void>(definition: FactoryDefinition<TArgs, TResult>): FactoryHandle<TArgs, TResult>;