@wrongstack/acp 1.0.32 → 1.0.35
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/dist/agent/protocol-contract.d.ts +0 -10
- package/dist/agent/protocol-handler.d.ts +1 -6
- package/dist/agent/server-agent-turn-content.d.ts +117 -0
- package/dist/agent/server-agent-turn.d.ts +4 -67
- package/dist/agent.js +138 -136
- package/dist/client/acp-session-prompt.d.ts +23 -0
- package/dist/client/acp-session.d.ts +1 -0
- package/dist/client.js +193 -169
- package/dist/index.js +193 -169
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2238,39 +2238,6 @@ async function ensureAuthenticated(host) {
|
|
|
2238
2238
|
);
|
|
2239
2239
|
}
|
|
2240
2240
|
|
|
2241
|
-
// src/client/acp-session-content.ts
|
|
2242
|
-
function textContent(text) {
|
|
2243
|
-
return { type: "text", text };
|
|
2244
|
-
}
|
|
2245
|
-
function imageContent(mimeType, data) {
|
|
2246
|
-
return { type: "image", mimeType, data };
|
|
2247
|
-
}
|
|
2248
|
-
function audioContent(mimeType, data) {
|
|
2249
|
-
return { type: "audio", mimeType, data };
|
|
2250
|
-
}
|
|
2251
|
-
function extractText(block) {
|
|
2252
|
-
if (typeof block !== "object" || block === null) return "";
|
|
2253
|
-
const b = block;
|
|
2254
|
-
if (b.type === "text" && typeof b.text === "string") return b.text;
|
|
2255
|
-
if (b.type === "resource" && b.resource && typeof b.resource === "object" && typeof b.resource.text === "string") {
|
|
2256
|
-
return b.resource.text;
|
|
2257
|
-
}
|
|
2258
|
-
return "";
|
|
2259
|
-
}
|
|
2260
|
-
function isRecord(v) {
|
|
2261
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2262
|
-
}
|
|
2263
|
-
function emptyRunResult(stopReason) {
|
|
2264
|
-
return {
|
|
2265
|
-
text: "",
|
|
2266
|
-
stopReason,
|
|
2267
|
-
hasText: false,
|
|
2268
|
-
toolCalls: [],
|
|
2269
|
-
diffs: [],
|
|
2270
|
-
thoughts: ""
|
|
2271
|
-
};
|
|
2272
|
-
}
|
|
2273
|
-
|
|
2274
2241
|
// src/client/acp-message-routing.ts
|
|
2275
2242
|
function isBestEffortAckMethod(method) {
|
|
2276
2243
|
return method === "mcp/connect" || method === "mcp/message" || method === "mcp/disconnect" || method === "elicitation/create" || method === "elicitation/complete";
|
|
@@ -2742,6 +2709,39 @@ function resolvePermissionDeadline(value) {
|
|
|
2742
2709
|
return DEFAULT_PERMISSION_TIMEOUT_MS;
|
|
2743
2710
|
}
|
|
2744
2711
|
|
|
2712
|
+
// src/client/acp-session-content.ts
|
|
2713
|
+
function textContent(text) {
|
|
2714
|
+
return { type: "text", text };
|
|
2715
|
+
}
|
|
2716
|
+
function imageContent(mimeType, data) {
|
|
2717
|
+
return { type: "image", mimeType, data };
|
|
2718
|
+
}
|
|
2719
|
+
function audioContent(mimeType, data) {
|
|
2720
|
+
return { type: "audio", mimeType, data };
|
|
2721
|
+
}
|
|
2722
|
+
function extractText(block) {
|
|
2723
|
+
if (typeof block !== "object" || block === null) return "";
|
|
2724
|
+
const b = block;
|
|
2725
|
+
if (b.type === "text" && typeof b.text === "string") return b.text;
|
|
2726
|
+
if (b.type === "resource" && b.resource && typeof b.resource === "object" && typeof b.resource.text === "string") {
|
|
2727
|
+
return b.resource.text;
|
|
2728
|
+
}
|
|
2729
|
+
return "";
|
|
2730
|
+
}
|
|
2731
|
+
function isRecord(v) {
|
|
2732
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2733
|
+
}
|
|
2734
|
+
function emptyRunResult(stopReason) {
|
|
2735
|
+
return {
|
|
2736
|
+
text: "",
|
|
2737
|
+
stopReason,
|
|
2738
|
+
hasText: false,
|
|
2739
|
+
toolCalls: [],
|
|
2740
|
+
diffs: [],
|
|
2741
|
+
thoughts: ""
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
2745
|
// src/client/acp-session-updates.ts
|
|
2746
2746
|
function createSessionScratch() {
|
|
2747
2747
|
return { text: "", thoughts: "", toolCalls: /* @__PURE__ */ new Map(), diffs: [] };
|
|
@@ -2937,6 +2937,146 @@ function emitProgress(event) {
|
|
|
2937
2937
|
}
|
|
2938
2938
|
}
|
|
2939
2939
|
|
|
2940
|
+
// src/client/acp-session-prompt.ts
|
|
2941
|
+
async function prompt(host, blocks, signal, onProgress) {
|
|
2942
|
+
if (host.closed) {
|
|
2943
|
+
throw new ACPSessionError("closed", "session is closed");
|
|
2944
|
+
}
|
|
2945
|
+
if (host.state !== "ready" && host.state !== "authenticated" && host.state !== "done") {
|
|
2946
|
+
throw new ACPSessionError("protocol_error", `prompt called in state=${host.state}`);
|
|
2947
|
+
}
|
|
2948
|
+
if (host.promptCallbackAbort) {
|
|
2949
|
+
throw new ACPSessionError("protocol_error", "prompt called while another prompt is running");
|
|
2950
|
+
}
|
|
2951
|
+
if (signal.aborted) {
|
|
2952
|
+
return emptyRunResult("cancelled");
|
|
2953
|
+
}
|
|
2954
|
+
const caps = host.agentCapabilities.promptCapabilities;
|
|
2955
|
+
for (const block of blocks) {
|
|
2956
|
+
const supported = block.type === "image" ? caps?.image : block.type === "audio" ? caps?.audio : block.type === "resource" ? caps?.embeddedContext : true;
|
|
2957
|
+
if (supported !== true) {
|
|
2958
|
+
throw new ACPSessionError(
|
|
2959
|
+
"unsupported_capability",
|
|
2960
|
+
`agent does not support ${block.type} prompt content`
|
|
2961
|
+
);
|
|
2962
|
+
}
|
|
2963
|
+
}
|
|
2964
|
+
let cancelled = false;
|
|
2965
|
+
host.promptCallbackAbort = new AbortController();
|
|
2966
|
+
const onAbort = () => {
|
|
2967
|
+
cancelled = true;
|
|
2968
|
+
host.promptCallbackAbort?.abort();
|
|
2969
|
+
if (host.sessionId) {
|
|
2970
|
+
host.transport.send({
|
|
2971
|
+
jsonrpc: "2.0",
|
|
2972
|
+
method: "session/cancel",
|
|
2973
|
+
params: { sessionId: host.sessionId }
|
|
2974
|
+
}).catch(() => {
|
|
2975
|
+
});
|
|
2976
|
+
}
|
|
2977
|
+
};
|
|
2978
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
2979
|
+
let rejectCreate;
|
|
2980
|
+
const onCreateAbort = () => {
|
|
2981
|
+
signal.removeEventListener("abort", onAbort);
|
|
2982
|
+
rejectCreate?.(new ACPSessionError("aborted", "prompt was aborted by the parent"));
|
|
2983
|
+
};
|
|
2984
|
+
if (!host.sessionId) {
|
|
2985
|
+
let sessionId;
|
|
2986
|
+
const createPromise = host.createSessionWithAuth();
|
|
2987
|
+
try {
|
|
2988
|
+
sessionId = await Promise.race([
|
|
2989
|
+
createPromise,
|
|
2990
|
+
new Promise((_, reject) => {
|
|
2991
|
+
rejectCreate = reject;
|
|
2992
|
+
signal.addEventListener("abort", onCreateAbort, { once: true });
|
|
2993
|
+
})
|
|
2994
|
+
]);
|
|
2995
|
+
} catch (err) {
|
|
2996
|
+
signal.removeEventListener("abort", onAbort);
|
|
2997
|
+
signal.removeEventListener("abort", onCreateAbort);
|
|
2998
|
+
rejectCreate = void 0;
|
|
2999
|
+
host.promptCallbackAbort?.abort();
|
|
3000
|
+
host.promptCallbackAbort = null;
|
|
3001
|
+
if (err instanceof ACPSessionError && err.kind === "aborted") {
|
|
3002
|
+
host.cancelLateSession(createPromise);
|
|
3003
|
+
return emptyRunResult("cancelled");
|
|
3004
|
+
}
|
|
3005
|
+
throw err;
|
|
3006
|
+
}
|
|
3007
|
+
signal.removeEventListener("abort", onCreateAbort);
|
|
3008
|
+
rejectCreate = void 0;
|
|
3009
|
+
host.sessionId = sessionId;
|
|
3010
|
+
}
|
|
3011
|
+
if (signal.aborted) {
|
|
3012
|
+
host.promptCallbackAbort = null;
|
|
3013
|
+
return emptyRunResult("cancelled");
|
|
3014
|
+
}
|
|
3015
|
+
host.resetScratch();
|
|
3016
|
+
host.progressHandler = onProgress ?? null;
|
|
3017
|
+
const promptId = host.allocId();
|
|
3018
|
+
let rejectTurn;
|
|
3019
|
+
const onTurnAbort = () => {
|
|
3020
|
+
rejectTurn?.(new ACPSessionError("aborted", "prompt was aborted by the parent"));
|
|
3021
|
+
};
|
|
3022
|
+
signal.addEventListener("abort", onTurnAbort, { once: true });
|
|
3023
|
+
const turnPromise = Promise.race([
|
|
3024
|
+
host.sendRequest(
|
|
3025
|
+
promptId,
|
|
3026
|
+
"session/prompt",
|
|
3027
|
+
{
|
|
3028
|
+
sessionId: host.sessionId,
|
|
3029
|
+
prompt: blocks
|
|
3030
|
+
},
|
|
3031
|
+
host.timeoutMs
|
|
3032
|
+
),
|
|
3033
|
+
new Promise((_, reject) => {
|
|
3034
|
+
rejectTurn = reject;
|
|
3035
|
+
})
|
|
3036
|
+
]);
|
|
3037
|
+
host.state = "prompting";
|
|
3038
|
+
let response;
|
|
3039
|
+
try {
|
|
3040
|
+
response = await turnPromise;
|
|
3041
|
+
} catch (err) {
|
|
3042
|
+
host.state = "done";
|
|
3043
|
+
const abortedKind = err instanceof ACPSessionError && err.kind === "aborted";
|
|
3044
|
+
if (cancelled || abortedKind) {
|
|
3045
|
+
return emptyRunResult("cancelled");
|
|
3046
|
+
}
|
|
3047
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3048
|
+
if (signal.aborted) {
|
|
3049
|
+
throw new ACPSessionError("aborted", "prompt was aborted by the parent", err);
|
|
3050
|
+
}
|
|
3051
|
+
throw new ACPSessionError("prompt_failed", `session/prompt failed: ${msg}`, err);
|
|
3052
|
+
} finally {
|
|
3053
|
+
signal.removeEventListener("abort", onAbort);
|
|
3054
|
+
signal.removeEventListener("abort", onTurnAbort);
|
|
3055
|
+
signal.removeEventListener("abort", onCreateAbort);
|
|
3056
|
+
rejectTurn = void 0;
|
|
3057
|
+
rejectCreate = void 0;
|
|
3058
|
+
host.promptCallbackAbort?.abort();
|
|
3059
|
+
host.promptCallbackAbort = null;
|
|
3060
|
+
host.progressHandler = null;
|
|
3061
|
+
}
|
|
3062
|
+
host.state = "done";
|
|
3063
|
+
if (isJsonRpcError(response)) {
|
|
3064
|
+
throw new ACPSessionError("prompt_failed", `agent error: ${response.message}`, response);
|
|
3065
|
+
}
|
|
3066
|
+
const stopReason = response.stopReason ?? "end_turn";
|
|
3067
|
+
const finalText = host.scratch.text;
|
|
3068
|
+
return {
|
|
3069
|
+
text: finalText,
|
|
3070
|
+
stopReason,
|
|
3071
|
+
hasText: finalText.length > 0,
|
|
3072
|
+
usage: host.scratch.usage,
|
|
3073
|
+
plan: host.scratch.plan,
|
|
3074
|
+
toolCalls: [...host.scratch.toolCalls.values()],
|
|
3075
|
+
diffs: host.scratch.diffs,
|
|
3076
|
+
thoughts: host.scratch.thoughts
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
|
|
2940
3080
|
// src/client/permission.ts
|
|
2941
3081
|
function pickAllow(options) {
|
|
2942
3082
|
const ranked = [...options].sort((a, b) => {
|
|
@@ -3835,142 +3975,7 @@ var ACPSession = class _ACPSession {
|
|
|
3835
3975
|
// Prompt
|
|
3836
3976
|
// ──────────────────────────────────────────────────────────────────────
|
|
3837
3977
|
async prompt(blocks, signal, onProgress) {
|
|
3838
|
-
|
|
3839
|
-
throw new ACPSessionError("closed", "session is closed");
|
|
3840
|
-
}
|
|
3841
|
-
if (this.state !== "ready" && this.state !== "authenticated" && this.state !== "done") {
|
|
3842
|
-
throw new ACPSessionError("protocol_error", `prompt called in state=${this.state}`);
|
|
3843
|
-
}
|
|
3844
|
-
if (this.promptCallbackAbort) {
|
|
3845
|
-
throw new ACPSessionError("protocol_error", "prompt called while another prompt is running");
|
|
3846
|
-
}
|
|
3847
|
-
if (signal.aborted) {
|
|
3848
|
-
return emptyRunResult("cancelled");
|
|
3849
|
-
}
|
|
3850
|
-
const caps = this.agentCapabilities.promptCapabilities;
|
|
3851
|
-
for (const block of blocks) {
|
|
3852
|
-
const supported = block.type === "image" ? caps?.image : block.type === "audio" ? caps?.audio : block.type === "resource" ? caps?.embeddedContext : true;
|
|
3853
|
-
if (supported !== true) {
|
|
3854
|
-
throw new ACPSessionError(
|
|
3855
|
-
"unsupported_capability",
|
|
3856
|
-
`agent does not support ${block.type} prompt content`
|
|
3857
|
-
);
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
let cancelled = false;
|
|
3861
|
-
this.promptCallbackAbort = new AbortController();
|
|
3862
|
-
const onAbort = () => {
|
|
3863
|
-
cancelled = true;
|
|
3864
|
-
this.promptCallbackAbort?.abort();
|
|
3865
|
-
if (this.sessionId) {
|
|
3866
|
-
this.transport.send({
|
|
3867
|
-
jsonrpc: "2.0",
|
|
3868
|
-
method: "session/cancel",
|
|
3869
|
-
params: { sessionId: this.sessionId }
|
|
3870
|
-
}).catch(() => {
|
|
3871
|
-
});
|
|
3872
|
-
}
|
|
3873
|
-
};
|
|
3874
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
3875
|
-
let rejectCreate;
|
|
3876
|
-
const onCreateAbort = () => {
|
|
3877
|
-
signal.removeEventListener("abort", onAbort);
|
|
3878
|
-
rejectCreate?.(new ACPSessionError("aborted", "prompt was aborted by the parent"));
|
|
3879
|
-
};
|
|
3880
|
-
if (!this.sessionId) {
|
|
3881
|
-
let sessionId;
|
|
3882
|
-
const createPromise = this.createSessionWithAuth();
|
|
3883
|
-
try {
|
|
3884
|
-
sessionId = await Promise.race([
|
|
3885
|
-
createPromise,
|
|
3886
|
-
new Promise((_, reject) => {
|
|
3887
|
-
rejectCreate = reject;
|
|
3888
|
-
signal.addEventListener("abort", onCreateAbort, { once: true });
|
|
3889
|
-
})
|
|
3890
|
-
]);
|
|
3891
|
-
} catch (err) {
|
|
3892
|
-
signal.removeEventListener("abort", onAbort);
|
|
3893
|
-
signal.removeEventListener("abort", onCreateAbort);
|
|
3894
|
-
rejectCreate = void 0;
|
|
3895
|
-
this.promptCallbackAbort?.abort();
|
|
3896
|
-
this.promptCallbackAbort = null;
|
|
3897
|
-
if (err instanceof ACPSessionError && err.kind === "aborted") {
|
|
3898
|
-
this.cancelLateSession(createPromise);
|
|
3899
|
-
return emptyRunResult("cancelled");
|
|
3900
|
-
}
|
|
3901
|
-
throw err;
|
|
3902
|
-
}
|
|
3903
|
-
signal.removeEventListener("abort", onCreateAbort);
|
|
3904
|
-
rejectCreate = void 0;
|
|
3905
|
-
this.sessionId = sessionId;
|
|
3906
|
-
}
|
|
3907
|
-
if (signal.aborted) {
|
|
3908
|
-
this.promptCallbackAbort = null;
|
|
3909
|
-
return emptyRunResult("cancelled");
|
|
3910
|
-
}
|
|
3911
|
-
this.resetScratch();
|
|
3912
|
-
this.progressHandler = onProgress ?? null;
|
|
3913
|
-
const promptId = this.allocId();
|
|
3914
|
-
let rejectTurn;
|
|
3915
|
-
const onTurnAbort = () => {
|
|
3916
|
-
rejectTurn?.(new ACPSessionError("aborted", "prompt was aborted by the parent"));
|
|
3917
|
-
};
|
|
3918
|
-
signal.addEventListener("abort", onTurnAbort, { once: true });
|
|
3919
|
-
const turnPromise = Promise.race([
|
|
3920
|
-
this.sendRequest(
|
|
3921
|
-
promptId,
|
|
3922
|
-
"session/prompt",
|
|
3923
|
-
{
|
|
3924
|
-
sessionId: this.sessionId,
|
|
3925
|
-
prompt: blocks
|
|
3926
|
-
},
|
|
3927
|
-
this.timeoutMs
|
|
3928
|
-
),
|
|
3929
|
-
new Promise((_, reject) => {
|
|
3930
|
-
rejectTurn = reject;
|
|
3931
|
-
})
|
|
3932
|
-
]);
|
|
3933
|
-
this.state = "prompting";
|
|
3934
|
-
let response;
|
|
3935
|
-
try {
|
|
3936
|
-
response = await turnPromise;
|
|
3937
|
-
} catch (err) {
|
|
3938
|
-
this.state = "done";
|
|
3939
|
-
const abortedKind = err instanceof ACPSessionError && err.kind === "aborted";
|
|
3940
|
-
if (cancelled || abortedKind) {
|
|
3941
|
-
return emptyRunResult("cancelled");
|
|
3942
|
-
}
|
|
3943
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
3944
|
-
if (signal.aborted) {
|
|
3945
|
-
throw new ACPSessionError("aborted", "prompt was aborted by the parent", err);
|
|
3946
|
-
}
|
|
3947
|
-
throw new ACPSessionError("prompt_failed", `session/prompt failed: ${msg}`, err);
|
|
3948
|
-
} finally {
|
|
3949
|
-
signal.removeEventListener("abort", onAbort);
|
|
3950
|
-
signal.removeEventListener("abort", onTurnAbort);
|
|
3951
|
-
signal.removeEventListener("abort", onCreateAbort);
|
|
3952
|
-
rejectTurn = void 0;
|
|
3953
|
-
rejectCreate = void 0;
|
|
3954
|
-
this.promptCallbackAbort?.abort();
|
|
3955
|
-
this.promptCallbackAbort = null;
|
|
3956
|
-
this.progressHandler = null;
|
|
3957
|
-
}
|
|
3958
|
-
this.state = "done";
|
|
3959
|
-
if (isJsonRpcError(response)) {
|
|
3960
|
-
throw new ACPSessionError("prompt_failed", `agent error: ${response.message}`, response);
|
|
3961
|
-
}
|
|
3962
|
-
const stopReason = response.stopReason ?? "end_turn";
|
|
3963
|
-
const finalText = this.scratch.text;
|
|
3964
|
-
return {
|
|
3965
|
-
text: finalText,
|
|
3966
|
-
stopReason,
|
|
3967
|
-
hasText: finalText.length > 0,
|
|
3968
|
-
usage: this.scratch.usage,
|
|
3969
|
-
plan: this.scratch.plan,
|
|
3970
|
-
toolCalls: [...this.scratch.toolCalls.values()],
|
|
3971
|
-
diffs: this.scratch.diffs,
|
|
3972
|
-
thoughts: this.scratch.thoughts
|
|
3973
|
-
};
|
|
3978
|
+
return prompt(this.acpSessionPromptHost(), blocks, signal, onProgress);
|
|
3974
3979
|
}
|
|
3975
3980
|
/**
|
|
3976
3981
|
* Best-effort cancel for a session the server confirmed after we already
|
|
@@ -4140,6 +4145,25 @@ var ACPSession = class _ACPSession {
|
|
|
4140
4145
|
void this.progressHandler;
|
|
4141
4146
|
return this;
|
|
4142
4147
|
}
|
|
4148
|
+
acpSessionPromptHost() {
|
|
4149
|
+
void {
|
|
4150
|
+
closed: this.closed,
|
|
4151
|
+
state: this.state,
|
|
4152
|
+
promptCallbackAbort: this.promptCallbackAbort,
|
|
4153
|
+
agentCapabilities: this.agentCapabilities,
|
|
4154
|
+
sessionId: this.sessionId,
|
|
4155
|
+
transport: this.transport,
|
|
4156
|
+
createSessionWithAuth: this.createSessionWithAuth,
|
|
4157
|
+
cancelLateSession: this.cancelLateSession,
|
|
4158
|
+
resetScratch: this.resetScratch,
|
|
4159
|
+
progressHandler: this.progressHandler,
|
|
4160
|
+
allocId: this.allocId,
|
|
4161
|
+
sendRequest: this.sendRequest,
|
|
4162
|
+
timeoutMs: this.timeoutMs,
|
|
4163
|
+
scratch: this.scratch
|
|
4164
|
+
};
|
|
4165
|
+
return this;
|
|
4166
|
+
}
|
|
4143
4167
|
};
|
|
4144
4168
|
|
|
4145
4169
|
// src/client/tool-translator.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/acp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.35",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "ACP (Agent Client Protocol) integration for WrongStack — client + agent support",
|
|
6
6
|
"keywords": [
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@agentclientprotocol/sdk": "^1.4.0",
|
|
55
|
-
"@wrongstack/core": "1.0.
|
|
56
|
-
"@wrongstack/primitives": "1.0.
|
|
55
|
+
"@wrongstack/core": "1.0.35",
|
|
56
|
+
"@wrongstack/primitives": "1.0.35"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/node": "^26.5.1",
|