happy-imou-cloud 2.0.3 → 2.0.5
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/{BaseReasoningProcessor-_wxlqKB8.cjs → BaseReasoningProcessor-DPVZIJ4n.cjs} +2 -2
- package/dist/{BaseReasoningProcessor-B37yOHxo.mjs → BaseReasoningProcessor-bFVTvf3Q.mjs} +2 -2
- package/dist/{api-D9dIR956.cjs → api-DaqnNHfl.cjs} +4 -2
- package/dist/{api-DpQIC-DJ.mjs → api-DoHt-HyL.mjs} +4 -2
- package/dist/{command-CdXv1zNF.cjs → command-D9-hmqVq.cjs} +3 -3
- package/dist/{command-DRqrBuHM.mjs → command-Dl9SrMnv.mjs} +3 -3
- package/dist/{index-CriPm_z9.mjs → index-C5wR2qKT.mjs} +359 -70
- package/dist/{index-LYPXVO_L.cjs → index-Dc92gnxM.cjs} +361 -72
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/lib.cjs +1 -1
- package/dist/lib.mjs +1 -1
- package/dist/{persistence-PzKU0QCa.cjs → persistence-D6Y0604_.cjs} +1 -1
- package/dist/{persistence-CqgPgbzN.mjs → persistence-QqeBvUxX.mjs} +1 -1
- package/dist/{registerKillSessionHandler-BDBPoQSA.cjs → registerKillSessionHandler-C6yXr8ky.cjs} +2 -2
- package/dist/{registerKillSessionHandler-C3M_-4Zg.mjs → registerKillSessionHandler-CC9zGBPE.mjs} +2 -2
- package/dist/{runClaude-D6Pdkevn.mjs → runClaude-CZ8gxaJL.mjs} +4 -4
- package/dist/{runClaude-IeRSC5qX.cjs → runClaude-gHKFB1UG.cjs} +5 -5
- package/dist/{runCodex-WRmgSK6L.cjs → runCodex-CdjzG1N7.cjs} +113 -25
- package/dist/{runCodex-CsfUU1Wb.mjs → runCodex-DT7g4MPm.mjs} +111 -26
- package/dist/{runGemini-CrH3dQ0Y.mjs → runGemini-CmY5386l.mjs} +55 -21
- package/dist/{runGemini-qBh6zs5G.cjs → runGemini-DxjvRmOc.cjs} +55 -21
- package/package.json +2 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import chalk from 'chalk';
|
|
2
|
-
import { l as logger, e as encodeBase64, c as configuration, h as buildAuthenticatedHeaders, S as SigningBootstrapRequiredError, j as SIGNING_BOOTSTRAP_REQUIRED_MESSAGE, k as encodeBase64Url, f as delay, m as buildClientHeaders, n as decodeBase64, H as HAPPY_CLOUD_DAEMON_PORT, p as packageJson, A as ApiClient, o as getLatestDaemonLog } from './api-
|
|
3
|
-
import { writeCredentialsLegacy, writeCredentialsDataKey, readCredentials, readSettings, updateSettings, readDaemonState, clearDaemonState, acquireDaemonLock, writeDaemonState, releaseDaemonLock, validateProfileForAgent, getProfileEnvironmentVariables, clearCredentials, clearMachineId } from './persistence-
|
|
2
|
+
import { l as logger, e as encodeBase64, c as configuration, h as buildAuthenticatedHeaders, S as SigningBootstrapRequiredError, j as SIGNING_BOOTSTRAP_REQUIRED_MESSAGE, k as encodeBase64Url, f as delay, m as buildClientHeaders, n as decodeBase64, H as HAPPY_CLOUD_DAEMON_PORT, p as packageJson, A as ApiClient, o as getLatestDaemonLog } from './api-DoHt-HyL.mjs';
|
|
3
|
+
import { writeCredentialsLegacy, writeCredentialsDataKey, readCredentials, readSettings, updateSettings, readDaemonState, clearDaemonState, acquireDaemonLock, writeDaemonState, releaseDaemonLock, validateProfileForAgent, getProfileEnvironmentVariables, clearCredentials, clearMachineId } from './persistence-QqeBvUxX.mjs';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import fs from 'fs/promises';
|
|
6
6
|
import os, { homedir } from 'os';
|
|
@@ -4505,6 +4505,107 @@ function parseArgsFromContent(content) {
|
|
|
4505
4505
|
}
|
|
4506
4506
|
return {};
|
|
4507
4507
|
}
|
|
4508
|
+
function appendToolOutput(existing, next) {
|
|
4509
|
+
if (!existing || existing.length === 0) {
|
|
4510
|
+
return next;
|
|
4511
|
+
}
|
|
4512
|
+
if (next === existing || existing.endsWith(next)) {
|
|
4513
|
+
return existing;
|
|
4514
|
+
}
|
|
4515
|
+
if (next.startsWith(existing)) {
|
|
4516
|
+
return next;
|
|
4517
|
+
}
|
|
4518
|
+
return `${existing}${next}`;
|
|
4519
|
+
}
|
|
4520
|
+
function isRecord(value) {
|
|
4521
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4522
|
+
}
|
|
4523
|
+
function hasMeaningfulContent(value) {
|
|
4524
|
+
if (value === null || value === void 0) {
|
|
4525
|
+
return false;
|
|
4526
|
+
}
|
|
4527
|
+
if (typeof value === "string") {
|
|
4528
|
+
return value.length > 0;
|
|
4529
|
+
}
|
|
4530
|
+
if (Array.isArray(value)) {
|
|
4531
|
+
return value.length > 0;
|
|
4532
|
+
}
|
|
4533
|
+
if (isRecord(value)) {
|
|
4534
|
+
return Object.keys(value).length > 0;
|
|
4535
|
+
}
|
|
4536
|
+
return true;
|
|
4537
|
+
}
|
|
4538
|
+
function looksLikeToolMetadata(record) {
|
|
4539
|
+
const metadataKeys = [
|
|
4540
|
+
"command",
|
|
4541
|
+
"cmd",
|
|
4542
|
+
"script",
|
|
4543
|
+
"argv",
|
|
4544
|
+
"cwd",
|
|
4545
|
+
"workingDirectory",
|
|
4546
|
+
"description",
|
|
4547
|
+
"title",
|
|
4548
|
+
"parsed_cmd"
|
|
4549
|
+
];
|
|
4550
|
+
if (metadataKeys.some((key) => key in record)) {
|
|
4551
|
+
return true;
|
|
4552
|
+
}
|
|
4553
|
+
const nestedKeys = ["input", "toolCall", "arguments", "content"];
|
|
4554
|
+
for (const key of nestedKeys) {
|
|
4555
|
+
const nested = record[key];
|
|
4556
|
+
if (isRecord(nested) && looksLikeToolMetadata(nested)) {
|
|
4557
|
+
return true;
|
|
4558
|
+
}
|
|
4559
|
+
}
|
|
4560
|
+
return false;
|
|
4561
|
+
}
|
|
4562
|
+
function extractToolOutputChunk(content) {
|
|
4563
|
+
if (typeof content === "string") {
|
|
4564
|
+
return content.length > 0 ? content : null;
|
|
4565
|
+
}
|
|
4566
|
+
if (Array.isArray(content)) {
|
|
4567
|
+
const parts = content.map((item) => extractToolOutputChunk(item)).filter((item) => Boolean(item));
|
|
4568
|
+
return parts.length > 0 ? parts.join("") : null;
|
|
4569
|
+
}
|
|
4570
|
+
if (!isRecord(content)) {
|
|
4571
|
+
return null;
|
|
4572
|
+
}
|
|
4573
|
+
const outputKeys = ["stdout", "stderr", "output", "text", "message", "data", "error", "reason"];
|
|
4574
|
+
const hasOutputKey = outputKeys.some((key) => key in content);
|
|
4575
|
+
if (!hasOutputKey && looksLikeToolMetadata(content)) {
|
|
4576
|
+
return null;
|
|
4577
|
+
}
|
|
4578
|
+
for (const key of outputKeys) {
|
|
4579
|
+
if (!(key in content)) {
|
|
4580
|
+
continue;
|
|
4581
|
+
}
|
|
4582
|
+
const value = content[key];
|
|
4583
|
+
const formatted2 = typeof value === "string" ? value : formatDisplayMessage(value);
|
|
4584
|
+
if (formatted2.length > 0) {
|
|
4585
|
+
return formatted2;
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
const formatted = formatDisplayMessage(content);
|
|
4589
|
+
return formatted.length > 0 ? formatted : null;
|
|
4590
|
+
}
|
|
4591
|
+
function mergeStreamedOutputWithResult(content, streamedOutput) {
|
|
4592
|
+
if (!streamedOutput || streamedOutput.length === 0) {
|
|
4593
|
+
return content;
|
|
4594
|
+
}
|
|
4595
|
+
if (!hasMeaningfulContent(content)) {
|
|
4596
|
+
return streamedOutput;
|
|
4597
|
+
}
|
|
4598
|
+
if (isRecord(content)) {
|
|
4599
|
+
const hasStructuredOutput = ["stdout", "stderr", "output", "text", "message", "data"].some((key) => key in content);
|
|
4600
|
+
if (!hasStructuredOutput) {
|
|
4601
|
+
return {
|
|
4602
|
+
...content,
|
|
4603
|
+
stdout: streamedOutput
|
|
4604
|
+
};
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
return content;
|
|
4608
|
+
}
|
|
4508
4609
|
function extractErrorDetail(content) {
|
|
4509
4610
|
if (!content) return void 0;
|
|
4510
4611
|
if (typeof content === "string") {
|
|
@@ -4652,11 +4753,13 @@ function completeToolCall(toolCallId, toolKind, content, ctx) {
|
|
|
4652
4753
|
clearTimeout(timeout);
|
|
4653
4754
|
ctx.toolCallTimeouts.delete(toolCallId);
|
|
4654
4755
|
}
|
|
4756
|
+
const streamedOutput = ctx.toolCallOutputs.get(toolCallId);
|
|
4757
|
+
ctx.toolCallOutputs.delete(toolCallId);
|
|
4655
4758
|
logger.debug(`[AcpBackend] \u2705 Tool call COMPLETED: ${toolCallId} (${toolKindStr}) - Duration: ${duration}. Active tool calls: ${ctx.activeToolCalls.size}`);
|
|
4656
4759
|
ctx.emit({
|
|
4657
4760
|
type: "tool-result",
|
|
4658
4761
|
toolName: toolKindStr,
|
|
4659
|
-
result: content,
|
|
4762
|
+
result: mergeStreamedOutputWithResult(content, streamedOutput),
|
|
4660
4763
|
callId: toolCallId
|
|
4661
4764
|
});
|
|
4662
4765
|
if (ctx.activeToolCalls.size === 0) {
|
|
@@ -4698,6 +4801,8 @@ function failToolCall(toolCallId, status, toolKind, content, ctx) {
|
|
|
4698
4801
|
}
|
|
4699
4802
|
const durationStr = formatDuration(startTime);
|
|
4700
4803
|
logger.debug(`[AcpBackend] \u274C Tool call ${status.toUpperCase()}: ${toolCallId} (${toolKindStr}) - Duration: ${durationStr}. Active tool calls: ${ctx.activeToolCalls.size}`);
|
|
4804
|
+
const streamedOutput = ctx.toolCallOutputs.get(toolCallId);
|
|
4805
|
+
ctx.toolCallOutputs.delete(toolCallId);
|
|
4701
4806
|
const errorDetail = extractErrorDetail(content);
|
|
4702
4807
|
if (errorDetail) {
|
|
4703
4808
|
logger.debug(`[AcpBackend] \u274C Tool call error details: ${errorDetail.substring(0, 500)}`);
|
|
@@ -4707,7 +4812,11 @@ function failToolCall(toolCallId, status, toolKind, content, ctx) {
|
|
|
4707
4812
|
ctx.emit({
|
|
4708
4813
|
type: "tool-result",
|
|
4709
4814
|
toolName: toolKindStr,
|
|
4710
|
-
result:
|
|
4815
|
+
result: streamedOutput ? {
|
|
4816
|
+
stdout: streamedOutput,
|
|
4817
|
+
error: errorDetail || `Tool call ${status}`,
|
|
4818
|
+
status
|
|
4819
|
+
} : errorDetail ? { error: errorDetail, status } : { error: `Tool call ${status}`, status },
|
|
4711
4820
|
callId: toolCallId
|
|
4712
4821
|
});
|
|
4713
4822
|
if (ctx.activeToolCalls.size === 0) {
|
|
@@ -4723,8 +4832,13 @@ function handleToolCallUpdate(update, ctx) {
|
|
|
4723
4832
|
logger.debug("[AcpBackend] Tool call update without toolCallId:", update);
|
|
4724
4833
|
return { handled: false };
|
|
4725
4834
|
}
|
|
4726
|
-
const toolKind = update.kind || "unknown";
|
|
4835
|
+
const toolKind = update.kind || ctx.toolCallIdToNameMap.get(toolCallId) || "unknown";
|
|
4727
4836
|
let toolCallCountSincePrompt = ctx.toolCallCountSincePrompt;
|
|
4837
|
+
const outputChunk = extractToolOutputChunk(update.content);
|
|
4838
|
+
if (outputChunk) {
|
|
4839
|
+
const nextOutput = appendToolOutput(ctx.toolCallOutputs.get(toolCallId), outputChunk);
|
|
4840
|
+
ctx.toolCallOutputs.set(toolCallId, nextOutput);
|
|
4841
|
+
}
|
|
4728
4842
|
if (status === "in_progress" || status === "pending") {
|
|
4729
4843
|
if (!ctx.activeToolCalls.has(toolCallId)) {
|
|
4730
4844
|
toolCallCountSincePrompt++;
|
|
@@ -4928,15 +5042,17 @@ async function withRetry(operation, options) {
|
|
|
4928
5042
|
return await operation();
|
|
4929
5043
|
} catch (error) {
|
|
4930
5044
|
lastError = normalizeAcpError(error);
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
options.maxDelayMs
|
|
4935
|
-
);
|
|
4936
|
-
logger.debug(`[AcpBackend] ${options.operationName} failed (attempt ${attempt}/${options.maxAttempts}): ${lastError.message}. Retrying in ${delayMs}ms...`);
|
|
4937
|
-
options.onRetry?.(attempt, lastError);
|
|
4938
|
-
await delay(delayMs);
|
|
5045
|
+
const retryable = options.shouldRetry?.(lastError) ?? true;
|
|
5046
|
+
if (!retryable || attempt >= options.maxAttempts) {
|
|
5047
|
+
throw lastError;
|
|
4939
5048
|
}
|
|
5049
|
+
const delayMs = Math.min(
|
|
5050
|
+
options.baseDelayMs * Math.pow(2, attempt - 1),
|
|
5051
|
+
options.maxDelayMs
|
|
5052
|
+
);
|
|
5053
|
+
logger.debug(`[AcpBackend] ${options.operationName} failed (attempt ${attempt}/${options.maxAttempts}): ${lastError.message}. Retrying in ${delayMs}ms...`);
|
|
5054
|
+
options.onRetry?.(attempt, lastError);
|
|
5055
|
+
await delay(delayMs);
|
|
4940
5056
|
}
|
|
4941
5057
|
}
|
|
4942
5058
|
throw lastError;
|
|
@@ -4973,6 +5089,11 @@ function normalizeAcpError(error) {
|
|
|
4973
5089
|
}
|
|
4974
5090
|
return normalized;
|
|
4975
5091
|
}
|
|
5092
|
+
function createAcpAbortError(message) {
|
|
5093
|
+
const error = new Error(message);
|
|
5094
|
+
error.name = "AbortError";
|
|
5095
|
+
return error;
|
|
5096
|
+
}
|
|
4976
5097
|
function enrichAcpError(error, stderrExcerpt) {
|
|
4977
5098
|
const normalized = normalizeAcpError(error);
|
|
4978
5099
|
if (!stderrExcerpt.trim()) {
|
|
@@ -4984,6 +5105,77 @@ function enrichAcpError(error, stderrExcerpt) {
|
|
|
4984
5105
|
}
|
|
4985
5106
|
return normalized;
|
|
4986
5107
|
}
|
|
5108
|
+
class AcpProcessStartupError extends Error {
|
|
5109
|
+
constructor(message, exitCode, signal) {
|
|
5110
|
+
super(message);
|
|
5111
|
+
this.exitCode = exitCode;
|
|
5112
|
+
this.signal = signal;
|
|
5113
|
+
this.name = "AcpProcessStartupError";
|
|
5114
|
+
}
|
|
5115
|
+
}
|
|
5116
|
+
function createProcessStartupError(agentName, operationName, code, signal) {
|
|
5117
|
+
if (code !== null) {
|
|
5118
|
+
return new AcpProcessStartupError(
|
|
5119
|
+
`${agentName} exited with code ${code} during ${operationName}`,
|
|
5120
|
+
code,
|
|
5121
|
+
signal
|
|
5122
|
+
);
|
|
5123
|
+
}
|
|
5124
|
+
if (signal) {
|
|
5125
|
+
return new AcpProcessStartupError(
|
|
5126
|
+
`${agentName} exited due to signal ${signal} during ${operationName}`,
|
|
5127
|
+
code,
|
|
5128
|
+
signal
|
|
5129
|
+
);
|
|
5130
|
+
}
|
|
5131
|
+
return new AcpProcessStartupError(
|
|
5132
|
+
`${agentName} exited unexpectedly during ${operationName}`,
|
|
5133
|
+
code,
|
|
5134
|
+
signal
|
|
5135
|
+
);
|
|
5136
|
+
}
|
|
5137
|
+
async function raceWithProcessExit(childProcess, operation, options) {
|
|
5138
|
+
if (childProcess.exitCode !== null) {
|
|
5139
|
+
throw createProcessStartupError(
|
|
5140
|
+
options.agentName,
|
|
5141
|
+
options.operationName,
|
|
5142
|
+
childProcess.exitCode,
|
|
5143
|
+
childProcess.signalCode ?? null
|
|
5144
|
+
);
|
|
5145
|
+
}
|
|
5146
|
+
return await new Promise((resolve, reject) => {
|
|
5147
|
+
let settled = false;
|
|
5148
|
+
const cleanup = () => {
|
|
5149
|
+
childProcess.off("error", handleError);
|
|
5150
|
+
childProcess.off("exit", handleExit);
|
|
5151
|
+
};
|
|
5152
|
+
const settleResolve = (value) => {
|
|
5153
|
+
if (settled) {
|
|
5154
|
+
return;
|
|
5155
|
+
}
|
|
5156
|
+
settled = true;
|
|
5157
|
+
cleanup();
|
|
5158
|
+
resolve(value);
|
|
5159
|
+
};
|
|
5160
|
+
const settleReject = (error) => {
|
|
5161
|
+
if (settled) {
|
|
5162
|
+
return;
|
|
5163
|
+
}
|
|
5164
|
+
settled = true;
|
|
5165
|
+
cleanup();
|
|
5166
|
+
reject(normalizeAcpError(error));
|
|
5167
|
+
};
|
|
5168
|
+
const handleError = (error) => {
|
|
5169
|
+
settleReject(error);
|
|
5170
|
+
};
|
|
5171
|
+
const handleExit = (code, signal) => {
|
|
5172
|
+
settleReject(createProcessStartupError(options.agentName, options.operationName, code, signal));
|
|
5173
|
+
};
|
|
5174
|
+
childProcess.once("error", handleError);
|
|
5175
|
+
childProcess.once("exit", handleExit);
|
|
5176
|
+
operation.then(settleResolve, settleReject);
|
|
5177
|
+
});
|
|
5178
|
+
}
|
|
4987
5179
|
class AcpBackend {
|
|
4988
5180
|
constructor(options) {
|
|
4989
5181
|
this.options = options;
|
|
@@ -4999,6 +5191,8 @@ class AcpBackend {
|
|
|
4999
5191
|
toolCallTimeouts = /* @__PURE__ */ new Map();
|
|
5000
5192
|
/** Track tool call start times for performance monitoring */
|
|
5001
5193
|
toolCallStartTimes = /* @__PURE__ */ new Map();
|
|
5194
|
+
/** Track streamed tool output between ACP updates and final completion */
|
|
5195
|
+
toolCallOutputs = /* @__PURE__ */ new Map();
|
|
5002
5196
|
/** Pending permission requests that need response */
|
|
5003
5197
|
pendingPermissions = /* @__PURE__ */ new Map();
|
|
5004
5198
|
/** Map from permission request ID to real tool call ID for tracking */
|
|
@@ -5009,6 +5203,14 @@ class AcpBackend {
|
|
|
5009
5203
|
toolCallCountSincePrompt = 0;
|
|
5010
5204
|
/** Timeout for emitting 'idle' status after last message chunk */
|
|
5011
5205
|
idleTimeout = null;
|
|
5206
|
+
/** Promise resolver for waitForResponseComplete */
|
|
5207
|
+
idleResolver = null;
|
|
5208
|
+
/** Promise rejecter for waitForResponseComplete */
|
|
5209
|
+
idleRejecter = null;
|
|
5210
|
+
/** Completion signal captured before waitForResponseComplete is attached */
|
|
5211
|
+
responseCompletionOutcome = null;
|
|
5212
|
+
/** Whether the current prompt is still waiting for completion */
|
|
5213
|
+
waitingForResponse = false;
|
|
5012
5214
|
/** Transport handler for agent-specific behavior */
|
|
5013
5215
|
transport;
|
|
5014
5216
|
/** Keep a short rolling stderr buffer so startup failures can surface the real cause. */
|
|
@@ -5026,6 +5228,44 @@ class AcpBackend {
|
|
|
5026
5228
|
getRecentStderrExcerpt() {
|
|
5027
5229
|
return this.recentStderrLines.slice(-6).join("\n");
|
|
5028
5230
|
}
|
|
5231
|
+
clearIdleTimeoutState() {
|
|
5232
|
+
if (this.idleTimeout) {
|
|
5233
|
+
clearTimeout(this.idleTimeout);
|
|
5234
|
+
this.idleTimeout = null;
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
clearToolCallTracking() {
|
|
5238
|
+
this.activeToolCalls.clear();
|
|
5239
|
+
for (const timeout of this.toolCallTimeouts.values()) {
|
|
5240
|
+
clearTimeout(timeout);
|
|
5241
|
+
}
|
|
5242
|
+
this.toolCallTimeouts.clear();
|
|
5243
|
+
this.toolCallStartTimes.clear();
|
|
5244
|
+
this.toolCallIdToNameMap.clear();
|
|
5245
|
+
this.toolCallOutputs.clear();
|
|
5246
|
+
this.toolCallCountSincePrompt = 0;
|
|
5247
|
+
}
|
|
5248
|
+
resetResponseTrackingForNewPrompt() {
|
|
5249
|
+
this.responseCompletionOutcome = null;
|
|
5250
|
+
this.clearIdleTimeoutState();
|
|
5251
|
+
this.clearToolCallTracking();
|
|
5252
|
+
}
|
|
5253
|
+
settleResponseWaiter(outcome) {
|
|
5254
|
+
const hasActiveWaiter = Boolean(this.idleResolver || this.idleRejecter);
|
|
5255
|
+
if (!this.waitingForResponse && !hasActiveWaiter) {
|
|
5256
|
+
return;
|
|
5257
|
+
}
|
|
5258
|
+
if (!hasActiveWaiter) {
|
|
5259
|
+
this.waitingForResponse = false;
|
|
5260
|
+
this.responseCompletionOutcome = outcome;
|
|
5261
|
+
return;
|
|
5262
|
+
}
|
|
5263
|
+
if (outcome.kind === "resolved") {
|
|
5264
|
+
this.idleResolver?.();
|
|
5265
|
+
return;
|
|
5266
|
+
}
|
|
5267
|
+
this.idleRejecter?.(outcome.error);
|
|
5268
|
+
}
|
|
5029
5269
|
onMessage(handler) {
|
|
5030
5270
|
this.listeners.push(handler);
|
|
5031
5271
|
}
|
|
@@ -5100,10 +5340,15 @@ class AcpBackend {
|
|
|
5100
5340
|
});
|
|
5101
5341
|
this.process.on("error", (err) => {
|
|
5102
5342
|
logger.debug(`[AcpBackend] Process error:`, err);
|
|
5343
|
+
this.settleResponseWaiter({ kind: "rejected", error: err });
|
|
5103
5344
|
this.emit({ type: "status", status: "error", detail: err.message });
|
|
5104
5345
|
});
|
|
5105
5346
|
this.process.on("exit", (code, signal) => {
|
|
5106
5347
|
if (!this.disposed && code !== 0 && code !== null) {
|
|
5348
|
+
this.settleResponseWaiter({
|
|
5349
|
+
kind: "rejected",
|
|
5350
|
+
error: new Error(`ACP process exited with code ${code}${signal ? ` (${signal})` : ""}`)
|
|
5351
|
+
});
|
|
5107
5352
|
logger.debug(`[AcpBackend] Process exited with code ${code}, signal ${signal}`);
|
|
5108
5353
|
this.emit({ type: "status", status: "stopped", detail: `Exit code: ${code}` });
|
|
5109
5354
|
}
|
|
@@ -5331,20 +5576,27 @@ class AcpBackend {
|
|
|
5331
5576
|
async () => {
|
|
5332
5577
|
let timeoutHandle = null;
|
|
5333
5578
|
try {
|
|
5334
|
-
const result = await
|
|
5335
|
-
this.
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
timeoutHandle
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5579
|
+
const result = await raceWithProcessExit(
|
|
5580
|
+
this.process,
|
|
5581
|
+
Promise.race([
|
|
5582
|
+
this.connection.initialize(initRequest).then((res) => {
|
|
5583
|
+
if (timeoutHandle) {
|
|
5584
|
+
clearTimeout(timeoutHandle);
|
|
5585
|
+
timeoutHandle = null;
|
|
5586
|
+
}
|
|
5587
|
+
return res;
|
|
5588
|
+
}),
|
|
5589
|
+
new Promise((_, reject) => {
|
|
5590
|
+
timeoutHandle = setTimeout(() => {
|
|
5591
|
+
reject(new Error(`Initialize timeout after ${initTimeout}ms - ${this.transport.agentName} did not respond`));
|
|
5592
|
+
}, initTimeout);
|
|
5593
|
+
})
|
|
5594
|
+
]),
|
|
5595
|
+
{
|
|
5596
|
+
agentName: this.transport.agentName,
|
|
5597
|
+
operationName: "initialize"
|
|
5598
|
+
}
|
|
5599
|
+
);
|
|
5348
5600
|
return result;
|
|
5349
5601
|
} finally {
|
|
5350
5602
|
if (timeoutHandle) {
|
|
@@ -5356,7 +5608,8 @@ class AcpBackend {
|
|
|
5356
5608
|
operationName: "Initialize",
|
|
5357
5609
|
maxAttempts: RETRY_CONFIG.maxAttempts,
|
|
5358
5610
|
baseDelayMs: RETRY_CONFIG.baseDelayMs,
|
|
5359
|
-
maxDelayMs: RETRY_CONFIG.maxDelayMs
|
|
5611
|
+
maxDelayMs: RETRY_CONFIG.maxDelayMs,
|
|
5612
|
+
shouldRetry: (error) => !(error instanceof AcpProcessStartupError)
|
|
5360
5613
|
}
|
|
5361
5614
|
);
|
|
5362
5615
|
logger.debug(`[AcpBackend] Initialize completed`);
|
|
@@ -5375,20 +5628,27 @@ class AcpBackend {
|
|
|
5375
5628
|
async () => {
|
|
5376
5629
|
let timeoutHandle = null;
|
|
5377
5630
|
try {
|
|
5378
|
-
const result = await
|
|
5379
|
-
this.
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
timeoutHandle
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5631
|
+
const result = await raceWithProcessExit(
|
|
5632
|
+
this.process,
|
|
5633
|
+
Promise.race([
|
|
5634
|
+
this.connection.newSession(newSessionRequest).then((res) => {
|
|
5635
|
+
if (timeoutHandle) {
|
|
5636
|
+
clearTimeout(timeoutHandle);
|
|
5637
|
+
timeoutHandle = null;
|
|
5638
|
+
}
|
|
5639
|
+
return res;
|
|
5640
|
+
}),
|
|
5641
|
+
new Promise((_, reject) => {
|
|
5642
|
+
timeoutHandle = setTimeout(() => {
|
|
5643
|
+
reject(new Error(`New session timeout after ${initTimeout}ms - ${this.transport.agentName} did not respond`));
|
|
5644
|
+
}, initTimeout);
|
|
5645
|
+
})
|
|
5646
|
+
]),
|
|
5647
|
+
{
|
|
5648
|
+
agentName: this.transport.agentName,
|
|
5649
|
+
operationName: "new session"
|
|
5650
|
+
}
|
|
5651
|
+
);
|
|
5392
5652
|
return result;
|
|
5393
5653
|
} finally {
|
|
5394
5654
|
if (timeoutHandle) {
|
|
@@ -5400,7 +5660,8 @@ class AcpBackend {
|
|
|
5400
5660
|
operationName: "NewSession",
|
|
5401
5661
|
maxAttempts: RETRY_CONFIG.maxAttempts,
|
|
5402
5662
|
baseDelayMs: RETRY_CONFIG.baseDelayMs,
|
|
5403
|
-
maxDelayMs: RETRY_CONFIG.maxDelayMs
|
|
5663
|
+
maxDelayMs: RETRY_CONFIG.maxDelayMs,
|
|
5664
|
+
shouldRetry: (error) => !(error instanceof AcpProcessStartupError)
|
|
5404
5665
|
}
|
|
5405
5666
|
);
|
|
5406
5667
|
this.acpSessionId = sessionResponse.sessionId;
|
|
@@ -5434,6 +5695,7 @@ class AcpBackend {
|
|
|
5434
5695
|
toolCallStartTimes: this.toolCallStartTimes,
|
|
5435
5696
|
toolCallTimeouts: this.toolCallTimeouts,
|
|
5436
5697
|
toolCallIdToNameMap: this.toolCallIdToNameMap,
|
|
5698
|
+
toolCallOutputs: this.toolCallOutputs,
|
|
5437
5699
|
idleTimeout: this.idleTimeout,
|
|
5438
5700
|
toolCallCountSincePrompt: this.toolCallCountSincePrompt,
|
|
5439
5701
|
emit: (msg) => this.emit(msg),
|
|
@@ -5510,20 +5772,24 @@ class AcpBackend {
|
|
|
5510
5772
|
this.emitUsageTelemetry(update, "acp-usage-update");
|
|
5511
5773
|
continue;
|
|
5512
5774
|
}
|
|
5775
|
+
if (sessionUpdateType === "task_complete") {
|
|
5776
|
+
this.emitUsageTelemetry(update.usage, "acp-session-usage");
|
|
5777
|
+
ctx.clearIdleTimeout();
|
|
5778
|
+
logger.debug("[AcpBackend] task_complete received, emitting idle status");
|
|
5779
|
+
this.emitIdleStatus();
|
|
5780
|
+
continue;
|
|
5781
|
+
}
|
|
5513
5782
|
const handledLegacy = handleLegacyMessageChunk(update, ctx).handled;
|
|
5514
5783
|
const handledPlan = handlePlanUpdate(update, ctx).handled;
|
|
5515
5784
|
const handledThinking = handleThinkingUpdate(update, ctx).handled;
|
|
5516
5785
|
const handledUsage = this.emitUsageTelemetry(update.usage, "acp-session-usage");
|
|
5517
5786
|
const updateTypeStr = sessionUpdateType;
|
|
5518
|
-
const handledTypes = ["agent_message_chunk", "tool_call_update", "agent_thought_chunk", "tool_call", "usage_update"];
|
|
5787
|
+
const handledTypes = ["agent_message_chunk", "tool_call_update", "agent_thought_chunk", "tool_call", "usage_update", "task_complete"];
|
|
5519
5788
|
if (updateTypeStr && !handledTypes.includes(updateTypeStr) && !handledLegacy && !handledPlan && !handledThinking && !handledUsage) {
|
|
5520
5789
|
logger.debug(`[AcpBackend] Unhandled session update type: ${updateTypeStr}`, JSON.stringify(update, null, 2));
|
|
5521
5790
|
}
|
|
5522
5791
|
}
|
|
5523
5792
|
}
|
|
5524
|
-
// Promise resolver for waitForIdle - set when waiting for response to complete
|
|
5525
|
-
idleResolver = null;
|
|
5526
|
-
waitingForResponse = false;
|
|
5527
5793
|
async sendPrompt(sessionId, prompt) {
|
|
5528
5794
|
this.toolCallCountSincePrompt = 0;
|
|
5529
5795
|
if (this.disposed) {
|
|
@@ -5532,6 +5798,7 @@ class AcpBackend {
|
|
|
5532
5798
|
if (!this.connection || !this.acpSessionId) {
|
|
5533
5799
|
throw new Error("Session not started");
|
|
5534
5800
|
}
|
|
5801
|
+
this.resetResponseTrackingForNewPrompt();
|
|
5535
5802
|
this.emit({ type: "status", status: "running" });
|
|
5536
5803
|
this.waitingForResponse = true;
|
|
5537
5804
|
try {
|
|
@@ -5550,7 +5817,6 @@ class AcpBackend {
|
|
|
5550
5817
|
logger.debug("[AcpBackend] Prompt request sent to ACP connection");
|
|
5551
5818
|
} catch (error) {
|
|
5552
5819
|
logger.debug("[AcpBackend] Error sending prompt:", error);
|
|
5553
|
-
this.waitingForResponse = false;
|
|
5554
5820
|
let errorDetail;
|
|
5555
5821
|
if (error instanceof Error) {
|
|
5556
5822
|
errorDetail = error.message;
|
|
@@ -5564,6 +5830,10 @@ class AcpBackend {
|
|
|
5564
5830
|
status: "error",
|
|
5565
5831
|
detail: errorDetail
|
|
5566
5832
|
});
|
|
5833
|
+
this.settleResponseWaiter({
|
|
5834
|
+
kind: "rejected",
|
|
5835
|
+
error: error instanceof Error ? error : normalizeAcpError(error)
|
|
5836
|
+
});
|
|
5567
5837
|
throw error;
|
|
5568
5838
|
}
|
|
5569
5839
|
}
|
|
@@ -5572,21 +5842,38 @@ class AcpBackend {
|
|
|
5572
5842
|
* Call this after sendPrompt to wait for Gemini to finish responding
|
|
5573
5843
|
*/
|
|
5574
5844
|
async waitForResponseComplete(timeoutMs = 12e4) {
|
|
5845
|
+
const pendingOutcome = this.responseCompletionOutcome;
|
|
5846
|
+
if (pendingOutcome) {
|
|
5847
|
+
this.responseCompletionOutcome = null;
|
|
5848
|
+
if (pendingOutcome.kind === "rejected") {
|
|
5849
|
+
throw pendingOutcome.error;
|
|
5850
|
+
}
|
|
5851
|
+
return;
|
|
5852
|
+
}
|
|
5575
5853
|
if (!this.waitingForResponse) {
|
|
5576
5854
|
return;
|
|
5577
5855
|
}
|
|
5578
5856
|
return new Promise((resolve, reject) => {
|
|
5579
5857
|
const timeout = setTimeout(() => {
|
|
5580
5858
|
this.idleResolver = null;
|
|
5859
|
+
this.idleRejecter = null;
|
|
5581
5860
|
this.waitingForResponse = false;
|
|
5582
5861
|
reject(new Error("Timeout waiting for response to complete"));
|
|
5583
5862
|
}, timeoutMs);
|
|
5584
5863
|
this.idleResolver = () => {
|
|
5585
5864
|
clearTimeout(timeout);
|
|
5586
5865
|
this.idleResolver = null;
|
|
5866
|
+
this.idleRejecter = null;
|
|
5587
5867
|
this.waitingForResponse = false;
|
|
5588
5868
|
resolve();
|
|
5589
5869
|
};
|
|
5870
|
+
this.idleRejecter = (error) => {
|
|
5871
|
+
clearTimeout(timeout);
|
|
5872
|
+
this.idleResolver = null;
|
|
5873
|
+
this.idleRejecter = null;
|
|
5874
|
+
this.waitingForResponse = false;
|
|
5875
|
+
reject(error);
|
|
5876
|
+
};
|
|
5590
5877
|
});
|
|
5591
5878
|
}
|
|
5592
5879
|
/**
|
|
@@ -5594,18 +5881,19 @@ class AcpBackend {
|
|
|
5594
5881
|
*/
|
|
5595
5882
|
emitIdleStatus() {
|
|
5596
5883
|
this.emit({ type: "status", status: "idle" });
|
|
5597
|
-
|
|
5598
|
-
logger.debug("[AcpBackend] Resolving idle waiter");
|
|
5599
|
-
this.idleResolver();
|
|
5600
|
-
}
|
|
5884
|
+
this.settleResponseWaiter({ kind: "resolved" });
|
|
5601
5885
|
}
|
|
5602
5886
|
async cancel(sessionId) {
|
|
5887
|
+
const cancelError = createAcpAbortError("Cancelled by user");
|
|
5888
|
+
this.clearIdleTimeoutState();
|
|
5889
|
+
this.clearToolCallTracking();
|
|
5890
|
+
this.settleResponseWaiter({ kind: "rejected", error: cancelError });
|
|
5891
|
+
this.emit({ type: "status", status: "stopped", detail: "Cancelled by user" });
|
|
5603
5892
|
if (!this.connection || !this.acpSessionId) {
|
|
5604
5893
|
return;
|
|
5605
5894
|
}
|
|
5606
5895
|
try {
|
|
5607
5896
|
await this.connection.cancel({ sessionId: this.acpSessionId });
|
|
5608
|
-
this.emit({ type: "status", status: "stopped", detail: "Cancelled by user" });
|
|
5609
5897
|
} catch (error) {
|
|
5610
5898
|
logger.debug("[AcpBackend] Error cancelling:", error);
|
|
5611
5899
|
}
|
|
@@ -5633,6 +5921,10 @@ class AcpBackend {
|
|
|
5633
5921
|
if (this.disposed) return;
|
|
5634
5922
|
logger.debug("[AcpBackend] Disposing backend");
|
|
5635
5923
|
this.disposed = true;
|
|
5924
|
+
this.settleResponseWaiter({
|
|
5925
|
+
kind: "rejected",
|
|
5926
|
+
error: createAcpAbortError("ACP backend disposed")
|
|
5927
|
+
});
|
|
5636
5928
|
if (this.connection && this.acpSessionId) {
|
|
5637
5929
|
try {
|
|
5638
5930
|
await Promise.race([
|
|
@@ -5661,19 +5953,11 @@ class AcpBackend {
|
|
|
5661
5953
|
});
|
|
5662
5954
|
this.process = null;
|
|
5663
5955
|
}
|
|
5664
|
-
|
|
5665
|
-
clearTimeout(this.idleTimeout);
|
|
5666
|
-
this.idleTimeout = null;
|
|
5667
|
-
}
|
|
5956
|
+
this.clearIdleTimeoutState();
|
|
5668
5957
|
this.listeners = [];
|
|
5669
5958
|
this.connection = null;
|
|
5670
5959
|
this.acpSessionId = null;
|
|
5671
|
-
this.
|
|
5672
|
-
for (const timeout of this.toolCallTimeouts.values()) {
|
|
5673
|
-
clearTimeout(timeout);
|
|
5674
|
-
}
|
|
5675
|
-
this.toolCallTimeouts.clear();
|
|
5676
|
-
this.toolCallStartTimes.clear();
|
|
5960
|
+
this.clearToolCallTracking();
|
|
5677
5961
|
this.pendingPermissions.clear();
|
|
5678
5962
|
}
|
|
5679
5963
|
}
|
|
@@ -5908,6 +6192,7 @@ function registerGeminiAgent() {
|
|
|
5908
6192
|
logger.debug("[Gemini] Registered with agent registry");
|
|
5909
6193
|
}
|
|
5910
6194
|
|
|
6195
|
+
const DEFAULT_CODEX_ACP_NPX_PACKAGE = "@zed-industries/codex-acp@0.9.5";
|
|
5911
6196
|
function readFirstEnv(...names) {
|
|
5912
6197
|
for (const name of names) {
|
|
5913
6198
|
const raw = process.env[name];
|
|
@@ -5962,6 +6247,10 @@ function readCodexAcpNpxMode() {
|
|
|
5962
6247
|
}
|
|
5963
6248
|
return "auto";
|
|
5964
6249
|
}
|
|
6250
|
+
function readCodexAcpNpxPackage() {
|
|
6251
|
+
const configured = readFirstEnv("HAPPY_CODEX_ACP_PACKAGE", "HAPPIER_CODEX_ACP_PACKAGE");
|
|
6252
|
+
return configured || DEFAULT_CODEX_ACP_NPX_PACKAGE;
|
|
6253
|
+
}
|
|
5965
6254
|
function isBinOnPath(baseName) {
|
|
5966
6255
|
return resolveCommandOnPath(baseName) !== null;
|
|
5967
6256
|
}
|
|
@@ -6027,7 +6316,7 @@ function resolveCodexAcpSpawn(options = {}) {
|
|
|
6027
6316
|
}
|
|
6028
6317
|
return {
|
|
6029
6318
|
command: resolveNpxCommand(),
|
|
6030
|
-
args: ["--prefer-offline", "-y",
|
|
6319
|
+
args: ["--prefer-offline", "-y", readCodexAcpNpxPackage(), ...directArgs]
|
|
6031
6320
|
};
|
|
6032
6321
|
}
|
|
6033
6322
|
function validateCodexAcpSpawn(options = {}) {
|
|
@@ -6314,12 +6603,12 @@ async function ensureUnifiedDaemonStarted() {
|
|
|
6314
6603
|
async function executeUnifiedProvider(opts) {
|
|
6315
6604
|
const credentials = await ensureUnifiedRuntimePrerequisites(opts.credentials);
|
|
6316
6605
|
if (opts.provider === "claude") {
|
|
6317
|
-
const { runClaude } = await import('./runClaude-
|
|
6606
|
+
const { runClaude } = await import('./runClaude-CZ8gxaJL.mjs');
|
|
6318
6607
|
await runClaude(credentials, opts.claudeOptions ?? {});
|
|
6319
6608
|
return;
|
|
6320
6609
|
}
|
|
6321
6610
|
if (opts.provider === "codex") {
|
|
6322
|
-
const { runCodex } = await import('./runCodex-
|
|
6611
|
+
const { runCodex } = await import('./runCodex-DT7g4MPm.mjs');
|
|
6323
6612
|
await runCodex({
|
|
6324
6613
|
credentials,
|
|
6325
6614
|
startedBy: opts.startedBy,
|
|
@@ -6329,7 +6618,7 @@ async function executeUnifiedProvider(opts) {
|
|
|
6329
6618
|
return;
|
|
6330
6619
|
}
|
|
6331
6620
|
if (opts.provider === "gemini") {
|
|
6332
|
-
const { runGemini } = await import('./runGemini-
|
|
6621
|
+
const { runGemini } = await import('./runGemini-CmY5386l.mjs');
|
|
6333
6622
|
await runGemini({
|
|
6334
6623
|
credentials,
|
|
6335
6624
|
startedBy: opts.startedBy
|
|
@@ -6371,7 +6660,7 @@ function shouldRunMainClaudeFlow(opts) {
|
|
|
6371
6660
|
return;
|
|
6372
6661
|
} else if (subcommand === "runtime") {
|
|
6373
6662
|
if (args[1] === "providers") {
|
|
6374
|
-
const { renderRuntimeProviders } = await import('./command-
|
|
6663
|
+
const { renderRuntimeProviders } = await import('./command-Dl9SrMnv.mjs');
|
|
6375
6664
|
console.log(renderRuntimeProviders());
|
|
6376
6665
|
return;
|
|
6377
6666
|
}
|
|
@@ -6549,8 +6838,8 @@ function shouldRunMainClaudeFlow(opts) {
|
|
|
6549
6838
|
const projectId = args[3];
|
|
6550
6839
|
try {
|
|
6551
6840
|
const { saveGoogleCloudProjectToConfig } = await Promise.resolve().then(function () { return config; });
|
|
6552
|
-
const { readCredentials: readCredentials2 } = await import('./persistence-
|
|
6553
|
-
const { ApiClient: ApiClient2 } = await import('./api-
|
|
6841
|
+
const { readCredentials: readCredentials2 } = await import('./persistence-QqeBvUxX.mjs');
|
|
6842
|
+
const { ApiClient: ApiClient2 } = await import('./api-DoHt-HyL.mjs').then(function (n) { return n.q; });
|
|
6554
6843
|
let userEmail = void 0;
|
|
6555
6844
|
try {
|
|
6556
6845
|
const credentials = await readCredentials2();
|