@github/copilot-sdk 1.0.11-preview.2 → 1.0.11

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.
@@ -291,6 +291,7 @@ class CopilotClient {
291
291
  /** Connection-level session filesystem config, set via constructor option. */
292
292
  sessionFsConfig = null;
293
293
  requestHandler = null;
294
+ builtinPluginDirectories = [];
294
295
  onGitHubTelemetry;
295
296
  clientGlobalHandlers = {};
296
297
  /**
@@ -419,6 +420,16 @@ class CopilotClient {
419
420
  if (options.sessionFs) {
420
421
  this.validateSessionFsConfig(options.sessionFs);
421
422
  }
423
+ if (options.builtinPluginDirectories) {
424
+ for (const path of options.builtinPluginDirectories) {
425
+ if (!(0, import_node_path.isAbsolute)(path)) {
426
+ throw new Error(
427
+ `builtinPluginDirectories must contain only absolute paths: ${path}`
428
+ );
429
+ }
430
+ }
431
+ this.builtinPluginDirectories = [...options.builtinPluginDirectories];
432
+ }
422
433
  if (conn.kind === "uri") {
423
434
  const { host, port } = this.parseCliUrl(conn.url);
424
435
  this.actualHost = host;
@@ -573,6 +584,16 @@ class CopilotClient {
573
584
  }
574
585
  await this.connectToServer();
575
586
  await this.verifyProtocolVersion();
587
+ if (this.builtinPluginDirectories.length > 0) {
588
+ try {
589
+ await this.connection.sendRequest("plugins.builtin.set", {
590
+ paths: this.builtinPluginDirectories
591
+ });
592
+ } catch (error) {
593
+ await this.forceStop();
594
+ throw error;
595
+ }
596
+ }
576
597
  if (this.sessionFsConfig) {
577
598
  await this.connection.sendRequest("sessionFs.setProvider", {
578
599
  initialCwd: this.sessionFsConfig.initialCwd,
package/dist/cjs/index.js CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  ToolSet: () => import_toolSet.ToolSet,
35
35
  approveAll: () => import_types2.approveAll,
36
36
  convertMcpCallToolResult: () => import_types2.convertMcpCallToolResult,
37
+ createAttributedPermissionResult: () => import_types2.createAttributedPermissionResult,
37
38
  createCanvas: () => import_canvas.createCanvas,
38
39
  createSessionFsAdapter: () => import_types2.createSessionFsAdapter,
39
40
  defineFactory: () => import_factory.defineFactory,
@@ -66,6 +67,7 @@ var import_types2 = require("./types.js");
66
67
  ToolSet,
67
68
  approveAll,
68
69
  convertMcpCallToolResult,
70
+ createAttributedPermissionResult,
69
71
  createCanvas,
70
72
  createSessionFsAdapter,
71
73
  defineFactory,
@@ -26,6 +26,7 @@ var import_node = require("vscode-jsonrpc/node.js");
26
26
  var import_rpc = require("./generated/rpc.js");
27
27
  var import_canvas = require("./canvas.js");
28
28
  var import_telemetry = require("./telemetry.js");
29
+ var import_types = require("./types.js");
29
30
  var import_factory = require("./factory.js");
30
31
  function isFactoryResumeErrorCode(value) {
31
32
  return value === "not_found" || value === "non_resumable" || value === "already_active" || value === "factory_already_running" || value === "factory_limits_invalid" || value === "factory_session_disposed" || value === "factory_storage_unavailable" || value === "factory_storage_corrupt";
@@ -736,17 +737,22 @@ class CopilotSession {
736
737
  */
737
738
  async _executePermissionAndRespond(requestId, permissionRequest) {
738
739
  try {
739
- const result = await this.permissionHandler(permissionRequest, {
740
+ const handlerResult = await this.permissionHandler(permissionRequest, {
740
741
  sessionId: this.sessionId,
741
742
  managedSettingsEnabled: this.managedSettingsEnabled
742
743
  });
744
+ const isAttributed = (0, import_types.isAttributedPermissionResult)(handlerResult);
745
+ const result = isAttributed ? handlerResult.result : handlerResult;
746
+ const decisionContext = isAttributed ? handlerResult.decisionContext : void 0;
743
747
  if (result.kind === "no-result") {
744
748
  return;
745
749
  }
746
750
  if (this.disconnected) {
747
751
  return;
748
752
  }
749
- await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result });
753
+ await this.rpc.permissions.handlePendingPermissionRequest(
754
+ decisionContext === void 0 ? { requestId, result } : { requestId, result, decisionContext }
755
+ );
750
756
  } catch (error) {
751
757
  if (this.disconnected) {
752
758
  return;
package/dist/cjs/types.js CHANGED
@@ -27,9 +27,11 @@ __export(types_exports, {
27
27
  SessionFsSqliteTransactionFailure: () => import_sessionFsProvider2.SessionFsSqliteTransactionFailure,
28
28
  approveAll: () => approveAll,
29
29
  convertMcpCallToolResult: () => convertMcpCallToolResult,
30
+ createAttributedPermissionResult: () => createAttributedPermissionResult,
30
31
  createSessionFsAdapter: () => import_sessionFsProvider.createSessionFsAdapter,
31
32
  defaultJoinSessionPermissionHandler: () => defaultJoinSessionPermissionHandler,
32
- defineTool: () => defineTool
33
+ defineTool: () => defineTool,
34
+ isAttributedPermissionResult: () => isAttributedPermissionResult
33
35
  });
34
36
  module.exports = __toCommonJS(types_exports);
35
37
  var import_sessionFsProvider = require("./sessionFsProvider.js");
@@ -141,6 +143,13 @@ const SYSTEM_MESSAGE_SECTIONS = {
141
143
  description: "End-of-prompt instructions: parallel tool calling, persistence, task completion"
142
144
  }
143
145
  };
146
+ function isAttributedPermissionResult(result) {
147
+ return result.kind === "attributed";
148
+ }
149
+ function createAttributedPermissionResult(result, decisionContext) {
150
+ const inner = isAttributedPermissionResult(result) ? result.result : result;
151
+ return { kind: "attributed", result: inner, decisionContext };
152
+ }
144
153
  const approveAll = (request, invocation) => {
145
154
  if (invocation.managedSettingsEnabled) {
146
155
  throw new Error("approveAll cannot be used when managed settings are enabled");
@@ -167,7 +176,9 @@ const defaultJoinSessionPermissionHandler = () => ({
167
176
  SessionFsSqliteTransactionFailure,
168
177
  approveAll,
169
178
  convertMcpCallToolResult,
179
+ createAttributedPermissionResult,
170
180
  createSessionFsAdapter,
171
181
  defaultJoinSessionPermissionHandler,
172
- defineTool
182
+ defineTool,
183
+ isAttributedPermissionResult
173
184
  });
package/dist/client.d.ts CHANGED
@@ -37,6 +37,7 @@ export declare class CopilotClient {
37
37
  /** Connection-level session filesystem config, set via constructor option. */
38
38
  private sessionFsConfig;
39
39
  private requestHandler;
40
+ private builtinPluginDirectories;
40
41
  private onGitHubTelemetry?;
41
42
  private clientGlobalHandlers;
42
43
  /**
package/dist/client.js CHANGED
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import { existsSync } from "node:fs";
4
4
  import { createRequire } from "node:module";
5
5
  import { Socket } from "node:net";
6
- import { dirname, join } from "node:path";
6
+ import { dirname, isAbsolute, join } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import {
9
9
  createMessageConnection,
@@ -268,6 +268,7 @@ class CopilotClient {
268
268
  /** Connection-level session filesystem config, set via constructor option. */
269
269
  sessionFsConfig = null;
270
270
  requestHandler = null;
271
+ builtinPluginDirectories = [];
271
272
  onGitHubTelemetry;
272
273
  clientGlobalHandlers = {};
273
274
  /**
@@ -396,6 +397,16 @@ class CopilotClient {
396
397
  if (options.sessionFs) {
397
398
  this.validateSessionFsConfig(options.sessionFs);
398
399
  }
400
+ if (options.builtinPluginDirectories) {
401
+ for (const path of options.builtinPluginDirectories) {
402
+ if (!isAbsolute(path)) {
403
+ throw new Error(
404
+ `builtinPluginDirectories must contain only absolute paths: ${path}`
405
+ );
406
+ }
407
+ }
408
+ this.builtinPluginDirectories = [...options.builtinPluginDirectories];
409
+ }
399
410
  if (conn.kind === "uri") {
400
411
  const { host, port } = this.parseCliUrl(conn.url);
401
412
  this.actualHost = host;
@@ -550,6 +561,16 @@ class CopilotClient {
550
561
  }
551
562
  await this.connectToServer();
552
563
  await this.verifyProtocolVersion();
564
+ if (this.builtinPluginDirectories.length > 0) {
565
+ try {
566
+ await this.connection.sendRequest("plugins.builtin.set", {
567
+ paths: this.builtinPluginDirectories
568
+ });
569
+ } catch (error) {
570
+ await this.forceStop();
571
+ throw error;
572
+ }
573
+ }
553
574
  if (this.sessionFsConfig) {
554
575
  await this.connection.sendRequest("sessionFs.setProvider", {
555
576
  initialCwd: this.sessionFsConfig.initialCwd,
package/dist/factory.d.ts CHANGED
@@ -17,12 +17,16 @@ export type JsonValue = null | boolean | number | string | JsonValue[] | {
17
17
  [key: string]: JsonValue;
18
18
  };
19
19
  /**
20
- * Conservative JSON shape language accepted for structured factory agent output.
20
+ * Conservative JSON shape language accepted by the Agent Factories surface, for
21
+ * both structured factory agent output and a factory's declared `argsSchema`.
21
22
  *
22
- * This is a best-effort structural guard used to decide whether a subagent's
23
- * structured output should be accepted or retried — **not** a full JSON Schema
23
+ * This is a best-effort structural guard — used to decide whether a subagent's
24
+ * structured output should be accepted or retried, and whether a caller's
25
+ * factory `args` match the declared shape — **not** a full JSON Schema
24
26
  * validator. Only these keywords are honored: `type`, `required`, `enum`,
25
- * `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf`.
27
+ * `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf`. A `type`
28
+ * is one of `null`, `boolean`, `integer`, `number`, `string`, `array`, or
29
+ * `object`, or a non-empty array of those (for example `["object", "null"]`).
26
30
  *
27
31
  * Everything else is **ignored, not enforced**. In particular, string
28
32
  * constraints (`pattern`, `minLength`, `maxLength`, `format`), numeric ranges
package/dist/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export { BuiltInTools, ToolSet } from "./toolSet.js";
9
9
  export { CopilotSession, type AssistantMessageEvent } from "./session.js";
10
10
  export { defineFactory, FactoryResumeError, isFactoryRunTerminal } from "./factory.js";
11
11
  export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasHostContextCapabilities, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js";
12
- export { defineTool, approveAll, convertMcpCallToolResult, createSessionFsAdapter, CopilotRequestHandler, CopilotWebSocketHandler, CopilotWebSocketCloseStatus, CopilotWebSocketForwarder, SessionFsSqliteTransactionFailure, SYSTEM_MESSAGE_SECTIONS, } from "./types.js";
12
+ export { defineTool, approveAll, createAttributedPermissionResult, convertMcpCallToolResult, createSessionFsAdapter, CopilotRequestHandler, CopilotWebSocketHandler, CopilotWebSocketCloseStatus, CopilotWebSocketForwarder, SessionFsSqliteTransactionFailure, SYSTEM_MESSAGE_SECTIONS, } from "./types.js";
13
13
  export type * from "./generated/session-events.js";
14
- export type { CommandContext, CommandDefinition, CommandHandler, CanvasProviderIdentity, CloudSessionOptions, CloudSessionRepository, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, AgentStopHandler, AgentStopHookInput, AgentStopHookOutput, UserPromptTransformedHandler, UserPromptTransformedHookInput, UserPromptTransformedHookOutput, CopilotClientMode, CopilotClientOptions, CopilotExpAssignmentResponse, StdioRuntimeConnection, InProcessRuntimeConnection, TcpRuntimeConnection, UriRuntimeConnection, ChildProcessRuntimeConnection, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ExpConfigEntry, ExpFlagValue, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ExtensionInfo, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, GitHubMcpToolConfig, GitHubTelemetryNotification, GitHubTelemetryEvent, GitHubTelemetryClientInfo, InfiniteSessionConfig, LargeToolOutputConfig, MemoryConfiguration, UiInputOptions, FactoryLimits, FactoryMeta, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, BearerTokenProvider, MessageOptions, ManagedSettings, ManagedSettingsPermissions, ModelBilling, ModelBillingTokenPrices, ModelBillingTokenPricesLongContext, CapiSessionOptions, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, NamedProviderConfig, PermissionHandler, PermissionRequest, PermissionRequestedData, PermissionRequestedEvent, PermissionRequestResult, ProviderConfig, ProviderModelConfig, ProviderTokenArgs, RemoteSessionMode, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionConfigBase, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventMetadata, SessionLifecycleEventType, SessionLifecycleHandler, SessionHooks, SessionCreatedEvent, SessionDeletedEvent, SessionUpdatedEvent, SessionForegroundEvent, SessionBackgroundEvent, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SessionFsSqliteQueryResult, SessionFsSqliteQueryType, SessionFsSqliteProvider, SessionFsSqliteStatement, SessionFsSqliteTransactionErrorClass, CopilotRequestContext, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemMessageSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, CurrentToolMetadata, ToolTelemetry, ToolResultObject, ToolSearchConfig, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
14
+ export type { CommandContext, CommandDefinition, CommandHandler, CanvasProviderIdentity, CloudSessionOptions, CloudSessionRepository, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, AgentStopHandler, AgentStopHookInput, AgentStopHookOutput, UserPromptTransformedHandler, UserPromptTransformedHookInput, UserPromptTransformedHookOutput, CopilotClientMode, CopilotClientOptions, CopilotExpAssignmentResponse, StdioRuntimeConnection, InProcessRuntimeConnection, TcpRuntimeConnection, UriRuntimeConnection, ChildProcessRuntimeConnection, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ExpConfigEntry, ExpFlagValue, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ExtensionInfo, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, GitHubMcpToolConfig, GitHubTelemetryNotification, GitHubTelemetryEvent, GitHubTelemetryClientInfo, InfiniteSessionConfig, LargeToolOutputConfig, MemoryConfiguration, UiInputOptions, FactoryLimits, FactoryMeta, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, BearerTokenProvider, MessageOptions, ManagedSettings, ManagedSettingsPermissions, ModelBilling, ModelBillingTokenPrices, ModelBillingTokenPricesLongContext, CapiSessionOptions, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, NamedProviderConfig, PermissionHandler, PermissionRequest, PermissionRequestedData, PermissionRequestedEvent, PermissionRequestResult, AttributedPermissionResult, PermissionDecisionContext, PermissionDecisionOutcome, PermissionDecisionSource, PermissionDecisionSurface, ProviderConfig, ProviderModelConfig, ProviderTokenArgs, RemoteSessionMode, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionConfigBase, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventMetadata, SessionLifecycleEventType, SessionLifecycleHandler, SessionHooks, SessionCreatedEvent, SessionDeletedEvent, SessionUpdatedEvent, SessionForegroundEvent, SessionBackgroundEvent, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SessionFsSqliteQueryResult, SessionFsSqliteQueryType, SessionFsSqliteProvider, SessionFsSqliteStatement, SessionFsSqliteTransactionErrorClass, CopilotRequestContext, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemMessageSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, CurrentToolMetadata, ToolTelemetry, ToolResultObject, ToolSearchConfig, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js";
15
15
  export type { RunOptions, ResumeOptions, FactoryResumeErrorCode, SessionFactoryApi, FactoryAgentOptions, FactoryContext, FactoryDefinition, FactoryHandle, FactoryJsonSchema, JsonValue, FactoryPipelineStage, FactoryStepOptions, FactoryRunResult, FactoryRunStatus, FactoryRunSummary, FactoryRunDetail, FactoryProgressPage, FactoryProgressLine, FactoryPhaseObservation, FactoryPhaseStatus, FactoryAgentSummary, } from "./factory.js";
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  import {
12
12
  defineTool,
13
13
  approveAll,
14
+ createAttributedPermissionResult,
14
15
  convertMcpCallToolResult,
15
16
  createSessionFsAdapter,
16
17
  CopilotRequestHandler,
@@ -37,6 +38,7 @@ export {
37
38
  ToolSet,
38
39
  approveAll,
39
40
  convertMcpCallToolResult,
41
+ createAttributedPermissionResult,
40
42
  createCanvas,
41
43
  createSessionFsAdapter,
42
44
  defineFactory,
package/dist/session.js CHANGED
@@ -3,6 +3,7 @@ import { ConnectionError, ErrorCodes, ResponseError } from "vscode-jsonrpc/node.
3
3
  import { createSessionRpc } from "./generated/rpc.js";
4
4
  import { CanvasError } from "./canvas.js";
5
5
  import { getTraceContext } from "./telemetry.js";
6
+ import { isAttributedPermissionResult } from "./types.js";
6
7
  import {
7
8
  FACTORY_AGENT_OPTION_KEYS,
8
9
  getFactoryDefinition,
@@ -718,17 +719,22 @@ class CopilotSession {
718
719
  */
719
720
  async _executePermissionAndRespond(requestId, permissionRequest) {
720
721
  try {
721
- const result = await this.permissionHandler(permissionRequest, {
722
+ const handlerResult = await this.permissionHandler(permissionRequest, {
722
723
  sessionId: this.sessionId,
723
724
  managedSettingsEnabled: this.managedSettingsEnabled
724
725
  });
726
+ const isAttributed = isAttributedPermissionResult(handlerResult);
727
+ const result = isAttributed ? handlerResult.result : handlerResult;
728
+ const decisionContext = isAttributed ? handlerResult.decisionContext : void 0;
725
729
  if (result.kind === "no-result") {
726
730
  return;
727
731
  }
728
732
  if (this.disconnected) {
729
733
  return;
730
734
  }
731
- await this.rpc.permissions.handlePendingPermissionRequest({ requestId, result });
735
+ await this.rpc.permissions.handlePendingPermissionRequest(
736
+ decisionContext === void 0 ? { requestId, result } : { requestId, result, decisionContext }
737
+ );
732
738
  } catch (error) {
733
739
  if (this.disconnected) {
734
740
  return;
package/dist/types.d.ts CHANGED
@@ -6,7 +6,7 @@ import type { SessionFsProvider } from "./sessionFsProvider.js";
6
6
  import type { CopilotRequestHandler } from "./copilotRequestHandler.js";
7
7
  import type { PermissionRequest as GeneratedPermissionRequest, PermissionRequestedData as GeneratedPermissionRequestedData, PermissionRequestedEvent as GeneratedPermissionRequestedEvent, ReasoningSummary, SessionLimitsConfig, SessionEvent as GeneratedSessionEvent } from "./generated/session-events.js";
8
8
  import type { CopilotSession } from "./session.js";
9
- import type { JsonValue } from "./factory.js";
9
+ import type { FactoryJsonSchema, JsonValue } from "./factory.js";
10
10
  import type { GitHubTelemetryNotification, ModelBillingTokenPrices, OpenCanvasInstance, RemoteSessionMode, CurrentToolMetadata } from "./generated/rpc.js";
11
11
  import type { ToolSet } from "./toolSet.js";
12
12
  export type { RemoteSessionMode } from "./generated/rpc.js";
@@ -27,6 +27,7 @@ export type { SessionFsSqliteStatement } from "./sessionFsProvider.js";
27
27
  export type { SessionFsSqliteTransactionErrorClass } from "./sessionFsProvider.js";
28
28
  export { SessionFsSqliteTransactionFailure } from "./sessionFsProvider.js";
29
29
  export type { LlmInferenceHeaders } from "./generated/rpc.js";
30
+ export type { PermissionDecisionContext, PermissionDecisionOutcome, PermissionDecisionSource, PermissionDecisionSurface, } from "./generated/rpc.js";
30
31
  export type { CopilotRequestContext } from "./copilotRequestHandler.js";
31
32
  export { CopilotRequestHandler, CopilotWebSocketHandler, CopilotWebSocketCloseStatus, CopilotWebSocketForwarder, } from "./copilotRequestHandler.js";
32
33
  /**
@@ -228,6 +229,12 @@ export interface CopilotClientOptions {
228
229
  * Ignored when connecting to an existing runtime via {@link RuntimeConnection.forUri}.
229
230
  */
230
231
  baseDirectory?: string;
232
+ /**
233
+ * Absolute paths to trusted plugin directories bundled by the host.
234
+ * When non-empty, the complete set is registered with the runtime during
235
+ * startup before any sessions can be created.
236
+ */
237
+ builtinPluginDirectories?: readonly string[];
231
238
  /**
232
239
  * Log level for the Copilot runtime. When omitted, the runtime uses its
233
240
  * own default (currently `"info"`).
@@ -853,7 +860,7 @@ export interface SystemMessageCustomizeConfig {
853
860
  * - Customize mode: Section-level overrides with graceful fallback
854
861
  */
855
862
  export type SystemMessageConfig = SystemMessageAppendConfig | SystemMessageReplaceConfig | SystemMessageCustomizeConfig;
856
- import type { PermissionDecisionRequest } from "./generated/rpc.js";
863
+ import type { PermissionDecisionRequest, PermissionDecisionContext } from "./generated/rpc.js";
857
864
  /**
858
865
  * Permission request types from the server. This is the generated
859
866
  * discriminated union from the runtime schema — switch on `kind` to
@@ -883,10 +890,35 @@ export type PermissionRequestedEvent = Omit<GeneratedPermissionRequestedEvent, "
883
890
  export type PermissionRequestResult = PermissionDecisionRequest["result"] | {
884
891
  kind: "no-result";
885
892
  };
893
+ /**
894
+ * A {@link PermissionRequestResult} annotated with the
895
+ * {@link PermissionDecisionContext} describing how and where the decision was
896
+ * reached. The context is informational only — it never changes permission
897
+ * behavior. Supplying it lets the runtime attribute auto-approval telemetry to
898
+ * the responding surface.
899
+ */
900
+ export interface AttributedPermissionResult {
901
+ kind: "attributed";
902
+ result: PermissionRequestResult;
903
+ decisionContext: PermissionDecisionContext;
904
+ }
905
+ /**
906
+ * Narrows a {@link PermissionHandler} return value to an attributed result.
907
+ */
908
+ export declare function isAttributedPermissionResult(result: PermissionRequestResult | AttributedPermissionResult): result is AttributedPermissionResult;
909
+ /**
910
+ * Pair a permission decision with the context describing how and where it was
911
+ * made, so the runtime can attribute auto-approval telemetry.
912
+ *
913
+ * Passing an already-attributed result replaces the previous context rather
914
+ * than nesting it. The context is informational only and never changes
915
+ * permission behavior.
916
+ */
917
+ export declare function createAttributedPermissionResult(result: PermissionRequestResult | AttributedPermissionResult, decisionContext: PermissionDecisionContext): AttributedPermissionResult;
886
918
  export type PermissionHandler = (request: PermissionRequest, invocation: {
887
919
  sessionId: string;
888
920
  managedSettingsEnabled?: boolean;
889
- }) => Promise<PermissionRequestResult> | PermissionRequestResult;
921
+ }) => Promise<PermissionRequestResult | AttributedPermissionResult> | PermissionRequestResult | AttributedPermissionResult;
890
922
  /**
891
923
  * Approves permission requests when managed settings are disabled.
892
924
  */
@@ -1619,6 +1651,30 @@ export interface FactoryMeta {
1619
1651
  title: string;
1620
1652
  detail?: string;
1621
1653
  }>;
1654
+ /**
1655
+ * Optional declared shape of the arguments this factory expects as `ctx.args`.
1656
+ *
1657
+ * Declaring one is strongly recommended for any factory that reads `ctx.args`.
1658
+ * When the model invokes the factory through the `run_factory` tool, the CLI
1659
+ * validates `args` against this declaration **before** the run starts, so a
1660
+ * malformed call is rejected with a correction hint and retried without ever
1661
+ * creating a run row, prompting the user for permission, or spending credits. A
1662
+ * factory that declares nothing is never validated: a malformed call starts,
1663
+ * takes an approval, spends credits, and then fails inside the factory body.
1664
+ * `factories_manage` with `operation: "inspect"` reports the declared shape so an
1665
+ * agent can read it before invoking.
1666
+ *
1667
+ * This covers the model's `run_factory` path only. `session.factory.run(...)` is
1668
+ * not validated against the declaration, so a factory should still check
1669
+ * `ctx.args` rather than assume the declared shape held.
1670
+ *
1671
+ * Enforcement covers structure — types, required properties, and enum/const
1672
+ * values. Finer constraints such as `minLength`, `pattern`, and
1673
+ * `additionalProperties` are recorded in the declaration but not enforced. See
1674
+ * {@link FactoryJsonSchema} for the accepted subset. A declaration outside that
1675
+ * subset is rejected at registration.
1676
+ */
1677
+ argsSchema?: FactoryJsonSchema;
1622
1678
  /** Optional resource ceilings presented to the user before execution. */
1623
1679
  limits?: FactoryLimits;
1624
1680
  }
package/dist/types.js CHANGED
@@ -112,6 +112,13 @@ const SYSTEM_MESSAGE_SECTIONS = {
112
112
  description: "End-of-prompt instructions: parallel tool calling, persistence, task completion"
113
113
  }
114
114
  };
115
+ function isAttributedPermissionResult(result) {
116
+ return result.kind === "attributed";
117
+ }
118
+ function createAttributedPermissionResult(result, decisionContext) {
119
+ const inner = isAttributedPermissionResult(result) ? result.result : result;
120
+ return { kind: "attributed", result: inner, decisionContext };
121
+ }
115
122
  const approveAll = (request, invocation) => {
116
123
  if (invocation.managedSettingsEnabled) {
117
124
  throw new Error("approveAll cannot be used when managed settings are enabled");
@@ -137,7 +144,9 @@ export {
137
144
  SessionFsSqliteTransactionFailure,
138
145
  approveAll,
139
146
  convertMcpCallToolResult,
147
+ createAttributedPermissionResult,
140
148
  createSessionFsAdapter,
141
149
  defaultJoinSessionPermissionHandler,
142
- defineTool
150
+ defineTool,
151
+ isAttributedPermissionResult
143
152
  };
package/docs/factories.md CHANGED
@@ -16,6 +16,13 @@ const reviewChanged = defineFactory({
16
16
  "Review changed files and verify the findings. " +
17
17
  "args: { files: string[] } — the paths to review.",
18
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
+ },
19
26
  limits: {
20
27
  maxConcurrentSubagents: 3,
21
28
  maxTotalSubagents: 10,
@@ -41,9 +48,19 @@ const reviewChanged = defineFactory({
41
48
  const session = await joinSession({ factories: [reviewChanged] });
42
49
  ```
43
50
 
44
- Factory metadata contains a stable `name`, a human-readable `description`, declared `phases`, and optional `limits`. Phase entries contain a `title` and optional `detail`.
51
+ 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`.
52
+
53
+ ## Declaring an argument shape
54
+
55
+ 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.
56
+
57
+ 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"`.
58
+
59
+ 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.
60
+
61
+ `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.
45
62
 
46
- There is no declared schema for `ctx.args`. The `run_factory` tool forwards `args` verbatim and its parameter is untyped, so **the `description` is the only thing telling an agent what arguments to supply** — state the expected shape there whenever a factory reads `ctx.args`, as the example above does. Arguments supplied by an extension calling `session.factory.run(...)` directly are typed through `defineFactory<TArgs>`, but that typing does not reach the model. A factory that reads `ctx.args` should validate it rather than assume a shape.
63
+ 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.
47
64
 
48
65
  `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.
49
66
 
@@ -193,7 +210,7 @@ async ({ args, agent, phase }) => {
193
210
  };
194
211
  ```
195
212
 
196
- 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, and limits before running it.
213
+ 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.
197
214
 
198
215
  ## Observe a run
199
216
 
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/github/copilot-sdk.git"
6
6
  },
7
- "version": "1.0.11-preview.2",
7
+ "version": "1.0.11",
8
8
  "description": "TypeScript SDK for programmatic control of GitHub Copilot CLI via JSON-RPC",
9
9
  "main": "./dist/cjs/index.js",
10
10
  "types": "./dist/index.d.ts",