@ai-sdk/harness-acp 1.0.0 → 1.0.2
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/CHANGELOG.md +22 -0
- package/README.md +5 -6
- package/dist/bridge/host-tool-mcp.mjs +1 -1
- package/dist/bridge/index.mjs +145 -39
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +137 -19
- package/dist/index.js +187 -110
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/acp-harness.ts +26 -60
- package/src/acp-tool-call.ts +124 -0
- package/src/index.ts +21 -3
- package/src/v1/acp-v1-bridge-protocol.ts +17 -1
- package/src/v1/acp-v1-harness.ts +111 -21
- package/src/v1/acp-v1-settings.ts +27 -20
- package/src/v1/acp-v1-turn-start-config.ts +3 -0
- package/src/v1/bridge/acp-diagnostics.ts +27 -1
- package/src/v1/bridge/agent-stderr-monitor.ts +52 -0
- package/src/v1/bridge/create-emit-stream-event.ts +8 -1
- package/src/v1/bridge/index.ts +66 -34
- package/src/v1/bridge/stream-translator.ts +62 -5
- package/src/v1/implementation.ts +73 -47
- package/src/v1/index.ts +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/harness-acp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"ws": "^8.21.0",
|
|
30
|
-
"@ai-sdk/harness": "1.0.
|
|
31
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
30
|
+
"@ai-sdk/harness": "1.0.65",
|
|
31
|
+
"@ai-sdk/provider-utils": "5.0.26"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"zod": "^3.25.76 || ^4.1.8"
|
package/src/acp-harness.ts
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import type { HarnessV1 } from '@ai-sdk/harness';
|
|
2
2
|
import type { ToolSet } from '@ai-sdk/provider-utils';
|
|
3
3
|
import { z } from 'zod/v4';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
resolveACPProviderAuthenticationCompatibility,
|
|
7
|
-
type ACPAuthenticationProfileIdentity,
|
|
8
|
-
type ACPClientApp,
|
|
9
|
-
} from './acp-auth';
|
|
4
|
+
import type { ACPClientApp } from './acp-auth';
|
|
5
|
+
import type { ACPToolCall } from './acp-tool-call';
|
|
10
6
|
import { createACPV1, type ACPV1Settings } from './v1';
|
|
11
|
-
import { createImplementationIdentity } from './v1/implementation';
|
|
12
7
|
import {
|
|
13
8
|
acpColdSessionStateSchema,
|
|
14
9
|
acpTurnStartConfigSchema,
|
|
15
|
-
type ACPColdSessionState,
|
|
16
|
-
type ACPTurnStartConfig,
|
|
17
10
|
} from './v1/acp-v1-bridge-protocol';
|
|
18
11
|
import { VERSION } from './version';
|
|
19
12
|
|
|
@@ -24,18 +17,29 @@ const ACP_CLIENT_APP = {
|
|
|
24
17
|
|
|
25
18
|
export type ACPHarnessSettings<TBuiltinTools extends ToolSet = {}> = {
|
|
26
19
|
readonly builtinTools?: TBuiltinTools;
|
|
20
|
+
/**
|
|
21
|
+
* MCP server definitions keyed by server name. Each definition uses the
|
|
22
|
+
* underlying runtime's native MCP server configuration format.
|
|
23
|
+
*/
|
|
24
|
+
readonly mcpServers?: Record<string, unknown>;
|
|
25
|
+
readonly isMcpToolCall?: (toolCall: ACPToolCall) => boolean;
|
|
27
26
|
readonly port?: number;
|
|
28
27
|
readonly startupTimeoutMs?: number;
|
|
29
28
|
readonly clientApp?: ACPClientApp;
|
|
30
29
|
readonly version?: ACPV1Settings['version'];
|
|
31
30
|
readonly harnessId: ACPV1Settings['harnessId'];
|
|
32
31
|
readonly auth?: ACPV1Settings['auth'];
|
|
33
|
-
readonly
|
|
32
|
+
readonly source: ACPV1Settings['source'];
|
|
33
|
+
readonly executable: ACPV1Settings['executable'];
|
|
34
|
+
readonly args?: ACPV1Settings['args'];
|
|
35
|
+
readonly forwardEnv?: ACPV1Settings['forwardEnv'];
|
|
36
|
+
readonly env?: ACPV1Settings['env'];
|
|
34
37
|
readonly authentication?: ACPV1Settings['authentication'];
|
|
35
38
|
readonly providerAuthentication?: ACPV1Settings['providerAuthentication'];
|
|
36
39
|
readonly modelId?: ACPV1Settings['modelId'];
|
|
37
40
|
readonly permissionModeMapping?: ACPV1Settings['permissionModeMapping'];
|
|
38
41
|
readonly session?: ACPV1Settings['session'];
|
|
42
|
+
readonly mintBridgeToken?: ACPV1Settings['mintBridgeToken'];
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
const ACP_BUILTIN_TOOLS = {} as const satisfies ToolSet;
|
|
@@ -86,59 +90,24 @@ const acpResumeStateSchema = z.object({
|
|
|
86
90
|
skillsFingerprint: z.string().optional(),
|
|
87
91
|
});
|
|
88
92
|
|
|
89
|
-
type ACPBridgeCoords = z.infer<typeof acpBridgeCoordsSchema>;
|
|
90
|
-
|
|
91
93
|
export function createACP<TBuiltinTools extends ToolSet = {}>(
|
|
92
94
|
settings: ACPHarnessSettings<TBuiltinTools>,
|
|
93
95
|
): HarnessV1<TBuiltinTools> {
|
|
96
|
+
if (
|
|
97
|
+
settings.mcpServers != null &&
|
|
98
|
+
Object.prototype.hasOwnProperty.call(
|
|
99
|
+
settings.mcpServers,
|
|
100
|
+
'ai-sdk-harness-tools',
|
|
101
|
+
)
|
|
102
|
+
) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
'ACP MCP server name "ai-sdk-harness-tools" is reserved for HarnessAgent tools.',
|
|
105
|
+
);
|
|
106
|
+
}
|
|
94
107
|
const version = (settings as { readonly version?: string }).version ?? 'v1';
|
|
95
108
|
switch (version) {
|
|
96
109
|
case 'v1': {
|
|
97
110
|
const clientApp = settings.clientApp ?? ACP_CLIENT_APP;
|
|
98
|
-
const providerAuthenticationCompatibility =
|
|
99
|
-
resolveACPProviderAuthenticationCompatibility({
|
|
100
|
-
auth: settings.auth,
|
|
101
|
-
providerAuthentication: settings.providerAuthentication,
|
|
102
|
-
env: process.env,
|
|
103
|
-
});
|
|
104
|
-
const implementationIdentity = createImplementationIdentity({
|
|
105
|
-
harnessId: settings.harnessId,
|
|
106
|
-
acpVersion: version,
|
|
107
|
-
implementation: settings.implementation,
|
|
108
|
-
clientApp,
|
|
109
|
-
providerAuthentication: providerAuthenticationCompatibility,
|
|
110
|
-
permissionModeMapping: settings.permissionModeMapping,
|
|
111
|
-
});
|
|
112
|
-
const authenticationProfile = createACPAuthenticationProfileIdentity({
|
|
113
|
-
authentication: settings.authentication,
|
|
114
|
-
providerAuthenticationCompatibility,
|
|
115
|
-
});
|
|
116
|
-
const lifecycleStateSchema: z.ZodType<{
|
|
117
|
-
readonly implementationIdentity: string;
|
|
118
|
-
readonly authenticationProfile?: ACPAuthenticationProfileIdentity;
|
|
119
|
-
readonly acpSessionId?: string;
|
|
120
|
-
readonly bridge?: ACPBridgeCoords;
|
|
121
|
-
readonly coldSession?: ACPColdSessionState;
|
|
122
|
-
readonly turnStartConfig?: ACPTurnStartConfig;
|
|
123
|
-
readonly recovery?: {
|
|
124
|
-
readonly mode: 'disk-replay' | 'lossy-rerun';
|
|
125
|
-
readonly reason: string;
|
|
126
|
-
};
|
|
127
|
-
readonly restoration?: {
|
|
128
|
-
readonly method: 'resume' | 'load';
|
|
129
|
-
};
|
|
130
|
-
readonly initialGuidanceApplied?: boolean;
|
|
131
|
-
readonly skillsMaterialized?: boolean;
|
|
132
|
-
readonly skillsFingerprint?: string;
|
|
133
|
-
}> = acpResumeStateSchema.extend({
|
|
134
|
-
implementationIdentity: z.literal(implementationIdentity),
|
|
135
|
-
authenticationProfile: acpResumeStateSchema.shape.authenticationProfile
|
|
136
|
-
.unwrap()
|
|
137
|
-
.extend({
|
|
138
|
-
digest: z.literal(authenticationProfile.digest),
|
|
139
|
-
})
|
|
140
|
-
.optional(),
|
|
141
|
-
});
|
|
142
111
|
return createACPV1({
|
|
143
112
|
settings,
|
|
144
113
|
builtinTools:
|
|
@@ -146,10 +115,7 @@ export function createACP<TBuiltinTools extends ToolSet = {}>(
|
|
|
146
115
|
port: settings.port,
|
|
147
116
|
startupTimeoutMs: settings.startupTimeoutMs,
|
|
148
117
|
clientApp,
|
|
149
|
-
|
|
150
|
-
authenticationProfile,
|
|
151
|
-
providerAuthenticationCompatibility,
|
|
152
|
-
lifecycleStateSchema,
|
|
118
|
+
lifecycleStateSchema: acpResumeStateSchema,
|
|
153
119
|
});
|
|
154
120
|
}
|
|
155
121
|
default:
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export type ACPMetadata = Record<string, unknown>;
|
|
2
|
+
|
|
3
|
+
export type ACPRole = 'assistant' | 'user';
|
|
4
|
+
|
|
5
|
+
export type ACPAnnotations = {
|
|
6
|
+
audience?: Array<ACPRole> | null;
|
|
7
|
+
lastModified?: string | null;
|
|
8
|
+
priority?: number | null;
|
|
9
|
+
_meta?: ACPMetadata | null;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type ACPTextContent = {
|
|
13
|
+
annotations?: ACPAnnotations | null;
|
|
14
|
+
text: string;
|
|
15
|
+
_meta?: ACPMetadata | null;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type ACPImageContent = {
|
|
19
|
+
annotations?: ACPAnnotations | null;
|
|
20
|
+
data: string;
|
|
21
|
+
mimeType: string;
|
|
22
|
+
uri?: string | null;
|
|
23
|
+
_meta?: ACPMetadata | null;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ACPAudioContent = {
|
|
27
|
+
annotations?: ACPAnnotations | null;
|
|
28
|
+
data: string;
|
|
29
|
+
mimeType: string;
|
|
30
|
+
_meta?: ACPMetadata | null;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type ACPResourceLink = {
|
|
34
|
+
annotations?: ACPAnnotations | null;
|
|
35
|
+
description?: string | null;
|
|
36
|
+
mimeType?: string | null;
|
|
37
|
+
name: string;
|
|
38
|
+
size?: number | null;
|
|
39
|
+
title?: string | null;
|
|
40
|
+
uri: string;
|
|
41
|
+
_meta?: ACPMetadata | null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type ACPTextResourceContents = {
|
|
45
|
+
mimeType?: string | null;
|
|
46
|
+
text: string;
|
|
47
|
+
uri: string;
|
|
48
|
+
_meta?: ACPMetadata | null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type ACPBlobResourceContents = {
|
|
52
|
+
blob: string;
|
|
53
|
+
mimeType?: string | null;
|
|
54
|
+
uri: string;
|
|
55
|
+
_meta?: ACPMetadata | null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export type ACPEmbeddedResource = {
|
|
59
|
+
annotations?: ACPAnnotations | null;
|
|
60
|
+
resource: ACPTextResourceContents | ACPBlobResourceContents;
|
|
61
|
+
_meta?: ACPMetadata | null;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type ACPContentBlock =
|
|
65
|
+
| (ACPTextContent & { type: 'text' })
|
|
66
|
+
| (ACPImageContent & { type: 'image' })
|
|
67
|
+
| (ACPAudioContent & { type: 'audio' })
|
|
68
|
+
| (ACPResourceLink & { type: 'resource_link' })
|
|
69
|
+
| (ACPEmbeddedResource & { type: 'resource' });
|
|
70
|
+
|
|
71
|
+
export type ACPToolCallContent =
|
|
72
|
+
| {
|
|
73
|
+
type: 'content';
|
|
74
|
+
content: ACPContentBlock;
|
|
75
|
+
_meta?: ACPMetadata | null;
|
|
76
|
+
}
|
|
77
|
+
| {
|
|
78
|
+
type: 'diff';
|
|
79
|
+
path: string;
|
|
80
|
+
oldText?: string | null;
|
|
81
|
+
newText: string;
|
|
82
|
+
_meta?: ACPMetadata | null;
|
|
83
|
+
}
|
|
84
|
+
| {
|
|
85
|
+
type: 'terminal';
|
|
86
|
+
terminalId: string;
|
|
87
|
+
_meta?: ACPMetadata | null;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type ACPToolKind =
|
|
91
|
+
| 'read'
|
|
92
|
+
| 'edit'
|
|
93
|
+
| 'delete'
|
|
94
|
+
| 'move'
|
|
95
|
+
| 'search'
|
|
96
|
+
| 'execute'
|
|
97
|
+
| 'think'
|
|
98
|
+
| 'fetch'
|
|
99
|
+
| 'switch_mode'
|
|
100
|
+
| 'other';
|
|
101
|
+
|
|
102
|
+
export type ACPToolCallStatus =
|
|
103
|
+
| 'pending'
|
|
104
|
+
| 'in_progress'
|
|
105
|
+
| 'completed'
|
|
106
|
+
| 'failed';
|
|
107
|
+
|
|
108
|
+
export type ACPToolCallLocation = {
|
|
109
|
+
path: string;
|
|
110
|
+
line?: number | null;
|
|
111
|
+
_meta?: ACPMetadata | null;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export type ACPToolCall = {
|
|
115
|
+
toolCallId: string;
|
|
116
|
+
title: string;
|
|
117
|
+
kind?: ACPToolKind;
|
|
118
|
+
status?: ACPToolCallStatus;
|
|
119
|
+
content?: Array<ACPToolCallContent>;
|
|
120
|
+
locations?: Array<ACPToolCallLocation>;
|
|
121
|
+
rawInput?: unknown;
|
|
122
|
+
rawOutput?: unknown;
|
|
123
|
+
_meta?: ACPMetadata | null;
|
|
124
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
export { createACP } from './acp-harness';
|
|
2
2
|
export type { ACPAuthOptions, ACPClientApp } from './acp-auth';
|
|
3
3
|
export type { ACPHarnessSettings } from './acp-harness';
|
|
4
|
+
export type {
|
|
5
|
+
ACPAnnotations,
|
|
6
|
+
ACPAudioContent,
|
|
7
|
+
ACPBlobResourceContents,
|
|
8
|
+
ACPContentBlock,
|
|
9
|
+
ACPEmbeddedResource,
|
|
10
|
+
ACPImageContent,
|
|
11
|
+
ACPMetadata,
|
|
12
|
+
ACPResourceLink,
|
|
13
|
+
ACPRole,
|
|
14
|
+
ACPTextContent,
|
|
15
|
+
ACPTextResourceContents,
|
|
16
|
+
ACPToolCall,
|
|
17
|
+
ACPToolCallContent,
|
|
18
|
+
ACPToolCallLocation,
|
|
19
|
+
ACPToolCallStatus,
|
|
20
|
+
ACPToolKind,
|
|
21
|
+
} from './acp-tool-call';
|
|
4
22
|
export type {
|
|
5
23
|
ACPAuthentication,
|
|
6
|
-
|
|
7
|
-
|
|
24
|
+
ACPNpmLockedSource,
|
|
25
|
+
ACPNpmSimpleSource,
|
|
8
26
|
ACPPermissionModeMapping,
|
|
9
27
|
ACPPermissionModeTarget,
|
|
10
28
|
ACPProfileValue,
|
|
@@ -12,7 +30,7 @@ export type {
|
|
|
12
30
|
ACPProviderAuthenticationMode,
|
|
13
31
|
ACPSerializablePrimitive,
|
|
14
32
|
ACPSerializableValue,
|
|
15
|
-
|
|
33
|
+
ACPSource,
|
|
16
34
|
ACPV1Settings,
|
|
17
35
|
ACPValueSource,
|
|
18
36
|
} from './v1';
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type HarnessV1ToolSpec,
|
|
12
12
|
} from '@ai-sdk/harness';
|
|
13
13
|
import { z } from 'zod/v4';
|
|
14
|
+
import type { ACPToolCall } from '../acp-tool-call';
|
|
14
15
|
import type { ACPPermissionModeMapping } from './acp-v1-settings';
|
|
15
16
|
import { acpTextContentBlockSchema } from './acp-v1-prompt';
|
|
16
17
|
|
|
@@ -126,11 +127,26 @@ const coldRestoreSchema = z.object({
|
|
|
126
127
|
acpSessionId: z.string(),
|
|
127
128
|
});
|
|
128
129
|
|
|
129
|
-
|
|
130
|
+
const acpToolCallCandidateSchema = z.object({
|
|
131
|
+
type: z.literal('acp-tool-call-candidate'),
|
|
132
|
+
toolCall: z.custom<ACPToolCall>(
|
|
133
|
+
value =>
|
|
134
|
+
value != null &&
|
|
135
|
+
typeof value === 'object' &&
|
|
136
|
+
typeof (value as { toolCallId?: unknown }).toolCallId === 'string' &&
|
|
137
|
+
typeof (value as { title?: unknown }).title === 'string',
|
|
138
|
+
),
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export const outboundMessageSchema = z.union([
|
|
142
|
+
harnessV1BridgeOutboundMessageSchema,
|
|
143
|
+
acpToolCallCandidateSchema,
|
|
144
|
+
]);
|
|
130
145
|
export type OutboundMessage = z.infer<typeof outboundMessageSchema>;
|
|
131
146
|
|
|
132
147
|
export const startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
133
148
|
prompt: z.array(acpTextContentBlockSchema),
|
|
149
|
+
mcpServers: z.record(z.string(), z.unknown()).optional(),
|
|
134
150
|
tools: z.array(acpSerializableToolSpecSchema).optional(),
|
|
135
151
|
builtinTools: z.array(builtinToolSchema).readonly().default([]),
|
|
136
152
|
permissionModeMapping: permissionModeMappingSchema.optional(),
|
package/src/v1/acp-v1-harness.ts
CHANGED
|
@@ -34,13 +34,17 @@ import {
|
|
|
34
34
|
} from '@ai-sdk/provider-utils';
|
|
35
35
|
import { WebSocket } from 'ws';
|
|
36
36
|
import {
|
|
37
|
+
createACPAuthenticationProfileIdentity,
|
|
37
38
|
resolveACPProviderAuthentication,
|
|
39
|
+
resolveACPProviderAuthenticationCompatibility,
|
|
38
40
|
type ACPAuthenticationProfileIdentity,
|
|
39
41
|
type ACPClientApp,
|
|
40
|
-
type ACPProviderAuthenticationCompatibility,
|
|
41
42
|
} from '../acp-auth';
|
|
43
|
+
import type { ACPToolCall } from '../acp-tool-call';
|
|
42
44
|
import {
|
|
45
|
+
createACPV1Implementation,
|
|
43
46
|
createImplementationDescriptor,
|
|
47
|
+
createImplementationIdentity,
|
|
44
48
|
createImplementationInstallCommand,
|
|
45
49
|
createImplementationManifest,
|
|
46
50
|
getImplementationLockfile,
|
|
@@ -112,9 +116,6 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
112
116
|
port: portOverride,
|
|
113
117
|
startupTimeoutMs,
|
|
114
118
|
clientApp,
|
|
115
|
-
implementationIdentity,
|
|
116
|
-
authenticationProfile,
|
|
117
|
-
providerAuthenticationCompatibility,
|
|
118
119
|
lifecycleStateSchema,
|
|
119
120
|
}: {
|
|
120
121
|
settings: ACPV1Settings;
|
|
@@ -122,21 +123,28 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
122
123
|
port?: number;
|
|
123
124
|
startupTimeoutMs?: number;
|
|
124
125
|
clientApp: ACPClientApp;
|
|
125
|
-
implementationIdentity: string;
|
|
126
|
-
authenticationProfile: ACPAuthenticationProfileIdentity;
|
|
127
|
-
providerAuthenticationCompatibility:
|
|
128
|
-
| ACPProviderAuthenticationCompatibility
|
|
129
|
-
| undefined;
|
|
130
126
|
lifecycleStateSchema: NonNullable<
|
|
131
127
|
HarnessV1<TBuiltinTools>['lifecycleStateSchema']
|
|
132
128
|
>;
|
|
133
129
|
}): HarnessV1<TBuiltinTools> {
|
|
130
|
+
if (
|
|
131
|
+
settings.mcpServers != null &&
|
|
132
|
+
Object.prototype.hasOwnProperty.call(
|
|
133
|
+
settings.mcpServers,
|
|
134
|
+
'ai-sdk-harness-tools',
|
|
135
|
+
)
|
|
136
|
+
) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
'ACP MCP server name "ai-sdk-harness-tools" is reserved for HarnessAgent tools.',
|
|
139
|
+
);
|
|
140
|
+
}
|
|
134
141
|
if (!HARNESS_ID_REGEXP.test(settings.harnessId)) {
|
|
135
142
|
throw new Error(
|
|
136
143
|
`ACP harnessId must be a stable kebab-case identifier; received ${JSON.stringify(settings.harnessId)}.`,
|
|
137
144
|
);
|
|
138
145
|
}
|
|
139
|
-
|
|
146
|
+
const implementation = createACPV1Implementation({ settings });
|
|
147
|
+
validateACPV1Implementation(implementation);
|
|
140
148
|
|
|
141
149
|
const BOOTSTRAP_DIR = `.harness-bootstrap/${settings.harnessId}`;
|
|
142
150
|
|
|
@@ -164,7 +172,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
164
172
|
readBridgeAsset({ name: 'host-tool-mcp.mjs' }),
|
|
165
173
|
]);
|
|
166
174
|
const implementationLock = getImplementationLockfile({
|
|
167
|
-
implementation
|
|
175
|
+
implementation,
|
|
168
176
|
});
|
|
169
177
|
cachedBootstrap = {
|
|
170
178
|
harnessId: settings.harnessId,
|
|
@@ -186,14 +194,13 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
186
194
|
{
|
|
187
195
|
path: `${BOOTSTRAP_DIR}/implementation/package.json`,
|
|
188
196
|
content: createImplementationManifest({
|
|
189
|
-
implementation
|
|
197
|
+
implementation,
|
|
190
198
|
}),
|
|
191
199
|
},
|
|
192
200
|
{
|
|
193
201
|
path: `${BOOTSTRAP_DIR}/implementation/implementation.json`,
|
|
194
202
|
content: createImplementationDescriptor({
|
|
195
|
-
implementation
|
|
196
|
-
implementationIdentity,
|
|
203
|
+
implementation,
|
|
197
204
|
}),
|
|
198
205
|
},
|
|
199
206
|
...(implementationLock == null
|
|
@@ -213,7 +220,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
213
220
|
command: createImplementationInstallCommand({
|
|
214
221
|
implementationDir: 'implementation',
|
|
215
222
|
storeDir: '../.pnpm-store',
|
|
216
|
-
implementation
|
|
223
|
+
implementation,
|
|
217
224
|
}),
|
|
218
225
|
},
|
|
219
226
|
],
|
|
@@ -229,6 +236,25 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
229
236
|
});
|
|
230
237
|
}
|
|
231
238
|
const permissionMode = startOptions.permissionMode ?? 'allow-all';
|
|
239
|
+
const env = { ...process.env };
|
|
240
|
+
const providerAuthenticationCompatibility =
|
|
241
|
+
resolveACPProviderAuthenticationCompatibility({
|
|
242
|
+
auth: settings.auth,
|
|
243
|
+
providerAuthentication: settings.providerAuthentication,
|
|
244
|
+
env,
|
|
245
|
+
});
|
|
246
|
+
const implementationIdentity = createImplementationIdentity({
|
|
247
|
+
harnessId: settings.harnessId,
|
|
248
|
+
acpVersion: 'v1',
|
|
249
|
+
implementation,
|
|
250
|
+
clientApp,
|
|
251
|
+
providerAuthentication: providerAuthenticationCompatibility,
|
|
252
|
+
permissionModeMapping: settings.permissionModeMapping,
|
|
253
|
+
});
|
|
254
|
+
const authenticationProfile = createACPAuthenticationProfileIdentity({
|
|
255
|
+
authentication: settings.authentication,
|
|
256
|
+
providerAuthenticationCompatibility,
|
|
257
|
+
});
|
|
232
258
|
|
|
233
259
|
const resolvedProviderAuthentication = resolveACPProviderAuthentication({
|
|
234
260
|
auth: {
|
|
@@ -236,7 +262,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
236
262
|
providerAuthentication: settings.providerAuthentication,
|
|
237
263
|
clientApp,
|
|
238
264
|
},
|
|
239
|
-
env
|
|
265
|
+
env,
|
|
240
266
|
compatibility: providerAuthenticationCompatibility,
|
|
241
267
|
});
|
|
242
268
|
const sandboxSession = startOptions.sandboxSession;
|
|
@@ -356,6 +382,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
356
382
|
builtinTools: builtinToolCatalog,
|
|
357
383
|
permissionMode,
|
|
358
384
|
permissionModeMapping,
|
|
385
|
+
mcpServers: settings.mcpServers,
|
|
386
|
+
isMcpToolCall: settings.isMcpToolCall,
|
|
359
387
|
initialGuidanceApplied: resolveACPInitialGuidanceApplied({
|
|
360
388
|
isResume: true,
|
|
361
389
|
lifecycleState: lifecycleData,
|
|
@@ -407,6 +435,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
407
435
|
sessionMeta: settings.session?.meta,
|
|
408
436
|
builtinTools: builtinToolCatalog,
|
|
409
437
|
permissionModeMapping,
|
|
438
|
+
mcpServers: settings.mcpServers,
|
|
410
439
|
});
|
|
411
440
|
respawnStrategy = {
|
|
412
441
|
mode: 'lossy-rerun',
|
|
@@ -436,6 +465,7 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
436
465
|
sessionMeta: settings.session?.meta,
|
|
437
466
|
builtinTools: builtinToolCatalog,
|
|
438
467
|
permissionModeMapping,
|
|
468
|
+
mcpServers: settings.mcpServers,
|
|
439
469
|
debug: startOptions.observability?.debug,
|
|
440
470
|
});
|
|
441
471
|
respawnStrategy = {
|
|
@@ -451,7 +481,10 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
451
481
|
override: portOverride,
|
|
452
482
|
harnessId: settings.harnessId,
|
|
453
483
|
});
|
|
454
|
-
const token =
|
|
484
|
+
const token =
|
|
485
|
+
settings.mintBridgeToken == null
|
|
486
|
+
? randomBytes(32).toString('hex')
|
|
487
|
+
: settings.mintBridgeToken(sandboxSession.id);
|
|
455
488
|
await sandbox.run({
|
|
456
489
|
command: `mkdir -p ${shellQuote(workDir)} ${shellQuote(bridgeStateDir)}`,
|
|
457
490
|
abortSignal: startOptions.abortSignal,
|
|
@@ -472,8 +505,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
472
505
|
` --bridge-type ${shellQuote(settings.harnessId)}`,
|
|
473
506
|
env: {
|
|
474
507
|
...resolveImplementationEnvironment({
|
|
475
|
-
implementation
|
|
476
|
-
env
|
|
508
|
+
implementation,
|
|
509
|
+
env,
|
|
477
510
|
}),
|
|
478
511
|
...createACPBridgeEnvironment({
|
|
479
512
|
authentication: settings.authentication,
|
|
@@ -556,6 +589,9 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
556
589
|
builtinTools: builtinToolCatalog,
|
|
557
590
|
permissionMode,
|
|
558
591
|
permissionModeMapping,
|
|
592
|
+
...(settings.mcpServers == null
|
|
593
|
+
? {}
|
|
594
|
+
: { mcpServers: settings.mcpServers }),
|
|
559
595
|
tools: respawnStrategy.turnStartConfig.tools,
|
|
560
596
|
turnStartConfig: respawnStrategy.turnStartConfig,
|
|
561
597
|
recoveryMode: {
|
|
@@ -592,6 +628,8 @@ export function createACPV1<TBuiltinTools extends ToolSet = {}>({
|
|
|
592
628
|
builtinTools: builtinToolCatalog,
|
|
593
629
|
permissionMode,
|
|
594
630
|
permissionModeMapping,
|
|
631
|
+
mcpServers: settings.mcpServers,
|
|
632
|
+
isMcpToolCall: settings.isMcpToolCall,
|
|
595
633
|
initialGuidanceApplied: resolveACPInitialGuidanceApplied({
|
|
596
634
|
isResume,
|
|
597
635
|
lifecycleState: lifecycleData,
|
|
@@ -793,6 +831,8 @@ function createSession({
|
|
|
793
831
|
builtinTools,
|
|
794
832
|
permissionMode,
|
|
795
833
|
permissionModeMapping,
|
|
834
|
+
mcpServers,
|
|
835
|
+
isMcpToolCall,
|
|
796
836
|
initialGuidanceApplied: initialGuidanceAppliedAtStart,
|
|
797
837
|
skillCatalog,
|
|
798
838
|
skillsFingerprint,
|
|
@@ -821,6 +861,8 @@ function createSession({
|
|
|
821
861
|
builtinTools: ReadonlyArray<ACPBuiltinToolMapping>;
|
|
822
862
|
permissionMode: NonNullable<StartMessage['permissionMode']>;
|
|
823
863
|
permissionModeMapping: StartMessage['permissionModeMapping'];
|
|
864
|
+
mcpServers: Record<string, unknown> | undefined;
|
|
865
|
+
isMcpToolCall: ((toolCall: ACPToolCall) => boolean) | undefined;
|
|
824
866
|
initialGuidanceApplied: boolean;
|
|
825
867
|
skillCatalog: ReadonlyArray<ACPSkillCatalogEntry>;
|
|
826
868
|
skillsFingerprint: string;
|
|
@@ -875,6 +917,8 @@ function createSession({
|
|
|
875
917
|
let openBlock:
|
|
876
918
|
| { readonly type: 'text' | 'reasoning'; readonly id: string }
|
|
877
919
|
| undefined;
|
|
920
|
+
const dynamicToolCalls = new Map<string, boolean>();
|
|
921
|
+
const toolCallClassificationErrors = new Map<string, unknown>();
|
|
878
922
|
const subscriptions: Array<() => void> = [];
|
|
879
923
|
const forward = (event: HarnessV1StreamPart) => {
|
|
880
924
|
if (event.type === 'text-start' || event.type === 'reasoning-start') {
|
|
@@ -909,9 +953,7 @@ function createSession({
|
|
|
909
953
|
'reasoning-start',
|
|
910
954
|
'reasoning-delta',
|
|
911
955
|
'reasoning-end',
|
|
912
|
-
'tool-call',
|
|
913
956
|
'tool-approval-request',
|
|
914
|
-
'tool-result',
|
|
915
957
|
'file-change',
|
|
916
958
|
'finish-step',
|
|
917
959
|
'raw',
|
|
@@ -940,6 +982,45 @@ function createSession({
|
|
|
940
982
|
settle({ error: abortError });
|
|
941
983
|
}
|
|
942
984
|
};
|
|
985
|
+
subscriptions.push(
|
|
986
|
+
channel.on('acp-tool-call-candidate', event => {
|
|
987
|
+
try {
|
|
988
|
+
dynamicToolCalls.set(
|
|
989
|
+
event.toolCall.toolCallId,
|
|
990
|
+
isMcpToolCall?.(event.toolCall) === true,
|
|
991
|
+
);
|
|
992
|
+
} catch (error) {
|
|
993
|
+
toolCallClassificationErrors.set(event.toolCall.toolCallId, error);
|
|
994
|
+
}
|
|
995
|
+
}),
|
|
996
|
+
);
|
|
997
|
+
subscriptions.push(
|
|
998
|
+
channel.on('tool-call', event => {
|
|
999
|
+
if (toolCallClassificationErrors.has(event.toolCallId)) {
|
|
1000
|
+
const error = toolCallClassificationErrors.get(event.toolCallId);
|
|
1001
|
+
closeForwardedBlock();
|
|
1002
|
+
forward({ type: 'error', error });
|
|
1003
|
+
try {
|
|
1004
|
+
channel.send({ type: 'abort' });
|
|
1005
|
+
} catch {}
|
|
1006
|
+
settle({ error });
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
forward(
|
|
1010
|
+
dynamicToolCalls.get(event.toolCallId) === true
|
|
1011
|
+
? { ...event, dynamic: true }
|
|
1012
|
+
: event,
|
|
1013
|
+
);
|
|
1014
|
+
}),
|
|
1015
|
+
);
|
|
1016
|
+
subscriptions.push(
|
|
1017
|
+
channel.on('tool-result', event => {
|
|
1018
|
+
const dynamic = dynamicToolCalls.get(event.toolCallId) === true;
|
|
1019
|
+
dynamicToolCalls.delete(event.toolCallId);
|
|
1020
|
+
toolCallClassificationErrors.delete(event.toolCallId);
|
|
1021
|
+
forward(dynamic ? { ...event, dynamic: true } : event);
|
|
1022
|
+
}),
|
|
1023
|
+
);
|
|
943
1024
|
for (const type of eventTypes) {
|
|
944
1025
|
subscriptions.push(channel.on(type, event => forward(event)));
|
|
945
1026
|
}
|
|
@@ -1096,6 +1177,7 @@ function createSession({
|
|
|
1096
1177
|
builtinTools,
|
|
1097
1178
|
permissionMode,
|
|
1098
1179
|
permissionModeMapping,
|
|
1180
|
+
mcpServers,
|
|
1099
1181
|
debug,
|
|
1100
1182
|
authenticationProfile,
|
|
1101
1183
|
sessionMeta,
|
|
@@ -1123,6 +1205,7 @@ function createSession({
|
|
|
1123
1205
|
builtinTools,
|
|
1124
1206
|
permissionMode,
|
|
1125
1207
|
permissionModeMapping,
|
|
1208
|
+
...(mcpServers == null ? {} : { mcpServers }),
|
|
1126
1209
|
tools: options.tools == null ? undefined : turnStartConfig.tools,
|
|
1127
1210
|
turnStartConfig,
|
|
1128
1211
|
});
|
|
@@ -1160,6 +1243,7 @@ function createSession({
|
|
|
1160
1243
|
builtinTools: turnStartConfig.builtinTools,
|
|
1161
1244
|
permissionMode: turnStartConfig.permissionMode,
|
|
1162
1245
|
permissionModeMapping: turnStartConfig.permissionModeMapping,
|
|
1246
|
+
...(mcpServers == null ? {} : { mcpServers }),
|
|
1163
1247
|
tools: turnStartConfig.tools,
|
|
1164
1248
|
turnStartConfig,
|
|
1165
1249
|
recoveryMode: {
|
|
@@ -1324,12 +1408,14 @@ function validateACPTurnStartConfig({
|
|
|
1324
1408
|
sessionMeta,
|
|
1325
1409
|
builtinTools,
|
|
1326
1410
|
permissionModeMapping,
|
|
1411
|
+
mcpServers,
|
|
1327
1412
|
}: {
|
|
1328
1413
|
turnStartConfig: ACPTurnStartConfig;
|
|
1329
1414
|
authenticationProfile: ACPAuthenticationProfileIdentity;
|
|
1330
1415
|
sessionMeta: Readonly<Record<string, ACPSerializableValue>> | undefined;
|
|
1331
1416
|
builtinTools: ReadonlyArray<ACPBuiltinToolMapping>;
|
|
1332
1417
|
permissionModeMapping: ACPPermissionModeMapping | undefined;
|
|
1418
|
+
mcpServers: Record<string, unknown> | undefined;
|
|
1333
1419
|
}): void {
|
|
1334
1420
|
const current = createACPTurnStartConfig({
|
|
1335
1421
|
prompt: turnStartConfig.prompt,
|
|
@@ -1337,6 +1423,7 @@ function validateACPTurnStartConfig({
|
|
|
1337
1423
|
builtinTools,
|
|
1338
1424
|
permissionMode: turnStartConfig.permissionMode,
|
|
1339
1425
|
permissionModeMapping,
|
|
1426
|
+
mcpServers,
|
|
1340
1427
|
debug: turnStartConfig.debug,
|
|
1341
1428
|
authenticationProfile,
|
|
1342
1429
|
sessionMeta,
|
|
@@ -1359,6 +1446,7 @@ function validateACPColdSessionConfiguration({
|
|
|
1359
1446
|
sessionMeta,
|
|
1360
1447
|
builtinTools,
|
|
1361
1448
|
permissionModeMapping,
|
|
1449
|
+
mcpServers,
|
|
1362
1450
|
debug,
|
|
1363
1451
|
}: {
|
|
1364
1452
|
coldSession: ACPColdSessionState;
|
|
@@ -1368,6 +1456,7 @@ function validateACPColdSessionConfiguration({
|
|
|
1368
1456
|
sessionMeta: Readonly<Record<string, ACPSerializableValue>> | undefined;
|
|
1369
1457
|
builtinTools: ReadonlyArray<ACPBuiltinToolMapping>;
|
|
1370
1458
|
permissionModeMapping: ACPPermissionModeMapping | undefined;
|
|
1459
|
+
mcpServers: Record<string, unknown> | undefined;
|
|
1371
1460
|
debug: HarnessV1DebugConfig | undefined;
|
|
1372
1461
|
}): ACPTurnStartConfig {
|
|
1373
1462
|
const current = createACPTurnStartConfig({
|
|
@@ -1376,6 +1465,7 @@ function validateACPColdSessionConfiguration({
|
|
|
1376
1465
|
builtinTools,
|
|
1377
1466
|
permissionMode,
|
|
1378
1467
|
permissionModeMapping,
|
|
1468
|
+
mcpServers,
|
|
1379
1469
|
debug,
|
|
1380
1470
|
authenticationProfile,
|
|
1381
1471
|
sessionMeta,
|