@github/copilot-sdk-darwin-arm64 0.0.1 → 1.0.13-preview.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/animations/app-install-nudge.json.gz +0 -0
- package/animations/banner.json.gz +0 -0
- package/builtin/customize-cloud-agent/SKILL.md +254 -0
- package/builtin/discover-resources/SKILL.md +35 -0
- package/builtin/github-pr-media/SKILL.md +108 -0
- package/builtin-skills/customize-cloud-agent/SKILL.md +254 -0
- package/builtin-skills/discover-resources/SKILL.md +35 -0
- package/builtin-skills/github-pr-media/SKILL.md +108 -0
- package/copilot-sdk/canvas.d.ts +126 -0
- package/copilot-sdk/client.d.ts +478 -0
- package/copilot-sdk/copilotRequestHandler.d.ts +85 -0
- package/copilot-sdk/docs/agent-author.md +295 -0
- package/copilot-sdk/docs/examples.md +682 -0
- package/copilot-sdk/docs/extensions.md +81 -0
- package/copilot-sdk/docs/factories.md +279 -0
- package/copilot-sdk/docs/factory-patterns.md +194 -0
- package/copilot-sdk/extension.d.ts +59 -0
- package/copilot-sdk/extension.js +11399 -0
- package/copilot-sdk/factory.d.ts +301 -0
- package/copilot-sdk/ffiRuntimeHost.d.ts +35 -0
- package/copilot-sdk/generated/rpc.d.ts +24623 -0
- package/copilot-sdk/generated/session-events.d.ts +11117 -0
- package/copilot-sdk/index.d.ts +15 -0
- package/copilot-sdk/index.js +11540 -0
- package/copilot-sdk/runtimeArtifacts.d.ts +6 -0
- package/copilot-sdk/sdkProtocolVersion.d.ts +10 -0
- package/copilot-sdk/session.d.ts +331 -0
- package/copilot-sdk/sessionFsProvider.d.ts +107 -0
- package/copilot-sdk/telemetry.d.ts +14 -0
- package/copilot-sdk/toolSet.d.ts +75 -0
- package/copilot-sdk/types.d.ts +2974 -0
- package/definitions/code-review.agent.yaml +94 -0
- package/definitions/explore.agent.yaml +75 -0
- package/definitions/rem-agent.agent.yaml +22 -0
- package/definitions/research.agent.yaml +111 -0
- package/definitions/rubber-duck.agent.yaml +67 -0
- package/definitions/security-review.agent.yaml +261 -0
- package/definitions/sidekick/cloud-session-search.yaml +37 -0
- package/definitions/sidekick/github-context-memory.yaml +46 -0
- package/definitions/sidekick/github-context.yaml +44 -0
- package/definitions/sidekick/session-search.yaml +37 -0
- package/definitions/sidekick/subconscious-agent.yaml +60 -0
- package/definitions/sidekick/test-sidekick-context-changed.yaml +24 -0
- package/definitions/sidekick/test-sidekick-persistent.yaml +23 -0
- package/definitions/sidekick/test-sidekick-restart.yaml +23 -0
- package/definitions/sidekick/test-sidekick-trigger-once.yaml +22 -0
- package/definitions/task.agent.yaml +44 -0
- package/package.json +14 -11
- package/plugins/computer-use/.mcp.json +10 -0
- package/plugins/computer-use/.plugin/plugin.json +6 -0
- package/plugins/computer-use/.release-target +1 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/CodeResources +0 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/Info.plist +38 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/MacOS/Copilot Computer Use +0 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/PkgInfo +1 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/Resources/Assets.car +0 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/Resources/icon.icns +0 -0
- package/plugins/computer-use/Copilot Computer Use.app/Contents/_CodeSignature/CodeResources +139 -0
- package/plugins/computer-use/computer-use-mcp +0 -0
- package/prebuilds/darwin-arm64/copilot-runtime +0 -0
- package/prebuilds/darwin-arm64/runtime.node +0 -0
- package/preloads/extension_bootstrap.mjs +68 -0
- package/preloads/extension_sdk_resolver.mjs +34 -0
- package/ripgrep/bin/darwin-arm64/rg +0 -0
- package/schemas/api.schema.json +41931 -0
- package/schemas/session-events.schema.json +20937 -0
- package/sdk/index.js +1489 -0
- package/tgrep/bin/darwin-arm64/tgrep +0 -0
- package/README.md +0 -3
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Copilot CLI Extensions
|
|
2
|
+
|
|
3
|
+
Extensions add custom tools, hooks, and behaviors to the Copilot CLI. They run as separate Node.js processes that communicate with the CLI over JSON-RPC via stdio.
|
|
4
|
+
|
|
5
|
+
## How Extensions Work
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────┐ JSON-RPC / stdio ┌──────────────────────┐
|
|
9
|
+
│ Copilot CLI │ ◄──────────────────────────────────► │ Extension Process │
|
|
10
|
+
│ (parent process) │ tool calls, events, hooks │ (forked child) │
|
|
11
|
+
│ │ │ │
|
|
12
|
+
│ • Discovers exts │ │ • Registers tools │
|
|
13
|
+
│ • Forks processes │ │ • Registers hooks │
|
|
14
|
+
│ • Routes tool calls │ │ • Listens to events │
|
|
15
|
+
│ • Manages lifecycle │ │ • Uses SDK APIs │
|
|
16
|
+
└─────────────────────┘ └──────────────────────┘
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
1. **Discovery**: The CLI scans `.github/extensions/` (project) and the user's copilot config extensions directory for subdirectories containing `extension.mjs`.
|
|
20
|
+
2. **Launch**: Each extension is forked as a child process with `@github/copilot-sdk` available via an automatic module resolver.
|
|
21
|
+
3. **Connection**: The extension calls `joinSession()` which establishes a JSON-RPC connection over stdio to the CLI and attaches to the user's current foreground session.
|
|
22
|
+
4. **Registration**: Tools and hooks declared in the session options are registered with the CLI and become available to the agent.
|
|
23
|
+
5. **Lifecycle**: Extensions are reloaded on `/clear` (or if the foreground session is replaced) and stopped on CLI exit (SIGTERM, then SIGKILL after 5s).
|
|
24
|
+
|
|
25
|
+
## File Structure
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
.github/extensions/
|
|
29
|
+
my-extension/
|
|
30
|
+
extension.mjs ← Entry point (required, must be .mjs)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- Only `.mjs` files are supported (ES modules). The file must be named `extension.mjs`.
|
|
34
|
+
- Each extension lives in its own subdirectory.
|
|
35
|
+
- The `@github/copilot-sdk` import is resolved automatically — you don't install it.
|
|
36
|
+
|
|
37
|
+
## The SDK
|
|
38
|
+
|
|
39
|
+
Extensions use `@github/copilot-sdk` for all interactions with the CLI:
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import { joinSession } from "@github/copilot-sdk/extension";
|
|
43
|
+
|
|
44
|
+
const session = await joinSession({
|
|
45
|
+
tools: [
|
|
46
|
+
/* ... */
|
|
47
|
+
],
|
|
48
|
+
hooks: {
|
|
49
|
+
/* ... */
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The `session` object provides methods for sending messages, logging to the timeline, listening to events, and accessing the RPC API. See the `.d.ts` files in the SDK package for full type information.
|
|
55
|
+
|
|
56
|
+
## Requesting Sensitive Environment Variables
|
|
57
|
+
|
|
58
|
+
The CLI strips sensitive environment variables (for example `GITHUB_TOKEN`) from every extension process before it starts. An extension that needs one asks for it by name:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
import { joinSession } from "@github/copilot-sdk/extension";
|
|
62
|
+
|
|
63
|
+
const session = await joinSession({
|
|
64
|
+
requestedEnvironmentVariables: ["GITHUB_TOKEN"],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Granted values are in process.env once joinSession resolves.
|
|
68
|
+
const token = process.env.GITHUB_TOKEN;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The CLI prompts the user with the extension's name and the exact list of variables requested. If the user approves, only those variables reach this extension and their values are written into `process.env` before `joinSession()` resolves. If the user denies, `joinSession()` rejects, the extension does not load, and its tools never reach the model.
|
|
72
|
+
|
|
73
|
+
An approval is remembered against the exact set of names the user saw, so an extension that later asks for an additional variable prompts again. Names that are unset, or that the CLI does not filter from extensions, are not prompted for.
|
|
74
|
+
|
|
75
|
+
An approved extension can pass a granted value to anything it starts, so ask only for what the extension genuinely needs.
|
|
76
|
+
|
|
77
|
+
## Further Reading
|
|
78
|
+
|
|
79
|
+
- `examples.md` — Practical code examples for tools, hooks, events, and complete extensions
|
|
80
|
+
- `factories.md`: Authoring, running, resuming, and observing Agent Factories
|
|
81
|
+
- `agent-author.md` — Step-by-step workflow for agents authoring extensions programmatically
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Agent Factories
|
|
2
|
+
|
|
3
|
+
Agent Factories are extension-authored, session-scoped workflows that coordinate subagents and durable steps. The API is experimental.
|
|
4
|
+
|
|
5
|
+
## Define and register a factory
|
|
6
|
+
|
|
7
|
+
Use `defineFactory` and pass the returned handle to `joinSession`:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
import { defineFactory, joinSession } from "@github/copilot-sdk/extension";
|
|
11
|
+
|
|
12
|
+
const reviewChanged = defineFactory({
|
|
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 factory run ${ctx.runId}`);
|
|
38
|
+
return report;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const session = await joinSession({ factories: [reviewChanged] });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Factory 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 factory that reads `ctx.args` should declare `meta.argsSchema`, as the example above does. When the model invokes the factory through the `run_factory` tool, the CLI validates `args` against the declaration **before** the run starts.
|
|
50
|
+
|
|
51
|
+
Declaring one turns an expensive failure into a cheap one. With a schema, a malformed call is rejected up front — the model gets a correction hint and retries, and no run row, permission prompt, or credit spend happens. Without one, nothing validates: the run starts, takes a user approval, spends credits, and then dies inside the factory body with a confusing error. Agents can read the declared shape with `factories_manage` using `operation: "inspect"`.
|
|
52
|
+
|
|
53
|
+
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 `FactoryJsonSchema` 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.
|
|
54
|
+
|
|
55
|
+
`argsSchema` is optional and backward compatible. A factory that omits it behaves exactly as before, so **the `description` is then the only thing telling an agent what arguments to supply** — state the expected shape there.
|
|
56
|
+
|
|
57
|
+
Validation covers the model's `run_factory` path only. An extension calling `session.factory.run(...)` directly is not validated against `argsSchema`; those arguments are typed through `defineFactory<TArgs>` instead, and that typing does not reach the model. So a factory that reads `ctx.args` should still validate it rather than assume a shape — the declared subset does not enforce every constraint, and it does not run at all on the SDK path.
|
|
58
|
+
|
|
59
|
+
`defineFactory<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 factory with no result. Other non-JSON values are rejected.
|
|
60
|
+
|
|
61
|
+
## Factory context
|
|
62
|
+
|
|
63
|
+
The `run()` context provides:
|
|
64
|
+
|
|
65
|
+
- `ctx.runId`: Stable ID reused across resumed attempts.
|
|
66
|
+
- `ctx.args`: Invocation arguments, forwarded verbatim. When the caller omits `args`, this is `{}` rather than `undefined`.
|
|
67
|
+
- `ctx.agent(prompt, options?)`: Runs one factory-owned subagent. Options are exactly `label`, `schema`, `model`, `agent`, `reasoningEffort`, and `contextTier`. See [Subagent calls](#subagent-calls).
|
|
68
|
+
- `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.
|
|
69
|
+
- `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.
|
|
70
|
+
- `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.
|
|
71
|
+
- `ctx.log(message)`: Appends a progress line. When a factory bounds its own coverage (top-N, sampling), log what was dropped.
|
|
72
|
+
- `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.
|
|
73
|
+
|
|
74
|
+
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.
|
|
75
|
+
- `ctx.session`: The session returned by `joinSession`. It refuses calls that start or resume a factory run. Call `extensions_manage` with `operation: "guide"` to read more about the session APIs.
|
|
76
|
+
- `ctx.signal`: Cooperative cancellation signal for extension work and subprocesses.
|
|
77
|
+
- `ctx.factory(...)`: Always rejects because nested factories are not supported.
|
|
78
|
+
|
|
79
|
+
Factory-owned subagents are intentionally hidden from `read_agent` and `write_agent`. Use the factory observability APIs instead.
|
|
80
|
+
|
|
81
|
+
### Subagent calls
|
|
82
|
+
|
|
83
|
+
`ctx.agent(prompt, options?)` spawns one factory-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.
|
|
84
|
+
|
|
85
|
+
**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:
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
// One subagent, awaited five times — almost certainly not what you want.
|
|
89
|
+
await ctx.parallel([1, 2, 3, 4, 5].map(() => () => ctx.agent("Find a bug")));
|
|
90
|
+
|
|
91
|
+
// Five independent subagents.
|
|
92
|
+
await ctx.parallel(
|
|
93
|
+
[1, 2, 3, 4, 5].map((i) => () => ctx.agent("Find a bug", { label: `finder:${i}` }))
|
|
94
|
+
);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**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(...)`:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
const finding = await ctx.agent(prompt, { label: "inspector" });
|
|
101
|
+
if (!finding) return { finding: null };
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
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 `""`.
|
|
105
|
+
|
|
106
|
+
**`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`.
|
|
107
|
+
|
|
108
|
+
### Choosing between pipeline and parallel
|
|
109
|
+
|
|
110
|
+
Prefer `pipeline` for multi-stage work. It has no barrier between stages, so each item advances as soon as its own prior stage finishes.
|
|
111
|
+
|
|
112
|
+
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.
|
|
113
|
+
|
|
114
|
+
See [factory-patterns.md](./factory-patterns.md) for composable orchestration patterns built on these primitives.
|
|
115
|
+
|
|
116
|
+
## Resource limits
|
|
117
|
+
|
|
118
|
+
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.
|
|
119
|
+
|
|
120
|
+
Set a ceiling only from real knowledge of what the factory costs, or because the user named one. A guessed ceiling does not make a run safer: it stops a healthy run partway with `factory_limit_reached`, after that run has already spent credits. An agent authoring or invoking a factory on the user's behalf has no basis for estimating a number, so it should leave `limits` unset and bound the work with the factory's own counters instead. Omitting limits does not remove oversight of a model-initiated run: `run_factory` requests permission first, and that prompt shows the effective limits. SDK-initiated `run` and `resume` do not request permission, so an SDK caller that wants a ceiling sets it deliberately, from the cost it already knows.
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
// Only when the cost profile is known, or the user asked for this ceiling.
|
|
124
|
+
limits: { maxTotalSubagents: 10 },
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
- `maxConcurrentSubagents`: Positive integer concurrent-subagent cap. Additional subagents wait in a queue. Queueing applies backpressure and does not fail the run.
|
|
128
|
+
- `maxTotalSubagents`: Positive integer cumulative admission cap. An attempted subagent beyond the cap ends the attempt with failure kind `maxTotalSubagents`.
|
|
129
|
+
- `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`.
|
|
130
|
+
- `maxAiCredits`: Positive finite AI-credit budget for the whole run's factory 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`.
|
|
131
|
+
|
|
132
|
+
`maxTotalSubagents`, `timeoutSeconds`, and `maxAiCredits` use reject-and-retry semantics. A rejected attempt ends with run status `error` and `failure.type` set to `factory_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.
|
|
133
|
+
|
|
134
|
+
## Run and resume
|
|
135
|
+
|
|
136
|
+
Run by registered name or handle:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
const run = await session.factory.run("review-changed", {
|
|
140
|
+
args: { files: ["src/a.ts"] },
|
|
141
|
+
limits: { maxAiCredits: 3 },
|
|
142
|
+
notifyOnComplete: true,
|
|
143
|
+
logPhaseNames: true,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (run.status === "completed") {
|
|
147
|
+
console.log(run.result);
|
|
148
|
+
} else {
|
|
149
|
+
console.error(`run ${run.runId} ended as ${run.status}`, run.failure ?? run.error);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The name overload is:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
session.factory.run(
|
|
157
|
+
name: string,
|
|
158
|
+
options?: {
|
|
159
|
+
args?: JsonValue;
|
|
160
|
+
limits?: FactoryLimits;
|
|
161
|
+
notifyOnComplete?: boolean;
|
|
162
|
+
logPhaseNames?: boolean;
|
|
163
|
+
},
|
|
164
|
+
): Promise<FactoryRunResult>;
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Resume by run ID without resending the name or arguments:
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
const run = await session.factory.resume(runId, {
|
|
171
|
+
limits: { maxAiCredits: 6 },
|
|
172
|
+
notifyOnComplete: true,
|
|
173
|
+
logPhaseNames: true,
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The signature is:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
session.factory.resume(
|
|
181
|
+
runId: string,
|
|
182
|
+
options?: {
|
|
183
|
+
limits?: FactoryLimits;
|
|
184
|
+
notifyOnComplete?: boolean;
|
|
185
|
+
logPhaseNames?: boolean;
|
|
186
|
+
},
|
|
187
|
+
): Promise<FactoryRunResult>;
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Set `notifyOnComplete` to `true` for factories that are likely to be invoked by an agent, so the originating session is notified when the factory completes. Set it to `false` for factories intended to be invoked programmatically, where the caller awaits the result directly. Set `logPhaseNames` to emit factory phase names to the session transcript. Both options apply to new and resumed runs.
|
|
191
|
+
|
|
192
|
+
Both resolve with the run envelope (`FactoryRunResult`) for **every** outcome — `completed`, `error`, `halted`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`. SDK-initiated `run` and `resume` do not request permission, so they have no declined outcome. The model's `run_factory` tool requests permission before the durable row exists; declining it creates no run row. 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 `FactoryResumeError`, whose `code` is one of `not_found`, `non_resumable`, `already_active`, `factory_already_running`, `factory_limits_invalid`, `factory_session_disposed`, `factory_storage_unavailable`, or `factory_storage_corrupt`.
|
|
193
|
+
|
|
194
|
+
An agent that no longer has a prior run's ID in context can recover it with `factories_manage` and `operation: "runs"`, which lists the session's factory runs with their IDs and statuses. This matters for resume: a run that reached a limit keeps its journal, so resuming it replays completed work for free, while restarting it from scratch pays for that work twice.
|
|
195
|
+
|
|
196
|
+
The agent-facing `run_factory` tool has exactly two input branches:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
{ name: string; args?: JsonValue; limits?: FactoryLimits }
|
|
200
|
+
{ resumeFromRunId: string; limits?: FactoryLimits }
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Authoring a factory from inside a session
|
|
204
|
+
|
|
205
|
+
The agent-facing `factories_manage` tool writes a factory into a session-scoped extension at runtime with `operation: "author"`. The rules above all apply, plus one constraint that does not affect an extension author.
|
|
206
|
+
|
|
207
|
+
**The `run` body is self-contained.** It is emitted verbatim into a generated module as a single async function expression. It closes over nothing: not the conversation that authored it, and not any authoring-time binding. Only its own locals, its `ctx` parameter, and standard Node and JavaScript globals are in scope, so every schema, constant, and helper must be defined *inside* the function. The generated module imports the SDK itself; the expression cannot add static `import` statements or use `require`. Load anything else with a dynamic `await import("...")` in the body.
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
async ({ args, agent, phase }) => {
|
|
211
|
+
// Defined inside — there is no outer scope to close over.
|
|
212
|
+
const VERDICT = { type: "object", properties: { real: { type: "boolean" } }, required: ["real"] };
|
|
213
|
+
|
|
214
|
+
phase("Inspect");
|
|
215
|
+
const finding = await agent(`Name one likely bug in ${args.file ?? "the code"}.`, {
|
|
216
|
+
label: "inspector",
|
|
217
|
+
});
|
|
218
|
+
if (!finding) return { finding: null, real: false };
|
|
219
|
+
|
|
220
|
+
phase("Verify");
|
|
221
|
+
const verdict = await agent(`Is this a real bug? Claim: ${finding}`, {
|
|
222
|
+
label: "verifier",
|
|
223
|
+
schema: VERDICT,
|
|
224
|
+
});
|
|
225
|
+
return { finding, real: verdict?.real === true };
|
|
226
|
+
};
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Authoring registers the factory but does not run it. Invoke it afterwards with `run_factory`. Use `factories_manage` with `operation: "list"` to see the factories already registered in the session and `operation: "inspect"` to read one factory's description, phases, declared argument shape, and limits before running it.
|
|
230
|
+
|
|
231
|
+
## Observe a run
|
|
232
|
+
|
|
233
|
+
The calling session can inspect its own factory runs:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
const runs = await session.factory.listRuns();
|
|
237
|
+
const runsPage = await session.factory.listRuns({
|
|
238
|
+
afterSeq,
|
|
239
|
+
beforeSeq,
|
|
240
|
+
limit,
|
|
241
|
+
});
|
|
242
|
+
const detail = await session.factory.getRunDetail(runId);
|
|
243
|
+
const progressPage = await session.factory.getRunProgress(runId, {
|
|
244
|
+
phaseId,
|
|
245
|
+
afterSeq,
|
|
246
|
+
beforeSeq,
|
|
247
|
+
limit,
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
- `listRuns()` returns only the runs array from the newest default page of this session's durable factory runs. This overload preserves the original convenience API.
|
|
252
|
+
- `listRuns({ afterSeq, beforeSeq, limit })` returns the full page. Its `oldestSeq`, `newestSeq`, `hasMoreNewer`, and `omittedOlder` fields let callers continue paging without raw RPC calls.
|
|
253
|
+
- `getRunDetail(runId)` returns phases, prompt-safe agent summaries, and the latest progress page.
|
|
254
|
+
- `getRunProgress(runId, options?)` pages progress forward, backward, by phase, or from the latest tail.
|
|
255
|
+
|
|
256
|
+
`getRun(runId)` reads the latest run envelope, and `cancel(runId)` cancels a run and returns its terminal envelope.
|
|
257
|
+
|
|
258
|
+
`waitForRun(runId, options?)` resolves with the terminal envelope once the run settles into `completed`, `error`, `halted`, or `cancelled`, and resolves immediately when it has already settled:
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
const settled = await session.factory.waitForRun(runId);
|
|
262
|
+
if (settled.status === "completed") {
|
|
263
|
+
console.log(settled.result);
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
It watches `factory.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:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
const controller = new AbortController();
|
|
271
|
+
setTimeout(() => controller.abort(), 30_000);
|
|
272
|
+
const settled = await session.factory.waitForRun(runId, { signal: controller.signal });
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Aborting rejects the wait and has no effect on the run, which keeps executing — use `cancel(runId)` to actually stop it. Because a terminal envelope is final, the resolved value never changes afterwards. `isFactoryRunTerminal(status)` exposes the same terminal-status test for callers driving their own loop.
|
|
276
|
+
|
|
277
|
+
Listen for the ephemeral `factory.run_updated` event. Its `{ runId, revision }` payload is an invalidation signal. Re-read the desired API when a newer monotonic revision arrives.
|
|
278
|
+
|
|
279
|
+
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. Factory prompts are never exposed by these APIs. A run is visible only through the session that owns it.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# Agent Factory patterns
|
|
2
|
+
|
|
3
|
+
Composable orchestration patterns built on the factory context. Read [factories.md](./factories.md) first for the API and its semantics. The API is experimental.
|
|
4
|
+
|
|
5
|
+
Every snippet below assumes the surrounding `async (ctx) => { ... }` run body and destructures the hooks it uses. Three rules apply throughout, because breaking them fails silently:
|
|
6
|
+
|
|
7
|
+
- **Give every independent subagent a unique `label`.** Identical prompt-and-options pairs memoize into a single shared subagent.
|
|
8
|
+
- **Guard every `agent()` result.** An ordinary failure resolves to `null` rather than throwing.
|
|
9
|
+
- **Filter with `v => v !== null`,** not `Boolean`, which also discards a valid `false`, `0`, or `""`.
|
|
10
|
+
|
|
11
|
+
## Multi-stage review
|
|
12
|
+
|
|
13
|
+
The default shape: fan out across dimensions, and let each dimension verify as soon as its own review lands. No barrier, so a slow dimension never holds up a fast one.
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
async ({ pipeline, parallel, agent, phase, log }) => {
|
|
17
|
+
const FINDINGS = {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
findings: {
|
|
21
|
+
type: "array",
|
|
22
|
+
items: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: { title: { type: "string" } },
|
|
25
|
+
required: ["title"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
required: ["findings"],
|
|
30
|
+
};
|
|
31
|
+
const VERDICT = {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: { isReal: { type: "boolean" } },
|
|
34
|
+
required: ["isReal"],
|
|
35
|
+
};
|
|
36
|
+
const DIMENSIONS = [
|
|
37
|
+
{ key: "bugs", prompt: "Review the diff for correctness bugs. Return JSON {findings:[{title}]}." },
|
|
38
|
+
{ key: "perf", prompt: "Review the diff for performance issues. Return JSON {findings:[{title}]}." },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
phase("Review"); // Run-global: set it before the fan-out, never inside a stage.
|
|
42
|
+
const perDimension = await pipeline(
|
|
43
|
+
DIMENSIONS,
|
|
44
|
+
(d) => agent(d.prompt, { label: `review:${d.key}`, schema: FINDINGS }),
|
|
45
|
+
(review, d) => {
|
|
46
|
+
if (!review) {
|
|
47
|
+
log(`review:${d.key} produced nothing`);
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return parallel(
|
|
51
|
+
(review.findings ?? []).map((f, i) => () =>
|
|
52
|
+
agent(`Adversarially verify this finding is real: ${f.title}`, {
|
|
53
|
+
label: `verify:${d.key}:${i}`,
|
|
54
|
+
schema: VERDICT,
|
|
55
|
+
}).then((v) => (v && v.isReal ? f : null))
|
|
56
|
+
)
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return { confirmed: perDimension.flat().filter((v) => v !== null) };
|
|
62
|
+
};
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## When a barrier is correct
|
|
66
|
+
|
|
67
|
+
Deduplicating across every finding needs the whole set in hand, so the barrier earns its cost here. Dedup itself is plain JavaScript, done in the body between the two fan-outs. This excerpt reuses `FINDINGS`, `VERDICT`, and `DIMENSIONS` from the previous example — define them inside your own function.
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
const all = await parallel(
|
|
71
|
+
DIMENSIONS.map((d) => () => agent(d.prompt, { label: `find:${d.key}`, schema: FINDINGS }))
|
|
72
|
+
);
|
|
73
|
+
const findings = all.filter((v) => v !== null).flatMap((r) => r.findings ?? []);
|
|
74
|
+
const deduped = [...new Map(findings.map((f) => [f.title, f])).values()]; // Needs all of them.
|
|
75
|
+
const verified = await parallel(
|
|
76
|
+
deduped.map((f, i) => () => agent(`Verify: ${f.title}`, { label: `verify:${i}`, schema: VERDICT }))
|
|
77
|
+
);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Loop until count
|
|
81
|
+
|
|
82
|
+
Accumulate toward a target. Each iteration needs a unique identity — a unique label plus a prompt that excludes what has already been found — a bounded attempt count, and a null guard.
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
const BUG = {
|
|
86
|
+
type: "object",
|
|
87
|
+
properties: { title: { type: "string" } },
|
|
88
|
+
required: ["title"],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const bugs = [];
|
|
92
|
+
let attempt = 0;
|
|
93
|
+
while (bugs.length < 10 && attempt < 30) {
|
|
94
|
+
const r = await agent(
|
|
95
|
+
`Find ONE distinct bug NOT already listed: ${JSON.stringify(bugs.map((b) => b.title))}. Return JSON {title}.`,
|
|
96
|
+
{ label: `finder:${attempt}`, schema: BUG }
|
|
97
|
+
);
|
|
98
|
+
attempt++;
|
|
99
|
+
if (r && r.title) bugs.push(r);
|
|
100
|
+
log(`${bugs.length}/10 found`);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Loop until dry
|
|
105
|
+
|
|
106
|
+
Keep spawning finders until some number of consecutive rounds surface nothing new. Deduplicate against everything *seen*, not just what was kept, or discarded findings resurface every round.
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
const BUGS = {
|
|
110
|
+
type: "object",
|
|
111
|
+
properties: {
|
|
112
|
+
bugs: {
|
|
113
|
+
type: "array",
|
|
114
|
+
items: { type: "object", properties: { title: { type: "string" } }, required: ["title"] },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
required: ["bugs"],
|
|
118
|
+
};
|
|
119
|
+
const VERDICT = {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: { real: { type: "boolean" } },
|
|
122
|
+
required: ["real"],
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const seen = new Set();
|
|
126
|
+
const confirmed = [];
|
|
127
|
+
const keyOf = (b) => b.title.toLowerCase();
|
|
128
|
+
let dry = 0;
|
|
129
|
+
let round = 0;
|
|
130
|
+
|
|
131
|
+
while (dry < 2 && round < 20) {
|
|
132
|
+
const found = (
|
|
133
|
+
await parallel(
|
|
134
|
+
[0, 1, 2].map((i) => () =>
|
|
135
|
+
agent(`Find bugs (finder ${i}, round ${round}). Return JSON {bugs:[{title}]}.`, {
|
|
136
|
+
label: `find:${round}:${i}`,
|
|
137
|
+
schema: BUGS,
|
|
138
|
+
})
|
|
139
|
+
)
|
|
140
|
+
)
|
|
141
|
+
)
|
|
142
|
+
.filter((v) => v !== null)
|
|
143
|
+
.flatMap((r) => r.bugs ?? []);
|
|
144
|
+
|
|
145
|
+
const fresh = found.filter((b) => {
|
|
146
|
+
const k = keyOf(b);
|
|
147
|
+
if (seen.has(k)) return false;
|
|
148
|
+
seen.add(k);
|
|
149
|
+
return true;
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!fresh.length) {
|
|
153
|
+
dry++;
|
|
154
|
+
round++;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
dry = 0;
|
|
158
|
+
|
|
159
|
+
const judged = await parallel(
|
|
160
|
+
fresh.map((b, i) => () =>
|
|
161
|
+
parallel(
|
|
162
|
+
["correctness", "security", "repro"].map((lens) => () =>
|
|
163
|
+
agent(`Judge via ${lens}: is "${b.title}" real? Return JSON {real}.`, {
|
|
164
|
+
label: `judge:${round}:${i}:${lens}`,
|
|
165
|
+
schema: VERDICT,
|
|
166
|
+
})
|
|
167
|
+
)
|
|
168
|
+
).then((vs) => ({ b, real: vs.filter((v) => v !== null).filter((v) => v.real).length >= 2 }))
|
|
169
|
+
)
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
confirmed.push(...judged.filter((v) => v !== null && v.real).map((v) => v.b));
|
|
173
|
+
round++;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Quality patterns
|
|
178
|
+
|
|
179
|
+
Compose these freely.
|
|
180
|
+
|
|
181
|
+
- **Adversarial verify.** Spawn several independent skeptics per finding, each prompted to *refute* it and to default to refuted when uncertain. Keep only what a majority fails to refute.
|
|
182
|
+
- **Perspective-diverse verify.** Give each verifier a distinct lens — correctness, security, performance, does-it-reproduce — instead of several identical skeptics. The distinct prompts also stop them memoizing into one subagent.
|
|
183
|
+
- **Judge panel.** Generate several independent attempts from different angles, score them with parallel judges, then synthesize from the winner while grafting the best ideas from the runners-up.
|
|
184
|
+
- **Multi-modal sweep.** Run parallel searchers that each look a different way: by container, by content, by entity, by time.
|
|
185
|
+
- **Completeness critic.** End with an agent asking what is missing — an angle not run, a claim unverified, a source unread — and use its answer to seed the next round.
|
|
186
|
+
- **No silent caps.** When the factory bounds its own coverage with a top-N, a sampling step, or a no-retry rule, `log()` what was dropped.
|
|
187
|
+
|
|
188
|
+
## Scaling
|
|
189
|
+
|
|
190
|
+
Match the orchestration to what was asked. A quick check wants a couple of subagents and single-vote verification; a request to be thorough or comprehensive wants a larger finder pool, a three-to-five vote adversarial pass, and a synthesis stage.
|
|
191
|
+
|
|
192
|
+
There is no in-script budget object. Scale with your own counters, as in the loop patterns above, and treat any declared limits as the safety ceiling rather than the control mechanism. Only `agent()` spawns are throttled, by `maxConcurrentSubagents` falling back to `maxTotalSubagents`; with neither declared there is no built-in concurrency cap, so bound a wide fan-out with the factory's own counters. Do not invent a ceiling to compensate, and see [Resource limits](./factories.md#resource-limits) for when declaring one is appropriate. `parallel` itself is `Promise.all`, so non-agent work in a thunk runs fully concurrently regardless.
|
|
193
|
+
|
|
194
|
+
These patterns are not exhaustive. Compose novel harnesses — tournament brackets, self-repair loops, staged escalation — when the task calls for it.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { CopilotSession } from "./session.js";
|
|
2
|
+
import { type PermissionHandler, type ResumeSessionConfig } from "./types.js";
|
|
3
|
+
import type { FactoryHandle } from "./factory.js";
|
|
4
|
+
export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js";
|
|
5
|
+
export type JoinSessionConfig = Omit<ResumeSessionConfig, "onPermissionRequest" | "extensionSdkPath"> & {
|
|
6
|
+
onPermissionRequest?: PermissionHandler;
|
|
7
|
+
/**
|
|
8
|
+
* Names of sensitive environment variables this extension needs, such as
|
|
9
|
+
* `"GITHUB_TOKEN"`.
|
|
10
|
+
*
|
|
11
|
+
* The Copilot CLI strips sensitive variables from every extension process
|
|
12
|
+
* before it starts, so an extension that needs one must ask for it by name.
|
|
13
|
+
* The CLI prompts the user with the extension's name and the exact list of
|
|
14
|
+
* variables requested. On approval the granted values are written into this
|
|
15
|
+
* process's `process.env` before {@link joinSession} resolves, so they are
|
|
16
|
+
* readable afterwards. On denial the join rejects and the extension does not
|
|
17
|
+
* load, so its tools never reach the model.
|
|
18
|
+
*
|
|
19
|
+
* An approval is remembered against the exact set of names the user saw, so
|
|
20
|
+
* asking for an additional variable later prompts again. Names that are unset
|
|
21
|
+
* or that the CLI does not filter from extensions are not prompted for. An
|
|
22
|
+
* empty list means the same as omitting the option: nothing is requested.
|
|
23
|
+
*
|
|
24
|
+
* Requires a Copilot CLI that supports extension environment access; older
|
|
25
|
+
* CLIs ignore the request and grant nothing.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const session = await joinSession({
|
|
30
|
+
* requestedEnvironmentVariables: ["GITHUB_TOKEN"],
|
|
31
|
+
* });
|
|
32
|
+
* const token = process.env.GITHUB_TOKEN;
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
requestedEnvironmentVariables?: string[];
|
|
36
|
+
/**
|
|
37
|
+
* Factory handles to register when the extension joins the session.
|
|
38
|
+
*
|
|
39
|
+
* @experimental Part of the experimental Agent Factories surface and may
|
|
40
|
+
* change or be removed in future SDK or CLI releases.
|
|
41
|
+
*/
|
|
42
|
+
factories?: FactoryHandle[];
|
|
43
|
+
};
|
|
44
|
+
export type { ExtensionInfo, FactoryLimits, FactoryMeta } from "./types.js";
|
|
45
|
+
export { defineFactory, FactoryResumeError, isFactoryRunTerminal, type RunOptions, type ResumeOptions, type FactoryResumeErrorCode, type SessionFactoryApi, type FactoryAgentOptions, type FactoryContext, type FactoryDefinition, type FactoryHandle, type FactoryJsonSchema, type JsonValue, type FactoryPipelineStage, type FactoryStepOptions, type FactoryRunResult, type FactoryRunStatus, type FactoryRunSummary, type FactoryListRunsOptions, type FactoryRunsPage, type FactoryRunDetail, type FactoryProgressPage, type FactoryProgressLine, type FactoryPhaseObservation, type FactoryPhaseStatus, type FactoryAgentSummary, } from "./factory.js";
|
|
46
|
+
/**
|
|
47
|
+
* Joins the current foreground session.
|
|
48
|
+
*
|
|
49
|
+
* @param config - Configuration to add to the session
|
|
50
|
+
* @returns A promise that resolves with the joined session
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { joinSession } from "@github/copilot-sdk/extension";
|
|
55
|
+
*
|
|
56
|
+
* const session = await joinSession({ tools: [myTool] });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare function joinSession(config?: JoinSessionConfig): Promise<CopilotSession>;
|