@borgee/agents-host 0.2.97 → 0.2.110

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +77 -5
  2. package/dist/agents-host.d.ts +16 -0
  3. package/dist/agents-host.js +608 -82
  4. package/dist/catalog-worker.js +21 -0
  5. package/dist/catalog-worker.js.map +7 -0
  6. package/dist/chat/chat-control-plane.d.ts +19 -4
  7. package/dist/chat/normalized-input.d.ts +9 -0
  8. package/dist/chat/normalized-input.js +24 -0
  9. package/dist/chat/sdk-chat-control-plane.d.ts +46 -6
  10. package/dist/chat/sdk-chat-control-plane.js +169 -6
  11. package/dist/cli-args.d.ts +1 -1
  12. package/dist/cli-args.js +13 -4
  13. package/dist/config.d.ts +3 -1
  14. package/dist/config.js +25 -0
  15. package/dist/context/injection.d.ts +16 -0
  16. package/dist/context/injection.js +37 -21
  17. package/dist/context/prompt.d.ts +12 -0
  18. package/dist/context/prompt.js +25 -0
  19. package/dist/context/skill-manual.js +1 -1
  20. package/dist/context/turn-preparation.d.ts +2 -1
  21. package/dist/context/turn-preparation.js +15 -0
  22. package/dist/execution-telemetry.d.ts +96 -0
  23. package/dist/execution-telemetry.js +583 -0
  24. package/dist/gateway/channel-file-workspace.d.ts +15 -0
  25. package/dist/gateway/channel-file-workspace.js +130 -0
  26. package/dist/gateway/localhost-gateway.js +167 -2
  27. package/dist/hosted-turn-content.js +3 -2
  28. package/dist/local-config.js +34 -1
  29. package/dist/managed-daemon.js +15 -0
  30. package/dist/native-environment.d.ts +2 -0
  31. package/dist/native-environment.js +9 -0
  32. package/dist/native-protocol-types/codec.d.ts +49 -0
  33. package/dist/native-protocol-types/commands.d.ts +71 -0
  34. package/dist/native-protocol-types/compatibility.d.ts +5 -0
  35. package/dist/native-protocol-types/cursor.d.ts +7 -0
  36. package/dist/native-protocol-types/envelope.d.ts +1105 -0
  37. package/dist/native-protocol-types/file-changes.d.ts +20 -0
  38. package/dist/native-protocol-types/history.d.ts +487 -0
  39. package/dist/native-protocol-types/index.d.ts +18 -0
  40. package/dist/native-protocol-types/interactions.d.ts +619 -0
  41. package/dist/native-protocol-types/messages.d.ts +2482 -0
  42. package/dist/native-protocol-types/public-validation.d.ts +10 -0
  43. package/dist/native-protocol-types/remote-host-uplink.d.ts +67 -0
  44. package/dist/native-protocol-types/resources.d.ts +126 -0
  45. package/dist/native-protocol-types/session-settings.d.ts +22 -0
  46. package/dist/native-protocol-types/snapshot.d.ts +575 -0
  47. package/dist/native-protocol-types/timeline.d.ts +1503 -0
  48. package/dist/native-protocol-types/tool-result.d.ts +26 -0
  49. package/dist/native-protocol-types/uplink.d.ts +56 -0
  50. package/dist/native-protocol-types/version.d.ts +5 -0
  51. package/dist/native-provider-types/commands.d.ts +51 -0
  52. package/dist/native-provider-types/control.d.ts +192 -0
  53. package/dist/native-provider-types/file-changes.d.ts +9 -0
  54. package/dist/native-provider-types/index.d.ts +8 -0
  55. package/dist/native-provider-types/interactions.d.ts +7 -0
  56. package/dist/native-provider-types/observation.d.ts +209 -0
  57. package/dist/native-provider-types/provider.d.ts +124 -0
  58. package/dist/native-provider-types/session-settings.d.ts +17 -0
  59. package/dist/native-provider-types/testing.d.ts +27 -0
  60. package/dist/native-provider-types/tool-result.d.ts +21 -0
  61. package/dist/native-providers.d.ts +21 -0
  62. package/dist/native-providers.js +18402 -0
  63. package/dist/native-providers.js.map +7 -0
  64. package/dist/plugin-sdk.js +10713 -229
  65. package/dist/plugin-sdk.js.map +4 -4
  66. package/dist/policy/copilot-permission.js +1 -8
  67. package/dist/policy/gateway-authorization.d.ts +1 -1
  68. package/dist/policy/gateway-authorization.js +22 -2
  69. package/dist/providers/claude/adapter.js +1 -0
  70. package/dist/providers/claude/cli-client.js +4 -0
  71. package/dist/providers/codex/adapter.js +1 -0
  72. package/dist/providers/codex/cli-client.js +5 -0
  73. package/dist/providers/copilot/adapter.js +4 -0
  74. package/dist/providers/copilot/cli-client.js +11 -1
  75. package/dist/providers/copilot/sdk-session.d.ts +12 -3
  76. package/dist/providers/copilot/sdk-session.js +230 -6
  77. package/dist/providers/create-provider.js +24 -0
  78. package/dist/providers/normalized/adapter.d.ts +107 -0
  79. package/dist/providers/normalized/adapter.js +1650 -0
  80. package/dist/providers/normalized/control-policy.d.ts +5 -0
  81. package/dist/providers/normalized/control-policy.js +12 -0
  82. package/dist/providers/normalized/interactions.d.ts +3 -0
  83. package/dist/providers/normalized/interactions.js +39 -0
  84. package/dist/providers/normalized/legacy-input-ownership.d.ts +34 -0
  85. package/dist/providers/normalized/legacy-input-ownership.js +123 -0
  86. package/dist/providers/normalized/session-management.d.ts +67 -0
  87. package/dist/providers/normalized/session-management.js +334 -0
  88. package/dist/providers/normalized/session-ownership.d.ts +3 -0
  89. package/dist/providers/normalized/session-ownership.js +90 -0
  90. package/dist/providers/prompt-usage.d.ts +8 -0
  91. package/dist/providers/prompt-usage.js +52 -0
  92. package/dist/providers/provider-adapter.d.ts +43 -1
  93. package/dist/providers/provider-adapter.js +8 -0
  94. package/dist/state-paths.d.ts +2 -0
  95. package/dist/state-paths.js +6 -0
  96. package/dist/types.d.ts +66 -0
  97. package/dist/typing-lease.d.ts +14 -0
  98. package/dist/typing-lease.js +31 -0
  99. package/dist/vendor/agent-provider-codex/LICENSE +211 -0
  100. package/dist/vendor/agent-provider-codex/NOTICE +13 -0
  101. package/package.json +22 -13
  102. package/skills/borgee-agent/SKILL.md +12 -4
  103. package/skills/borgee-agent/scripts/borgee-agent.mjs +110 -0
  104. package/skills/borgee-agent/scripts/borgee-agent.py +116 -0
@@ -0,0 +1,21 @@
1
+ import { createRequire as __nodeCreateRequire } from 'node:module';
2
+ const require = __nodeCreateRequire(import.meta.url);
3
+
4
+ // ../agent-provider-claude/src/catalog-worker.ts
5
+ import { getSessionInfo, getSessionMessages, listSessions, listSubagents, getSubagentMessages } from "@borgee/claude-native-sdk";
6
+ var [operation, sessionId, childId] = process.argv.slice(2);
7
+ try {
8
+ const result = operation === "list" ? await listSessions() : operation === "info" && sessionId ? await getSessionInfo(sessionId) : operation === "messages" && sessionId ? await getSessionMessages(sessionId) : operation === "child-messages" && sessionId && childId ? await getSubagentMessages(sessionId, childId) : operation === "children" && sessionId ? await readChildren(sessionId) : (() => {
9
+ throw new Error("Unknown catalog operation.");
10
+ })();
11
+ process.stdout.write(JSON.stringify(result ?? null));
12
+ } catch {
13
+ process.stderr.write("Claude native catalog could not be read.\n");
14
+ process.exitCode = 1;
15
+ }
16
+ async function readChildren(parentId) {
17
+ const children = [];
18
+ for (const id of await listSubagents(parentId)) children.push({ id, messages: await getSubagentMessages(parentId, id) });
19
+ return children;
20
+ }
21
+ //# sourceMappingURL=catalog-worker.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../agent-provider-claude/src/catalog-worker.ts"],
4
+ "sourcesContent": ["import { getSessionInfo, getSessionMessages, listSessions, listSubagents, getSubagentMessages } from '@anthropic-ai/claude-agent-sdk';\n\nconst [operation, sessionId, childId] = process.argv.slice(2);\ntry {\n const result = operation === 'list' ? await listSessions() : operation === 'info' && sessionId ? await getSessionInfo(sessionId)\n : operation === 'messages' && sessionId ? await getSessionMessages(sessionId)\n : operation === 'child-messages' && sessionId && childId ? await getSubagentMessages(sessionId, childId)\n : operation === 'children' && sessionId ? await readChildren(sessionId)\n : (() => { throw new Error('Unknown catalog operation.'); })();\n process.stdout.write(JSON.stringify(result ?? null));\n} catch {\n process.stderr.write('Claude native catalog could not be read.\\n');\n process.exitCode = 1;\n}\n\nasync function readChildren(parentId: string) {\n const children = [];\n for (const id of await listSubagents(parentId)) children.push({ id, messages: await getSubagentMessages(parentId, id) });\n return children;\n}\n"],
5
+ "mappings": ";;;;AAAA,SAAS,gBAAgB,oBAAoB,cAAc,eAAe,2BAA2B;AAErG,IAAM,CAAC,WAAW,WAAW,OAAO,IAAI,QAAQ,KAAK,MAAM,CAAC;AAC5D,IAAI;AACF,QAAM,SAAS,cAAc,SAAS,MAAM,aAAa,IAAI,cAAc,UAAU,YAAY,MAAM,eAAe,SAAS,IAC3H,cAAc,cAAc,YAAY,MAAM,mBAAmB,SAAS,IAC1E,cAAc,oBAAoB,aAAa,UAAU,MAAM,oBAAoB,WAAW,OAAO,IACrG,cAAc,cAAc,YAAY,MAAM,aAAa,SAAS,KACnE,MAAM;AAAE,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAAG,GAAG;AAC/D,UAAQ,OAAO,MAAM,KAAK,UAAU,UAAU,IAAI,CAAC;AACrD,QAAQ;AACN,UAAQ,OAAO,MAAM,4CAA4C;AACjE,UAAQ,WAAW;AACrB;AAEA,eAAe,aAAa,UAAkB;AAC5C,QAAM,WAAW,CAAC;AAClB,aAAW,MAAM,MAAM,cAAc,QAAQ,EAAG,UAAS,KAAK,EAAE,IAAI,UAAU,MAAM,oBAAoB,UAAU,EAAE,EAAE,CAAC;AACvH,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -1,24 +1,39 @@
1
- import type { AgentActivity, ReportTaskFinishedInput, ReportTurnActivityInput, StopBackgroundRunHandler, StopTurnHandler, TurnActivityReporter } from '../plugin-sdk.js';
2
- import type { ChannelSummary, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
1
+ import type { AgentActivity, ExecutionTelemetryFrame, ServerRequestHandler, ReportTaskFinishedInput, ReportTurnActivityInput, StopBackgroundRunHandler, StopTurnHandler, TurnActivityReporter } from '../plugin-sdk.js';
2
+ import type { ChannelSummary, ChannelFileEntry, ChannelFileContent, PublishChannelFileInput, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
3
3
  export interface ChatControlPlane {
4
+ reportExecutionTelemetryFrame?(frame: ExecutionTelemetryFrame): void;
5
+ onExecutionTelemetryAck?(handler: (ack: import('../plugin-sdk.js').ExecutionTelemetryAck) => void): () => void;
6
+ onExecutionTransportReady?(handler: () => void): () => void;
7
+ onServerRequest?(handler: ServerRequestHandler | undefined): void;
4
8
  onStopTurn?(handler: StopTurnHandler | undefined): void;
5
9
  onStopBackgroundRun?(handler: StopBackgroundRunHandler | undefined): void;
6
10
  onActivityTransportReady?(handler: (() => void) | undefined): void;
7
11
  connect(onMessage: (message: ChannelMessageEvent) => void): Promise<void>;
8
12
  close(): Promise<void>;
9
- postMessage(input: PostMessageInput): Promise<PostedMessage>;
13
+ postMessage(input: PostMessageInput, source?: Pick<import('../plugin-sdk.js').ServerRequestContext, 'isConnectionCurrent'>): Promise<PostedMessage>;
10
14
  editMessage(messageId: string, content: string): Promise<void>;
11
15
  deleteMessage(messageId: string): Promise<void>;
12
- startTyping(channelId: string): () => void;
16
+ reportTyping(channelId: string): void;
13
17
  /** Opens one turn's report on the activity rail. Fire-and-forget: nothing recovers what it sends. */
14
18
  reportTurnActivity(input: ReportTurnActivityInput): TurnActivityReporter;
19
+ reportExecutionTelemetry?(frame: ExecutionTelemetryFrame): Promise<void>;
15
20
  reportTaskFinished?(input: ReportTaskFinishedInput): void;
21
+ readonly sessionBindingsSupported?: boolean;
16
22
  reportActivity?(input: {
17
23
  channelId: string;
18
24
  activity: AgentActivity;
19
25
  }): void;
20
26
  getMe(): Promise<MeResponseUser>;
21
27
  listUsers(): Promise<DirectoryUser[]>;
28
+ listChannelFiles(input: {
29
+ channelId: string;
30
+ }): Promise<ChannelFileEntry[]>;
31
+ readChannelFile(input: {
32
+ channelId: string;
33
+ path: string;
34
+ textOnly: boolean;
35
+ }): Promise<ChannelFileContent>;
36
+ publishChannelFile(input: PublishChannelFileInput): Promise<ChannelFileEntry>;
22
37
  listChannels(): Promise<ChannelSummary[]>;
23
38
  readChannelHistory(input: ReadChannelHistoryInput): Promise<ChannelHistoryEntry[]>;
24
39
  createTask(input: CreateTaskInput): Promise<Task>;
@@ -0,0 +1,9 @@
1
+ import type { ChannelMessageEvent } from '../types.js';
2
+ import type { ChatControlPlane } from './chat-control-plane.js';
3
+ /** Plugin bodies may include server-only instructions; only the durable row is public input. */
4
+ export declare function readNormalizedInputText(controlPlane: Pick<ChatControlPlane, 'readChannelHistory'>, message: ChannelMessageEvent, timeoutMs?: number): Promise<string | null>;
5
+ export declare function readDurableInputText(controlPlane: Pick<ChatControlPlane, 'readChannelHistory'>, inputRef: {
6
+ channelId: string;
7
+ inputMessageId?: string;
8
+ createdAt?: number;
9
+ }, timeoutMs?: number): Promise<string | null>;
@@ -0,0 +1,24 @@
1
+ /** Plugin bodies may include server-only instructions; only the durable row is public input. */
2
+ export async function readNormalizedInputText(controlPlane, message, timeoutMs = 2000) {
3
+ return readDurableInputText(controlPlane, { channelId: message.channel_id, inputMessageId: message.message_id, createdAt: message.created_at }, timeoutMs);
4
+ }
5
+ export async function readDurableInputText(controlPlane, inputRef, timeoutMs = 2000) {
6
+ if (!inputRef.inputMessageId)
7
+ return null;
8
+ let timer;
9
+ try {
10
+ const history = await Promise.race([
11
+ controlPlane.readChannelHistory({ channelId: inputRef.channelId, before: inputRef.createdAt == null ? undefined : inputRef.createdAt + 1, limit: 200 }),
12
+ new Promise(resolve => { timer = setTimeout(() => resolve(null), timeoutMs); }),
13
+ ]);
14
+ const input = history?.find(entry => entry.id === inputRef.inputMessageId && entry.channelId === inputRef.channelId);
15
+ return typeof input?.body === 'string' ? input.body : null;
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ finally {
21
+ if (timer)
22
+ clearTimeout(timer);
23
+ }
24
+ }
@@ -1,9 +1,25 @@
1
- import { type BorgeePluginClient, type BorgeePluginOptions, type InboundMessageEvent, type ReportTaskFinishedInput, type ReportTurnActivityInput, type StopTurnHandler, type StopBackgroundRunHandler, type TurnActivityReporter } from '../plugin-sdk.js';
2
- import type { ChannelSummary, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
1
+ import { type BorgeePluginClient, type BorgeePluginOptions, type ExecutionTelemetryFrame, type InboundMessageEvent, type ReportTaskFinishedInput, type ReportTurnActivityInput, type StopTurnHandler, type ServerRequestHandler, type StopBackgroundRunHandler, type TurnActivityReporter } from '../plugin-sdk.js';
2
+ import { type ExecutionTelemetryOutboxPolicy } from '../execution-telemetry.js';
3
+ import type { ChannelSummary, ChannelFileEntry, ChannelFileContent, PublishChannelFileInput, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
3
4
  import type { ChatControlPlane } from './chat-control-plane.js';
4
- type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'createTask' | 'deleteMessage' | 'editMessage' | 'getMe' | 'getTask' | 'listChannels' | 'listTasks' | 'listUsers' | 'on' | 'onStopTurn' | 'onStopBackgroundRun' | 'reportActivity' | 'readHistory' | 'reportTurnActivity' | 'sendMessage' | 'startTyping' | 'updateTask' | 'setTaskProperty' | 'deleteTaskProperty'> & Partial<Pick<BorgeePluginClient, 'reportTaskFinished'>>;
5
+ type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'createTask' | 'deleteMessage' | 'editMessage' | 'getMe' | 'getTask' | 'listChannelFiles' | 'readChannelFile' | 'publishChannelFile' | 'listChannels' | 'listTasks' | 'listUsers' | 'on' | 'onStopTurn' | 'onStopBackgroundRun' | 'reportActivity' | 'readHistory' | 'reportTurnActivity' | 'reportTyping' | 'sendMessage' | 'updateTask' | 'setTaskProperty' | 'deleteTaskProperty'> & Partial<Pick<BorgeePluginClient, 'connectionState' | 'reportExecutionTelemetry' | 'reportTaskFinished' | 'onServerRequest' | 'sessionBindingsSupported'>>;
5
6
  type PluginClientFactory = (options: BorgeePluginOptions) => PluginClientLike;
6
- type SdkChatControlPlaneOptions = Pick<BorgeePluginOptions, 'pluginId'>;
7
+ type SdkChatControlPlaneOptions = Pick<BorgeePluginOptions, 'pluginId'> & {
8
+ providerOutputMode?: () => 'normalized' | 'legacy';
9
+ normalizedActivitySync?: () => boolean;
10
+ sessionControl?: () => boolean;
11
+ sessionBindings?: () => boolean;
12
+ sessionDirectory?: () => boolean;
13
+ sessionManagement?: () => boolean;
14
+ sessionRelations?: () => boolean;
15
+ sessionObservation?: () => boolean;
16
+ connectionLiveness?: () => BorgeePluginOptions['connectionLiveness'];
17
+ sessionInputOperations?: () => readonly ('start_turn' | 'steer' | 'next_turn')[];
18
+ executionTelemetryCapacityWaitMs?: number;
19
+ executionTelemetryOutboxPath?: string;
20
+ executionTelemetryOutboxPolicy?: Partial<ExecutionTelemetryOutboxPolicy>;
21
+ onExecutionTelemetryError?: (error: unknown) => void;
22
+ };
7
23
  /**
8
24
  * Thin adapter over `@borgee/plugin-sdk` (the same BPP/`/ws/plugin` SDK used by
9
25
  * the OpenClaw plugin) that implements the minimal `ChatControlPlane` surface
@@ -14,24 +30,48 @@ export declare class SdkChatControlPlane implements ChatControlPlane {
14
30
  private pendingMessages;
15
31
  private unsubscribe;
16
32
  private stateUnsubscribe;
33
+ private telemetryAckUnsubscribe;
34
+ private executionTelemetryRetry?;
17
35
  private activityTransportReady;
36
+ private readonly executionTelemetryOutbox;
37
+ private readonly onExecutionTelemetryError;
18
38
  private connected;
39
+ private transportOnline;
40
+ private readonly executionTelemetryCapacityWaitMs;
19
41
  private me;
20
42
  constructor(baseUrl: string, apiKey: string, createClient?: PluginClientFactory, options?: SdkChatControlPlaneOptions);
43
+ reportExecutionTelemetryFrame(frame: ExecutionTelemetryFrame): void;
44
+ onExecutionTelemetryAck(handler: (ack: import('../plugin-sdk.js').ExecutionTelemetryAck) => void): () => void;
45
+ onExecutionTransportReady(handler: () => void): () => void;
46
+ onServerRequest(handler: ServerRequestHandler | undefined): void;
21
47
  onStopTurn(handler: StopTurnHandler | undefined): void;
22
48
  onStopBackgroundRun(handler: StopBackgroundRunHandler | undefined): void;
23
49
  onActivityTransportReady(handler: (() => void) | undefined): void;
24
50
  connect(onMessage: (message: ChannelMessageEvent) => void): Promise<void>;
25
51
  close(): Promise<void>;
26
- postMessage(input: PostMessageInput): Promise<PostedMessage>;
52
+ postMessage(input: PostMessageInput, source?: Pick<import('../plugin-sdk.js').ServerRequestContext, 'isConnectionCurrent'>): Promise<PostedMessage>;
53
+ get sessionBindingsSupported(): boolean;
27
54
  reportActivity(input: Parameters<BorgeePluginClient['reportActivity']>[0]): void;
28
55
  reportTaskFinished(input: ReportTaskFinishedInput): void;
29
56
  editMessage(messageId: string, content: string): Promise<void>;
30
57
  deleteMessage(messageId: string): Promise<void>;
31
- startTyping(channelId: string): () => void;
58
+ reportTyping(channelId: string): void;
32
59
  reportTurnActivity(input: ReportTurnActivityInput): TurnActivityReporter;
60
+ reportExecutionTelemetry(frame: ExecutionTelemetryFrame): Promise<void>;
61
+ private flushExecutionTelemetry;
62
+ private scheduleExecutionTelemetryRetry;
63
+ private cancelExecutionTelemetryRetry;
33
64
  getMe(): Promise<MeResponseUser>;
34
65
  listUsers(): Promise<DirectoryUser[]>;
66
+ listChannelFiles(input: {
67
+ channelId: string;
68
+ }): Promise<ChannelFileEntry[]>;
69
+ readChannelFile(input: {
70
+ channelId: string;
71
+ path: string;
72
+ textOnly: boolean;
73
+ }): Promise<ChannelFileContent>;
74
+ publishChannelFile(input: PublishChannelFileInput): Promise<ChannelFileEntry>;
35
75
  readChannelHistory(input: ReadChannelHistoryInput): Promise<ChannelHistoryEntry[]>;
36
76
  listChannels(): Promise<ChannelSummary[]>;
37
77
  createTask(input: CreateTaskInput): Promise<Task>;
@@ -1,4 +1,5 @@
1
1
  import { createBorgeePlugin, } from '../plugin-sdk.js';
2
+ import { ExecutionTelemetryOutbox, ExecutionTelemetryOutboxCapacityError, } from '../execution-telemetry.js';
2
3
  import { normalizeHostedMessageAttachment } from '../hosted-turn-content.js';
3
4
  /**
4
5
  * Thin adapter over `@borgee/plugin-sdk` (the same BPP/`/ws/plugin` SDK used by
@@ -10,11 +11,63 @@ export class SdkChatControlPlane {
10
11
  pendingMessages = [];
11
12
  unsubscribe = null;
12
13
  stateUnsubscribe = null;
14
+ telemetryAckUnsubscribe = null;
15
+ executionTelemetryRetry;
13
16
  activityTransportReady;
17
+ executionTelemetryOutbox;
18
+ onExecutionTelemetryError;
14
19
  connected = false;
20
+ transportOnline = false;
21
+ executionTelemetryCapacityWaitMs;
15
22
  me = null;
16
23
  constructor(baseUrl, apiKey, createClient = createBorgeePlugin, options = {}) {
17
- this.client = createClient({ baseUrl, apiKey, ...options });
24
+ const clientOptions = { baseUrl, apiKey, pluginId: options.pluginId };
25
+ // The adapter is selected after its control plane; read its policy at connect.
26
+ if (options.providerOutputMode)
27
+ Object.defineProperty(clientOptions, 'providerOutputMode', { enumerable: true, get: options.providerOutputMode });
28
+ if (options.normalizedActivitySync)
29
+ Object.defineProperty(clientOptions, 'normalizedActivitySync', { enumerable: true, get: options.normalizedActivitySync });
30
+ if (options.sessionControl)
31
+ Object.defineProperty(clientOptions, 'sessionControl', { enumerable: true, get: options.sessionControl });
32
+ if (options.sessionBindings)
33
+ Object.defineProperty(clientOptions, 'sessionBindings', { enumerable: true, get: options.sessionBindings });
34
+ if (options.sessionManagement)
35
+ Object.defineProperty(clientOptions, 'sessionManagement', { enumerable: true, get: options.sessionManagement });
36
+ if (options.sessionDirectory)
37
+ Object.defineProperty(clientOptions, 'sessionDirectory', { enumerable: true, get: options.sessionDirectory });
38
+ if (options.sessionRelations)
39
+ Object.defineProperty(clientOptions, 'sessionRelations', { enumerable: true, get: options.sessionRelations });
40
+ if (options.sessionObservation)
41
+ Object.defineProperty(clientOptions, 'sessionObservation', { enumerable: true, get: options.sessionObservation });
42
+ if (options.connectionLiveness)
43
+ Object.defineProperty(clientOptions, 'connectionLiveness', { enumerable: true, get: options.connectionLiveness });
44
+ if (options.sessionInputOperations)
45
+ clientOptions.sessionInputOperations = options.sessionInputOperations;
46
+ this.client = createClient(clientOptions);
47
+ this.onExecutionTelemetryError =
48
+ options.onExecutionTelemetryError ??
49
+ (() => console.error('[agents-host] execution telemetry persistence failed'));
50
+ this.executionTelemetryCapacityWaitMs =
51
+ options.executionTelemetryCapacityWaitMs ?? 1_000;
52
+ this.executionTelemetryOutbox = new ExecutionTelemetryOutbox(options.executionTelemetryOutboxPath, {
53
+ onRetired: (count) => {
54
+ this.onExecutionTelemetryError(new Error(`Retired ${count} unacknowledged execution telemetry event(s)`));
55
+ },
56
+ policy: options.executionTelemetryOutboxPolicy,
57
+ });
58
+ }
59
+ reportExecutionTelemetryFrame(frame) {
60
+ this.client.reportExecutionTelemetry?.(frame);
61
+ }
62
+ onExecutionTelemetryAck(handler) {
63
+ return this.client.on('executionTelemetryAck', handler);
64
+ }
65
+ onExecutionTransportReady(handler) {
66
+ return this.client.on('connectionState', state => { if (state.status === 'online')
67
+ handler(); });
68
+ }
69
+ onServerRequest(handler) {
70
+ this.client.onServerRequest?.(handler);
18
71
  }
19
72
  onStopTurn(handler) {
20
73
  this.client.onStopTurn(handler);
@@ -26,6 +79,7 @@ export class SdkChatControlPlane {
26
79
  this.activityTransportReady = handler;
27
80
  }
28
81
  async connect(onMessage) {
82
+ await this.executionTelemetryOutbox.load();
29
83
  this.unsubscribe = this.client.on('message', (event) => {
30
84
  const message = mapInboundToChannelMessage(event);
31
85
  if (!this.connected) {
@@ -35,13 +89,26 @@ export class SdkChatControlPlane {
35
89
  onMessage(message);
36
90
  });
37
91
  this.stateUnsubscribe = this.client.on('connectionState', (state) => {
92
+ this.transportOnline = state.status === 'online';
38
93
  if (state.status === 'online') {
39
94
  this.activityTransportReady?.();
95
+ void this.flushExecutionTelemetry(true);
96
+ }
97
+ else {
98
+ this.cancelExecutionTelemetryRetry();
40
99
  }
41
100
  });
101
+ this.telemetryAckUnsubscribe = this.client.on('executionTelemetryAck', (ack) => {
102
+ void this.executionTelemetryOutbox
103
+ .acknowledge(ack.eventId)
104
+ .then(() => this.scheduleExecutionTelemetryRetry())
105
+ .catch(this.onExecutionTelemetryError);
106
+ });
42
107
  try {
43
108
  await this.client.connect();
44
109
  this.connected = true;
110
+ this.transportOnline =
111
+ this.transportOnline || this.client.connectionState?.status === 'online';
45
112
  if (this.client.agentId) {
46
113
  this.me = { id: this.client.agentId };
47
114
  }
@@ -49,36 +116,48 @@ export class SdkChatControlPlane {
49
116
  onMessage(message);
50
117
  }
51
118
  this.pendingMessages = [];
119
+ await this.flushExecutionTelemetry(true);
52
120
  }
53
121
  catch (error) {
122
+ this.transportOnline = false;
123
+ this.cancelExecutionTelemetryRetry();
54
124
  this.unsubscribe?.();
55
125
  this.unsubscribe = null;
56
126
  this.stateUnsubscribe?.();
57
127
  this.stateUnsubscribe = null;
128
+ this.telemetryAckUnsubscribe?.();
129
+ this.telemetryAckUnsubscribe = null;
58
130
  this.pendingMessages = [];
59
131
  throw error;
60
132
  }
61
133
  }
62
134
  async close() {
63
135
  this.connected = false;
136
+ this.transportOnline = false;
137
+ this.cancelExecutionTelemetryRetry();
64
138
  this.pendingMessages = [];
65
139
  this.unsubscribe?.();
66
140
  this.unsubscribe = null;
67
141
  this.stateUnsubscribe?.();
68
142
  this.stateUnsubscribe = null;
143
+ this.telemetryAckUnsubscribe?.();
144
+ this.telemetryAckUnsubscribe = null;
69
145
  this.activityTransportReady = undefined;
70
146
  this.client.onStopTurn(undefined);
71
147
  this.client.onStopBackgroundRun?.(undefined);
148
+ await this.executionTelemetryOutbox.settle();
72
149
  await this.client.close();
73
150
  }
74
- async postMessage(input) {
75
- const sent = await this.client.sendMessage({
151
+ async postMessage(input, source) {
152
+ const message = {
76
153
  channelId: input.channelId,
77
154
  body: input.body,
78
155
  replyToId: input.replyToId,
79
- });
156
+ };
157
+ const sent = source ? await this.client.sendMessage(message, source) : await this.client.sendMessage(message);
80
158
  return { messageId: sent.messageId };
81
159
  }
160
+ get sessionBindingsSupported() { return this.client.sessionBindingsSupported ?? false; }
82
161
  reportActivity(input) {
83
162
  this.client.reportActivity(input);
84
163
  }
@@ -91,12 +170,65 @@ export class SdkChatControlPlane {
91
170
  async deleteMessage(messageId) {
92
171
  await this.client.deleteMessage({ messageId });
93
172
  }
94
- startTyping(channelId) {
95
- return this.client.startTyping(channelId);
173
+ reportTyping(channelId) {
174
+ this.client.reportTyping(channelId);
96
175
  }
97
176
  reportTurnActivity(input) {
98
177
  return this.client.reportTurnActivity(input);
99
178
  }
179
+ async reportExecutionTelemetry(frame) {
180
+ if (!this.client.reportExecutionTelemetry) {
181
+ throw new Error('Plugin SDK execution telemetry is unavailable');
182
+ }
183
+ try {
184
+ await this.executionTelemetryOutbox.enqueue(frame);
185
+ }
186
+ catch (error) {
187
+ if (!(error instanceof ExecutionTelemetryOutboxCapacityError) ||
188
+ !this.transportOnline) {
189
+ throw error;
190
+ }
191
+ await this.flushExecutionTelemetry(true);
192
+ const capacityAvailable = await this.executionTelemetryOutbox.waitForCapacity(this.executionTelemetryCapacityWaitMs);
193
+ if (!capacityAvailable)
194
+ throw error;
195
+ await this.executionTelemetryOutbox.enqueue(frame);
196
+ }
197
+ await this.flushExecutionTelemetry();
198
+ }
199
+ async flushExecutionTelemetry(force = false) {
200
+ if (!this.connected || !this.transportOnline || !this.client.reportExecutionTelemetry)
201
+ return;
202
+ try {
203
+ await this.executionTelemetryOutbox.flush((frame) => {
204
+ this.client.reportExecutionTelemetry?.(frame);
205
+ }, force);
206
+ }
207
+ catch (error) {
208
+ this.onExecutionTelemetryError(error);
209
+ }
210
+ finally {
211
+ this.scheduleExecutionTelemetryRetry();
212
+ }
213
+ }
214
+ scheduleExecutionTelemetryRetry() {
215
+ this.cancelExecutionTelemetryRetry();
216
+ if (!this.connected || !this.transportOnline)
217
+ return;
218
+ const delay = this.executionTelemetryOutbox.nextRetryDelayMs();
219
+ if (delay === undefined)
220
+ return;
221
+ this.executionTelemetryRetry = setTimeout(() => {
222
+ this.executionTelemetryRetry = undefined;
223
+ void this.flushExecutionTelemetry();
224
+ }, Math.max(1, delay));
225
+ }
226
+ cancelExecutionTelemetryRetry() {
227
+ if (!this.executionTelemetryRetry)
228
+ return;
229
+ clearTimeout(this.executionTelemetryRetry);
230
+ this.executionTelemetryRetry = undefined;
231
+ }
100
232
  async getMe() {
101
233
  if (this.me) {
102
234
  return this.me;
@@ -117,6 +249,34 @@ export class SdkChatControlPlane {
117
249
  kind: user.kind,
118
250
  }));
119
251
  }
252
+ async listChannelFiles(input) {
253
+ const files = await this.client.listChannelFiles({ channelId: input.channelId });
254
+ return files.map((file) => ({
255
+ id: file.id,
256
+ ownerUserId: file.ownerUserId,
257
+ channelId: file.channelId,
258
+ path: file.path,
259
+ parentPath: file.parentPath,
260
+ name: file.name,
261
+ isDirectory: file.isDirectory,
262
+ mimeType: file.mimeType,
263
+ sizeBytes: file.sizeBytes,
264
+ source: file.source,
265
+ sourceMessageId: file.sourceMessageId,
266
+ createdAt: file.createdAt,
267
+ updatedAt: file.updatedAt,
268
+ }));
269
+ }
270
+ async readChannelFile(input) {
271
+ return await this.client.readChannelFile(input);
272
+ }
273
+ async publishChannelFile(input) {
274
+ const file = await this.client.publishChannelFile(input);
275
+ return {
276
+ ...file,
277
+ sourceMessageId: file.sourceMessageId,
278
+ };
279
+ }
120
280
  async readChannelHistory(input) {
121
281
  const messages = await this.client.readHistory({
122
282
  channelId: input.channelId,
@@ -167,6 +327,9 @@ export class SdkChatControlPlane {
167
327
  export function mapInboundToChannelMessage(event) {
168
328
  return {
169
329
  type: event.kind,
330
+ ...(event.executionGrant ? { execution_grant: { ...event.executionGrant } } : {}),
331
+ ...(event.sessionTarget ? { sessionTarget: { ...event.sessionTarget } } : {}),
332
+ ...(event.sourceCurrent ? { sourceCurrent: event.sourceCurrent } : {}),
170
333
  ...(event.message?.type != null ? { message_type: event.message.type } : {}),
171
334
  channel_id: event.channelId,
172
335
  channel_type: event.channelType,
@@ -85,4 +85,4 @@ export declare function parseCleanupManagedArgs(argv: string[]): ParsedCleanupMa
85
85
  export declare function parseApplyManagedArgs(argv: string[]): ParsedApplyManagedArgs;
86
86
  /** `update` always installs the latest published release; it takes no options. */
87
87
  export declare function assertNoUpdateArgs(argv: string[]): void;
88
- export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start-managed <serverUrl>\n agents-host start-managed <serverUrl> <apiKey> [agent-options]\n agents-host describe-managed <serverUrl>\n agents-host cleanup-managed <serverUrl> [--purge]\n agents-host apply-managed <serverUrl> --stdin\n agents-host apply-managed <serverUrl> --spec-json <json>\n agents-host log <serverUrl> [--lines <n>] [--follow]\n agents-host log <serverUrl> --path\n agents-host start --config <path-to-host-config> [--debug]\n agents-host validate --config <path-to-host-config>\n agents-host describe --config <path-to-host-config>\n agents-host print-layout --root <dir>\n agents-host generate-config --root <dir> --stdin\n agents-host generate-config --root <dir> --spec-json <json>\n agents-host update\n\nForeground start options:\n --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)\n\nSingle-agent agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|codex|copilot>\n Runtime provider (default: claude)\n --claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)\n --claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)\n --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)\n --codex-args <args> Local Codex ACP adapter args\n --copilot-command <cmd> Local Copilot CLI command (default: copilot)\n --copilot-args <args> Ignored by the Copilot ACP prototype\n --copilot-session-ttl-minutes <minutes>\n Idle session TTL for Copilot ACP sessions (default: 2880)\n --provider-idle-shutdown-minutes <minutes>\n Shut the shared ACP adapter process down after this much idle\n time and re-spawn it on the next turn; 0 keeps it resident\n (default: 10)\n\nCommand summary:\n start <serverUrl> <apiKey> Start one foreground hosted agent (legacy-compatible behavior)\n start --config <path> Start agents + supervisor + watchers from a host config file\n start-managed <serverUrl> Restart or resume an existing per-serverUrl managed daemon\n start-managed <serverUrl> <apiKey>\n Upsert one agent into the per-serverUrl local daemon and exit after reconcile\n describe-managed <serverUrl> Print managed-runtime spec JSON for machine callers\n cleanup-managed <serverUrl> Stop one managed-runtime daemon locally; --purge also removes its runtime root\n apply-managed <serverUrl> Apply one managed-runtime full-set spec for machine callers\n log <serverUrl> Print the managed daemon log tail for one server runtime\n validate --config <path> Validate local-config files without starting agents or watchers\n describe --config <path> Print the current managed full-set spec as JSON\n print-layout --root <dir> Print the canonical default local-config layout as JSON\n generate-config --root <dir> --stdin Materialize canonical local-config files from stdin\n generate-config --root <dir> --spec-json <json>\n Compatibility input; JSON is exposed in process arguments\n update Update the globally installed @borgee/agents-host to the latest release\n\nStartup update check:\n Startup commands print an advisory notice on stderr when a newer release is published.\n Set AGENTS_HOST_DISABLE_UPDATE_CHECK=1 to turn that check off.\n\nExamples:\n agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug\n agents-host start-managed https://borgee.example.com\n agents-host start-managed https://borgee.example.com bgr_xxxxxxxx --provider copilot\n agents-host describe-managed https://borgee.example.com\n agents-host cleanup-managed https://borgee.example.com --purge\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host apply-managed https://borgee.example.com --stdin\n agents-host log https://borgee.example.com --lines 200 --follow\n agents-host log https://borgee.example.com --path\n agents-host start --config ./agents-host.yaml --debug\n agents-host validate --config ./agents-host.yaml\n agents-host describe --config ./agents-host.yaml\n agents-host print-layout --root ./runtime-root\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host generate-config --root ./runtime-root --stdin\n agents-host update\n";
88
+ export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start-managed <serverUrl>\n agents-host start-managed <serverUrl> <apiKey> [agent-options]\n agents-host describe-managed <serverUrl>\n agents-host cleanup-managed <serverUrl> [--purge]\n agents-host apply-managed <serverUrl> --stdin\n agents-host apply-managed <serverUrl> --spec-json <json>\n agents-host log <serverUrl> [--lines <n>] [--follow]\n agents-host log <serverUrl> --path\n agents-host start --config <path-to-host-config> [--debug]\n agents-host validate --config <path-to-host-config>\n agents-host describe --config <path-to-host-config>\n agents-host print-layout --root <dir>\n agents-host generate-config --root <dir> --stdin\n agents-host generate-config --root <dir> --spec-json <json>\n agents-host update\n\nForeground start options:\n --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)\n\nSingle-agent agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|codex|copilot>\n Runtime provider (default: claude)\n --provider-output-mode <legacy|normalized>\n Output adapter (default: legacy; overrides PROVIDER_OUTPUT_MODE)\n --native-provider-command <path>\n Native executable for normalized output (overrides NATIVE_PROVIDER_COMMAND)\n --codex-connection-mode <shared|stdio>\n Normalized Codex transport (default: stdio; overrides CODEX_CONNECTION_MODE)\n --claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)\n --claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)\n --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)\n --codex-args <args> Local Codex ACP adapter args\n --copilot-command <cmd> Legacy Copilot CLI command (default: copilot)\n --copilot-args <args> Parsed but ignored by the legacy Copilot SDK adapter\n --copilot-session-ttl-minutes <minutes>\n Idle session TTL for legacy Copilot SDK sessions (default: 2880)\n --provider-idle-shutdown-minutes <minutes>\n Shut the legacy provider process down after this much idle\n time and re-spawn it on the next turn; 0 keeps it resident\n (default: 10)\n\nCommand summary:\n start <serverUrl> <apiKey> Start one foreground hosted agent (legacy-compatible behavior)\n start --config <path> Start agents + supervisor + watchers from a host config file\n start-managed <serverUrl> Restart or resume an existing per-serverUrl managed daemon\n start-managed <serverUrl> <apiKey>\n Upsert one agent into the per-serverUrl local daemon and exit after reconcile\n describe-managed <serverUrl> Print managed-runtime spec JSON for machine callers\n cleanup-managed <serverUrl> Stop one managed-runtime daemon locally; --purge also removes its runtime root\n apply-managed <serverUrl> Apply one managed-runtime full-set spec for machine callers\n log <serverUrl> Print the managed daemon log tail for one server runtime\n validate --config <path> Validate local-config files without starting agents or watchers\n describe --config <path> Print the current managed full-set spec as JSON\n print-layout --root <dir> Print the canonical default local-config layout as JSON\n generate-config --root <dir> --stdin Materialize canonical local-config files from stdin\n generate-config --root <dir> --spec-json <json>\n Compatibility input; JSON is exposed in process arguments\n update Update the globally installed @borgee/agents-host to the latest release\n\nStartup update check:\n Startup commands print an advisory notice on stderr when a newer release is published.\n Set AGENTS_HOST_DISABLE_UPDATE_CHECK=1 to turn that check off.\n\nExamples:\n agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug\n agents-host start-managed https://borgee.example.com\n agents-host start-managed https://borgee.example.com bgr_xxxxxxxx --provider copilot\n agents-host describe-managed https://borgee.example.com\n agents-host cleanup-managed https://borgee.example.com --purge\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host apply-managed https://borgee.example.com --stdin\n agents-host log https://borgee.example.com --lines 200 --follow\n agents-host log https://borgee.example.com --path\n agents-host start --config ./agents-host.yaml --debug\n agents-host validate --config ./agents-host.yaml\n agents-host describe --config ./agents-host.yaml\n agents-host print-layout --root ./runtime-root\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host generate-config --root ./runtime-root --stdin\n agents-host update\n";
package/dist/cli-args.js CHANGED
@@ -8,6 +8,9 @@
8
8
  export const CLI_FLAG_TO_ENV = {
9
9
  name: 'BORGEE_AGENT_NAME',
10
10
  provider: 'RUNTIME_PROVIDER',
11
+ 'provider-output-mode': 'PROVIDER_OUTPUT_MODE',
12
+ 'native-provider-command': 'NATIVE_PROVIDER_COMMAND',
13
+ 'codex-connection-mode': 'CODEX_CONNECTION_MODE',
11
14
  'claude-command': 'CLAUDE_COMMAND',
12
15
  'claude-args': 'CLAUDE_ARGS',
13
16
  'codex-command': 'CODEX_COMMAND',
@@ -505,16 +508,22 @@ Single-agent agent options:
505
508
  --name <name> Display name (default: Assistant)
506
509
  --provider <claude|codex|copilot>
507
510
  Runtime provider (default: claude)
511
+ --provider-output-mode <legacy|normalized>
512
+ Output adapter (default: legacy; overrides PROVIDER_OUTPUT_MODE)
513
+ --native-provider-command <path>
514
+ Native executable for normalized output (overrides NATIVE_PROVIDER_COMMAND)
515
+ --codex-connection-mode <shared|stdio>
516
+ Normalized Codex transport (default: stdio; overrides CODEX_CONNECTION_MODE)
508
517
  --claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)
509
518
  --claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)
510
519
  --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)
511
520
  --codex-args <args> Local Codex ACP adapter args
512
- --copilot-command <cmd> Local Copilot CLI command (default: copilot)
513
- --copilot-args <args> Ignored by the Copilot ACP prototype
521
+ --copilot-command <cmd> Legacy Copilot CLI command (default: copilot)
522
+ --copilot-args <args> Parsed but ignored by the legacy Copilot SDK adapter
514
523
  --copilot-session-ttl-minutes <minutes>
515
- Idle session TTL for Copilot ACP sessions (default: 2880)
524
+ Idle session TTL for legacy Copilot SDK sessions (default: 2880)
516
525
  --provider-idle-shutdown-minutes <minutes>
517
- Shut the shared ACP adapter process down after this much idle
526
+ Shut the legacy provider process down after this much idle
518
527
  time and re-spawn it on the next turn; 0 keeps it resident
519
528
  (default: 10)
520
529
 
package/dist/config.d.ts CHANGED
@@ -21,6 +21,8 @@ export declare function isLegacyClaudeCompatibilityAlias(command: string, args:
21
21
  export declare function isLegacyClaudeBinaryCommand(command: string): boolean;
22
22
  export declare function hasLegacyClaudeOneShotArgs(args: string[]): boolean;
23
23
  export declare function assertClaudeCommandCompatibility(command: string, args: string[], sourceLabel: string): void;
24
- export declare function assertProviderCommandCompatibility(provider: ProviderKind, config: Pick<ProviderCommandConfig, 'claudeCommand' | 'claudeArgs'>, sourceLabel: string): void;
24
+ export declare function assertProviderCommandCompatibility(provider: ProviderKind, config: Pick<ProviderCommandConfig, 'claudeCommand' | 'claudeArgs'> & Partial<Pick<ProviderCommandConfig, 'providerOutputMode' | 'codexConnectionMode' | 'codexSharedSocketPath'>>, sourceLabel: string): void;
25
+ export declare function parseCodexConnectionMode(value: unknown): 'shared' | 'stdio';
26
+ export declare function parseProviderOutputMode(value: unknown): 'legacy' | 'normalized';
25
27
  export declare function resolveProviderCommandConfig(overrides?: Partial<ProviderCommandConfig>): ProviderCommandConfig;
26
28
  export declare function loadConfigFromEnv(env?: NodeJS.ProcessEnv): AgentsHostConfig;
package/dist/config.js CHANGED
@@ -137,9 +137,28 @@ export function assertProviderCommandCompatibility(provider, config, sourceLabel
137
137
  if (provider === 'claude') {
138
138
  assertClaudeCommandCompatibility(config.claudeCommand, config.claudeArgs, sourceLabel);
139
139
  }
140
+ if (provider === 'codex' && config.providerOutputMode === 'normalized' && (config.codexConnectionMode ?? 'stdio') === 'stdio' && config.codexSharedSocketPath !== undefined) {
141
+ throw new Error(`${sourceLabel}: a Codex shared socket cannot be configured in stdio mode. Set codexConnectionMode: shared (CODEX_CONNECTION_MODE=shared) explicitly to use a shared daemon.`);
142
+ }
143
+ }
144
+ export function parseCodexConnectionMode(value) {
145
+ if (value !== 'shared' && value !== 'stdio')
146
+ throw new Error('codexConnectionMode must be shared or stdio.');
147
+ return value;
148
+ }
149
+ export function parseProviderOutputMode(value) {
150
+ if (value !== 'legacy' && value !== 'normalized')
151
+ throw new Error('providerOutputMode must be legacy or normalized.');
152
+ return value;
140
153
  }
141
154
  export function resolveProviderCommandConfig(overrides = {}) {
142
155
  return {
156
+ ...(overrides.providerOutputMode !== undefined ? { providerOutputMode: parseProviderOutputMode(overrides.providerOutputMode) } : {}),
157
+ ...(overrides.sessionWorkspaceRoot !== undefined ? { sessionWorkspaceRoot: overrides.sessionWorkspaceRoot } : {}),
158
+ ...(overrides.nativeProviderCommand !== undefined ? { nativeProviderCommand: overrides.nativeProviderCommand } : {}),
159
+ ...(overrides.codexConnectionMode !== undefined ? { codexConnectionMode: parseCodexConnectionMode(overrides.codexConnectionMode) } : {}),
160
+ ...(overrides.codexSharedSocketPath !== undefined ? { codexSharedSocketPath: overrides.codexSharedSocketPath } : {}),
161
+ ...(overrides.codexTrustShared !== undefined ? { codexTrustShared: parseBooleanValue(overrides.codexTrustShared, 'codexTrustShared', 'provider configuration') } : {}),
143
162
  claudeCommand: overrides.claudeCommand ?? DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand,
144
163
  claudeArgs: [...(overrides.claudeArgs ?? DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs)],
145
164
  codexCommand: overrides.codexCommand ?? DEFAULT_PROVIDER_COMMAND_CONFIG.codexCommand,
@@ -158,8 +177,14 @@ export function loadConfigFromEnv(env = process.env) {
158
177
  assertProviderCompatibility(provider, 'Unsupported RUNTIME_PROVIDER', env);
159
178
  const agentApiKey = requireEnv('BORGEE_AGENT_API_KEY', env);
160
179
  const providerConfig = resolveProviderCommandConfig({
180
+ ...(env.PROVIDER_OUTPUT_MODE ? { providerOutputMode: parseProviderOutputMode(env.PROVIDER_OUTPUT_MODE) } : {}),
181
+ ...(env.SESSION_WORKSPACE_ROOT ? { sessionWorkspaceRoot: requireNonEmptyString(env.SESSION_WORKSPACE_ROOT, 'SESSION_WORKSPACE_ROOT') } : {}),
182
+ ...(env.NATIVE_PROVIDER_COMMAND ? { nativeProviderCommand: env.NATIVE_PROVIDER_COMMAND } : {}),
161
183
  claudeCommand: envOr('CLAUDE_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand, env),
162
184
  claudeArgs: parseArgs(envOr('CLAUDE_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs.join(' '), env)),
185
+ ...(env.CODEX_CONNECTION_MODE !== undefined ? { codexConnectionMode: parseCodexConnectionMode(env.CODEX_CONNECTION_MODE) } : {}),
186
+ ...(env.CODEX_SHARED_SOCKET_PATH ? { codexSharedSocketPath: requireNonEmptyString(env.CODEX_SHARED_SOCKET_PATH, 'CODEX_SHARED_SOCKET_PATH') } : {}),
187
+ ...(env.CODEX_TRUST_SHARED !== undefined ? { codexTrustShared: parseBooleanValue(env.CODEX_TRUST_SHARED, 'CODEX_TRUST_SHARED', 'environment') } : {}),
163
188
  codexCommand: envOr('CODEX_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.codexCommand, env),
164
189
  codexArgs: parseArgs(envOr('CODEX_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.codexArgs.join(' '), env)),
165
190
  copilotCommand: envOr('COPILOT_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotCommand, env),
@@ -57,6 +57,10 @@ export interface ChannelContextStore {
57
57
  incomingContent?: string;
58
58
  taskAssignmentContextOverride?: TaskAssignmentThreadContext;
59
59
  taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
60
+ independentSessionWorkspace?: {
61
+ bindingId: string;
62
+ cwd: string;
63
+ };
60
64
  }): Promise<PreparedChannelContext>;
61
65
  prepare(channelId: string, options?: {
62
66
  provider?: ProviderKind;
@@ -72,6 +76,10 @@ export interface ChannelContextStore {
72
76
  incomingContent?: string;
73
77
  taskAssignmentContextOverride?: TaskAssignmentThreadContext;
74
78
  taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
79
+ independentSessionWorkspace?: {
80
+ bindingId: string;
81
+ cwd: string;
82
+ };
75
83
  }): Promise<PreparedChannelContext>;
76
84
  }
77
85
  export interface SkillAssetResolver {
@@ -173,6 +181,10 @@ export declare class FileChannelContextStore implements ChannelContextStore {
173
181
  incomingContent?: string;
174
182
  taskAssignmentContextOverride?: TaskAssignmentThreadContext;
175
183
  taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
184
+ independentSessionWorkspace?: {
185
+ bindingId: string;
186
+ cwd: string;
187
+ };
176
188
  } | string, options?: {
177
189
  provider?: ProviderKind;
178
190
  projectionStrategy?: ProjectionStrategy;
@@ -187,6 +199,10 @@ export declare class FileChannelContextStore implements ChannelContextStore {
187
199
  incomingContent?: string;
188
200
  taskAssignmentContextOverride?: TaskAssignmentThreadContext;
189
201
  taskAssignmentContextOverridePersistence?: 'persist' | 'ephemeral';
202
+ independentSessionWorkspace?: {
203
+ bindingId: string;
204
+ cwd: string;
205
+ };
190
206
  }): Promise<PreparedChannelContext>;
191
207
  private resolveSkillRuntimeBestEffort;
192
208
  }