@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
|
@@ -10,6 +10,7 @@ export interface CopilotPermissionPolicyContext {
|
|
|
10
10
|
auditSink?: AuthorizationAuditSinkLike;
|
|
11
11
|
agentId?: string;
|
|
12
12
|
channelId?: string;
|
|
13
|
+
toolPermissionMode?: 'default' | 'deny-all';
|
|
13
14
|
}
|
|
14
15
|
export declare function resolveCopilotPermissionResponse(context: CopilotPermissionPolicyContext): RequestPermissionResponse;
|
|
15
16
|
export declare function createLegacyMissingAllowOptionError(): Error;
|
|
@@ -84,6 +84,24 @@ function appendAuditRecord(context, effectiveDecision, reason, policyDecision) {
|
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
86
|
export function resolveCopilotPermissionResponse(context) {
|
|
87
|
+
if (context.toolPermissionMode === 'deny-all') {
|
|
88
|
+
const rejectOption = resolveRejectOption(context.params.options);
|
|
89
|
+
const deniedDecision = rejectOption
|
|
90
|
+
? {
|
|
91
|
+
outcome: 'selected',
|
|
92
|
+
optionId: rejectOption.optionId,
|
|
93
|
+
optionKind: rejectOption.kind,
|
|
94
|
+
reason: 'discussion-only-task-thread',
|
|
95
|
+
toolKind: normalizeToolKind(context.params.toolCall.kind),
|
|
96
|
+
}
|
|
97
|
+
: {
|
|
98
|
+
outcome: 'cancelled',
|
|
99
|
+
reason: 'discussion-only-task-thread',
|
|
100
|
+
toolKind: normalizeToolKind(context.params.toolCall.kind),
|
|
101
|
+
};
|
|
102
|
+
appendAuditRecord(context, deniedDecision, deniedDecision.reason, deniedDecision);
|
|
103
|
+
return decisionToResponse(deniedDecision);
|
|
104
|
+
}
|
|
87
105
|
if (!context.gateEnabled) {
|
|
88
106
|
const legacyOption = legacySelectPermissionOption(context.params.options);
|
|
89
107
|
return {
|
|
@@ -33,7 +33,7 @@ function decodePathSegment(segment) {
|
|
|
33
33
|
export function matchChannelRoute(pathname, allowCollaborationRoutes = false) {
|
|
34
34
|
const resources = allowCollaborationRoutes
|
|
35
35
|
? '(bootstrap|me|history|draft|users|messages|tasks|current-task)'
|
|
36
|
-
: '(bootstrap|me|history|tasks|current-task)';
|
|
36
|
+
: '(bootstrap|me|history|users|tasks|current-task)';
|
|
37
37
|
const match = new RegExp(`^/v1/channels/([^/]+)/${resources}$`).exec(pathname);
|
|
38
38
|
if (!match) {
|
|
39
39
|
return null;
|
|
@@ -112,7 +112,7 @@ function allowedMethodsForRoute(route, collaborationRoutesEnabled) {
|
|
|
112
112
|
export function evaluateGatewayAuthorization(input) {
|
|
113
113
|
const url = new URL(input.request.url ?? '/', input.baseUrl);
|
|
114
114
|
const hiddenCollaborationRoute = !input.allowCollaborationRoutes
|
|
115
|
-
&& ['draft', '
|
|
115
|
+
&& ['draft', 'messages'].includes(matchChannelRoute(url.pathname, true)?.resource ?? '');
|
|
116
116
|
if (hasVisibleHeader(input.request.headers.origin)) {
|
|
117
117
|
return {
|
|
118
118
|
reason: 'browser-origin-not-allowed',
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AgentActivity } from './plugin-sdk.js';
|
|
2
|
+
import type { ProviderProgressUpdate } from './types.js';
|
|
3
|
+
/** Everything a provider reports. The turn boundary is the reporter's own and never arrives here. */
|
|
4
|
+
export type ReportedActivity = Exclude<AgentActivity, {
|
|
5
|
+
shape: 'turn';
|
|
6
|
+
}>;
|
|
7
|
+
/**
|
|
8
|
+
* Restates one progress update in the rail's own vocabulary.
|
|
9
|
+
*
|
|
10
|
+
* This is the one part of reporting that belongs to this host rather than to the
|
|
11
|
+
* SDK: `ProviderProgressUpdate` is the seam the provider adapters speak, and
|
|
12
|
+
* nothing outside this package has it. What happens to a report afterwards —
|
|
13
|
+
* how often it may travel, what supersedes it, where a turn begins and ends —
|
|
14
|
+
* is the rail's and lives with the client.
|
|
15
|
+
*/
|
|
16
|
+
export declare function toReportedActivity(update: ProviderProgressUpdate): ReportedActivity | null;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Restates one progress update in the rail's own vocabulary.
|
|
3
|
+
*
|
|
4
|
+
* This is the one part of reporting that belongs to this host rather than to the
|
|
5
|
+
* SDK: `ProviderProgressUpdate` is the seam the provider adapters speak, and
|
|
6
|
+
* nothing outside this package has it. What happens to a report afterwards —
|
|
7
|
+
* how often it may travel, what supersedes it, where a turn begins and ends —
|
|
8
|
+
* is the rail's and lives with the client.
|
|
9
|
+
*/
|
|
10
|
+
export function toReportedActivity(update) {
|
|
11
|
+
switch (update.type) {
|
|
12
|
+
case 'text':
|
|
13
|
+
return { shape: 'output', stream: update.stream, text: update.text };
|
|
14
|
+
case 'plan':
|
|
15
|
+
return {
|
|
16
|
+
shape: 'plan',
|
|
17
|
+
entries: update.items.map((item) => ({ label: item.label, status: item.status })),
|
|
18
|
+
};
|
|
19
|
+
case 'activity':
|
|
20
|
+
return { shape: 'activity', ...update.activity };
|
|
21
|
+
case 'compaction':
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ProjectionStrategy } from './types.js';
|
|
2
|
+
export declare const DEFAULT_PROJECTION_STRATEGY: ProjectionStrategy;
|
|
3
|
+
export declare function normalizeProjectionStrategy(value: string | undefined | null): ProjectionStrategy | undefined;
|
|
4
|
+
export declare function isProjectionStrategy(value: string | undefined | null): value is ProjectionStrategy;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const DEFAULT_PROJECTION_STRATEGY = 'turn-thin';
|
|
2
|
+
export function normalizeProjectionStrategy(value) {
|
|
3
|
+
switch (value?.trim()) {
|
|
4
|
+
case 'session-brief':
|
|
5
|
+
case 'session-augmented':
|
|
6
|
+
case 'sessionized':
|
|
7
|
+
return 'session-brief';
|
|
8
|
+
case 'turn-full':
|
|
9
|
+
case 'inline-full':
|
|
10
|
+
case 'legacy':
|
|
11
|
+
return 'turn-full';
|
|
12
|
+
case 'message-only':
|
|
13
|
+
case 'zero-turn':
|
|
14
|
+
return 'message-only';
|
|
15
|
+
case 'turn-thin':
|
|
16
|
+
case 'grounded-thin':
|
|
17
|
+
case 'minimal-turn':
|
|
18
|
+
return 'turn-thin';
|
|
19
|
+
case 'projected-brief':
|
|
20
|
+
case 'file-brief':
|
|
21
|
+
return 'file-brief';
|
|
22
|
+
default:
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function isProjectionStrategy(value) {
|
|
27
|
+
return normalizeProjectionStrategy(value) !== undefined;
|
|
28
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ActiveSession } from '@agentclientprotocol/sdk';
|
|
2
|
+
import type { ProviderGenerateOptions } from '../types.js';
|
|
3
|
+
type AcpSessionUpdate = Awaited<ReturnType<ActiveSession['nextUpdate']>>;
|
|
4
|
+
export type AcpProgressNotification = Extract<AcpSessionUpdate, {
|
|
5
|
+
kind: 'session_update';
|
|
6
|
+
}>;
|
|
7
|
+
type AcpToolCall = Extract<AcpProgressNotification['update'], {
|
|
8
|
+
sessionUpdate: 'tool_call';
|
|
9
|
+
}>;
|
|
10
|
+
type AcpToolCallUpdate = Extract<AcpProgressNotification['update'], {
|
|
11
|
+
sessionUpdate: 'tool_call_update';
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* What a provider says about a tool call beside what the protocol says. Every
|
|
15
|
+
* field here is one the protocol has no place for, which is why each provider
|
|
16
|
+
* hangs it under its own namespace and why reading it is the one thing about
|
|
17
|
+
* this stream that cannot be written once for all three.
|
|
18
|
+
*/
|
|
19
|
+
export interface AcpActivityMetadata {
|
|
20
|
+
description?: string;
|
|
21
|
+
parentId?: string;
|
|
22
|
+
subagent?: boolean;
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
25
|
+
export type AcpActivityMetadataReader = (meta: AcpToolCall['_meta'] | AcpToolCallUpdate['_meta']) => AcpActivityMetadata;
|
|
26
|
+
/**
|
|
27
|
+
* Turns one ACP session's notifications into progress updates and keeps the
|
|
28
|
+
* turn's answer text so the caller can resolve the reply once the turn stops.
|
|
29
|
+
* The three providers speak the same protocol version and their streams map
|
|
30
|
+
* identically; what differs between them sits in provider metadata, read here
|
|
31
|
+
* through one injected function rather than through a per-provider branch or a
|
|
32
|
+
* per-provider copy of this class.
|
|
33
|
+
*/
|
|
34
|
+
export declare class AcpProgressCollector {
|
|
35
|
+
private readonly onProgress?;
|
|
36
|
+
private readonly readMetadata;
|
|
37
|
+
private answerText;
|
|
38
|
+
private reasoningText;
|
|
39
|
+
constructor(onProgress?: ProviderGenerateOptions['onProgress'], readMetadata?: AcpActivityMetadataReader);
|
|
40
|
+
consume(notification: AcpProgressNotification): void;
|
|
41
|
+
getFinalText(): string;
|
|
42
|
+
private publishStream;
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
const ACTIVITY_KINDS = new Set([
|
|
2
|
+
'read',
|
|
3
|
+
'edit',
|
|
4
|
+
'delete',
|
|
5
|
+
'move',
|
|
6
|
+
'search',
|
|
7
|
+
'execute',
|
|
8
|
+
'think',
|
|
9
|
+
'fetch',
|
|
10
|
+
'switch_mode',
|
|
11
|
+
'other',
|
|
12
|
+
]);
|
|
13
|
+
/** The protocol's four. Ours adds `waiting`, which no agent can report. */
|
|
14
|
+
const ACTIVITY_STATUSES = new Set([
|
|
15
|
+
'pending',
|
|
16
|
+
'in_progress',
|
|
17
|
+
'completed',
|
|
18
|
+
'failed',
|
|
19
|
+
]);
|
|
20
|
+
/** For a provider that hangs nothing beside the protocol, or whose namespace nobody has read yet. */
|
|
21
|
+
const noProviderMetadata = () => ({});
|
|
22
|
+
function hasVisibleText(value) {
|
|
23
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
24
|
+
}
|
|
25
|
+
/** An unknown kind is not an error: the enum is closed in this protocol version and open in the next. */
|
|
26
|
+
function toActivityKind(kind) {
|
|
27
|
+
return ACTIVITY_KINDS.has(kind ?? '') ? kind : 'other';
|
|
28
|
+
}
|
|
29
|
+
/** A status outside the vocabulary leaves the entry where it stands rather than inventing a transition. */
|
|
30
|
+
function toActivityStatus(status) {
|
|
31
|
+
return ACTIVITY_STATUSES.has(status ?? '') ? status : undefined;
|
|
32
|
+
}
|
|
33
|
+
function toActivityPaths(locations) {
|
|
34
|
+
return locations ? locations.map((location) => location.path) : undefined;
|
|
35
|
+
}
|
|
36
|
+
/** Only the id and the title are required on the wire, so the rest of a new entry defaults here. */
|
|
37
|
+
function toCreatedActivity(update, metadata) {
|
|
38
|
+
const paths = toActivityPaths(update.locations);
|
|
39
|
+
return {
|
|
40
|
+
id: update.toolCallId,
|
|
41
|
+
label: update.title,
|
|
42
|
+
...metadata,
|
|
43
|
+
kind: toActivityKind(update.kind),
|
|
44
|
+
status: toActivityStatus(update.status) ?? 'pending',
|
|
45
|
+
...(paths ? { paths } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function toPatchedActivity(update, metadata) {
|
|
49
|
+
const paths = toActivityPaths(update.locations);
|
|
50
|
+
const status = toActivityStatus(update.status);
|
|
51
|
+
return {
|
|
52
|
+
id: update.toolCallId,
|
|
53
|
+
...(typeof update.title === 'string' ? { label: update.title } : {}),
|
|
54
|
+
...metadata,
|
|
55
|
+
...(update.kind == null ? {} : { kind: toActivityKind(update.kind) }),
|
|
56
|
+
...(status ? { status } : {}),
|
|
57
|
+
...(paths ? { paths } : {}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function toPlanItem(entry) {
|
|
61
|
+
return { label: entry.content, status: entry.status };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Turns one ACP session's notifications into progress updates and keeps the
|
|
65
|
+
* turn's answer text so the caller can resolve the reply once the turn stops.
|
|
66
|
+
* The three providers speak the same protocol version and their streams map
|
|
67
|
+
* identically; what differs between them sits in provider metadata, read here
|
|
68
|
+
* through one injected function rather than through a per-provider branch or a
|
|
69
|
+
* per-provider copy of this class.
|
|
70
|
+
*/
|
|
71
|
+
export class AcpProgressCollector {
|
|
72
|
+
onProgress;
|
|
73
|
+
readMetadata;
|
|
74
|
+
answerText = '';
|
|
75
|
+
reasoningText = '';
|
|
76
|
+
constructor(onProgress, readMetadata = noProviderMetadata) {
|
|
77
|
+
this.onProgress = onProgress;
|
|
78
|
+
this.readMetadata = readMetadata;
|
|
79
|
+
}
|
|
80
|
+
consume(notification) {
|
|
81
|
+
const update = notification.update;
|
|
82
|
+
switch (update.sessionUpdate) {
|
|
83
|
+
case 'agent_message_chunk':
|
|
84
|
+
if (update.content.type !== 'text') {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.answerText += update.content.text;
|
|
88
|
+
this.publishStream('answer', this.answerText, update.messageId);
|
|
89
|
+
return;
|
|
90
|
+
case 'agent_thought_chunk':
|
|
91
|
+
if (update.content.type !== 'text') {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
this.reasoningText += update.content.text;
|
|
95
|
+
this.publishStream('reasoning', this.reasoningText, update.messageId);
|
|
96
|
+
return;
|
|
97
|
+
case 'tool_call':
|
|
98
|
+
this.onProgress?.({
|
|
99
|
+
type: 'activity',
|
|
100
|
+
activity: toCreatedActivity(update, this.readMetadata(update._meta)),
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
case 'tool_call_update':
|
|
104
|
+
this.onProgress?.({
|
|
105
|
+
type: 'activity',
|
|
106
|
+
activity: toPatchedActivity(update, this.readMetadata(update._meta)),
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
case 'plan':
|
|
110
|
+
this.onProgress?.({ type: 'plan', items: update.entries.map(toPlanItem) });
|
|
111
|
+
return;
|
|
112
|
+
default:
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
getFinalText() {
|
|
117
|
+
return this.answerText.trim();
|
|
118
|
+
}
|
|
119
|
+
publishStream(stream, text, messageId) {
|
|
120
|
+
if (!hasVisibleText(text)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.onProgress?.({
|
|
124
|
+
type: 'text',
|
|
125
|
+
stream,
|
|
126
|
+
text,
|
|
127
|
+
...(typeof messageId === 'string' ? { messageId } : {}),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type { ProviderGenerateOptions, ProviderReply } from '../types.js';
|
|
1
|
+
import type { ProviderGenerateOptions, ProviderProgressUpdate, ProviderReply } from '../types.js';
|
|
2
2
|
export declare const HOST_CONTROL_PREFIX = "[[BORGEE_CONTROL]] ";
|
|
3
3
|
export declare const AWAITING_USER_CONTROL_PREFIX = "[[BORGEE_CONTROL]] ";
|
|
4
4
|
export declare function parseProviderReply(text: string): ProviderReply;
|
|
5
5
|
export declare function sanitizeAwaitingUserProgressText(text: string): string;
|
|
6
6
|
export declare class AwaitingUserProgressSanitizer {
|
|
7
7
|
private readonly onProgress?;
|
|
8
|
-
private lastPublished;
|
|
9
8
|
constructor(onProgress?: ProviderGenerateOptions['onProgress']);
|
|
10
|
-
|
|
9
|
+
publishStructured(update: ProviderProgressUpdate): void;
|
|
11
10
|
}
|
|
12
11
|
export declare function createAwaitingUserProgressHandler(onProgress?: ProviderGenerateOptions['onProgress']): ProviderGenerateOptions['onProgress'] | undefined;
|
|
@@ -165,20 +165,18 @@ export function sanitizeAwaitingUserProgressText(text) {
|
|
|
165
165
|
}
|
|
166
166
|
export class AwaitingUserProgressSanitizer {
|
|
167
167
|
onProgress;
|
|
168
|
-
lastPublished = null;
|
|
169
168
|
constructor(onProgress) {
|
|
170
169
|
this.onProgress = onProgress;
|
|
171
170
|
}
|
|
172
|
-
|
|
171
|
+
publishStructured(update) {
|
|
173
172
|
if (!this.onProgress) {
|
|
174
173
|
return;
|
|
175
174
|
}
|
|
176
|
-
|
|
177
|
-
|
|
175
|
+
if (update.type === 'text') {
|
|
176
|
+
this.onProgress({ ...update, text: sanitizeAwaitingUserProgressText(update.text) });
|
|
178
177
|
return;
|
|
179
178
|
}
|
|
180
|
-
this.
|
|
181
|
-
this.onProgress({ text: sanitizedText });
|
|
179
|
+
this.onProgress(update);
|
|
182
180
|
}
|
|
183
181
|
}
|
|
184
182
|
export function createAwaitingUserProgressHandler(onProgress) {
|
|
@@ -187,6 +185,6 @@ export function createAwaitingUserProgressHandler(onProgress) {
|
|
|
187
185
|
}
|
|
188
186
|
const sanitizer = new AwaitingUserProgressSanitizer(onProgress);
|
|
189
187
|
return (update) => {
|
|
190
|
-
sanitizer.
|
|
188
|
+
sanitizer.publishStructured(update);
|
|
191
189
|
};
|
|
192
190
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AcpActivityMetadataReader } from '../acp-progress-collector.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reads what Claude says about a tool call beside what the protocol says.
|
|
4
|
+
*
|
|
5
|
+
* The description is the phrasing the adapter would show a user, which for a
|
|
6
|
+
* shell tool is not the title: the protocol reserves the title for the raw
|
|
7
|
+
* command line so a client can render a shell preview.
|
|
8
|
+
*
|
|
9
|
+
* The container flag is only ever set, never cleared, so it is read as a fact
|
|
10
|
+
* about the call rather than as a value that could arrive false. It is stamped
|
|
11
|
+
* on the call that spawns a sub-agent; the calls that sub-agent then makes point
|
|
12
|
+
* back at it through the parent id.
|
|
13
|
+
*/
|
|
14
|
+
export declare const readClaudeActivityMetadata: AcpActivityMetadataReader;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where Claude's adapter hangs its own account of a tool call. The protocol
|
|
3
|
+
* fields carry what the protocol defines; everything the adapter knows in
|
|
4
|
+
* addition — the phrasing it would show a user, the call that spawned this one,
|
|
5
|
+
* why a call never ran — lives here under its own key.
|
|
6
|
+
*/
|
|
7
|
+
const NAMESPACE = 'claudeCode';
|
|
8
|
+
function readString(source, key) {
|
|
9
|
+
const value = source[key];
|
|
10
|
+
return typeof value === 'string' && value.trim().length > 0 ? value : undefined;
|
|
11
|
+
}
|
|
12
|
+
function readObject(value) {
|
|
13
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
14
|
+
? value
|
|
15
|
+
: undefined;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Why a call ended as it did, from the two places the adapter reports it.
|
|
19
|
+
*
|
|
20
|
+
* A permission denial and an ordinary failure are different shapes, not two
|
|
21
|
+
* spellings of one: a denial is a nested object naming the rule or the mode that
|
|
22
|
+
* refused, and everything else is a flat token drawn from an open set the
|
|
23
|
+
* adapter itself declines to validate. They arrive on different upstream events
|
|
24
|
+
* and rarely meet, so the rule is fixed here rather than left to whichever is
|
|
25
|
+
* read first: the denial wins, because it accounts for the same refusal at a
|
|
26
|
+
* finer grain than the token, which collapses a human's rejection and a rule's
|
|
27
|
+
* into one value on the permission wire this host answers over.
|
|
28
|
+
*
|
|
29
|
+
* `toolResponse` is a general slot the adapter also fills with a running call's
|
|
30
|
+
* elapsed time and with hook output, so a denial is recognised by the field that
|
|
31
|
+
* only a denial has, never by the slot being occupied.
|
|
32
|
+
*/
|
|
33
|
+
function readReason(provider) {
|
|
34
|
+
const response = readObject(provider.toolResponse);
|
|
35
|
+
if (response && readString(response, 'decisionReasonType')) {
|
|
36
|
+
return (readString(response, 'decisionReason')
|
|
37
|
+
?? readString(response, 'message')
|
|
38
|
+
?? readString(response, 'decisionReasonType'));
|
|
39
|
+
}
|
|
40
|
+
const nonExecutionKind = readString(provider, 'nonExecutionKind');
|
|
41
|
+
if (!nonExecutionKind) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
const feedback = readString(provider, 'userFeedback');
|
|
45
|
+
return feedback ? `${nonExecutionKind}: ${feedback}` : nonExecutionKind;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Reads what Claude says about a tool call beside what the protocol says.
|
|
49
|
+
*
|
|
50
|
+
* The description is the phrasing the adapter would show a user, which for a
|
|
51
|
+
* shell tool is not the title: the protocol reserves the title for the raw
|
|
52
|
+
* command line so a client can render a shell preview.
|
|
53
|
+
*
|
|
54
|
+
* The container flag is only ever set, never cleared, so it is read as a fact
|
|
55
|
+
* about the call rather than as a value that could arrive false. It is stamped
|
|
56
|
+
* on the call that spawns a sub-agent; the calls that sub-agent then makes point
|
|
57
|
+
* back at it through the parent id.
|
|
58
|
+
*/
|
|
59
|
+
export const readClaudeActivityMetadata = (meta) => {
|
|
60
|
+
const provider = readObject(meta?.[NAMESPACE]);
|
|
61
|
+
if (!provider) {
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
const metadata = {};
|
|
65
|
+
const description = readString(provider, 'title');
|
|
66
|
+
if (description) {
|
|
67
|
+
metadata.description = description;
|
|
68
|
+
}
|
|
69
|
+
const parentId = readString(provider, 'parentToolUseId');
|
|
70
|
+
if (parentId) {
|
|
71
|
+
metadata.parentId = parentId;
|
|
72
|
+
}
|
|
73
|
+
if (provider.subagent === true) {
|
|
74
|
+
metadata.subagent = true;
|
|
75
|
+
}
|
|
76
|
+
const reason = readReason(provider);
|
|
77
|
+
if (reason) {
|
|
78
|
+
metadata.reason = reason;
|
|
79
|
+
}
|
|
80
|
+
return metadata;
|
|
81
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import spawn from 'cross-spawn';
|
|
2
2
|
import { PROTOCOL_VERSION, client, methods, ndJsonStream } from '@agentclientprotocol/sdk';
|
|
3
3
|
import { type DebugLogger } from '../../debug.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PreparedProviderTurnInput, ProviderGenerateOptions } from '../../types.js';
|
|
5
5
|
import type { ClaudeChannelSessionStore } from './session-store.js';
|
|
6
6
|
interface ClaudeAcpRuntime {
|
|
7
7
|
spawn: typeof spawn;
|
|
@@ -20,7 +20,6 @@ interface ClaudeHostedImageInputConfig {
|
|
|
20
20
|
borgeeBaseUrl?: string;
|
|
21
21
|
agentApiKey?: string;
|
|
22
22
|
}
|
|
23
|
-
export declare function buildClaudeSessionSystemPrompt(promptContext?: PreparedPromptContext): string | undefined;
|
|
24
23
|
/**
|
|
25
24
|
* Persistent ACP-backed client for the Claude ACP adapter.
|
|
26
25
|
*
|
|
@@ -94,7 +93,7 @@ export declare class ClaudeCliClient {
|
|
|
94
93
|
private invalidateSession;
|
|
95
94
|
private closeSession;
|
|
96
95
|
private rejectQueuedTurnsAfterSessionTaint;
|
|
97
|
-
private
|
|
96
|
+
private findChannelStateBySessionId;
|
|
98
97
|
private currentSessionStoreAgentId;
|
|
99
98
|
private ensureSessionStoreLoaded;
|
|
100
99
|
private readPersistedSessionId;
|