@ai-sdk/harness-acp 1.0.38 → 1.0.40
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 +24 -0
- package/README.md +4 -3
- package/dist/bridge/host-tool-mcp.mjs +1 -1
- package/dist/bridge/index.mjs +556 -43
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.d.ts +56 -6
- package/dist/index.js +280 -72
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/acp-harness.ts +51 -9
- package/src/index.ts +2 -0
- package/src/v1/acp-v1-bridge-protocol.ts +19 -0
- package/src/v1/acp-v1-harness.ts +307 -19
- package/src/v1/acp-v1-settings.ts +42 -0
- package/src/v1/acp-v1-skills.ts +4 -65
- package/src/v1/bridge/acp-v1-bridge-environment.ts +16 -0
- package/src/v1/bridge/create-emit-stream-event.ts +6 -0
- package/src/v1/bridge/host-tool-correlation.ts +34 -0
- package/src/v1/bridge/host-tool-mcp-definition.ts +69 -0
- package/src/v1/bridge/host-tool-mcp-http.ts +182 -0
- package/src/v1/bridge/host-tool-relay.ts +87 -7
- package/src/v1/bridge/index.ts +111 -24
- package/src/v1/bridge/instruction-mapping.ts +12 -0
- package/src/v1/bridge/stream-translator.ts +41 -2
- package/src/v1/index.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// src/acp-harness.ts
|
|
2
|
+
import {
|
|
3
|
+
HARNESS_V1_BUILTIN_TOOLS
|
|
4
|
+
} from "@ai-sdk/harness";
|
|
2
5
|
import { z as z4 } from "zod/v4";
|
|
3
6
|
|
|
4
7
|
// src/v1/acp-v1-harness.ts
|
|
@@ -26,7 +29,9 @@ import {
|
|
|
26
29
|
shellQuote,
|
|
27
30
|
warnCredentialBrokeringUnavailable,
|
|
28
31
|
waitForBridgeReady,
|
|
29
|
-
withBridgeToken
|
|
32
|
+
withBridgeToken,
|
|
33
|
+
writeInstructions,
|
|
34
|
+
writeSkills
|
|
30
35
|
} from "@ai-sdk/harness/utils";
|
|
31
36
|
import {
|
|
32
37
|
asSchema
|
|
@@ -706,6 +711,10 @@ var instructionMappingSchema = z2.discriminatedUnion("type", [
|
|
|
706
711
|
type: z2.literal("launch-env-json"),
|
|
707
712
|
variable: z2.string().min(1),
|
|
708
713
|
path: instructionMappingPathSchema
|
|
714
|
+
}),
|
|
715
|
+
z2.object({
|
|
716
|
+
type: z2.literal("filesystem"),
|
|
717
|
+
path: z2.string().min(1)
|
|
709
718
|
})
|
|
710
719
|
]);
|
|
711
720
|
var outputSchemaMappingSchema = z2.object({
|
|
@@ -756,13 +765,26 @@ var coldRestoreSchema = z2.object({
|
|
|
756
765
|
});
|
|
757
766
|
var acpToolCallCandidateSchema = z2.object({
|
|
758
767
|
type: z2.literal("acp-tool-call-candidate"),
|
|
768
|
+
requestId: z2.string(),
|
|
759
769
|
toolCall: z2.custom(
|
|
760
770
|
(value) => value != null && typeof value === "object" && typeof value.toolCallId === "string" && typeof value.title === "string"
|
|
761
771
|
)
|
|
762
772
|
});
|
|
773
|
+
var acpQuestionRequestSchema = z2.object({
|
|
774
|
+
type: z2.literal("acp-question-request"),
|
|
775
|
+
requestId: z2.string(),
|
|
776
|
+
nativeRequest: z2.unknown(),
|
|
777
|
+
nativeToolCall: acpToolCallCandidateSchema.shape.toolCall.optional()
|
|
778
|
+
});
|
|
779
|
+
var acpQuestionResolvedSchema = z2.object({
|
|
780
|
+
type: z2.literal("acp-question-resolved"),
|
|
781
|
+
requestId: z2.string()
|
|
782
|
+
});
|
|
763
783
|
var outboundMessageSchema = z2.union([
|
|
764
784
|
harnessV1BridgeOutboundMessageSchema,
|
|
765
|
-
acpToolCallCandidateSchema
|
|
785
|
+
acpToolCallCandidateSchema,
|
|
786
|
+
acpQuestionRequestSchema,
|
|
787
|
+
acpQuestionResolvedSchema
|
|
766
788
|
]);
|
|
767
789
|
var startMessageSchema = harnessV1BridgeStartBaseSchema.extend({
|
|
768
790
|
prompt: z2.array(acpTextContentBlockSchema),
|
|
@@ -809,6 +831,10 @@ var profileValueSchema = z3.lazy(
|
|
|
809
831
|
z3.record(z3.string(), profileValueSchema)
|
|
810
832
|
])
|
|
811
833
|
);
|
|
834
|
+
var hostToolMcpTransportSchema = z3.enum([
|
|
835
|
+
"stdio",
|
|
836
|
+
"http"
|
|
837
|
+
]);
|
|
812
838
|
var serializableRecordSchema = z3.record(z3.string(), serializableValueSchema);
|
|
813
839
|
var profileRecordSchema = z3.record(z3.string(), profileValueSchema);
|
|
814
840
|
var authenticationSchema = z3.object({
|
|
@@ -828,14 +854,18 @@ var bridgeConfigurationSchema = z3.object({
|
|
|
828
854
|
providerAuthentication: providerAuthenticationSchema.optional(),
|
|
829
855
|
providerEnvironment: z3.record(z3.string(), z3.string()).optional(),
|
|
830
856
|
sessionMeta: serializableRecordSchema.optional(),
|
|
831
|
-
clientCapabilities: serializableRecordSchema.optional()
|
|
857
|
+
clientCapabilities: serializableRecordSchema.optional(),
|
|
858
|
+
askUserQuestionsRequestMethod: z3.string().optional(),
|
|
859
|
+
hostToolMcpTransport: hostToolMcpTransportSchema.optional()
|
|
832
860
|
});
|
|
833
861
|
function createACPBridgeEnvironment({
|
|
834
862
|
authentication,
|
|
835
863
|
providerAuthentication,
|
|
836
864
|
providerEnvironment,
|
|
837
865
|
sessionMeta,
|
|
838
|
-
clientCapabilities
|
|
866
|
+
clientCapabilities,
|
|
867
|
+
askUserQuestionsRequestMethod,
|
|
868
|
+
hostToolMcpTransport
|
|
839
869
|
}) {
|
|
840
870
|
return {
|
|
841
871
|
[ACP_BRIDGE_CONFIGURATION_ENV]: JSON.stringify({
|
|
@@ -843,7 +873,9 @@ function createACPBridgeEnvironment({
|
|
|
843
873
|
...providerAuthentication == null ? {} : { providerAuthentication },
|
|
844
874
|
...providerEnvironment == null ? {} : { providerEnvironment },
|
|
845
875
|
...sessionMeta == null ? {} : { sessionMeta },
|
|
846
|
-
...clientCapabilities == null ? {} : { clientCapabilities }
|
|
876
|
+
...clientCapabilities == null ? {} : { clientCapabilities },
|
|
877
|
+
...askUserQuestionsRequestMethod == null ? {} : { askUserQuestionsRequestMethod },
|
|
878
|
+
...hostToolMcpTransport == null ? {} : { hostToolMcpTransport }
|
|
847
879
|
})
|
|
848
880
|
};
|
|
849
881
|
}
|
|
@@ -1066,51 +1098,25 @@ function validateACPLifecycleCompatibility({
|
|
|
1066
1098
|
// src/v1/acp-v1-skills.ts
|
|
1067
1099
|
import { createHash as createHash4 } from "crypto";
|
|
1068
1100
|
import path from "path";
|
|
1069
|
-
import { writeSkills } from "@ai-sdk/harness/utils";
|
|
1070
1101
|
var ACP_SKILL_NAME_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
1071
1102
|
var DEFAULT_ACP_SKILLS_DIRECTORY = ".agents/skills";
|
|
1072
1103
|
function resolveACPPrivateSessionDirectory({
|
|
1073
1104
|
sandboxHomeDir,
|
|
1074
|
-
sessionWorkDir,
|
|
1075
1105
|
harnessId,
|
|
1076
1106
|
sessionId
|
|
1077
1107
|
}) {
|
|
1078
1108
|
const sessionKey = createHash4("sha256").update(sessionId).digest("hex");
|
|
1079
|
-
|
|
1109
|
+
return path.posix.join(
|
|
1080
1110
|
sandboxHomeDir,
|
|
1081
1111
|
".ai-sdk",
|
|
1082
1112
|
"harness-acp",
|
|
1083
1113
|
harnessId,
|
|
1084
1114
|
sessionKey
|
|
1085
1115
|
);
|
|
1086
|
-
assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
|
|
1087
|
-
return rootDir;
|
|
1088
|
-
}
|
|
1089
|
-
async function materializeACPSkills({
|
|
1090
|
-
sandbox,
|
|
1091
|
-
rootDir,
|
|
1092
|
-
sessionWorkDir,
|
|
1093
|
-
skills,
|
|
1094
|
-
abortSignal
|
|
1095
|
-
}) {
|
|
1096
|
-
validateACPSkills({ skills });
|
|
1097
|
-
assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
|
|
1098
|
-
return writeSkills({
|
|
1099
|
-
sandbox,
|
|
1100
|
-
rootDir,
|
|
1101
|
-
skills,
|
|
1102
|
-
abortSignal,
|
|
1103
|
-
skillNamePattern: ACP_SKILL_NAME_PATTERN,
|
|
1104
|
-
invalidSkillNameMessage: ({ name }) => `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
|
|
1105
|
-
invalidSkillFilePathMessage: ({ skillName, filePath }) => `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
|
|
1106
|
-
skillName
|
|
1107
|
-
)}: expected a relative POSIX path without traversal.`
|
|
1108
|
-
});
|
|
1109
1116
|
}
|
|
1110
1117
|
function resolveACPSkillsDirectory({
|
|
1111
1118
|
implementationHomeDir,
|
|
1112
|
-
skillsDirectory = DEFAULT_ACP_SKILLS_DIRECTORY
|
|
1113
|
-
sessionWorkDir
|
|
1119
|
+
skillsDirectory = DEFAULT_ACP_SKILLS_DIRECTORY
|
|
1114
1120
|
}) {
|
|
1115
1121
|
const containsTraversal = skillsDirectory.split(/[\\/]/).some((segment) => segment === "..");
|
|
1116
1122
|
const normalizedDirectory = path.posix.normalize(skillsDirectory);
|
|
@@ -1119,9 +1125,7 @@ function resolveACPSkillsDirectory({
|
|
|
1119
1125
|
`ACP skillsDirectory ${JSON.stringify(skillsDirectory)} must be a relative POSIX path without traversal.`
|
|
1120
1126
|
);
|
|
1121
1127
|
}
|
|
1122
|
-
|
|
1123
|
-
assertOutsideSessionWorkDir({ rootDir, sessionWorkDir });
|
|
1124
|
-
return rootDir;
|
|
1128
|
+
return path.posix.join(implementationHomeDir, normalizedDirectory);
|
|
1125
1129
|
}
|
|
1126
1130
|
function validateACPSkills({
|
|
1127
1131
|
skills
|
|
@@ -1179,20 +1183,6 @@ function validateACPAttachedFilePath({
|
|
|
1179
1183
|
}
|
|
1180
1184
|
return normalizedPath;
|
|
1181
1185
|
}
|
|
1182
|
-
function assertOutsideSessionWorkDir({
|
|
1183
|
-
rootDir,
|
|
1184
|
-
sessionWorkDir
|
|
1185
|
-
}) {
|
|
1186
|
-
const relative = path.posix.relative(sessionWorkDir, rootDir);
|
|
1187
|
-
const isInside = relative === "" || !relative.startsWith("../") && !path.posix.isAbsolute(relative);
|
|
1188
|
-
if (isInside) {
|
|
1189
|
-
throw new Error(
|
|
1190
|
-
`ACP skill directory ${JSON.stringify(rootDir)} must be outside sessionWorkDir ${JSON.stringify(
|
|
1191
|
-
sessionWorkDir
|
|
1192
|
-
)}.`
|
|
1193
|
-
);
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
1186
|
|
|
1197
1187
|
// src/v1/acp-v1-harness.ts
|
|
1198
1188
|
var HARNESS_ID_REGEXP = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
@@ -1359,7 +1349,8 @@ function createACPV1({
|
|
|
1359
1349
|
};
|
|
1360
1350
|
const requestTransformations = settings.credentialBrokering({
|
|
1361
1351
|
env: brokeringEnvironment,
|
|
1362
|
-
sandboxEnv: sandboxImplementationEnvironment
|
|
1352
|
+
sandboxEnv: sandboxImplementationEnvironment,
|
|
1353
|
+
...startOptions.headers == null ? {} : { headers: startOptions.headers }
|
|
1363
1354
|
});
|
|
1364
1355
|
if (requestTransformations.length > 0) {
|
|
1365
1356
|
await sandboxSession.addRequestTransformations(
|
|
@@ -1397,14 +1388,14 @@ function createACPV1({
|
|
|
1397
1388
|
});
|
|
1398
1389
|
const privateSessionDir = resolveACPPrivateSessionDirectory({
|
|
1399
1390
|
sandboxHomeDir,
|
|
1400
|
-
sessionWorkDir: workDir,
|
|
1401
1391
|
harnessId: settings.harnessId,
|
|
1402
1392
|
sessionId: startOptions.sessionId
|
|
1403
1393
|
});
|
|
1394
|
+
const implementationHomeDir = implementation.source.type === "install-command" ? `${resolvedImplementationDir}/home` : sandboxHomeDir;
|
|
1395
|
+
const skillsDir = settings.skillsDirectory ?? DEFAULT_ACP_SKILLS_DIRECTORY;
|
|
1404
1396
|
const skillsDirectory = resolveACPSkillsDirectory({
|
|
1405
|
-
implementationHomeDir
|
|
1406
|
-
skillsDirectory: settings.skillsDirectory
|
|
1407
|
-
sessionWorkDir: workDir
|
|
1397
|
+
implementationHomeDir,
|
|
1398
|
+
skillsDirectory: settings.skillsDirectory
|
|
1408
1399
|
});
|
|
1409
1400
|
const bridgeStateDir = `${privateSessionDir}/bridge`;
|
|
1410
1401
|
const report = startOptions.observability?.report;
|
|
@@ -1461,6 +1452,7 @@ function createACPV1({
|
|
|
1461
1452
|
sessionMeta: settings.session?.meta,
|
|
1462
1453
|
instructionMapping: settings.instructionMapping,
|
|
1463
1454
|
outputSchemaMapping: settings.outputSchemaMapping,
|
|
1455
|
+
askUserQuestions: settings.askUserQuestions,
|
|
1464
1456
|
debug: startOptions.observability?.debug,
|
|
1465
1457
|
implementationIdentity,
|
|
1466
1458
|
authenticationProfile,
|
|
@@ -1475,7 +1467,8 @@ function createACPV1({
|
|
|
1475
1467
|
}),
|
|
1476
1468
|
instructionsFingerprint: lifecycleData.instructionsFingerprint,
|
|
1477
1469
|
sandbox: toolSafeSandboxSession,
|
|
1478
|
-
|
|
1470
|
+
homePath: implementationHomeDir,
|
|
1471
|
+
skillsDir,
|
|
1479
1472
|
skillsDirectory,
|
|
1480
1473
|
acpSessionId: lifecycleData.acpSessionId,
|
|
1481
1474
|
bridgePort: coords.port,
|
|
@@ -1612,7 +1605,9 @@ function createACPV1({
|
|
|
1612
1605
|
providerAuthentication: resolvedProviderAuthentication.providerAuthentication,
|
|
1613
1606
|
providerEnvironment: sandboxProviderEnvironment == null ? void 0 : {},
|
|
1614
1607
|
sessionMeta: settings.session?.meta,
|
|
1615
|
-
clientCapabilities: settings.clientCapabilities
|
|
1608
|
+
clientCapabilities: settings.clientCapabilities,
|
|
1609
|
+
askUserQuestionsRequestMethod: settings.askUserQuestions?.requestMethod,
|
|
1610
|
+
hostToolMcpTransport: settings.hostToolMcpTransport
|
|
1616
1611
|
}),
|
|
1617
1612
|
...sandboxProviderAuthenticationEnvironment,
|
|
1618
1613
|
BRIDGE_CHANNEL_TOKEN: token,
|
|
@@ -1720,6 +1715,7 @@ function createACPV1({
|
|
|
1720
1715
|
sessionMeta: settings.session?.meta,
|
|
1721
1716
|
instructionMapping: settings.instructionMapping,
|
|
1722
1717
|
outputSchemaMapping: settings.outputSchemaMapping,
|
|
1718
|
+
askUserQuestions: settings.askUserQuestions,
|
|
1723
1719
|
debug: startOptions.observability?.debug,
|
|
1724
1720
|
implementationIdentity,
|
|
1725
1721
|
authenticationProfile,
|
|
@@ -1734,7 +1730,8 @@ function createACPV1({
|
|
|
1734
1730
|
}),
|
|
1735
1731
|
instructionsFingerprint: lifecycleData?.instructionsFingerprint,
|
|
1736
1732
|
sandbox: toolSafeSandboxSession,
|
|
1737
|
-
|
|
1733
|
+
homePath: implementationHomeDir,
|
|
1734
|
+
skillsDir,
|
|
1738
1735
|
skillsDirectory,
|
|
1739
1736
|
acpSessionId: lifecycleData?.acpSessionId,
|
|
1740
1737
|
bridgePort: boundPort,
|
|
@@ -1957,6 +1954,7 @@ function createSession({
|
|
|
1957
1954
|
sessionMeta,
|
|
1958
1955
|
instructionMapping,
|
|
1959
1956
|
outputSchemaMapping,
|
|
1957
|
+
askUserQuestions,
|
|
1960
1958
|
debug,
|
|
1961
1959
|
implementationIdentity,
|
|
1962
1960
|
authenticationProfile,
|
|
@@ -1968,7 +1966,8 @@ function createSession({
|
|
|
1968
1966
|
initialGuidanceApplied: initialGuidanceAppliedAtStart,
|
|
1969
1967
|
instructionsFingerprint: instructionsFingerprintAtStart,
|
|
1970
1968
|
sandbox,
|
|
1971
|
-
|
|
1969
|
+
homePath,
|
|
1970
|
+
skillsDir,
|
|
1972
1971
|
skillsDirectory,
|
|
1973
1972
|
acpSessionId: acpSessionIdAtStart,
|
|
1974
1973
|
bridgePort,
|
|
@@ -1990,6 +1989,7 @@ function createSession({
|
|
|
1990
1989
|
let instructionsFingerprint = instructionsFingerprintAtStart;
|
|
1991
1990
|
let latestACPSessionId = acpSessionIdAtStart;
|
|
1992
1991
|
let latestTurnStartConfig = turnStartConfigAtStart;
|
|
1992
|
+
const bufferedQuestionResults = /* @__PURE__ */ new Map();
|
|
1993
1993
|
const markTurnFinished = () => {
|
|
1994
1994
|
turnInFlight = false;
|
|
1995
1995
|
};
|
|
@@ -2019,6 +2019,8 @@ function createSession({
|
|
|
2019
2019
|
let openBlock;
|
|
2020
2020
|
const dynamicToolCalls = /* @__PURE__ */ new Map();
|
|
2021
2021
|
const toolCallClassificationErrors = /* @__PURE__ */ new Map();
|
|
2022
|
+
const activeQuestionRequests = /* @__PURE__ */ new Map();
|
|
2023
|
+
const questionToolCallIdsByRequestId = /* @__PURE__ */ new Map();
|
|
2022
2024
|
const subscriptions = [];
|
|
2023
2025
|
const forward = (event) => {
|
|
2024
2026
|
if (event.type === "text-start" || event.type === "reasoning-start") {
|
|
@@ -2082,12 +2084,115 @@ function createSession({
|
|
|
2082
2084
|
subscriptions.push(
|
|
2083
2085
|
channel.on("acp-tool-call-candidate", (event) => {
|
|
2084
2086
|
try {
|
|
2087
|
+
const suppress = askUserQuestions?.isNativeToolCall?.({
|
|
2088
|
+
nativeToolCall: event.toolCall
|
|
2089
|
+
}) === true;
|
|
2085
2090
|
dynamicToolCalls.set(
|
|
2086
2091
|
event.toolCall.toolCallId,
|
|
2087
2092
|
isMcpToolCall?.(event.toolCall) === true
|
|
2088
2093
|
);
|
|
2094
|
+
channel.send({
|
|
2095
|
+
type: "tool-result",
|
|
2096
|
+
toolCallId: event.requestId,
|
|
2097
|
+
output: { suppress }
|
|
2098
|
+
});
|
|
2089
2099
|
} catch (error) {
|
|
2090
2100
|
toolCallClassificationErrors.set(event.toolCall.toolCallId, error);
|
|
2101
|
+
channel.send({
|
|
2102
|
+
type: "tool-result",
|
|
2103
|
+
toolCallId: event.requestId,
|
|
2104
|
+
output: { suppress: false }
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
})
|
|
2108
|
+
);
|
|
2109
|
+
subscriptions.push(
|
|
2110
|
+
channel.on("acp-question-request", (event) => {
|
|
2111
|
+
if (askUserQuestions == null) {
|
|
2112
|
+
channel.send({
|
|
2113
|
+
type: "tool-result",
|
|
2114
|
+
toolCallId: event.requestId,
|
|
2115
|
+
output: { type: "unhandled" }
|
|
2116
|
+
});
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
try {
|
|
2120
|
+
const nativeToolCall = askUserQuestions.fromNativeRequest({
|
|
2121
|
+
nativeRequest: event.nativeRequest,
|
|
2122
|
+
nativeToolCall: event.nativeToolCall
|
|
2123
|
+
});
|
|
2124
|
+
if (nativeToolCall == null) {
|
|
2125
|
+
channel.send({
|
|
2126
|
+
type: "tool-result",
|
|
2127
|
+
toolCallId: event.requestId,
|
|
2128
|
+
output: { type: "unhandled" }
|
|
2129
|
+
});
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
if (nativeToolCall.toolName !== "askUserQuestions" || nativeToolCall.providerExecuted !== false) {
|
|
2133
|
+
throw new Error(
|
|
2134
|
+
`${harnessId} ACP askUserQuestions.fromNativeRequest must return a client-executed askUserQuestions tool call.`
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2137
|
+
const toolCall = withNativeQuestionRequest({
|
|
2138
|
+
harnessId,
|
|
2139
|
+
nativeRequest: event.nativeRequest,
|
|
2140
|
+
toolCall: nativeToolCall
|
|
2141
|
+
});
|
|
2142
|
+
const bufferedResult = takeBufferedQuestionResult({
|
|
2143
|
+
bufferedQuestionResults,
|
|
2144
|
+
toolCallId: toolCall.toolCallId,
|
|
2145
|
+
nativeRequest: event.nativeRequest,
|
|
2146
|
+
matchesNativeRequest: askUserQuestions.matchesNativeRequest,
|
|
2147
|
+
harnessId
|
|
2148
|
+
});
|
|
2149
|
+
activeQuestionRequests.set(toolCall.toolCallId, {
|
|
2150
|
+
requestId: event.requestId,
|
|
2151
|
+
nativeRequest: event.nativeRequest
|
|
2152
|
+
});
|
|
2153
|
+
questionToolCallIdsByRequestId.set(
|
|
2154
|
+
event.requestId,
|
|
2155
|
+
toolCall.toolCallId
|
|
2156
|
+
);
|
|
2157
|
+
channel.send({
|
|
2158
|
+
type: "tool-result",
|
|
2159
|
+
toolCallId: event.requestId,
|
|
2160
|
+
output: {
|
|
2161
|
+
type: "handled",
|
|
2162
|
+
toolCallId: toolCall.toolCallId
|
|
2163
|
+
}
|
|
2164
|
+
});
|
|
2165
|
+
if (bufferedResult == null) {
|
|
2166
|
+
forward(toolCall);
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
channel.send({
|
|
2170
|
+
type: "tool-result",
|
|
2171
|
+
toolCallId: toolCall.toolCallId,
|
|
2172
|
+
output: askUserQuestions.toNativeResponse({
|
|
2173
|
+
nativeRequest: event.nativeRequest,
|
|
2174
|
+
toolResult: bufferedResult.toolResult
|
|
2175
|
+
}),
|
|
2176
|
+
isError: bufferedResult.isError,
|
|
2177
|
+
toolResult: bufferedResult.toolResult
|
|
2178
|
+
});
|
|
2179
|
+
} catch (error) {
|
|
2180
|
+
closeForwardedBlock();
|
|
2181
|
+
forward({ type: "error", error });
|
|
2182
|
+
try {
|
|
2183
|
+
channel.send({ type: "abort" });
|
|
2184
|
+
} catch {
|
|
2185
|
+
}
|
|
2186
|
+
settle({ error });
|
|
2187
|
+
}
|
|
2188
|
+
})
|
|
2189
|
+
);
|
|
2190
|
+
subscriptions.push(
|
|
2191
|
+
channel.on("acp-question-resolved", (event) => {
|
|
2192
|
+
const toolCallId = questionToolCallIdsByRequestId.get(event.requestId);
|
|
2193
|
+
if (toolCallId != null) {
|
|
2194
|
+
activeQuestionRequests.delete(toolCallId);
|
|
2195
|
+
questionToolCallIdsByRequestId.delete(event.requestId);
|
|
2091
2196
|
}
|
|
2092
2197
|
})
|
|
2093
2198
|
);
|
|
@@ -2173,11 +2278,48 @@ function createSession({
|
|
|
2173
2278
|
});
|
|
2174
2279
|
},
|
|
2175
2280
|
submitToolResult: async (input) => {
|
|
2281
|
+
if (askUserQuestions != null && input.toolResult?.toolName === "askUserQuestions") {
|
|
2282
|
+
const activeRequest = activeQuestionRequests.get(input.toolCallId);
|
|
2283
|
+
if (activeRequest == null) {
|
|
2284
|
+
const previousNativeRequest = input.toolResult.providerOptions?.[harnessId]?.nativeRequest;
|
|
2285
|
+
if (!lossyRerun && previousNativeRequest !== void 0) {
|
|
2286
|
+
channel.send({
|
|
2287
|
+
type: "tool-result",
|
|
2288
|
+
toolCallId: input.toolCallId,
|
|
2289
|
+
output: askUserQuestions.toNativeResponse({
|
|
2290
|
+
nativeRequest: previousNativeRequest,
|
|
2291
|
+
toolResult: input.toolResult
|
|
2292
|
+
}),
|
|
2293
|
+
isError: input.isError,
|
|
2294
|
+
toolResult: input.toolResult
|
|
2295
|
+
});
|
|
2296
|
+
return;
|
|
2297
|
+
}
|
|
2298
|
+
bufferedQuestionResults.set(input.toolCallId, {
|
|
2299
|
+
output: input.output,
|
|
2300
|
+
...input.isError == null ? {} : { isError: input.isError },
|
|
2301
|
+
toolResult: input.toolResult
|
|
2302
|
+
});
|
|
2303
|
+
return;
|
|
2304
|
+
}
|
|
2305
|
+
channel.send({
|
|
2306
|
+
type: "tool-result",
|
|
2307
|
+
toolCallId: input.toolCallId,
|
|
2308
|
+
output: askUserQuestions.toNativeResponse({
|
|
2309
|
+
nativeRequest: activeRequest.nativeRequest,
|
|
2310
|
+
toolResult: input.toolResult
|
|
2311
|
+
}),
|
|
2312
|
+
isError: input.isError,
|
|
2313
|
+
toolResult: input.toolResult
|
|
2314
|
+
});
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2176
2317
|
channel.send({
|
|
2177
2318
|
type: "tool-result",
|
|
2178
2319
|
toolCallId: input.toolCallId,
|
|
2179
2320
|
output: input.output,
|
|
2180
|
-
isError: input.isError
|
|
2321
|
+
isError: input.isError,
|
|
2322
|
+
toolResult: input.toolResult
|
|
2181
2323
|
});
|
|
2182
2324
|
},
|
|
2183
2325
|
done
|
|
@@ -2241,14 +2383,34 @@ function createSession({
|
|
|
2241
2383
|
skills,
|
|
2242
2384
|
abortSignal
|
|
2243
2385
|
}) => {
|
|
2244
|
-
|
|
2386
|
+
validateACPSkills({ skills });
|
|
2387
|
+
await writeSkills({
|
|
2245
2388
|
sandbox,
|
|
2246
|
-
|
|
2247
|
-
|
|
2389
|
+
homePath,
|
|
2390
|
+
skillsDir,
|
|
2248
2391
|
skills,
|
|
2249
|
-
abortSignal
|
|
2392
|
+
abortSignal,
|
|
2393
|
+
skillNamePattern: ACP_SKILL_NAME_PATTERN,
|
|
2394
|
+
invalidSkillNameMessage: ({ name }) => `Invalid ACP skill name ${JSON.stringify(name)}: expected a kebab-case slug.`,
|
|
2395
|
+
invalidSkillFilePathMessage: ({ skillName, filePath }) => `Invalid ACP skill file path ${JSON.stringify(filePath)} for skill ${JSON.stringify(
|
|
2396
|
+
skillName
|
|
2397
|
+
)}: expected a relative POSIX path without traversal.`
|
|
2250
2398
|
});
|
|
2251
2399
|
};
|
|
2400
|
+
const synchronizeInstructions = async ({
|
|
2401
|
+
instructions,
|
|
2402
|
+
abortSignal
|
|
2403
|
+
}) => {
|
|
2404
|
+
if (instructionMapping?.type === "filesystem") {
|
|
2405
|
+
await writeInstructions({
|
|
2406
|
+
sandbox,
|
|
2407
|
+
homePath,
|
|
2408
|
+
instructionsFile: instructionMapping.path,
|
|
2409
|
+
instructions,
|
|
2410
|
+
abortSignal
|
|
2411
|
+
});
|
|
2412
|
+
}
|
|
2413
|
+
};
|
|
2252
2414
|
return {
|
|
2253
2415
|
sessionId,
|
|
2254
2416
|
isResume,
|
|
@@ -2257,6 +2419,10 @@ function createSession({
|
|
|
2257
2419
|
skills: options.skills,
|
|
2258
2420
|
abortSignal: options.abortSignal
|
|
2259
2421
|
});
|
|
2422
|
+
await synchronizeInstructions({
|
|
2423
|
+
instructions: options.instructions,
|
|
2424
|
+
abortSignal: options.abortSignal
|
|
2425
|
+
});
|
|
2260
2426
|
if (options.responseFormat?.type === "json") {
|
|
2261
2427
|
if (options.responseFormat.schema == null) {
|
|
2262
2428
|
throw unsupported({
|
|
@@ -2315,7 +2481,7 @@ function createSession({
|
|
|
2315
2481
|
turnInFlight = true;
|
|
2316
2482
|
channel.send({
|
|
2317
2483
|
type: "start",
|
|
2318
|
-
prompt: instructionsFingerprint !== nextInstructionsFingerprint && (instructionMapping == null || initialGuidanceApplied) ? prependACPInstructionGuidance({
|
|
2484
|
+
prompt: instructionMapping?.type !== "filesystem" && instructionsFingerprint !== nextInstructionsFingerprint && (instructionMapping == null || initialGuidanceApplied) ? prependACPInstructionGuidance({
|
|
2319
2485
|
prompt,
|
|
2320
2486
|
instructions: options.instructions
|
|
2321
2487
|
}) : prompt,
|
|
@@ -2346,6 +2512,10 @@ function createSession({
|
|
|
2346
2512
|
skills: options.skills,
|
|
2347
2513
|
abortSignal: options.abortSignal
|
|
2348
2514
|
});
|
|
2515
|
+
await synchronizeInstructions({
|
|
2516
|
+
instructions: options.instructions,
|
|
2517
|
+
abortSignal: options.abortSignal
|
|
2518
|
+
});
|
|
2349
2519
|
if (options.responseFormat?.type === "json") {
|
|
2350
2520
|
if (options.responseFormat.schema == null) {
|
|
2351
2521
|
throw unsupported({
|
|
@@ -2421,11 +2591,6 @@ function createSession({
|
|
|
2421
2591
|
`${harnessId} ACP session ${sessionId} is stopped; cannot suspend.`
|
|
2422
2592
|
);
|
|
2423
2593
|
}
|
|
2424
|
-
if (!turnInFlight) {
|
|
2425
|
-
throw new Error(
|
|
2426
|
-
`${harnessId} ACP session ${sessionId} has no in-flight turn to suspend.`
|
|
2427
|
-
);
|
|
2428
|
-
}
|
|
2429
2594
|
stopped = true;
|
|
2430
2595
|
const lastSeenEventId = await channel.suspend();
|
|
2431
2596
|
return {
|
|
@@ -2491,6 +2656,45 @@ function isCompletePermissionModeMapping({
|
|
|
2491
2656
|
}) {
|
|
2492
2657
|
return isPermissionModeMappingValue({ value: value?.["allow-reads"] }) && isPermissionModeMappingValue({ value: value?.["allow-edits"] }) && isPermissionModeMappingValue({ value: value?.["allow-all"] });
|
|
2493
2658
|
}
|
|
2659
|
+
function withNativeQuestionRequest({
|
|
2660
|
+
harnessId,
|
|
2661
|
+
nativeRequest,
|
|
2662
|
+
toolCall
|
|
2663
|
+
}) {
|
|
2664
|
+
const harnessMetadata = toolCall.providerMetadata?.[harnessId];
|
|
2665
|
+
return {
|
|
2666
|
+
...toolCall,
|
|
2667
|
+
providerMetadata: {
|
|
2668
|
+
...toolCall.providerMetadata,
|
|
2669
|
+
[harnessId]: {
|
|
2670
|
+
...harnessMetadata ?? {},
|
|
2671
|
+
nativeRequest
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
function takeBufferedQuestionResult({
|
|
2677
|
+
bufferedQuestionResults,
|
|
2678
|
+
toolCallId,
|
|
2679
|
+
nativeRequest,
|
|
2680
|
+
matchesNativeRequest,
|
|
2681
|
+
harnessId
|
|
2682
|
+
}) {
|
|
2683
|
+
const exact = bufferedQuestionResults.get(toolCallId);
|
|
2684
|
+
if (exact != null) {
|
|
2685
|
+
bufferedQuestionResults.delete(toolCallId);
|
|
2686
|
+
return exact;
|
|
2687
|
+
}
|
|
2688
|
+
if (matchesNativeRequest == null) return void 0;
|
|
2689
|
+
for (const [bufferedToolCallId, buffered] of bufferedQuestionResults) {
|
|
2690
|
+
const previousNativeRequest = buffered.toolResult.providerOptions?.[harnessId]?.nativeRequest;
|
|
2691
|
+
if (previousNativeRequest !== void 0 && matchesNativeRequest({ previousNativeRequest, nativeRequest })) {
|
|
2692
|
+
bufferedQuestionResults.delete(bufferedToolCallId);
|
|
2693
|
+
return buffered;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
return void 0;
|
|
2697
|
+
}
|
|
2494
2698
|
function isPermissionModeMappingValue({
|
|
2495
2699
|
value
|
|
2496
2700
|
}) {
|
|
@@ -2636,7 +2840,7 @@ function deserializeBridgeError({
|
|
|
2636
2840
|
}
|
|
2637
2841
|
|
|
2638
2842
|
// src/version.ts
|
|
2639
|
-
var VERSION = true ? "1.0.
|
|
2843
|
+
var VERSION = true ? "1.0.40" : "0.0.0-test";
|
|
2640
2844
|
|
|
2641
2845
|
// src/acp-harness.ts
|
|
2642
2846
|
var ACP_CLIENT_APP = {
|
|
@@ -2696,9 +2900,13 @@ function createACP(settings) {
|
|
|
2696
2900
|
switch (version) {
|
|
2697
2901
|
case "v1": {
|
|
2698
2902
|
const clientApp = settings.clientApp ?? ACP_CLIENT_APP;
|
|
2903
|
+
const builtinTools = settings.askUserQuestions == null ? settings.builtinTools ?? ACP_BUILTIN_TOOLS : {
|
|
2904
|
+
...settings.builtinTools ?? ACP_BUILTIN_TOOLS,
|
|
2905
|
+
askUserQuestions: HARNESS_V1_BUILTIN_TOOLS.askUserQuestions
|
|
2906
|
+
};
|
|
2699
2907
|
return createACPV1({
|
|
2700
2908
|
settings,
|
|
2701
|
-
builtinTools
|
|
2909
|
+
builtinTools,
|
|
2702
2910
|
port: settings.port,
|
|
2703
2911
|
portEndpoint: settings.portEndpoint,
|
|
2704
2912
|
startupTimeoutMs: settings.startupTimeoutMs,
|