@github/copilot-sdk 1.0.17-preview.0 → 1.0.17-preview.10
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/README.md +108 -0
- package/dist/canvas.d.ts +6 -1
- package/dist/cjs/cliVersion.js +1 -1
- package/dist/cjs/client.js +69 -4
- package/dist/cjs/extension.js +2 -0
- package/dist/cjs/generated/rpc.js +577 -251
- package/dist/cjs/index.js +2 -0
- package/dist/cjs/runtimeArtifacts.js +1 -0
- package/dist/cjs/session.js +151 -2
- package/dist/cjs/sessionFsProvider.js +57 -0
- package/dist/cjs/types.js +5 -2
- package/dist/cliVersion.d.ts +1 -1
- package/dist/cliVersion.js +1 -1
- package/dist/client.d.ts +1 -0
- package/dist/client.js +69 -4
- package/dist/extension.d.ts +1 -1
- package/dist/extension.js +2 -0
- package/dist/generated/rpc.d.ts +2250 -684
- package/dist/generated/rpc.js +577 -251
- package/dist/generated/session-events.d.ts +292 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -0
- package/dist/runtimeArtifacts.js +1 -0
- package/dist/session.d.ts +52 -1
- package/dist/session.js +151 -2
- package/dist/sessionFsProvider.d.ts +9 -1
- package/dist/sessionFsProvider.js +56 -0
- package/dist/types.d.ts +159 -2
- package/dist/types.js +4 -2
- package/docs/agent-author.md +29 -2
- package/package.json +13 -12
package/dist/session.js
CHANGED
|
@@ -20,6 +20,18 @@ function copyDefinedWorkflowAgentOption(source, target, key) {
|
|
|
20
20
|
target[key] = value;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
function toToolDefinition(tool) {
|
|
24
|
+
return {
|
|
25
|
+
name: tool.name,
|
|
26
|
+
description: tool.description ?? "",
|
|
27
|
+
parameters: toJsonSchema(tool.parameters),
|
|
28
|
+
overridesBuiltInTool: tool.overridesBuiltInTool,
|
|
29
|
+
skipPermission: tool.skipPermission,
|
|
30
|
+
defer: tool.defer,
|
|
31
|
+
metadata: tool.metadata,
|
|
32
|
+
isTerminal: tool.isTerminal
|
|
33
|
+
};
|
|
34
|
+
}
|
|
23
35
|
const workflowExecutionStore = new AsyncLocalStorage();
|
|
24
36
|
function throwIfWorkflowExecutionIsActive() {
|
|
25
37
|
if (workflowExecutionStore.getStore()?.active) {
|
|
@@ -240,6 +252,8 @@ class CopilotSession {
|
|
|
240
252
|
eventHandlers = /* @__PURE__ */ new Set();
|
|
241
253
|
typedEventHandlers = /* @__PURE__ */ new Map();
|
|
242
254
|
toolHandlers = /* @__PURE__ */ new Map();
|
|
255
|
+
/** Settles once every earlier `setTools` call has finished. */
|
|
256
|
+
setToolsQueue = Promise.resolve();
|
|
243
257
|
pendingExternalTools = /* @__PURE__ */ new Map();
|
|
244
258
|
canvases = /* @__PURE__ */ new Map();
|
|
245
259
|
bearerTokenProviders = /* @__PURE__ */ new Map();
|
|
@@ -252,6 +266,7 @@ class CopilotSession {
|
|
|
252
266
|
elicitationHandler;
|
|
253
267
|
exitPlanModeHandler;
|
|
254
268
|
autoModeSwitchHandler;
|
|
269
|
+
skillProvider;
|
|
255
270
|
hooks;
|
|
256
271
|
transformCallbacks;
|
|
257
272
|
_rpc = null;
|
|
@@ -664,6 +679,7 @@ class CopilotSession {
|
|
|
664
679
|
this.elicitationHandler = void 0;
|
|
665
680
|
this.exitPlanModeHandler = void 0;
|
|
666
681
|
this.autoModeSwitchHandler = void 0;
|
|
682
|
+
this.skillProvider = void 0;
|
|
667
683
|
this.commandHandlers.clear();
|
|
668
684
|
this.canvases.clear();
|
|
669
685
|
this.workflows.clear();
|
|
@@ -1051,7 +1067,20 @@ class CopilotSession {
|
|
|
1051
1067
|
}
|
|
1052
1068
|
for (const tool of tools) {
|
|
1053
1069
|
if (tool.handler) {
|
|
1054
|
-
|
|
1070
|
+
const handler = tool.handler;
|
|
1071
|
+
if (tool.name === "apply_patch" && tool.overridesBuiltInTool && toJsonSchema(tool.parameters)?.type === "string") {
|
|
1072
|
+
this.toolHandlers.set(tool.name, (args, invocation) => {
|
|
1073
|
+
if (typeof args === "string") {
|
|
1074
|
+
return handler(args, invocation);
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof args === "object" && args !== null && "input" in args && typeof args.input === "string") {
|
|
1077
|
+
return handler(args.input, invocation);
|
|
1078
|
+
}
|
|
1079
|
+
throw new TypeError("apply_patch string override requires a string input");
|
|
1080
|
+
});
|
|
1081
|
+
} else {
|
|
1082
|
+
this.toolHandlers.set(tool.name, handler);
|
|
1083
|
+
}
|
|
1055
1084
|
}
|
|
1056
1085
|
}
|
|
1057
1086
|
}
|
|
@@ -1557,6 +1586,68 @@ class CopilotSession {
|
|
|
1557
1586
|
registerUserInputHandler(handler) {
|
|
1558
1587
|
this.userInputHandler = handler;
|
|
1559
1588
|
}
|
|
1589
|
+
/**
|
|
1590
|
+
* Registers the session's skill provider.
|
|
1591
|
+
*
|
|
1592
|
+
* @param provider - The skill provider, or undefined to remove it
|
|
1593
|
+
* @internal This method is typically called internally when creating a session.
|
|
1594
|
+
*/
|
|
1595
|
+
registerSkillProvider(provider) {
|
|
1596
|
+
this.skillProvider = provider;
|
|
1597
|
+
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Handles a `skillProvider.list` request from the runtime.
|
|
1600
|
+
*
|
|
1601
|
+
* @internal This method is for internal use by the SDK.
|
|
1602
|
+
*/
|
|
1603
|
+
async _handleSkillProviderList(token) {
|
|
1604
|
+
const provider = this.requireSkillProvider();
|
|
1605
|
+
return await this.callSkillProvider("listSkills", token, async (options) => ({
|
|
1606
|
+
skills: await provider.listSkills(options) ?? []
|
|
1607
|
+
}));
|
|
1608
|
+
}
|
|
1609
|
+
/**
|
|
1610
|
+
* Handles a `skillProvider.read` request from the runtime.
|
|
1611
|
+
*
|
|
1612
|
+
* @internal This method is for internal use by the SDK.
|
|
1613
|
+
*/
|
|
1614
|
+
async _handleSkillProviderRead(name, token) {
|
|
1615
|
+
const provider = this.requireSkillProvider();
|
|
1616
|
+
return await this.callSkillProvider("readSkill", token, async (options) => ({
|
|
1617
|
+
markdown: await provider.readSkill(name, options) ?? null
|
|
1618
|
+
}));
|
|
1619
|
+
}
|
|
1620
|
+
requireSkillProvider() {
|
|
1621
|
+
if (!this.skillProvider) {
|
|
1622
|
+
throw new Error(`No skill provider for session: ${this.sessionId}`);
|
|
1623
|
+
}
|
|
1624
|
+
return this.skillProvider;
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Runs a provider call with an abort signal tied to the runtime's request
|
|
1628
|
+
* cancellation. Failures are logged locally and reported generically.
|
|
1629
|
+
*/
|
|
1630
|
+
async callSkillProvider(operation, token, call) {
|
|
1631
|
+
const controller = new AbortController();
|
|
1632
|
+
const subscription = token?.onCancellationRequested(() => controller.abort());
|
|
1633
|
+
if (token?.isCancellationRequested) {
|
|
1634
|
+
controller.abort();
|
|
1635
|
+
}
|
|
1636
|
+
try {
|
|
1637
|
+
return await call({ signal: controller.signal });
|
|
1638
|
+
} catch (error) {
|
|
1639
|
+
if (controller.signal.aborted) {
|
|
1640
|
+
throw new ResponseError(-32800, `Skill provider ${operation} cancelled`);
|
|
1641
|
+
}
|
|
1642
|
+
console.error(`Skill provider ${operation} failed`, {
|
|
1643
|
+
sessionId: this.sessionId,
|
|
1644
|
+
error
|
|
1645
|
+
});
|
|
1646
|
+
throw skillProviderFailure(operation);
|
|
1647
|
+
} finally {
|
|
1648
|
+
subscription?.dispose();
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1560
1651
|
/**
|
|
1561
1652
|
* Registers hook handlers for session lifecycle events.
|
|
1562
1653
|
*
|
|
@@ -1646,7 +1737,9 @@ class CopilotSession {
|
|
|
1646
1737
|
sessionStart: this.hooks.onSessionStart,
|
|
1647
1738
|
sessionEnd: this.hooks.onSessionEnd,
|
|
1648
1739
|
errorOccurred: this.hooks.onErrorOccurred,
|
|
1649
|
-
agentStop: this.hooks.onAgentStop
|
|
1740
|
+
agentStop: this.hooks.onAgentStop,
|
|
1741
|
+
subagentStart: this.hooks.onSubagentStart,
|
|
1742
|
+
subagentStop: this.hooks.onSubagentStop
|
|
1650
1743
|
};
|
|
1651
1744
|
const handler = handlerMap[hookType];
|
|
1652
1745
|
if (!handler) {
|
|
@@ -1810,6 +1903,59 @@ class CopilotSession {
|
|
|
1810
1903
|
async setAutoTier(autoTier) {
|
|
1811
1904
|
return await this.rpc.model.switchAutoTier({ autoTier });
|
|
1812
1905
|
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Replace the tools this client supplies to the session.
|
|
1908
|
+
*
|
|
1909
|
+
* `tools` becomes the complete set of tools this client implements,
|
|
1910
|
+
* replacing the ones it supplied when the session was created or resumed,
|
|
1911
|
+
* or in an earlier call. Built-in, MCP, and plugin tools, and tools other
|
|
1912
|
+
* connected clients supply, are unaffected. Pass an empty array to remove
|
|
1913
|
+
* all of this client's tools.
|
|
1914
|
+
*
|
|
1915
|
+
* Tools are defined the same way as for `createSession`: calls to tools
|
|
1916
|
+
* with a `handler` are dispatched to it, and tools without one are
|
|
1917
|
+
* declaration-only. Once the runtime accepts the replacement, every tool
|
|
1918
|
+
* call this session dispatches uses the new handlers; calls already
|
|
1919
|
+
* running finish on their original handlers. If the runtime rejects the
|
|
1920
|
+
* replacement, this rejects and the previous tools and handlers stay in
|
|
1921
|
+
* place. Concurrent calls on the same session are applied one at a time,
|
|
1922
|
+
* in the order they are made.
|
|
1923
|
+
*
|
|
1924
|
+
* The agent sees the new tools from its next model request, which can fall
|
|
1925
|
+
* within a turn in progress. A model request already in flight was made
|
|
1926
|
+
* with the previous tools, so the agent can still call a tool you removed.
|
|
1927
|
+
* This session doesn't answer that call, and it can stay pending until the
|
|
1928
|
+
* turn is aborted. If a running turn might still call a tool you remove,
|
|
1929
|
+
* replace tools while the session is idle.
|
|
1930
|
+
*
|
|
1931
|
+
* @param tools - The complete set of tools this client supplies
|
|
1932
|
+
*
|
|
1933
|
+
* @experimental Wraps the experimental `session.tools.set` RPC and may change
|
|
1934
|
+
* or be removed in a future release.
|
|
1935
|
+
*
|
|
1936
|
+
* @example
|
|
1937
|
+
* ```typescript
|
|
1938
|
+
* await session.setTools([
|
|
1939
|
+
* defineTool("search_issues", {
|
|
1940
|
+
* description: "Search the issues shown on the current page",
|
|
1941
|
+
* parameters: z.object({ query: z.string() }),
|
|
1942
|
+
* handler: async ({ query }) => searchIssues(query),
|
|
1943
|
+
* }),
|
|
1944
|
+
* ]);
|
|
1945
|
+
* ```
|
|
1946
|
+
*/
|
|
1947
|
+
async setTools(tools) {
|
|
1948
|
+
const definitions = tools.map(toToolDefinition);
|
|
1949
|
+
const replacement = this.setToolsQueue.then(async () => {
|
|
1950
|
+
await this.rpc.tools.set({ tools: definitions });
|
|
1951
|
+
this.registerTools(tools);
|
|
1952
|
+
});
|
|
1953
|
+
this.setToolsQueue = replacement.then(
|
|
1954
|
+
() => void 0,
|
|
1955
|
+
() => void 0
|
|
1956
|
+
);
|
|
1957
|
+
await replacement;
|
|
1958
|
+
}
|
|
1813
1959
|
/**
|
|
1814
1960
|
* Log a message to the session timeline.
|
|
1815
1961
|
* The message appears in the session event stream and is visible to SDK consumers
|
|
@@ -1855,6 +2001,9 @@ function toCanvasRpcError(error) {
|
|
|
1855
2001
|
const message = error instanceof Error ? error.message : String(error);
|
|
1856
2002
|
return new ResponseError(ErrorCodes.InternalError, message, { code, message });
|
|
1857
2003
|
}
|
|
2004
|
+
function skillProviderFailure(operation) {
|
|
2005
|
+
return new ResponseError(ErrorCodes.InternalError, `Skill provider ${operation} failed`);
|
|
2006
|
+
}
|
|
1858
2007
|
function strictJsonValidationError(context, category, message, path) {
|
|
1859
2008
|
return new ResponseError(ErrorCodes.InternalError, message, {
|
|
1860
2009
|
code: context.code,
|
|
@@ -37,6 +37,10 @@ export declare class SessionFsSqliteTransactionFailure extends Error {
|
|
|
37
37
|
readonly errorClass: SessionFsSqliteTransactionErrorClass;
|
|
38
38
|
constructor(message: string, errorClass?: SessionFsSqliteTransactionErrorClass);
|
|
39
39
|
}
|
|
40
|
+
/** Throw from `writeFile` only when the provider changed the target before failing. */
|
|
41
|
+
export declare class SessionFsWriteFailure extends Error {
|
|
42
|
+
readonly writeChanged = true;
|
|
43
|
+
}
|
|
40
44
|
/**
|
|
41
45
|
* SQLite operations for the per-session database.
|
|
42
46
|
* Implementers provide query execution and existence checking.
|
|
@@ -78,7 +82,11 @@ export interface SessionFsSqliteProvider {
|
|
|
78
82
|
export interface SessionFsProvider {
|
|
79
83
|
/** Reads the full content of a file. Throw if the file does not exist. */
|
|
80
84
|
readFile(path: string): Promise<string>;
|
|
81
|
-
/**
|
|
85
|
+
/** Read exact file bytes. Required when capabilities.binary is enabled. */
|
|
86
|
+
readFileBytes?(path: string): Promise<Uint8Array>;
|
|
87
|
+
/** Write exact file bytes. Required when capabilities.binary is enabled. */
|
|
88
|
+
writeFileBytes?(path: string, content: Uint8Array, mode?: number): Promise<void>;
|
|
89
|
+
/** Writes content to a file, creating parent directories if needed. Throw {@link SessionFsWriteFailure} if a failed write changed the target. */
|
|
82
90
|
writeFile(path: string, content: string, mode?: number): Promise<void>;
|
|
83
91
|
/** Appends content to a file, creating parent directories if needed. */
|
|
84
92
|
appendFile(path: string, content: string, mode?: number): Promise<void>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const MAX_BINARY_BYTES = (64 * 1024 * 1024 - 1024) / 4 * 3;
|
|
2
|
+
const MAX_BINARY_CONTENT_LENGTH = Math.ceil(MAX_BINARY_BYTES / 3) * 4;
|
|
1
3
|
class SessionFsSqliteTransactionFailure extends Error {
|
|
2
4
|
/** Failure classification reported to the runtime. */
|
|
3
5
|
errorClass;
|
|
@@ -7,6 +9,9 @@ class SessionFsSqliteTransactionFailure extends Error {
|
|
|
7
9
|
this.errorClass = errorClass;
|
|
8
10
|
}
|
|
9
11
|
}
|
|
12
|
+
class SessionFsWriteFailure extends Error {
|
|
13
|
+
writeChanged = true;
|
|
14
|
+
}
|
|
10
15
|
function normalizeSqliteParams(params) {
|
|
11
16
|
if (!params) {
|
|
12
17
|
return void 0;
|
|
@@ -29,10 +34,60 @@ function createSessionFsAdapter(provider) {
|
|
|
29
34
|
return { content: "", error: toSessionFsError(err) };
|
|
30
35
|
}
|
|
31
36
|
},
|
|
37
|
+
readFileBytes: async ({ path }) => {
|
|
38
|
+
if (!provider.readFileBytes) {
|
|
39
|
+
return {
|
|
40
|
+
content: "",
|
|
41
|
+
error: { code: "UNKNOWN", message: "Binary reads are not supported" }
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const bytes = await provider.readFileBytes(path);
|
|
46
|
+
if (bytes.length > MAX_BINARY_BYTES) {
|
|
47
|
+
return {
|
|
48
|
+
content: "",
|
|
49
|
+
error: {
|
|
50
|
+
code: "UNKNOWN",
|
|
51
|
+
message: "sessionFs.readFileBytes content exceeds the binary read limit"
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
content: Buffer.from(bytes).toString("base64")
|
|
57
|
+
};
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return { content: "", error: toSessionFsError(err) };
|
|
60
|
+
}
|
|
61
|
+
},
|
|
32
62
|
writeFile: async ({ path, content, mode }) => {
|
|
33
63
|
try {
|
|
34
64
|
await provider.writeFile(path, content, mode);
|
|
35
65
|
return void 0;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
const error = toSessionFsError(err);
|
|
68
|
+
return err instanceof SessionFsWriteFailure ? { ...error, writeChanged: true } : error;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
writeFileBytes: async ({ path, content, mode }) => {
|
|
72
|
+
if (!provider.writeFileBytes) {
|
|
73
|
+
return { code: "UNKNOWN", message: "Binary writes are not supported" };
|
|
74
|
+
}
|
|
75
|
+
if (content.length > MAX_BINARY_CONTENT_LENGTH) {
|
|
76
|
+
return {
|
|
77
|
+
code: "UNKNOWN",
|
|
78
|
+
message: "sessionFs.writeFileBytes content exceeds the binary write limit"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const bytes = Buffer.from(content, "base64");
|
|
82
|
+
if (bytes.toString("base64") !== content || bytes.length > MAX_BINARY_BYTES) {
|
|
83
|
+
return {
|
|
84
|
+
code: "UNKNOWN",
|
|
85
|
+
message: "invalid sessionFs.writeFileBytes base64 content"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await provider.writeFileBytes(path, bytes, mode);
|
|
90
|
+
return void 0;
|
|
36
91
|
} catch (err) {
|
|
37
92
|
return toSessionFsError(err);
|
|
38
93
|
}
|
|
@@ -169,5 +224,6 @@ function toSqliteTransactionError(err) {
|
|
|
169
224
|
}
|
|
170
225
|
export {
|
|
171
226
|
SessionFsSqliteTransactionFailure,
|
|
227
|
+
SessionFsWriteFailure,
|
|
172
228
|
createSessionFsAdapter
|
|
173
229
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -48,7 +48,10 @@ export type { SessionFsSqliteProvider } from "./sessionFsProvider.js";
|
|
|
48
48
|
export type { SessionFsSqliteStatement } from "./sessionFsProvider.js";
|
|
49
49
|
export type { SessionFsSqliteTransactionErrorClass } from "./sessionFsProvider.js";
|
|
50
50
|
export { SessionFsSqliteTransactionFailure } from "./sessionFsProvider.js";
|
|
51
|
+
export { SessionFsWriteFailure } from "./sessionFsProvider.js";
|
|
51
52
|
export type { LlmInferenceHeaders } from "./generated/rpc.js";
|
|
53
|
+
import type { SkillProviderDescriptor } from "./generated/rpc.js";
|
|
54
|
+
export type { SkillProviderDescriptor };
|
|
52
55
|
export type { PermissionDecisionContext, PermissionDecisionOutcome, PermissionDecisionSurface, PermissionResponseCapability, } from "./generated/rpc.js";
|
|
53
56
|
export type { PermissionDecisionSource } from "./generated/session-events.js";
|
|
54
57
|
export type { CopilotRequestContext } from "./copilotRequestHandler.js";
|
|
@@ -922,6 +925,8 @@ export interface SystemMessageReplaceConfig {
|
|
|
922
925
|
/**
|
|
923
926
|
* Customize mode: Override individual sections of the system prompt.
|
|
924
927
|
* Keeps the SDK-managed prompt structure while allowing targeted modifications.
|
|
928
|
+
* The `last_instructions` section includes configured subagent-model guidance.
|
|
929
|
+
* Its overrides and transforms control that prose, not runtime model selection or tool availability.
|
|
925
930
|
*/
|
|
926
931
|
export interface SystemMessageCustomizeConfig {
|
|
927
932
|
mode: "customize";
|
|
@@ -1098,8 +1103,9 @@ export type AutoModeSwitchHandler = (request: AutoModeSwitchRequest, invocation:
|
|
|
1098
1103
|
* Base interface for all hook inputs
|
|
1099
1104
|
*/
|
|
1100
1105
|
export interface BaseHookInput {
|
|
1101
|
-
/** The runtime session ID
|
|
1102
|
-
*
|
|
1106
|
+
/** The runtime session ID associated with the hook. Child tool hooks use
|
|
1107
|
+
* the child session ID; sub-agent lifecycle hooks use the parent session ID,
|
|
1108
|
+
* matching `invocation.sessionId`. */
|
|
1103
1109
|
sessionId: string;
|
|
1104
1110
|
/** Time at which the hook event was emitted by the runtime. */
|
|
1105
1111
|
timestamp: Date;
|
|
@@ -1366,6 +1372,54 @@ export interface AgentStopHookOutput {
|
|
|
1366
1372
|
export type AgentStopHandler = (input: AgentStopHookInput, invocation: {
|
|
1367
1373
|
sessionId: string;
|
|
1368
1374
|
}) => Promise<AgentStopHookOutput | void> | AgentStopHookOutput | void;
|
|
1375
|
+
/**
|
|
1376
|
+
* Input for the hook fired before a sub-agent's first turn.
|
|
1377
|
+
*
|
|
1378
|
+
* The session metadata belongs to the parent session, not the child.
|
|
1379
|
+
*/
|
|
1380
|
+
export interface SubagentStartHookInput extends BaseHookInput {
|
|
1381
|
+
transcriptPath: string;
|
|
1382
|
+
agentName: string;
|
|
1383
|
+
agentDisplayName?: string;
|
|
1384
|
+
agentDescription?: string;
|
|
1385
|
+
}
|
|
1386
|
+
/** Output for the sub-agent start hook. Context is prepended to the child's initial prompt. */
|
|
1387
|
+
export interface SubagentStartHookOutput {
|
|
1388
|
+
additionalContext?: string;
|
|
1389
|
+
}
|
|
1390
|
+
/** Handler for the sub-agent start hook. */
|
|
1391
|
+
export type SubagentStartHandler = (input: SubagentStartHookInput, invocation: {
|
|
1392
|
+
sessionId: string;
|
|
1393
|
+
}) => Promise<SubagentStartHookOutput | void> | SubagentStartHookOutput | void;
|
|
1394
|
+
/**
|
|
1395
|
+
* Input for the hook fired after a sub-agent completes a turn.
|
|
1396
|
+
*
|
|
1397
|
+
* The response is the child's last assistant message before any hook rewrite.
|
|
1398
|
+
*/
|
|
1399
|
+
export interface SubagentStopHookInput extends SubagentStartHookInput {
|
|
1400
|
+
agentId?: string;
|
|
1401
|
+
agentType: string;
|
|
1402
|
+
stopReason: "end_turn";
|
|
1403
|
+
response: string;
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Output for the sub-agent stop hook. `"block"` with a nonempty `reason` continues
|
|
1407
|
+
* the child; otherwise `modifiedResponse` replaces the response reported to the parent.
|
|
1408
|
+
* When both are supplied, a valid block takes precedence over the rewrite.
|
|
1409
|
+
*/
|
|
1410
|
+
export type SubagentStopHookOutput = {
|
|
1411
|
+
decision: "block";
|
|
1412
|
+
reason: string;
|
|
1413
|
+
modifiedResponse?: string;
|
|
1414
|
+
} | {
|
|
1415
|
+
decision?: "allow";
|
|
1416
|
+
reason?: never;
|
|
1417
|
+
modifiedResponse?: string;
|
|
1418
|
+
};
|
|
1419
|
+
/** Handler for the sub-agent stop hook. */
|
|
1420
|
+
export type SubagentStopHandler = (input: SubagentStopHookInput, invocation: {
|
|
1421
|
+
sessionId: string;
|
|
1422
|
+
}) => Promise<SubagentStopHookOutput | void> | SubagentStopHookOutput | void;
|
|
1369
1423
|
/**
|
|
1370
1424
|
* Configuration for session hooks
|
|
1371
1425
|
*/
|
|
@@ -1422,6 +1476,13 @@ export interface SessionHooks {
|
|
|
1422
1476
|
* agent stop.
|
|
1423
1477
|
*/
|
|
1424
1478
|
onAgentStop?: AgentStopHandler;
|
|
1479
|
+
/** Called before a sub-agent's first turn. Return context to prepend to its prompt. */
|
|
1480
|
+
onSubagentStart?: SubagentStartHandler;
|
|
1481
|
+
/**
|
|
1482
|
+
* Called after a sub-agent completes a turn. Return a block reason to
|
|
1483
|
+
* continue the child, or a replacement response to report to the parent.
|
|
1484
|
+
*/
|
|
1485
|
+
onSubagentStop?: SubagentStopHandler;
|
|
1425
1486
|
}
|
|
1426
1487
|
/**
|
|
1427
1488
|
* Base interface for MCP server configuration.
|
|
@@ -1821,6 +1882,13 @@ export interface ManagedSettingsPermissions {
|
|
|
1821
1882
|
* (across managed layers) must admit an operation for it to be allowed.
|
|
1822
1883
|
*/
|
|
1823
1884
|
allow?: string[];
|
|
1885
|
+
/**
|
|
1886
|
+
* Closed-world host boundary expressed as `Domain(hostname)`, `Domain(IP)`,
|
|
1887
|
+
* or `Domain(*.example.com)` rules. Schemes, ports, paths, queries, and
|
|
1888
|
+
* fragments are rejected. Multiple managed layers intersect their lists;
|
|
1889
|
+
* an empty list denies all hosts.
|
|
1890
|
+
*/
|
|
1891
|
+
limitTo?: string[];
|
|
1824
1892
|
}
|
|
1825
1893
|
/**
|
|
1826
1894
|
* Host-injected enterprise managed settings. The first supported contract is
|
|
@@ -1834,6 +1902,57 @@ export interface ManagedSettings {
|
|
|
1834
1902
|
}
|
|
1835
1903
|
/** Selects the model-facing shape of the built-in `ask_user` tool. */
|
|
1836
1904
|
export type AskUserVariant = "legacy" | "elicitation";
|
|
1905
|
+
/**
|
|
1906
|
+
* Supplies session-scoped skills from the host's own storage, such as a
|
|
1907
|
+
* database, instead of `SKILL.md` files on disk.
|
|
1908
|
+
*
|
|
1909
|
+
* The runtime calls {@link SkillProvider.listSkills} when it builds the
|
|
1910
|
+
* session's skill catalog, and {@link SkillProvider.readSkill} each time it
|
|
1911
|
+
* needs a skill's instructions: when the model loads the skill through the
|
|
1912
|
+
* `skill` tool, when a user runs `/skill-name`, or when a custom agent lists
|
|
1913
|
+
* the skill. Calls may run concurrently, including on behalf of sub-agents, and
|
|
1914
|
+
* each call must finish within 30 seconds. Errors thrown by a provider are
|
|
1915
|
+
* never shown to the model.
|
|
1916
|
+
*
|
|
1917
|
+
* Supply a provider with {@link SessionConfigBase.skillProvider}. Providers
|
|
1918
|
+
* aren't supported for cloud sessions.
|
|
1919
|
+
*
|
|
1920
|
+
* @experimental Session-scoped skill providers are experimental and may change
|
|
1921
|
+
* or be removed in future SDK or CLI releases.
|
|
1922
|
+
*/
|
|
1923
|
+
export interface SkillProvider {
|
|
1924
|
+
/**
|
|
1925
|
+
* Returns catalog metadata for every skill the provider supplies. The
|
|
1926
|
+
* descriptors are authoritative: names must be unique ignoring case, and
|
|
1927
|
+
* the runtime validates their limits.
|
|
1928
|
+
*/
|
|
1929
|
+
listSkills(options: SkillProviderCallOptions): SkillProviderDescriptor[] | Promise<SkillProviderDescriptor[]>;
|
|
1930
|
+
/**
|
|
1931
|
+
* Returns the `SKILL.md` text for the named skill, or `null`/`undefined`
|
|
1932
|
+
* when the skill no longer exists.
|
|
1933
|
+
*
|
|
1934
|
+
* YAML frontmatter is optional. Fields it omits come from the skill's
|
|
1935
|
+
* descriptor, fields it declares must match the descriptor, and
|
|
1936
|
+
* `allowed-tools` can only be set there. Text whose first line is `---` is
|
|
1937
|
+
* parsed as frontmatter.
|
|
1938
|
+
*
|
|
1939
|
+
* @param name - The skill's name, as listed by {@link SkillProvider.listSkills}.
|
|
1940
|
+
*/
|
|
1941
|
+
readSkill(name: string, options: SkillProviderCallOptions): string | null | undefined | Promise<string | null | undefined>;
|
|
1942
|
+
}
|
|
1943
|
+
/**
|
|
1944
|
+
* Per-call options passed to {@link SkillProvider} methods.
|
|
1945
|
+
*
|
|
1946
|
+
* @experimental Session-scoped skill providers are experimental and may change
|
|
1947
|
+
* or be removed in future SDK or CLI releases.
|
|
1948
|
+
*/
|
|
1949
|
+
export interface SkillProviderCallOptions {
|
|
1950
|
+
/**
|
|
1951
|
+
* Aborted when the runtime cancels the call, for example when it times out
|
|
1952
|
+
* or the session disconnects. The runtime ignores any later result.
|
|
1953
|
+
*/
|
|
1954
|
+
signal: AbortSignal;
|
|
1955
|
+
}
|
|
1837
1956
|
/**
|
|
1838
1957
|
* Shared configuration fields used by both {@link SessionConfig} (for
|
|
1839
1958
|
* creating a new session) and {@link ResumeSessionConfig} (for resuming
|
|
@@ -2253,6 +2372,22 @@ export interface SessionConfigBase {
|
|
|
2253
2372
|
* Directories to load skills from.
|
|
2254
2373
|
*/
|
|
2255
2374
|
skillDirectories?: string[];
|
|
2375
|
+
/**
|
|
2376
|
+
* Supplies skills from the host's own storage instead of `SKILL.md` files on
|
|
2377
|
+
* disk. Provider skills join the session's skill catalog alongside file-based
|
|
2378
|
+
* skills. See {@link SkillProvider}.
|
|
2379
|
+
*
|
|
2380
|
+
* Supplying a provider enables skills unless `enableSkills` is set explicitly,
|
|
2381
|
+
* so set `enableSkills: true` when the client runs in `"empty"` mode. With
|
|
2382
|
+
* `enableSkills: false` the provider stays bound but receives no calls.
|
|
2383
|
+
*
|
|
2384
|
+
* The provider isn't persisted. Pass it again when resuming the session;
|
|
2385
|
+
* resuming without one removes the provider's skills.
|
|
2386
|
+
*
|
|
2387
|
+
* @experimental Session-scoped skill providers are experimental and may change
|
|
2388
|
+
* or be removed in future SDK or CLI releases.
|
|
2389
|
+
*/
|
|
2390
|
+
skillProvider?: SkillProvider;
|
|
2256
2391
|
/**
|
|
2257
2392
|
* Local filesystem paths to Open Plugins-format directories
|
|
2258
2393
|
* (https://open-plugins.com/) to load for this session.
|
|
@@ -2522,6 +2657,12 @@ export interface ProviderTokenArgs {
|
|
|
2522
2657
|
* surface and may change or be removed in future SDK or CLI releases.
|
|
2523
2658
|
*/
|
|
2524
2659
|
export type BearerTokenProvider = (args: ProviderTokenArgs) => Promise<string>;
|
|
2660
|
+
/**
|
|
2661
|
+
* Product serving a configured provider's model. Allowed values are
|
|
2662
|
+
* "openai", "anthropic", "azure_openai", "ollama", "lm_studio",
|
|
2663
|
+
* "foundry_local", and "llama_cpp".
|
|
2664
|
+
*/
|
|
2665
|
+
export type ProviderConfigModelProvider = "openai" | "anthropic" | "azure_openai" | "ollama" | "lm_studio" | "foundry_local" | "llama_cpp";
|
|
2525
2666
|
/**
|
|
2526
2667
|
* Configuration for a custom API provider.
|
|
2527
2668
|
*/
|
|
@@ -2544,6 +2685,11 @@ export interface ProviderConfig {
|
|
|
2544
2685
|
* providers using `wireApi: "responses"`.
|
|
2545
2686
|
*/
|
|
2546
2687
|
transport?: "http" | "websockets";
|
|
2688
|
+
/**
|
|
2689
|
+
* Product serving the model, such as "ollama" or "lm_studio", reported in
|
|
2690
|
+
* telemetry as `model_provider`. Only affects telemetry.
|
|
2691
|
+
*/
|
|
2692
|
+
modelProvider?: ProviderConfigModelProvider;
|
|
2547
2693
|
/**
|
|
2548
2694
|
* API endpoint URL
|
|
2549
2695
|
*/
|
|
@@ -2637,6 +2783,11 @@ export interface NamedProviderConfig {
|
|
|
2637
2783
|
* Wire API format (openai/azure only). Defaults to "completions".
|
|
2638
2784
|
*/
|
|
2639
2785
|
wireApi?: "completions" | "responses";
|
|
2786
|
+
/**
|
|
2787
|
+
* Product serving this provider's models, such as "ollama" or "lm_studio",
|
|
2788
|
+
* reported in telemetry as `model_provider`. Only affects telemetry.
|
|
2789
|
+
*/
|
|
2790
|
+
modelProvider?: ProviderConfigModelProvider;
|
|
2640
2791
|
/**
|
|
2641
2792
|
* API endpoint URL.
|
|
2642
2793
|
*/
|
|
@@ -2878,6 +3029,12 @@ export interface SessionFsConfig {
|
|
|
2878
3029
|
* @default false
|
|
2879
3030
|
*/
|
|
2880
3031
|
sqlite?: boolean;
|
|
3032
|
+
/**
|
|
3033
|
+
* Whether this provider supports exact binary reads and writes through readFileBytes and writeFileBytes.
|
|
3034
|
+
* Required to view images stored only in the provider.
|
|
3035
|
+
* @default false
|
|
3036
|
+
*/
|
|
3037
|
+
binary?: boolean;
|
|
2881
3038
|
};
|
|
2882
3039
|
}
|
|
2883
3040
|
/**
|
package/dist/types.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSessionFsAdapter } from "./sessionFsProvider.js";
|
|
2
2
|
import { SessionFsSqliteTransactionFailure } from "./sessionFsProvider.js";
|
|
3
|
+
import { SessionFsWriteFailure } from "./sessionFsProvider.js";
|
|
3
4
|
import {
|
|
4
5
|
CopilotRequestHandler,
|
|
5
6
|
CopilotWebSocketHandler,
|
|
@@ -106,10 +107,10 @@ const SYSTEM_MESSAGE_SECTIONS = {
|
|
|
106
107
|
tool_instructions: { description: "Per-tool usage instructions" },
|
|
107
108
|
custom_instructions: { description: "Repository and organization custom instructions" },
|
|
108
109
|
runtime_instructions: {
|
|
109
|
-
description: "Runtime-provided context and instructions
|
|
110
|
+
description: "Runtime-provided system-prompt context and instructions, such as system notifications, memories, workspace context, and content-exclusion policy. Mode-specific instructions can travel in transition messages instead."
|
|
110
111
|
},
|
|
111
112
|
last_instructions: {
|
|
112
|
-
description: "End-of-prompt instructions: parallel tool calling, persistence, task completion"
|
|
113
|
+
description: "End-of-prompt instructions: parallel tool calling, persistence, task completion, and configured subagent-model guidance when the task tool is available"
|
|
113
114
|
}
|
|
114
115
|
};
|
|
115
116
|
function isAttributedPermissionResult(result) {
|
|
@@ -149,6 +150,7 @@ export {
|
|
|
149
150
|
RuntimeConnection,
|
|
150
151
|
SYSTEM_MESSAGE_SECTIONS,
|
|
151
152
|
SessionFsSqliteTransactionFailure,
|
|
153
|
+
SessionFsWriteFailure,
|
|
152
154
|
approveAll,
|
|
153
155
|
convertMcpCallToolResult,
|
|
154
156
|
createAttributedPermissionResult,
|
package/docs/agent-author.md
CHANGED
|
@@ -122,10 +122,12 @@ hooks: {
|
|
|
122
122
|
onSessionStart: async (input, invocation) => { ... },
|
|
123
123
|
onSessionEnd: async (input, invocation) => { ... },
|
|
124
124
|
onErrorOccurred: async (input, invocation) => { ... },
|
|
125
|
+
onSubagentStart: async (input, invocation) => { ... },
|
|
126
|
+
onSubagentStop: async (input, invocation) => { ... },
|
|
125
127
|
}
|
|
126
128
|
```
|
|
127
129
|
|
|
128
|
-
All hook inputs include `timestamp` (`Date`) and `workingDirectory`.
|
|
130
|
+
All hook inputs include `sessionId`, `timestamp` (`Date`) and `workingDirectory`.
|
|
129
131
|
All handlers receive `invocation: { sessionId: string }` as the second argument.
|
|
130
132
|
All handlers may return `void`/`undefined` (no-op) or an output object.
|
|
131
133
|
|
|
@@ -214,7 +216,32 @@ fire it.
|
|
|
214
216
|
| `retryCount` | `number` | Max retries (when errorHandling is "retry") |
|
|
215
217
|
| `userNotification` | `string` | Message shown to the user |
|
|
216
218
|
|
|
217
|
-
|
|
219
|
+
### onSubagentStart
|
|
220
|
+
|
|
221
|
+
Fires before a sub-agent's first turn. The input's `sessionId` and the
|
|
222
|
+
invocation's `sessionId` identify the parent session, not the child.
|
|
223
|
+
|
|
224
|
+
**Input:** `{ sessionId: string, transcriptPath: string, agentName: string, agentDisplayName?: string, agentDescription?: string, timestamp, workingDirectory }`
|
|
225
|
+
|
|
226
|
+
**Output (optional):**
|
|
227
|
+
| Field | Type | Effect |
|
|
228
|
+
|-------|------|--------|
|
|
229
|
+
| `additionalContext` | `string` | Prepended to the child's initial prompt |
|
|
230
|
+
|
|
231
|
+
### onSubagentStop
|
|
232
|
+
|
|
233
|
+
Fires after a sub-agent completes a turn. The input includes the child's last
|
|
234
|
+
assistant `response` and the parent's session metadata. `agentId` is available
|
|
235
|
+
when the task registry supplies one. This is distinct from `onAgentStop`, which
|
|
236
|
+
only runs for the top-level agent.
|
|
237
|
+
|
|
238
|
+
**Input:** `{ sessionId: string, transcriptPath: string, agentName: string, agentDisplayName?: string, agentDescription?: string, agentId?: string, agentType: string, stopReason: "end_turn", response: string, timestamp, workingDirectory }`
|
|
239
|
+
|
|
240
|
+
**Output (choose one, or return nothing):**
|
|
241
|
+
| Field | Type | Effect |
|
|
242
|
+
|-------|------|--------|
|
|
243
|
+
| `decision` and `reason` | `"block"` and `string` | Continue the child for another turn using `reason` |
|
|
244
|
+
| `modifiedResponse` | `string` | Replace the child's response reported to the parent |
|
|
218
245
|
|
|
219
246
|
## Session Object
|
|
220
247
|
|
package/package.json
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"url": "https://github.com/github/copilot-agent-runtime.git",
|
|
6
6
|
"directory": "src/sdk/nodejs"
|
|
7
7
|
},
|
|
8
|
-
"version": "1.0.17-preview.
|
|
9
|
-
"copilotCliVersion": "1.0.
|
|
8
|
+
"version": "1.0.17-preview.10",
|
|
9
|
+
"copilotCliVersion": "1.0.93-4",
|
|
10
10
|
"description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
|
|
11
11
|
"main": "./dist/cjs/index.js",
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
@@ -98,22 +98,23 @@
|
|
|
98
98
|
},
|
|
99
99
|
"files": [
|
|
100
100
|
"dist/**/*",
|
|
101
|
+
"!dist/tsconfig.tsbuildinfo",
|
|
101
102
|
"docs/**/*",
|
|
102
103
|
"README.md"
|
|
103
104
|
],
|
|
104
105
|
"copilotRuntime": {
|
|
105
|
-
"sourceSha": "
|
|
106
|
-
"version": "1.0.
|
|
106
|
+
"sourceSha": "0e56b9a0033f48e4358ee027a4077cd6ebd61f32",
|
|
107
|
+
"version": "1.0.93-4",
|
|
107
108
|
"visibility": "public"
|
|
108
109
|
},
|
|
109
110
|
"optionalDependencies": {
|
|
110
|
-
"@github/copilot-sdk-darwin-arm64": "1.0.17-preview.
|
|
111
|
-
"@github/copilot-sdk-darwin-x64": "1.0.17-preview.
|
|
112
|
-
"@github/copilot-sdk-linux-arm64": "1.0.17-preview.
|
|
113
|
-
"@github/copilot-sdk-linux-x64": "1.0.17-preview.
|
|
114
|
-
"@github/copilot-sdk-linuxmusl-arm64": "1.0.17-preview.
|
|
115
|
-
"@github/copilot-sdk-linuxmusl-x64": "1.0.17-preview.
|
|
116
|
-
"@github/copilot-sdk-win32-arm64": "1.0.17-preview.
|
|
117
|
-
"@github/copilot-sdk-win32-x64": "1.0.17-preview.
|
|
111
|
+
"@github/copilot-sdk-darwin-arm64": "1.0.17-preview.10",
|
|
112
|
+
"@github/copilot-sdk-darwin-x64": "1.0.17-preview.10",
|
|
113
|
+
"@github/copilot-sdk-linux-arm64": "1.0.17-preview.10",
|
|
114
|
+
"@github/copilot-sdk-linux-x64": "1.0.17-preview.10",
|
|
115
|
+
"@github/copilot-sdk-linuxmusl-arm64": "1.0.17-preview.10",
|
|
116
|
+
"@github/copilot-sdk-linuxmusl-x64": "1.0.17-preview.10",
|
|
117
|
+
"@github/copilot-sdk-win32-arm64": "1.0.17-preview.10",
|
|
118
|
+
"@github/copilot-sdk-win32-x64": "1.0.17-preview.10"
|
|
118
119
|
}
|
|
119
120
|
}
|