@borgee/agents-host 0.2.44 → 0.2.62
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 +24 -27
- package/dist/agents-host.d.ts +27 -5
- package/dist/agents-host.js +266 -201
- package/dist/chat/chat-control-plane.d.ts +3 -0
- package/dist/chat/sdk-chat-control-plane.d.ts +4 -3
- package/dist/chat/sdk-chat-control-plane.js +3 -0
- package/dist/cli.js +1 -5
- package/dist/compatibility-gates.d.ts +4 -0
- package/dist/compatibility-gates.js +20 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +21 -0
- package/dist/context/claude-file-brief.d.ts +2 -0
- package/dist/context/claude-file-brief.js +83 -0
- package/dist/context/compaction.d.ts +20 -0
- package/dist/context/compaction.js +59 -0
- package/dist/context/injection.d.ts +58 -7
- package/dist/context/injection.js +370 -36
- package/dist/context/main-session-delegation.d.ts +1 -1
- package/dist/context/projection-strategy.d.ts +24 -0
- package/dist/context/projection-strategy.js +90 -0
- package/dist/context/prompt.d.ts +16 -1
- package/dist/context/prompt.js +464 -26
- package/dist/context/resolved-workspace.d.ts +3 -0
- package/dist/context/resolved-workspace.js +106 -0
- package/dist/context/skill-manual.d.ts +1 -0
- package/dist/context/skill-manual.js +4 -1
- package/dist/context/turn-preparation.d.ts +8 -2
- package/dist/context/turn-preparation.js +64 -14
- package/dist/gateway/localhost-gateway.js +4 -5
- package/dist/local-config.js +11 -1
- package/dist/managed-daemon.js +127 -9
- package/dist/plugin-sdk.js +264 -364
- package/dist/plugin-sdk.js.map +4 -4
- package/dist/policy/copilot-permission.d.ts +1 -0
- package/dist/policy/copilot-permission.js +18 -0
- package/dist/policy/gateway-authorization.js +2 -2
- package/dist/progress-to-activity.d.ts +16 -0
- package/dist/progress-to-activity.js +24 -0
- package/dist/projection-strategy-values.d.ts +4 -0
- package/dist/projection-strategy-values.js +28 -0
- package/dist/providers/acp-progress-collector.d.ts +44 -0
- package/dist/providers/acp-progress-collector.js +130 -0
- package/dist/providers/awaiting-user.d.ts +2 -3
- package/dist/providers/awaiting-user.js +5 -7
- package/dist/providers/claude/activity-metadata.d.ts +14 -0
- package/dist/providers/claude/activity-metadata.js +81 -0
- package/dist/providers/claude/cli-client.d.ts +2 -3
- package/dist/providers/claude/cli-client.js +220 -120
- package/dist/providers/codex/cli-client.d.ts +2 -0
- package/dist/providers/codex/cli-client.js +28 -104
- package/dist/providers/codex/project-doc.js +12 -11
- package/dist/providers/copilot/cli-client.d.ts +1 -1
- package/dist/providers/copilot/cli-client.js +12 -86
- package/dist/providers/create-provider.d.ts +2 -0
- package/dist/providers/create-provider.js +22 -4
- package/dist/state-paths.d.ts +1 -1
- package/dist/state-paths.js +3 -3
- package/dist/task-thread-resolution.d.ts +3 -2
- package/dist/types.d.ts +143 -6
- package/package.json +2 -2
- package/skills/borgee-agent/SKILL.md +12 -4
- package/skills/borgee-agent/references/errors.md +2 -2
- package/skills/borgee-agent/references/task-properties.md +6 -2
- package/dist/durable-cursor-store.d.ts +0 -5
- package/dist/durable-cursor-store.js +0 -7
|
@@ -5,8 +5,11 @@ import { createRequire } from 'node:module';
|
|
|
5
5
|
import spawn from 'cross-spawn';
|
|
6
6
|
import { PROTOCOL_VERSION, client, methods, ndJsonStream, } from '@agentclientprotocol/sdk';
|
|
7
7
|
import { HostLogger, summarizeChildStderr, summarizeError } from '../../debug.js';
|
|
8
|
+
import { AcpProgressCollector } from '../acp-progress-collector.js';
|
|
8
9
|
import { assertCodexProjectDocumentSize, buildCodexProjectDocument } from './project-doc.js';
|
|
9
10
|
import { isGatewayCredentialSidecarBasename } from '../../context/injection.js';
|
|
11
|
+
import { isDiscussionOnlyResolvedWorkspace } from '../../context/resolved-workspace.js';
|
|
12
|
+
import { resolveCopilotPermissionResponse } from '../../policy/copilot-permission.js';
|
|
10
13
|
import { IDLE_BACKEND_SHUTDOWN_DISABLED_MS, IdleBackendShutdownScheduler, } from '../idle-backend-shutdown.js';
|
|
11
14
|
const SESSION_TAINTED_ERRORS = new WeakSet();
|
|
12
15
|
const DEFAULT_IDLE_SESSION_TTL_MS = 2 * 24 * 60 * 60 * 1000;
|
|
@@ -60,9 +63,6 @@ const DEFAULT_RUNTIME = {
|
|
|
60
63
|
},
|
|
61
64
|
fetch: async (input, init) => fetch(input, init),
|
|
62
65
|
};
|
|
63
|
-
function hasVisibleText(value) {
|
|
64
|
-
return typeof value === 'string' && value.trim().length > 0;
|
|
65
|
-
}
|
|
66
66
|
function cloneDirectories(directories) {
|
|
67
67
|
return directories ? [...directories] : undefined;
|
|
68
68
|
}
|
|
@@ -103,84 +103,6 @@ function serializePersistedSessionRecord(record) {
|
|
|
103
103
|
...(record.cwd ? { cwd: record.cwd } : {}),
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
-
function formatToolProgress(title, status) {
|
|
107
|
-
const normalizedTitle = hasVisibleText(title) ? title.trim() : null;
|
|
108
|
-
switch (status) {
|
|
109
|
-
case 'completed':
|
|
110
|
-
return normalizedTitle ? `Completed ${normalizedTitle}` : 'Completed tool call';
|
|
111
|
-
case 'failed':
|
|
112
|
-
return normalizedTitle ? `Failed ${normalizedTitle}` : 'Tool call failed';
|
|
113
|
-
case 'pending':
|
|
114
|
-
case 'in_progress':
|
|
115
|
-
case undefined:
|
|
116
|
-
case null:
|
|
117
|
-
return normalizedTitle ? `Running ${normalizedTitle}…` : 'Running tool…';
|
|
118
|
-
default:
|
|
119
|
-
return normalizedTitle ? `${status} ${normalizedTitle}` : status;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function formatPlanProgress(entries) {
|
|
123
|
-
const current = entries.find((entry) => entry.status === 'in_progress') ??
|
|
124
|
-
entries.find((entry) => entry.status === 'pending') ??
|
|
125
|
-
entries[0];
|
|
126
|
-
return hasVisibleText(current?.content) ? `Plan: ${current.content.trim()}` : null;
|
|
127
|
-
}
|
|
128
|
-
class CodexProgressCollector {
|
|
129
|
-
onProgress;
|
|
130
|
-
publicText = '';
|
|
131
|
-
lastPublished = null;
|
|
132
|
-
toolTitles = new Map();
|
|
133
|
-
constructor(onProgress) {
|
|
134
|
-
this.onProgress = onProgress;
|
|
135
|
-
}
|
|
136
|
-
consume(update) {
|
|
137
|
-
switch (update.update.sessionUpdate) {
|
|
138
|
-
case 'agent_message_chunk':
|
|
139
|
-
if (update.update.content.type !== 'text') {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
this.publicText += update.update.content.text;
|
|
143
|
-
this.publish(this.publicText);
|
|
144
|
-
return;
|
|
145
|
-
case 'tool_call':
|
|
146
|
-
this.toolTitles.set(update.update.toolCallId, update.update.title);
|
|
147
|
-
this.publishFallback(formatToolProgress(update.update.title, update.update.status));
|
|
148
|
-
return;
|
|
149
|
-
case 'tool_call_update': {
|
|
150
|
-
const nextTitle = update.update.title ?? this.toolTitles.get(update.update.toolCallId);
|
|
151
|
-
if (hasVisibleText(nextTitle)) {
|
|
152
|
-
this.toolTitles.set(update.update.toolCallId, nextTitle);
|
|
153
|
-
}
|
|
154
|
-
this.publishFallback(formatToolProgress(nextTitle, update.update.status));
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
case 'plan':
|
|
158
|
-
this.publishFallback(formatPlanProgress(update.update.entries.map((entry) => ({
|
|
159
|
-
content: entry.content,
|
|
160
|
-
status: entry.status,
|
|
161
|
-
}))));
|
|
162
|
-
return;
|
|
163
|
-
default:
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
getFinalText() {
|
|
168
|
-
return this.publicText.trim();
|
|
169
|
-
}
|
|
170
|
-
publishFallback(text) {
|
|
171
|
-
if (hasVisibleText(this.publicText)) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
this.publish(text);
|
|
175
|
-
}
|
|
176
|
-
publish(text) {
|
|
177
|
-
if (!this.onProgress || !hasVisibleText(text) || text === this.lastPublished) {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
this.lastPublished = text;
|
|
181
|
-
this.onProgress({ text });
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
106
|
function createDeferredTurn(channelId, preparedTurn, sessionPersistence, options) {
|
|
185
107
|
let settled = false;
|
|
186
108
|
let resolvePromise;
|
|
@@ -273,26 +195,6 @@ function markSessionTainted(error) {
|
|
|
273
195
|
function isSessionTainted(error) {
|
|
274
196
|
return error instanceof Error && SESSION_TAINTED_ERRORS.has(error);
|
|
275
197
|
}
|
|
276
|
-
function createPermissionResponse(params) {
|
|
277
|
-
const options = Array.isArray(params.options) ? params.options : [];
|
|
278
|
-
const preferredKinds = ['allow_once', 'allow_always', 'reject_once', 'reject_always'];
|
|
279
|
-
for (const kind of preferredKinds) {
|
|
280
|
-
const match = options.find((option) => option.kind === kind);
|
|
281
|
-
if (match) {
|
|
282
|
-
return {
|
|
283
|
-
outcome: {
|
|
284
|
-
outcome: 'selected',
|
|
285
|
-
optionId: match.optionId,
|
|
286
|
-
},
|
|
287
|
-
};
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return {
|
|
291
|
-
outcome: {
|
|
292
|
-
outcome: 'cancelled',
|
|
293
|
-
},
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
198
|
function resolveBundledCodexAdapterPath() {
|
|
297
199
|
return require.resolve('@agentclientprotocol/codex-acp');
|
|
298
200
|
}
|
|
@@ -503,7 +405,7 @@ export class CodexCliClient {
|
|
|
503
405
|
const stream = this.runtime.ndJsonStream(output, input);
|
|
504
406
|
const app = this.runtime
|
|
505
407
|
.client({ name: 'borgee-agents-host' })
|
|
506
|
-
.onRequest(this.runtime.methods.client.session.requestPermission, ({ params }) => (
|
|
408
|
+
.onRequest(this.runtime.methods.client.session.requestPermission, ({ params }) => (this.handlePermissionRequest(params)));
|
|
507
409
|
const connection = app.connect(stream);
|
|
508
410
|
this.connection = connection;
|
|
509
411
|
void connection.closed.then(() => {
|
|
@@ -567,6 +469,9 @@ export class CodexCliClient {
|
|
|
567
469
|
state.activeTurn = turn;
|
|
568
470
|
try {
|
|
569
471
|
state.cwd = await this.resolveSessionCwd(turn.preparedTurn.promptContext);
|
|
472
|
+
state.toolPermissionMode = isDiscussionOnlyResolvedWorkspace(turn.preparedTurn.promptContext)
|
|
473
|
+
? 'deny-all'
|
|
474
|
+
: 'default';
|
|
570
475
|
const projectedPromptContext = await this.refreshProjectedPromptContextBestEffort(turn.channelId, turn.preparedTurn.promptContext);
|
|
571
476
|
state.additionalDirectories = this.resolveSessionAdditionalDirectories(projectedPromptContext);
|
|
572
477
|
state.visibilityKey = this.resolveSessionVisibilityKey(projectedPromptContext);
|
|
@@ -734,7 +639,7 @@ export class CodexCliClient {
|
|
|
734
639
|
}
|
|
735
640
|
}
|
|
736
641
|
async resolveSessionCwd(promptContext) {
|
|
737
|
-
return promptContext?.
|
|
642
|
+
return promptContext?.resolvedWorkspace?.rootPath ?? this.runtime.cwd;
|
|
738
643
|
}
|
|
739
644
|
async recycleSessionIfInjectionScopeChanged(channelId, state) {
|
|
740
645
|
const session = state.session;
|
|
@@ -906,7 +811,7 @@ export class CodexCliClient {
|
|
|
906
811
|
const promptFailure = new Promise((_, reject) => {
|
|
907
812
|
void promptPromise.catch((error) => reject(markSessionTainted(error)));
|
|
908
813
|
});
|
|
909
|
-
const collector = new
|
|
814
|
+
const collector = new AcpProgressCollector(options?.onProgress);
|
|
910
815
|
for (;;) {
|
|
911
816
|
let update;
|
|
912
817
|
try {
|
|
@@ -1033,6 +938,25 @@ export class CodexCliClient {
|
|
|
1033
938
|
clearTimeout(state.idleTimer);
|
|
1034
939
|
state.idleTimer = undefined;
|
|
1035
940
|
}
|
|
941
|
+
handlePermissionRequest(params) {
|
|
942
|
+
const state = this.findChannelStateBySessionId(params.sessionId);
|
|
943
|
+
return resolveCopilotPermissionResponse({
|
|
944
|
+
gateEnabled: true,
|
|
945
|
+
policyMode: 'enforce',
|
|
946
|
+
params,
|
|
947
|
+
logger: this.logger,
|
|
948
|
+
channelId: state?.channelId,
|
|
949
|
+
toolPermissionMode: state?.toolPermissionMode ?? 'default',
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
findChannelStateBySessionId(sessionId) {
|
|
953
|
+
for (const state of this.channels.values()) {
|
|
954
|
+
if (state.session?.sessionId === sessionId) {
|
|
955
|
+
return state;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return undefined;
|
|
959
|
+
}
|
|
1036
960
|
reconcileIdleChannelState(channelId, state) {
|
|
1037
961
|
if (this.channels.get(channelId) !== state) {
|
|
1038
962
|
return;
|
|
@@ -2,17 +2,20 @@ import { buildAttentionSummaryLines } from '../../context/attention.js';
|
|
|
2
2
|
import { buildCollaborationCapabilityDeclarationSummaryLines, buildMissedCollaborationDiagnosticSummaryLines, } from '../../context/collaboration-capabilities-diagnostics.js';
|
|
3
3
|
import { buildCollaborationOutcomeSummaryLines } from '../../context/collaboration-outcome.js';
|
|
4
4
|
import { MAIN_SESSION_DELEGATION_LINES } from '../../context/main-session-delegation.js';
|
|
5
|
-
import {
|
|
5
|
+
import { buildResolvedWorkspaceGuidanceLines } from '../../context/resolved-workspace.js';
|
|
6
|
+
import { buildSkillManualLines, buildSkillManualReadLine } from '../../context/skill-manual.js';
|
|
6
7
|
import { buildTaskThreadCollaborationSummaryLines } from '../../context/task-thread-collaboration.js';
|
|
7
8
|
const PROJECT_DOC_MAX_BYTES = 32 * 1024;
|
|
8
9
|
// Every command the CLI carries needs the gateway credential file, so the capability is only
|
|
9
10
|
// worth naming in a workspace that also names one; otherwise the model is handed an invocation
|
|
10
11
|
// template it cannot fill.
|
|
11
12
|
function buildSkillRuntimeLines(context) {
|
|
12
|
-
if (!context?.skillRuntime
|
|
13
|
+
if (!context?.skillRuntime) {
|
|
13
14
|
return [];
|
|
14
15
|
}
|
|
15
|
-
return
|
|
16
|
+
return context.gatewayCredentialPath
|
|
17
|
+
? buildSkillManualLines(context.skillRuntime)
|
|
18
|
+
: [buildSkillManualReadLine(context.skillRuntime)];
|
|
16
19
|
}
|
|
17
20
|
// The credential file is the whole handoff: it carries the gateway's base URL along with the
|
|
18
21
|
// channel id and the token, and the CLI reads all three out of it. Naming the base URL separately
|
|
@@ -24,20 +27,18 @@ function buildGatewayCredentialLines(context) {
|
|
|
24
27
|
return [`Gateway credential file: ${context.gatewayCredentialPath}`];
|
|
25
28
|
}
|
|
26
29
|
export function buildCodexProjectDocument(context) {
|
|
30
|
+
const sessionDelegationLines = context?.skillRuntime ? [] : MAIN_SESSION_DELEGATION_LINES;
|
|
27
31
|
const lines = [
|
|
28
32
|
'# Borgee channel workspace',
|
|
29
33
|
'',
|
|
30
34
|
'This workspace belongs to one Borgee channel session hosted by agents-host.',
|
|
31
35
|
'Keep visible replies concise, do not claim actions you did not perform, and prefer the per-turn prompt when it provides newer turn-local details.',
|
|
32
36
|
'',
|
|
33
|
-
...
|
|
34
|
-
...(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
'That writable task workspace is local to agents-host for the current task thread and does not imply that the target repository has already been checked out there.',
|
|
39
|
-
]
|
|
40
|
-
: []),
|
|
37
|
+
...sessionDelegationLines,
|
|
38
|
+
...(() => {
|
|
39
|
+
const workspaceLines = buildResolvedWorkspaceGuidanceLines(context);
|
|
40
|
+
return workspaceLines.length > 0 ? ['', ...workspaceLines] : [];
|
|
41
|
+
})(),
|
|
41
42
|
...(() => {
|
|
42
43
|
const collaborationOutcomeLines = buildCollaborationOutcomeSummaryLines(context?.collaborationOutcome);
|
|
43
44
|
return collaborationOutcomeLines.length > 0 ? ['', ...collaborationOutcomeLines] : [];
|
|
@@ -103,7 +103,7 @@ export declare class CopilotCliClient {
|
|
|
103
103
|
private closeSession;
|
|
104
104
|
private rejectQueuedTurnsAfterSessionTaint;
|
|
105
105
|
private clearIdleTimer;
|
|
106
|
-
private
|
|
106
|
+
private findChannelStateBySessionId;
|
|
107
107
|
private reconcileIdleChannelState;
|
|
108
108
|
private ensureSessionStoreLoaded;
|
|
109
109
|
private readPersistedSessionId;
|
|
@@ -2,7 +2,9 @@ import { Readable, Writable } from 'node:stream';
|
|
|
2
2
|
import spawn from 'cross-spawn';
|
|
3
3
|
import { PROTOCOL_VERSION, client, methods, ndJsonStream, } from '@agentclientprotocol/sdk';
|
|
4
4
|
import { HostLogger, summarizeChildStderr, summarizeError } from '../../debug.js';
|
|
5
|
+
import { AcpProgressCollector } from '../acp-progress-collector.js';
|
|
5
6
|
import { resolveCopilotPermissionResponse } from '../../policy/copilot-permission.js';
|
|
7
|
+
import { isDiscussionOnlyResolvedWorkspace } from '../../context/resolved-workspace.js';
|
|
6
8
|
import { IDLE_BACKEND_SHUTDOWN_DISABLED_MS, IdleBackendShutdownScheduler, } from '../idle-backend-shutdown.js';
|
|
7
9
|
const SESSION_TAINTED_ERRORS = new WeakSet();
|
|
8
10
|
const DEFAULT_IDLE_SESSION_TTL_MS = 2 * 24 * 60 * 60 * 1000;
|
|
@@ -36,9 +38,6 @@ const DEFAULT_SESSION_CAPABILITIES = {
|
|
|
36
38
|
loadSession: false,
|
|
37
39
|
resumeSession: false,
|
|
38
40
|
};
|
|
39
|
-
function hasVisibleText(value) {
|
|
40
|
-
return typeof value === 'string' && value.trim().length > 0;
|
|
41
|
-
}
|
|
42
41
|
function isAbsoluteHttpUrl(value) {
|
|
43
42
|
return value.startsWith('http://') || value.startsWith('https://');
|
|
44
43
|
}
|
|
@@ -61,84 +60,6 @@ function isSameOrigin(left, right) {
|
|
|
61
60
|
function asImagePart(part) {
|
|
62
61
|
return part.type === 'image' ? part : null;
|
|
63
62
|
}
|
|
64
|
-
function formatToolProgress(title, status) {
|
|
65
|
-
const normalizedTitle = hasVisibleText(title) ? title.trim() : null;
|
|
66
|
-
switch (status) {
|
|
67
|
-
case 'completed':
|
|
68
|
-
return normalizedTitle ? `Completed ${normalizedTitle}` : 'Completed tool call';
|
|
69
|
-
case 'failed':
|
|
70
|
-
return normalizedTitle ? `Failed ${normalizedTitle}` : 'Tool call failed';
|
|
71
|
-
case 'pending':
|
|
72
|
-
case 'in_progress':
|
|
73
|
-
case undefined:
|
|
74
|
-
case null:
|
|
75
|
-
return normalizedTitle ? `Running ${normalizedTitle}…` : 'Running tool…';
|
|
76
|
-
default:
|
|
77
|
-
return normalizedTitle ? `${status} ${normalizedTitle}` : status;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function formatPlanProgress(entries) {
|
|
81
|
-
const current = entries.find((entry) => entry.status === 'in_progress') ??
|
|
82
|
-
entries.find((entry) => entry.status === 'pending') ??
|
|
83
|
-
entries[0];
|
|
84
|
-
return hasVisibleText(current?.content) ? `Plan: ${current.content.trim()}` : null;
|
|
85
|
-
}
|
|
86
|
-
class CopilotProgressCollector {
|
|
87
|
-
onProgress;
|
|
88
|
-
publicText = '';
|
|
89
|
-
lastPublished = null;
|
|
90
|
-
toolTitles = new Map();
|
|
91
|
-
constructor(onProgress) {
|
|
92
|
-
this.onProgress = onProgress;
|
|
93
|
-
}
|
|
94
|
-
consume(update) {
|
|
95
|
-
switch (update.update.sessionUpdate) {
|
|
96
|
-
case 'agent_message_chunk':
|
|
97
|
-
if (update.update.content.type !== 'text') {
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
this.publicText += update.update.content.text;
|
|
101
|
-
this.publish(this.publicText);
|
|
102
|
-
return;
|
|
103
|
-
case 'tool_call':
|
|
104
|
-
this.toolTitles.set(update.update.toolCallId, update.update.title);
|
|
105
|
-
this.publishFallback(formatToolProgress(update.update.title, update.update.status));
|
|
106
|
-
return;
|
|
107
|
-
case 'tool_call_update': {
|
|
108
|
-
const nextTitle = update.update.title ?? this.toolTitles.get(update.update.toolCallId);
|
|
109
|
-
if (hasVisibleText(nextTitle)) {
|
|
110
|
-
this.toolTitles.set(update.update.toolCallId, nextTitle);
|
|
111
|
-
}
|
|
112
|
-
this.publishFallback(formatToolProgress(nextTitle, update.update.status));
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
case 'plan':
|
|
116
|
-
this.publishFallback(formatPlanProgress(update.update.entries.map((entry) => ({
|
|
117
|
-
content: entry.content,
|
|
118
|
-
status: entry.status,
|
|
119
|
-
}))));
|
|
120
|
-
return;
|
|
121
|
-
default:
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
getFinalText() {
|
|
126
|
-
return this.publicText.trim();
|
|
127
|
-
}
|
|
128
|
-
publishFallback(text) {
|
|
129
|
-
if (hasVisibleText(this.publicText)) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
this.publish(text);
|
|
133
|
-
}
|
|
134
|
-
publish(text) {
|
|
135
|
-
if (!this.onProgress || !hasVisibleText(text) || text === this.lastPublished) {
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
this.lastPublished = text;
|
|
139
|
-
this.onProgress({ text });
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
63
|
function createDeferredTurn(channelId, preparedTurn, sessionPersistence, options) {
|
|
143
64
|
let settled = false;
|
|
144
65
|
let resolvePromise;
|
|
@@ -487,6 +408,9 @@ export class CopilotCliClient {
|
|
|
487
408
|
state.activeTurn = turn;
|
|
488
409
|
try {
|
|
489
410
|
state.cwd = await this.resolveSessionCwd(turn.preparedTurn.promptContext);
|
|
411
|
+
state.toolPermissionMode = isDiscussionOnlyResolvedWorkspace(turn.preparedTurn.promptContext)
|
|
412
|
+
? 'deny-all'
|
|
413
|
+
: 'default';
|
|
490
414
|
await this.ensureStarted();
|
|
491
415
|
await this.recycleSessionIfCwdChanged(channelId, state);
|
|
492
416
|
const session = await this.getOrCreateSession(channelId, state);
|
|
@@ -647,7 +571,7 @@ export class CopilotCliClient {
|
|
|
647
571
|
}
|
|
648
572
|
}
|
|
649
573
|
async resolveSessionCwd(promptContext) {
|
|
650
|
-
return promptContext?.
|
|
574
|
+
return promptContext?.resolvedWorkspace?.rootPath ?? this.runtime.cwd;
|
|
651
575
|
}
|
|
652
576
|
async buildPromptInput(turn) {
|
|
653
577
|
const imageParts = turn.incomingParts.map(asImagePart).filter((part) => part !== null);
|
|
@@ -707,7 +631,7 @@ export class CopilotCliClient {
|
|
|
707
631
|
const promptFailure = new Promise((_, reject) => {
|
|
708
632
|
void promptPromise.catch((error) => reject(markSessionTainted(error)));
|
|
709
633
|
});
|
|
710
|
-
const collector = new
|
|
634
|
+
const collector = new AcpProgressCollector(options?.onProgress);
|
|
711
635
|
for (;;) {
|
|
712
636
|
let update;
|
|
713
637
|
try {
|
|
@@ -746,6 +670,7 @@ export class CopilotCliClient {
|
|
|
746
670
|
return Promise.race([promise, this.fatalPromise]);
|
|
747
671
|
}
|
|
748
672
|
handlePermissionRequest(params) {
|
|
673
|
+
const state = this.findChannelStateBySessionId(params.sessionId);
|
|
749
674
|
return resolveCopilotPermissionResponse({
|
|
750
675
|
gateEnabled: this.permissionPolicy.gateEnabled ?? false,
|
|
751
676
|
policyMode: this.permissionPolicy.policyMode ?? 'audit-only',
|
|
@@ -753,7 +678,8 @@ export class CopilotCliClient {
|
|
|
753
678
|
logger: this.logger,
|
|
754
679
|
auditSink: this.permissionPolicy.auditSink,
|
|
755
680
|
agentId: this.resolveSessionStoreAgentId()?.trim() || undefined,
|
|
756
|
-
channelId:
|
|
681
|
+
channelId: state?.channelId,
|
|
682
|
+
toolPermissionMode: state?.toolPermissionMode ?? 'default',
|
|
757
683
|
});
|
|
758
684
|
}
|
|
759
685
|
failAll(error) {
|
|
@@ -841,10 +767,10 @@ export class CopilotCliClient {
|
|
|
841
767
|
clearTimeout(state.idleTimer);
|
|
842
768
|
state.idleTimer = undefined;
|
|
843
769
|
}
|
|
844
|
-
|
|
770
|
+
findChannelStateBySessionId(sessionId) {
|
|
845
771
|
for (const state of this.channels.values()) {
|
|
846
772
|
if (state.session?.sessionId === sessionId) {
|
|
847
|
-
return state
|
|
773
|
+
return state;
|
|
848
774
|
}
|
|
849
775
|
}
|
|
850
776
|
return undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DebugLogger } from '../debug.js';
|
|
2
2
|
import type { ProviderRuntimeConfig } from '../types.js';
|
|
3
|
+
import type { ChatControlPlane } from '../chat/chat-control-plane.js';
|
|
3
4
|
import { type ProviderAdapter } from './provider-adapter.js';
|
|
4
5
|
import type { LocalhostGatewayContextPublisher } from '../context/injection.js';
|
|
5
6
|
import type { AuthorizationAuditSinkLike } from '../policy/authorization-audit.js';
|
|
@@ -7,6 +8,7 @@ interface CreateProviderOptions {
|
|
|
7
8
|
compatibilityGates?: ReadonlySet<string>;
|
|
8
9
|
localhostGateway?: LocalhostGatewayContextPublisher;
|
|
9
10
|
authorizationAuditSink?: AuthorizationAuditSinkLike;
|
|
11
|
+
controlPlane?: Pick<ChatControlPlane, 'getTask' | 'listChannels' | 'listTasks' | 'listUsers'>;
|
|
10
12
|
}
|
|
11
13
|
export declare function createProvider(config: ProviderRuntimeConfig, debugLogger?: DebugLogger, options?: CreateProviderOptions): ProviderAdapter;
|
|
12
14
|
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { FileChannelContextStore } from '../context/injection.js';
|
|
2
|
+
import { ServerProjectionStrategyResolver } from '../context/projection-strategy.js';
|
|
2
3
|
import { createProviderConnectionsSessionStore } from '../connections-state-store.js';
|
|
3
4
|
import { ProviderTurnPreparer } from '../context/turn-preparation.js';
|
|
4
|
-
import { CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE, CONTEXT_INJECTION_COMPATIBILITY_GATE, CODEX_PROVIDER_COMPATIBILITY_GATE, COPILOT_PROVIDER_V2_COMPATIBILITY_GATE, INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV, LOCALHOST_GATEWAY_COMPATIBILITY_GATE, parseInternalProviderImplementationOverrides, POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE, resolveInternalPolicyMode, resolveInternalCompatibilityGates, SKILL_RUNTIME_COMPATIBILITY_GATE, } from '../compatibility-gates.js';
|
|
5
|
+
import { CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE, CONTEXT_INJECTION_COMPATIBILITY_GATE, CODEX_PROVIDER_COMPATIBILITY_GATE, COPILOT_PROVIDER_V2_COMPATIBILITY_GATE, INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV, LOCALHOST_GATEWAY_COMPATIBILITY_GATE, parseInternalProviderImplementationOverrides, POLICY_AUDIT_ENFORCEMENT_COMPATIBILITY_GATE, resolveInternalPolicyMode, resolveInternalCompatibilityGates, resolveInternalProjectionStrategy, SKILL_RUNTIME_COMPATIBILITY_GATE, } from '../compatibility-gates.js';
|
|
5
6
|
import { resolveIdleBackendShutdownMs } from './idle-backend-shutdown.js';
|
|
6
7
|
import { ClaudeCliClient } from './claude/cli-client.js';
|
|
7
8
|
import { ClaudeProviderAdapter } from './claude/adapter.js';
|
|
@@ -52,7 +53,6 @@ class CliBackedProviderV2 {
|
|
|
52
53
|
}
|
|
53
54
|
class CopilotProviderV2 extends CliBackedProviderV2 {
|
|
54
55
|
}
|
|
55
|
-
const TASK_WORKSPACE_ROOT_DIR_ENV = 'AGENTS_HOST_INTERNAL_TASK_WORKSPACE_ROOT_DIR';
|
|
56
56
|
const PROVIDER_V2_COMPATIBILITY_GATES = {
|
|
57
57
|
copilot: COPILOT_PROVIDER_V2_COMPATIBILITY_GATE,
|
|
58
58
|
};
|
|
@@ -131,13 +131,31 @@ export function createProvider(config, debugLogger, options = {}) {
|
|
|
131
131
|
const channelContextStore = contextInjectionGateEnabled
|
|
132
132
|
? new FileChannelContextStore(config.stateRootDir, {
|
|
133
133
|
skillRuntimeEnabled: skillRuntimeGateEnabled,
|
|
134
|
-
taskWorkspaceRootDir: process.env[TASK_WORKSPACE_ROOT_DIR_ENV],
|
|
135
134
|
localhostGateway: skillRuntimeGateEnabled && localhostGatewayGateEnabled
|
|
136
135
|
? options.localhostGateway
|
|
137
136
|
: undefined,
|
|
137
|
+
taskReader: options.controlPlane,
|
|
138
|
+
allowCrossAgentIndependentWorkspaceHandoff: config.allowCrossAgentIndependentWorkspaceHandoff,
|
|
139
|
+
resolveStableAgentId: config.resolveStableAgentId,
|
|
138
140
|
})
|
|
139
141
|
: undefined;
|
|
140
|
-
const
|
|
142
|
+
const resolveInternalProjection = () => resolveInternalProjectionStrategy();
|
|
143
|
+
const projectionStrategyResolver = new ServerProjectionStrategyResolver({
|
|
144
|
+
baseUrl: config.borgeeBaseUrl,
|
|
145
|
+
agentApiKey: config.agentApiKey,
|
|
146
|
+
resolveStableAgentId: config.resolveStableAgentId,
|
|
147
|
+
fallback: resolveInternalProjection,
|
|
148
|
+
logger: debugLogger,
|
|
149
|
+
taskReader: options.controlPlane,
|
|
150
|
+
});
|
|
151
|
+
const turnPreparer = new ProviderTurnPreparer(channelContextStore, debugLogger, {
|
|
152
|
+
resolveProjectionStrategy: async (input) => {
|
|
153
|
+
if (input.provider !== 'claude') {
|
|
154
|
+
return resolveInternalProjection();
|
|
155
|
+
}
|
|
156
|
+
return projectionStrategyResolver.resolve(input.channelId);
|
|
157
|
+
},
|
|
158
|
+
});
|
|
141
159
|
switch (config.provider) {
|
|
142
160
|
case 'claude': {
|
|
143
161
|
return createClaudeProvider(config, debugLogger, connectionsStateGateEnabled, turnPreparer, idleBackendShutdownMs);
|
package/dist/state-paths.d.ts
CHANGED
|
@@ -20,11 +20,11 @@ export declare function resolveManagedDaemonLogPath(rootPath: string): string;
|
|
|
20
20
|
export declare function resolveManagedRuntimeSettingsPath(rootPath: string): string;
|
|
21
21
|
export declare function resolveManagedBootstrapLockPath(rootPath: string): string;
|
|
22
22
|
export declare function resolveLocalConfigAgentStateRoot(rootPath: string, agentKey: string): string;
|
|
23
|
-
export declare function resolveAgentCursorPath(stateRootDir: string, agentId: string): string;
|
|
24
23
|
export declare function resolveSharedProtocolKickoffDecisionPath(stateRootDir: string, channelId: string, anchorMessageId: string): string;
|
|
25
24
|
export declare function resolveSharedProtocolStatusPath(stateRootDir: string, channelId: string, anchorMessageId: string): string;
|
|
26
25
|
export declare function resolveConnectionsStatePath(stateRootDir: string): string;
|
|
27
26
|
export declare function resolveAttentionStatePath(stateRootDir: string, channelId: string): string;
|
|
27
|
+
export declare function resolveCompactionStatePath(stateRootDir: string, channelId: string): string;
|
|
28
28
|
export declare function resolveAuthorizationAuditPath(stateRootDir: string): string;
|
|
29
29
|
export declare function resolvePreviousAuthorizationAuditPath(stateRootDir: string): string;
|
|
30
30
|
export declare function resolveClaudeSessionMapPath(stateRootDir: string, agentId: string): string;
|
package/dist/state-paths.js
CHANGED
|
@@ -129,9 +129,6 @@ export function resolveManagedBootstrapLockPath(rootPath) {
|
|
|
129
129
|
export function resolveLocalConfigAgentStateRoot(rootPath, agentKey) {
|
|
130
130
|
return join(resolveManagedStateRoot(rootPath), `${sanitizeStateRootLabel(agentKey)}-${hashStateRootKey(agentKey)}`);
|
|
131
131
|
}
|
|
132
|
-
export function resolveAgentCursorPath(stateRootDir, agentId) {
|
|
133
|
-
return join(stateRootDir, `bpp-cursor-${encodeSegment(agentId)}.json`);
|
|
134
|
-
}
|
|
135
132
|
export function resolveSharedProtocolKickoffDecisionPath(stateRootDir, channelId, anchorMessageId) {
|
|
136
133
|
return join(dirname(resolve(stateRootDir)), 'protocol-kickoff-decisions', `${encodeSegment(channelId)}--${encodeSegment(anchorMessageId)}.json`);
|
|
137
134
|
}
|
|
@@ -144,6 +141,9 @@ export function resolveConnectionsStatePath(stateRootDir) {
|
|
|
144
141
|
export function resolveAttentionStatePath(stateRootDir, channelId) {
|
|
145
142
|
return join(stateRootDir, 'attention-state', `${encodeSegment(channelId)}.json`);
|
|
146
143
|
}
|
|
144
|
+
export function resolveCompactionStatePath(stateRootDir, channelId) {
|
|
145
|
+
return join(stateRootDir, 'compaction-state', `${encodeSegment(channelId)}.json`);
|
|
146
|
+
}
|
|
147
147
|
export function resolveAuthorizationAuditPath(stateRootDir) {
|
|
148
148
|
return join(stateRootDir, 'authorization-audit.jsonl');
|
|
149
149
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ChatControlPlane } from './chat/chat-control-plane.js';
|
|
2
2
|
import type { Task } from './types.js';
|
|
3
|
+
type TaskThreadResolutionControlPlane = Pick<ChatControlPlane, 'getTask' | 'listChannels' | 'listTasks'>;
|
|
3
4
|
interface WaitForTaskForThreadOptions {
|
|
4
5
|
preferredTaskId?: string;
|
|
5
6
|
attempts?: number;
|
|
6
7
|
delayMs?: number;
|
|
7
8
|
}
|
|
8
|
-
export declare function findTaskForThread(controlPlane:
|
|
9
|
-
export declare function waitForTaskForThread(controlPlane:
|
|
9
|
+
export declare function findTaskForThread(controlPlane: TaskThreadResolutionControlPlane, threadId: string, preferredTaskId?: string): Promise<Task | null>;
|
|
10
|
+
export declare function waitForTaskForThread(controlPlane: TaskThreadResolutionControlPlane, threadId: string, options?: WaitForTaskForThreadOptions): Promise<Task | null>;
|
|
10
11
|
export {};
|