@ai-sdk/harness-acp 1.0.1 → 1.0.3
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 +19 -0
- package/README.md +13 -0
- package/dist/bridge/host-tool-mcp.mjs +1 -1
- package/dist/bridge/index.mjs +176 -18
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +132 -1
- package/dist/index.js +130 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/acp-harness.ts +20 -0
- package/src/acp-tool-call.ts +124 -0
- package/src/index.ts +19 -0
- package/src/v1/acp-v1-bridge-protocol.ts +38 -2
- package/src/v1/acp-v1-harness.ts +116 -4
- package/src/v1/acp-v1-settings.ts +29 -0
- package/src/v1/acp-v1-turn-start-config.ts +7 -0
- package/src/v1/bridge/create-emit-stream-event.ts +8 -1
- package/src/v1/bridge/index.ts +61 -6
- package/src/v1/bridge/instruction-mapping.ts +132 -0
- package/src/v1/bridge/stream-translator.ts +62 -5
- package/src/v1/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @ai-sdk/harness-acp
|
|
2
2
|
|
|
3
|
+
## 1.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9ee30bf: fix(harness): pass instructions appended to system / developer prompt instead of using the workaround of first user prompt
|
|
8
|
+
- Updated dependencies [9ee30bf]
|
|
9
|
+
- @ai-sdk/harness@1.0.66
|
|
10
|
+
|
|
11
|
+
## 1.0.2
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- a03ff6c: feat(harness): add support for per-harness MCP servers
|
|
16
|
+
- fc3baaf: feat(harness): add optional `mintBridgeToken(sandboxId)` to harness settings to control the bridge token value
|
|
17
|
+
- Updated dependencies [401a4ba]
|
|
18
|
+
- Updated dependencies [a03ff6c]
|
|
19
|
+
- @ai-sdk/provider-utils@5.0.26
|
|
20
|
+
- @ai-sdk/harness@1.0.65
|
|
21
|
+
|
|
3
22
|
## 1.0.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -34,6 +34,11 @@ const codexACP = createACP({
|
|
|
34
34
|
},
|
|
35
35
|
executable: 'codex-acp',
|
|
36
36
|
forwardEnv: ['CODEX_API_KEY', 'OPENAI_API_KEY'],
|
|
37
|
+
instructionMapping: {
|
|
38
|
+
type: 'launch-env-json',
|
|
39
|
+
variable: 'CODEX_CONFIG',
|
|
40
|
+
path: ['developer_instructions'],
|
|
41
|
+
},
|
|
37
42
|
permissionModeMapping: {
|
|
38
43
|
'allow-reads': null,
|
|
39
44
|
'allow-edits': null,
|
|
@@ -69,3 +74,11 @@ resolves the value when the ACP process starts and does not store it in the
|
|
|
69
74
|
profile. Codex ACP supports only `permissionMode: 'allow-all'` because its
|
|
70
75
|
restrictive modes enable Codex's internal sandbox. A bridge-backed ACP harness
|
|
71
76
|
requires a sandbox with at least one exposed port.
|
|
77
|
+
|
|
78
|
+
Use `instructionMapping` when the ACP implementation exposes a native system
|
|
79
|
+
or developer prompt. A `session-meta` mapping writes `HarnessAgent`
|
|
80
|
+
instructions below the ACP session request's `_meta` field. A
|
|
81
|
+
`launch-env-json` mapping merges them into a JSON environment variable before
|
|
82
|
+
the implementation starts. Without a mapping, the adapter preserves its
|
|
83
|
+
backward-compatible behavior and prepends instructions to the first user
|
|
84
|
+
prompt.
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
ListToolsRequestSchema,
|
|
13
13
|
McpError
|
|
14
14
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
15
|
-
var VERSION = true ? "1.0.
|
|
15
|
+
var VERSION = true ? "1.0.3" : "0.0.0-test";
|
|
16
16
|
function createHostToolMCPServer({
|
|
17
17
|
tools: tools2,
|
|
18
18
|
revision = 1,
|
package/dist/bridge/index.mjs
CHANGED
|
@@ -890,6 +890,7 @@ function monitorACPAgentStderr({
|
|
|
890
890
|
// src/v1/bridge/stream-translator.ts
|
|
891
891
|
function createACPStreamTranslator({
|
|
892
892
|
emit,
|
|
893
|
+
emitToolCallCandidate,
|
|
893
894
|
builtinTools = []
|
|
894
895
|
}) {
|
|
895
896
|
let openBlock;
|
|
@@ -1000,13 +1001,12 @@ function createACPStreamTranslator({
|
|
|
1000
1001
|
if (builtin != null) {
|
|
1001
1002
|
state.toolName = builtin.toolName;
|
|
1002
1003
|
state.nativeName = builtin.nativeName != null && builtin.toolName !== builtin.nativeName ? builtin.nativeName : void 0;
|
|
1003
|
-
state.dynamic = false;
|
|
1004
1004
|
} else {
|
|
1005
1005
|
state.toolName = createDynamicToolName({
|
|
1006
1006
|
programmaticName,
|
|
1007
1007
|
toolCallId: state.toolCallId
|
|
1008
1008
|
});
|
|
1009
|
-
state
|
|
1009
|
+
emitToolCallCandidate?.({ toolCall: createACPToolCall({ state }) });
|
|
1010
1010
|
}
|
|
1011
1011
|
emit({
|
|
1012
1012
|
type: "tool-call",
|
|
@@ -1014,7 +1014,6 @@ function createACPStreamTranslator({
|
|
|
1014
1014
|
toolName: state.toolName,
|
|
1015
1015
|
input: stringifyToolInput({ input: state.values.rawInput }),
|
|
1016
1016
|
providerExecuted: true,
|
|
1017
|
-
...state.dynamic ? { dynamic: true } : {},
|
|
1018
1017
|
...state.nativeName == null ? {} : { nativeName: state.nativeName }
|
|
1019
1018
|
});
|
|
1020
1019
|
state.emittedCall = true;
|
|
@@ -1029,8 +1028,7 @@ function createACPStreamTranslator({
|
|
|
1029
1028
|
toolCallId: state.toolCallId,
|
|
1030
1029
|
toolName: state.toolName,
|
|
1031
1030
|
result: createToolResult({ state }),
|
|
1032
|
-
...state.values.status === "failed" ? { isError: true } : {}
|
|
1033
|
-
...state.dynamic ? { dynamic: true } : {}
|
|
1031
|
+
...state.values.status === "failed" ? { isError: true } : {}
|
|
1034
1032
|
});
|
|
1035
1033
|
state.emittedResult = true;
|
|
1036
1034
|
pendingToolCallIds.delete(state.toolCallId);
|
|
@@ -1345,6 +1343,31 @@ function mergeToolUpdate({
|
|
|
1345
1343
|
});
|
|
1346
1344
|
if (programmaticName != null) state.values.name = programmaticName;
|
|
1347
1345
|
}
|
|
1346
|
+
function createACPToolCall({ state }) {
|
|
1347
|
+
const title = getStringProperty2({
|
|
1348
|
+
value: state.values,
|
|
1349
|
+
property: "title"
|
|
1350
|
+
});
|
|
1351
|
+
const kind = state.values.kind;
|
|
1352
|
+
const status = state.values.status;
|
|
1353
|
+
return {
|
|
1354
|
+
toolCallId: state.toolCallId,
|
|
1355
|
+
title: title ?? state.toolName ?? `Tool ${state.toolCallId}`,
|
|
1356
|
+
...isACPToolKind(kind) ? { kind } : {},
|
|
1357
|
+
...isACPToolCallStatus(status) ? { status } : {},
|
|
1358
|
+
...Array.isArray(state.values.content) ? { content: state.values.content } : {},
|
|
1359
|
+
...Array.isArray(state.values.locations) ? { locations: state.values.locations } : {},
|
|
1360
|
+
...Object.prototype.hasOwnProperty.call(state.values, "rawInput") ? { rawInput: state.values.rawInput } : {},
|
|
1361
|
+
...Object.prototype.hasOwnProperty.call(state.values, "rawOutput") ? { rawOutput: state.values.rawOutput } : {},
|
|
1362
|
+
...state.values._meta === null || isRecord3(state.values._meta) ? { _meta: state.values._meta } : {}
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
function isACPToolKind(value) {
|
|
1366
|
+
return value === "read" || value === "edit" || value === "delete" || value === "move" || value === "search" || value === "execute" || value === "think" || value === "fetch" || value === "switch_mode" || value === "other";
|
|
1367
|
+
}
|
|
1368
|
+
function isACPToolCallStatus(value) {
|
|
1369
|
+
return value === "pending" || value === "in_progress" || value === "completed" || value === "failed";
|
|
1370
|
+
}
|
|
1348
1371
|
function emitFileChanges({
|
|
1349
1372
|
state,
|
|
1350
1373
|
emit
|
|
@@ -1946,11 +1969,16 @@ function isTerminalToolUpdate(message) {
|
|
|
1946
1969
|
// src/v1/bridge/create-emit-stream-event.ts
|
|
1947
1970
|
function createEmitStreamEvent({
|
|
1948
1971
|
emit,
|
|
1972
|
+
emitToolCallCandidate,
|
|
1949
1973
|
builtinTools,
|
|
1950
1974
|
hostToolServerName,
|
|
1951
1975
|
hostTools
|
|
1952
1976
|
}) {
|
|
1953
|
-
const translator = createACPStreamTranslator({
|
|
1977
|
+
const translator = createACPStreamTranslator({
|
|
1978
|
+
emit,
|
|
1979
|
+
emitToolCallCandidate,
|
|
1980
|
+
builtinTools
|
|
1981
|
+
});
|
|
1954
1982
|
const correlation = createHostToolCorrelation({
|
|
1955
1983
|
emitSemanticUpdate: ({ message, rawUpdate }) => {
|
|
1956
1984
|
translator.update({
|
|
@@ -1996,6 +2024,90 @@ function createEmitStreamEvent({
|
|
|
1996
2024
|
};
|
|
1997
2025
|
}
|
|
1998
2026
|
|
|
2027
|
+
// src/v1/bridge/instruction-mapping.ts
|
|
2028
|
+
import { z as z2 } from "zod/v4";
|
|
2029
|
+
var UNSAFE_PATH_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2030
|
+
var serializableRecordSchema2 = z2.record(z2.string(), z2.json());
|
|
2031
|
+
async function resolveACPInstructionConfiguration({
|
|
2032
|
+
instructions,
|
|
2033
|
+
instructionMapping,
|
|
2034
|
+
sessionMeta,
|
|
2035
|
+
environment
|
|
2036
|
+
}) {
|
|
2037
|
+
const resolvedEnvironment = { ...environment };
|
|
2038
|
+
if (instructionMapping == null || instructions == null || instructions.length === 0) {
|
|
2039
|
+
return { sessionMeta, environment: resolvedEnvironment };
|
|
2040
|
+
}
|
|
2041
|
+
assertSafePath({ path: instructionMapping.path });
|
|
2042
|
+
if (instructionMapping.type === "session-meta") {
|
|
2043
|
+
return {
|
|
2044
|
+
sessionMeta: setStringAtPath({
|
|
2045
|
+
record: sessionMeta ?? {},
|
|
2046
|
+
path: instructionMapping.path,
|
|
2047
|
+
value: instructions
|
|
2048
|
+
}),
|
|
2049
|
+
environment: resolvedEnvironment
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
const serialized = resolvedEnvironment[instructionMapping.variable];
|
|
2053
|
+
let configuration = {};
|
|
2054
|
+
if (serialized != null && serialized.length > 0) {
|
|
2055
|
+
configuration = parseSerializableRecord({
|
|
2056
|
+
serialized,
|
|
2057
|
+
variable: instructionMapping.variable
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
resolvedEnvironment[instructionMapping.variable] = JSON.stringify(
|
|
2061
|
+
setStringAtPath({
|
|
2062
|
+
record: configuration,
|
|
2063
|
+
path: instructionMapping.path,
|
|
2064
|
+
value: instructions
|
|
2065
|
+
})
|
|
2066
|
+
);
|
|
2067
|
+
return { sessionMeta, environment: resolvedEnvironment };
|
|
2068
|
+
}
|
|
2069
|
+
function parseSerializableRecord({
|
|
2070
|
+
serialized,
|
|
2071
|
+
variable
|
|
2072
|
+
}) {
|
|
2073
|
+
try {
|
|
2074
|
+
const result = serializableRecordSchema2.safeParse(JSON.parse(serialized));
|
|
2075
|
+
if (result.success) return result.data;
|
|
2076
|
+
} catch {
|
|
2077
|
+
}
|
|
2078
|
+
throw new Error(
|
|
2079
|
+
`ACP instruction mapping environment variable ${JSON.stringify(variable)} must contain a JSON object.`
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
function setStringAtPath({
|
|
2083
|
+
record,
|
|
2084
|
+
path,
|
|
2085
|
+
value
|
|
2086
|
+
}) {
|
|
2087
|
+
const [key, ...remainingPath] = path;
|
|
2088
|
+
if (key == null) return { ...record };
|
|
2089
|
+
return {
|
|
2090
|
+
...record,
|
|
2091
|
+
[key]: remainingPath.length === 0 ? value : setStringAtPath({
|
|
2092
|
+
record: isRecord5(record[key]) ? record[key] : {},
|
|
2093
|
+
path: remainingPath,
|
|
2094
|
+
value
|
|
2095
|
+
})
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
function assertSafePath({ path }) {
|
|
2099
|
+
if (path.length === 0 || path.some(
|
|
2100
|
+
(segment) => segment.length === 0 || UNSAFE_PATH_SEGMENTS.has(segment)
|
|
2101
|
+
)) {
|
|
2102
|
+
throw new Error(
|
|
2103
|
+
"ACP instruction mapping path must contain only safe, non-empty property names."
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
function isRecord5(value) {
|
|
2108
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
2109
|
+
}
|
|
2110
|
+
|
|
1999
2111
|
// src/v1/bridge/host-tool-relay.ts
|
|
2000
2112
|
import { randomBytes, timingSafeEqual } from "crypto";
|
|
2001
2113
|
import { createServer } from "http";
|
|
@@ -2122,7 +2234,7 @@ async function handleCatalogNext({
|
|
|
2122
2234
|
body,
|
|
2123
2235
|
state
|
|
2124
2236
|
}) {
|
|
2125
|
-
if (!
|
|
2237
|
+
if (!isRecord6(body) || !Number.isSafeInteger(body.afterRevision) || body.afterRevision < 0) {
|
|
2126
2238
|
throw new RelayRequestError({
|
|
2127
2239
|
status: 400,
|
|
2128
2240
|
message: "Invalid host tool catalog poll request."
|
|
@@ -2141,7 +2253,7 @@ function handleCatalogSeen({
|
|
|
2141
2253
|
body,
|
|
2142
2254
|
state
|
|
2143
2255
|
}) {
|
|
2144
|
-
if (!
|
|
2256
|
+
if (!isRecord6(body) || !Number.isSafeInteger(body.revision) || body.revision < 1 || body.revision > state.revision) {
|
|
2145
2257
|
throw new RelayRequestError({
|
|
2146
2258
|
status: 400,
|
|
2147
2259
|
message: "Invalid host tool catalog acknowledgment."
|
|
@@ -2167,7 +2279,7 @@ async function handleInvocation({
|
|
|
2167
2279
|
message: "No ACP prompt turn is active."
|
|
2168
2280
|
});
|
|
2169
2281
|
}
|
|
2170
|
-
if (!
|
|
2282
|
+
if (!isRecord6(body) || typeof body.requestId !== "string" || typeof body.toolName !== "string" || !isRecord6(body.input) || !Number.isSafeInteger(body.catalogRevision)) {
|
|
2171
2283
|
throw new RelayRequestError({
|
|
2172
2284
|
status: 400,
|
|
2173
2285
|
message: "Invalid host tool relay request."
|
|
@@ -2283,7 +2395,7 @@ function canonicalizeJSON2({ value }) {
|
|
|
2283
2395
|
if (Array.isArray(value)) {
|
|
2284
2396
|
return value.map((item) => canonicalizeJSON2({ value: item }));
|
|
2285
2397
|
}
|
|
2286
|
-
if (!
|
|
2398
|
+
if (!isRecord6(value)) return value;
|
|
2287
2399
|
return Object.fromEntries(
|
|
2288
2400
|
Object.keys(value).sort().filter((key) => value[key] !== void 0).map((key) => [key, canonicalizeJSON2({ value: value[key] })])
|
|
2289
2401
|
);
|
|
@@ -2341,7 +2453,7 @@ function closeServer({ server }) {
|
|
|
2341
2453
|
});
|
|
2342
2454
|
});
|
|
2343
2455
|
}
|
|
2344
|
-
function
|
|
2456
|
+
function isRecord6(value) {
|
|
2345
2457
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
2346
2458
|
}
|
|
2347
2459
|
var RelayRequestError = class extends Error {
|
|
@@ -2906,6 +3018,12 @@ async function runTurn(start, turn) {
|
|
|
2906
3018
|
turn.emit({ type: "stream-start" });
|
|
2907
3019
|
const emitStreamEvent = createEmitStreamEvent({
|
|
2908
3020
|
emit: (event) => turn.emit(event),
|
|
3021
|
+
emitToolCallCandidate: ({ toolCall }) => {
|
|
3022
|
+
turn.emit({
|
|
3023
|
+
type: "acp-tool-call-candidate",
|
|
3024
|
+
toolCall
|
|
3025
|
+
});
|
|
3026
|
+
},
|
|
2909
3027
|
builtinTools: start.builtinTools,
|
|
2910
3028
|
hostToolServerName: HOST_TOOL_MCP_SERVER_NAME,
|
|
2911
3029
|
hostTools: start.tools ?? []
|
|
@@ -2990,8 +3108,10 @@ async function ensureSession({
|
|
|
2990
3108
|
authentication: bridgeConfiguration.authentication,
|
|
2991
3109
|
providerAuthentication: bridgeConfiguration.providerAuthentication,
|
|
2992
3110
|
sessionMeta: bridgeConfiguration.sessionMeta,
|
|
3111
|
+
instructionMapping: start.instructionMapping,
|
|
2993
3112
|
permissionMode: start.permissionMode,
|
|
2994
|
-
permissionModeMapping: start.permissionModeMapping
|
|
3113
|
+
permissionModeMapping: start.permissionModeMapping,
|
|
3114
|
+
mcpServers: start.mcpServers
|
|
2995
3115
|
});
|
|
2996
3116
|
if (session != null) {
|
|
2997
3117
|
if (catalogRefreshError != null) throw catalogRefreshError;
|
|
@@ -3026,12 +3146,18 @@ async function ensureSession({
|
|
|
3026
3146
|
providerAuthentication: bridgeConfiguration.providerAuthentication,
|
|
3027
3147
|
gateway
|
|
3028
3148
|
});
|
|
3149
|
+
const instructionConfiguration = await resolveACPInstructionConfiguration({
|
|
3150
|
+
instructions: start.instructions,
|
|
3151
|
+
instructionMapping: start.instructionMapping,
|
|
3152
|
+
sessionMeta: bridgeConfiguration.sessionMeta,
|
|
3153
|
+
environment: createChildEnvironment({ launchEnv })
|
|
3154
|
+
});
|
|
3029
3155
|
child = spawn(
|
|
3030
3156
|
`${implementationDir}/node_modules/.bin/${implementation.executable}`,
|
|
3031
3157
|
[...implementation.args],
|
|
3032
3158
|
{
|
|
3033
3159
|
cwd: workDir,
|
|
3034
|
-
env:
|
|
3160
|
+
env: instructionConfiguration.environment,
|
|
3035
3161
|
shell: false,
|
|
3036
3162
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3037
3163
|
}
|
|
@@ -3088,6 +3214,10 @@ async function ensureSession({
|
|
|
3088
3214
|
authentication
|
|
3089
3215
|
});
|
|
3090
3216
|
}
|
|
3217
|
+
const externalMcpServers = createExternalMcpServers({
|
|
3218
|
+
mcpServers: start.mcpServers,
|
|
3219
|
+
initialization
|
|
3220
|
+
});
|
|
3091
3221
|
const tools = start.tools ?? [];
|
|
3092
3222
|
const catalogPath = `${bridgeStateDir}/host-tools.json`;
|
|
3093
3223
|
await writeFile2(catalogPath, JSON.stringify(tools), { mode: 384 });
|
|
@@ -3096,6 +3226,7 @@ async function ensureSession({
|
|
|
3096
3226
|
serverName: HOST_TOOL_MCP_SERVER_NAME
|
|
3097
3227
|
});
|
|
3098
3228
|
const mcpServers = [
|
|
3229
|
+
...externalMcpServers,
|
|
3099
3230
|
{
|
|
3100
3231
|
name: HOST_TOOL_MCP_SERVER_NAME,
|
|
3101
3232
|
command: process.execPath,
|
|
@@ -3125,7 +3256,7 @@ async function ensureSession({
|
|
|
3125
3256
|
sessionId: recoveredSessionId,
|
|
3126
3257
|
cwd: workDir,
|
|
3127
3258
|
mcpServers,
|
|
3128
|
-
...
|
|
3259
|
+
...instructionConfiguration.sessionMeta == null ? {} : { _meta: instructionConfiguration.sessionMeta }
|
|
3129
3260
|
});
|
|
3130
3261
|
createdSession = createACPRecoveredSession({
|
|
3131
3262
|
agent: connection.agent,
|
|
@@ -3142,7 +3273,7 @@ async function ensureSession({
|
|
|
3142
3273
|
sessionId: recoveredSessionId,
|
|
3143
3274
|
cwd: workDir,
|
|
3144
3275
|
mcpServers,
|
|
3145
|
-
meta:
|
|
3276
|
+
meta: instructionConfiguration.sessionMeta,
|
|
3146
3277
|
harnessId: bridgeType,
|
|
3147
3278
|
setHistoricalUpdatesSuppressed: ({ suppressed }) => {
|
|
3148
3279
|
historicalUpdatesSuppressed = suppressed;
|
|
@@ -3162,7 +3293,7 @@ async function ensureSession({
|
|
|
3162
3293
|
createdSession = await connection.agent.buildSession({
|
|
3163
3294
|
cwd: workDir,
|
|
3164
3295
|
mcpServers,
|
|
3165
|
-
...
|
|
3296
|
+
...instructionConfiguration.sessionMeta == null ? {} : { _meta: instructionConfiguration.sessionMeta }
|
|
3166
3297
|
}).start();
|
|
3167
3298
|
}
|
|
3168
3299
|
try {
|
|
@@ -3197,6 +3328,33 @@ async function ensureSession({
|
|
|
3197
3328
|
});
|
|
3198
3329
|
sessionConfigurationFingerprint = fingerprint;
|
|
3199
3330
|
}
|
|
3331
|
+
function createExternalMcpServers({
|
|
3332
|
+
mcpServers,
|
|
3333
|
+
initialization
|
|
3334
|
+
}) {
|
|
3335
|
+
if (mcpServers == null) return [];
|
|
3336
|
+
return Object.entries(mcpServers).map(([name2, value]) => {
|
|
3337
|
+
if (!isRecord7(value)) {
|
|
3338
|
+
throw new Error(
|
|
3339
|
+
`ACP MCP server ${JSON.stringify(name2)} must be configured with an object value.`
|
|
3340
|
+
);
|
|
3341
|
+
}
|
|
3342
|
+
if (value.type === "acp") {
|
|
3343
|
+
throw new HarnessBridgeCapabilityUnsupportedError({
|
|
3344
|
+
harnessId: bridgeType,
|
|
3345
|
+
message: "ACP-transport MCP servers require client-side mcp/connect handling, which this harness does not provide."
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
const mcpCapabilities = initialization.agentCapabilities?.mcpCapabilities;
|
|
3349
|
+
if (value.type === "http" && mcpCapabilities?.http !== true || value.type === "sse" && mcpCapabilities?.sse !== true) {
|
|
3350
|
+
throw new HarnessBridgeCapabilityUnsupportedError({
|
|
3351
|
+
harnessId: bridgeType,
|
|
3352
|
+
message: `The ACP agent does not advertise support for ${value.type.toUpperCase()} MCP servers.`
|
|
3353
|
+
});
|
|
3354
|
+
}
|
|
3355
|
+
return { ...value, name: name2 };
|
|
3356
|
+
});
|
|
3357
|
+
}
|
|
3200
3358
|
function unknownUsage2() {
|
|
3201
3359
|
return {
|
|
3202
3360
|
inputTokens: {
|
|
@@ -3272,7 +3430,7 @@ function createChildEnvironment({
|
|
|
3272
3430
|
...launchEnv
|
|
3273
3431
|
};
|
|
3274
3432
|
}
|
|
3275
|
-
function
|
|
3433
|
+
function isRecord7(value) {
|
|
3276
3434
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
3277
3435
|
}
|
|
3278
3436
|
async function readImplementationDescriptor({
|
|
@@ -3282,7 +3440,7 @@ async function readImplementationDescriptor({
|
|
|
3282
3440
|
const value = await new Response(text, {
|
|
3283
3441
|
headers: { "content-type": "application/json" }
|
|
3284
3442
|
}).json();
|
|
3285
|
-
if (!
|
|
3443
|
+
if (!isRecord7(value) || typeof value.executable !== "string" || !Array.isArray(value.args) || !value.args.every((item) => typeof item === "string") || !Array.isArray(value.envKeys) || !value.envKeys.every((item) => typeof item === "string")) {
|
|
3286
3444
|
throw new Error("Invalid ACP implementation descriptor.");
|
|
3287
3445
|
}
|
|
3288
3446
|
return {
|