@ycodium-ai/agent-acp 0.2.2800 → 0.2.2834

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.
Files changed (2) hide show
  1. package/dist/index.js +80 -66
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -23885,22 +23885,28 @@ function createAcpConnection(options) {
23885
23885
  options.readable.on("end", onEnd);
23886
23886
  options.readable.on("error", onError);
23887
23887
  options.writable.once("error", onWritableError);
23888
- const request = (async (method, params) => {
23888
+ const begin = (method, params) => {
23889
23889
  failIfClosed();
23890
23890
  const id = nextRequestId;
23891
23891
  nextRequestId += 1;
23892
23892
  const { promise: promise2, resolve: resolve2, reject } = Promise.withResolvers();
23893
23893
  pending.set(String(id), { method, resolve: resolve2, reject });
23894
23894
  const message = params === void 0 ? { jsonrpc: "2.0", id, method } : { jsonrpc: "2.0", id, method, params };
23895
- try {
23896
- await Promise.race([writeMessage(message), promise2]);
23897
- } catch (error62) {
23898
- if (pending.delete(String(id))) {
23899
- reject(error62);
23895
+ const written = Promise.race([writeMessage(message), promise2]).then(
23896
+ () => void 0,
23897
+ (error62) => {
23898
+ if (pending.delete(String(id))) {
23899
+ reject(error62);
23900
+ }
23901
+ throw error62;
23900
23902
  }
23901
- throw error62;
23902
- }
23903
- return promise2;
23903
+ );
23904
+ return { written, response: promise2 };
23905
+ };
23906
+ const request = (async (method, params) => {
23907
+ const { written, response } = begin(method, params);
23908
+ await written;
23909
+ return response;
23904
23910
  });
23905
23911
  const notify = async (method, params) => {
23906
23912
  failIfClosed();
@@ -23921,6 +23927,7 @@ function createAcpConnection(options) {
23921
23927
  const close = (error62) => shutdown(error62 ?? new AcpConnectionClosedError());
23922
23928
  return {
23923
23929
  request,
23930
+ begin,
23924
23931
  notify,
23925
23932
  awaitInboundIdle,
23926
23933
  close,
@@ -25353,6 +25360,13 @@ function modelSelectionStateFromSetup(setup) {
25353
25360
  };
25354
25361
  }
25355
25362
 
25363
+ // ../../packages/ycodium-acp-executor/src/user-input-pending.ts
25364
+ var userInputAnswerOptionId = (question, answers) => {
25365
+ const answer = answers[question.id];
25366
+ const selected = typeof answer === "string" ? answer : Array.isArray(answer) && answer.length === 1 && typeof answer[0] === "string" ? answer[0] : void 0;
25367
+ return selected !== void 0 && question.options.some((option) => option.id === selected) ? selected : void 0;
25368
+ };
25369
+
25356
25370
  // ../../packages/ycodium-acp-executor/src/vendor-hooks.ts
25357
25371
  var defaultVendorHooks = {
25358
25372
  completedStopReason: (response) => response.stopReason
@@ -25360,11 +25374,6 @@ var defaultVendorHooks = {
25360
25374
 
25361
25375
  // ../../packages/ycodium-acp-executor/src/executor.ts
25362
25376
  var DEFAULT_CANCEL_GRACE_MS = 5e3;
25363
- var userInputAnswerOptionId = (question, answers) => {
25364
- const answer = answers[question.id];
25365
- const selected = typeof answer === "string" ? answer : Array.isArray(answer) && answer.length === 1 && typeof answer[0] === "string" ? answer[0] : void 0;
25366
- return selected !== void 0 && question.options.some((option) => option.id === selected) ? selected : void 0;
25367
- };
25368
25377
  function defaultNowIso() {
25369
25378
  return (/* @__PURE__ */ new Date()).toISOString();
25370
25379
  }
@@ -26188,7 +26197,7 @@ function createAcpExecutor(options) {
26188
26197
  };
26189
26198
  const settleTurn = (input2) => {
26190
26199
  if (!isLive(input2.expectedGeneration)) {
26191
- return;
26200
+ return false;
26192
26201
  }
26193
26202
  if (!acpPromptSettlementBelongsToContext({
26194
26203
  liveAcpSessionId: sessionId ?? "",
@@ -26197,37 +26206,40 @@ function createAcpExecutor(options) {
26197
26206
  liveSessionActiveTurnId: activeTurnId,
26198
26207
  turnId: input2.turnId
26199
26208
  })) {
26200
- return;
26209
+ return false;
26201
26210
  }
26202
26211
  closeActiveAssistantSegment(input2.turnId);
26203
26212
  promptsInFlight = Math.max(0, promptsInFlight - 1);
26204
- if (promptsInFlight === 0 && activeTurnId === input2.turnId) {
26205
- activeTurnId = void 0;
26206
- if (status !== "disposed") {
26207
- status = "ready";
26208
- }
26209
- emit({
26210
- type: "turn.completed",
26211
- ...stamp(),
26212
- provider: options.provider,
26213
- threadId: options.threadId,
26214
- turnId: input2.turnId,
26215
- payload: {
26216
- state: input2.state,
26217
- stopReason: input2.stopReason
26218
- }
26219
- });
26220
- interruptedTurnIds.delete(input2.turnId);
26213
+ if (promptsInFlight !== 0 || activeTurnId !== input2.turnId) return false;
26214
+ activeTurnId = void 0;
26215
+ if (status !== "disposed") {
26216
+ status = "ready";
26221
26217
  }
26218
+ emit({
26219
+ type: "turn.completed",
26220
+ ...stamp(),
26221
+ provider: options.provider,
26222
+ threadId: options.threadId,
26223
+ turnId: input2.turnId,
26224
+ payload: {
26225
+ state: input2.state,
26226
+ stopReason: input2.stopReason,
26227
+ ...input2.errorMessage === void 0 ? {} : { errorMessage: input2.errorMessage }
26228
+ }
26229
+ });
26230
+ interruptedTurnIds.delete(input2.turnId);
26231
+ return true;
26222
26232
  };
26223
- const sendPromptRpc = async (sessionId2, promptParts) => {
26233
+ const sendPromptRpc = async (sessionId2, promptParts, onWritten) => {
26224
26234
  const settlementHooks = hooks.promptSettlement;
26225
26235
  const promptKey = settlementHooks === void 0 ? void 0 : randomId();
26226
- const promptRpc = connection.request("session/prompt", {
26236
+ const pending = connection.begin("session/prompt", {
26227
26237
  sessionId: sessionId2,
26228
26238
  prompt: promptParts,
26229
26239
  ...settlementHooks !== void 0 && promptKey !== void 0 ? settlementHooks.requestFields(promptKey) : {}
26230
26240
  });
26241
+ void pending.written.then(onWritten, () => void 0);
26242
+ const promptRpc = pending.response;
26231
26243
  if (settlementHooks === void 0 || promptKey === void 0) {
26232
26244
  return await promptRpc;
26233
26245
  } else {
@@ -26253,6 +26265,11 @@ function createAcpExecutor(options) {
26253
26265
  const prompt = async (input2) => {
26254
26266
  failIfDisposed();
26255
26267
  const started = requireStarted();
26268
+ const settle2 = (rest) => settleTurn({
26269
+ expectedGeneration: started.generation,
26270
+ expectedSessionId: started.sessionId,
26271
+ ...rest
26272
+ });
26256
26273
  let turnId;
26257
26274
  await threadMutex.acquire();
26258
26275
  try {
@@ -26280,13 +26297,7 @@ function createAcpExecutor(options) {
26280
26297
  try {
26281
26298
  failIfDisposed();
26282
26299
  if (interruptedTurnIds.has(turnId)) {
26283
- settleTurn({
26284
- expectedGeneration: started.generation,
26285
- expectedSessionId: started.sessionId,
26286
- turnId,
26287
- stopReason: "cancelled",
26288
- state: "cancelled"
26289
- });
26300
+ settle2({ turnId, stopReason: "cancelled", state: "cancelled" });
26290
26301
  return {
26291
26302
  threadId: options.threadId,
26292
26303
  turnId,
@@ -26300,12 +26311,24 @@ function createAcpExecutor(options) {
26300
26311
  expectedGeneration: started.generation
26301
26312
  });
26302
26313
  closeActiveAssistantSegment(turnId);
26314
+ let written = false;
26303
26315
  try {
26304
- response = await sendPromptRpc(started.sessionId, promptParts);
26316
+ response = await sendPromptRpc(started.sessionId, promptParts, () => {
26317
+ written = true;
26318
+ input2.onDispatched?.(turnId);
26319
+ });
26305
26320
  } catch (error62) {
26306
26321
  if (disposed) {
26307
26322
  throw new AcpExecutorDisposedError();
26308
26323
  }
26324
+ if (written && input2.onDispatched !== void 0 && !interruptedTurnIds.has(turnId)) {
26325
+ const errorMessage = error62 instanceof Error && error62.message.trim() || "ACP prompt failed";
26326
+ if (settle2({ turnId, stopReason: "error", state: "failed", errorMessage }))
26327
+ options.log?.warn?.("turn failed after dispatch", {
26328
+ threadId: options.threadId,
26329
+ failure: errorMessage
26330
+ });
26331
+ }
26309
26332
  throw error62;
26310
26333
  }
26311
26334
  await connection.awaitInboundIdle();
@@ -26336,13 +26359,7 @@ function createAcpExecutor(options) {
26336
26359
  }
26337
26360
  const finishPrompt = () => {
26338
26361
  if (interruptedTurnIds.has(settledTurnId)) {
26339
- settleTurn({
26340
- expectedGeneration: started.generation,
26341
- expectedSessionId: started.sessionId,
26342
- turnId: settledTurnId,
26343
- stopReason: "cancelled",
26344
- state: "cancelled"
26345
- });
26362
+ settle2({ turnId: settledTurnId, stopReason: "cancelled", state: "cancelled" });
26346
26363
  return {
26347
26364
  threadId: options.threadId,
26348
26365
  turnId: settledTurnId,
@@ -26365,9 +26382,7 @@ function createAcpExecutor(options) {
26365
26382
  }
26366
26383
  });
26367
26384
  }
26368
- settleTurn({
26369
- expectedGeneration: started.generation,
26370
- expectedSessionId: started.sessionId,
26385
+ settle2({
26371
26386
  turnId: settledTurnId,
26372
26387
  stopReason,
26373
26388
  state: response.stopReason === "cancelled" ? "cancelled" : "completed"
@@ -26625,6 +26640,17 @@ function createAcpExecutor(options) {
26625
26640
  };
26626
26641
  }
26627
26642
 
26643
+ // ../../packages/ycodium-acp-executor/src/prompt-dispatch.ts
26644
+ var dispatchAcpPrompt = (executor, input2) => {
26645
+ const { promise: dispatched, resolve: resolve2 } = Promise.withResolvers();
26646
+ const finished = executor.prompt({ ...input2, onDispatched: resolve2 });
26647
+ return Promise.race([
26648
+ dispatched.then((turnId) => ({ turnId })),
26649
+ // 写入之前就落定:成功(写入前被取消)带 turnId;拒绝原样交给调用方,那是起轮失败。
26650
+ finished.then((result) => ({ turnId: result.turnId }))
26651
+ ]);
26652
+ };
26653
+
26628
26654
  // ../../packages/ycodium-acp-executor/src/mcp-servers.ts
26629
26655
  function toAcpMcpServers(entries) {
26630
26656
  return (entries ?? []).map(
@@ -27287,26 +27313,14 @@ var createAcpInstance = (config2, host) => {
27287
27313
  void booked.executor.cancel(input2.expectedTurnId).catch(() => void 0);
27288
27314
  };
27289
27315
  signal?.addEventListener("abort", onAbort);
27290
- booked.session = {
27291
- ...booked.session,
27292
- status: "running",
27293
- updatedAt: nowIso()
27294
- };
27295
27316
  try {
27296
27317
  const requestedModelId = modelIdFromSelection(input2.modelSelection);
27297
- const turn = await booked.executor.prompt({
27318
+ const turn = await dispatchAcpPrompt(booked.executor, {
27298
27319
  text: input2.input ?? "",
27299
27320
  ...input2.expectedTurnId === void 0 ? {} : { turnId: input2.expectedTurnId },
27300
27321
  ...requestedModelId === void 0 ? {} : { requestedModelId }
27301
27322
  });
27302
- await yieldTick();
27303
27323
  booked.turns.push({ id: turn.turnId, items: [] });
27304
- booked.session = {
27305
- ...booked.session,
27306
- status: "idle",
27307
- updatedAt: nowIso(),
27308
- ...booked.executor.modelId === void 0 ? {} : { model: booked.executor.modelId }
27309
- };
27310
27324
  return {
27311
27325
  threadId: input2.threadId,
27312
27326
  turnId: turn.turnId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-acp",
3
- "version": "0.2.2800",
3
+ "version": "0.2.2834",
4
4
  "description": "Generic ACP executor: user-supplied CLI over Agent Client Protocol stdio.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -21,9 +21,9 @@
21
21
  "@types/node": "24.12.4",
22
22
  "esbuild": "0.28.1",
23
23
  "vite-plus": "0.2.2",
24
- "@ycodium-ai/plugin-api": "0.2.2800",
24
+ "ycodium-acp-executor": "0.2.2834",
25
25
  "ycodium-executor-testing": "0.0.0",
26
- "ycodium-acp-executor": "0.2.2800"
26
+ "@ycodium-ai/plugin-api": "0.2.2834"
27
27
  },
28
28
  "ycodium": {
29
29
  "plugin": "./dist/index.js",