@vedmalex/ai-connect 0.7.0 → 0.8.0
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/README.md +21 -0
- package/dist/bun/index.js +153 -4
- package/dist/bun/index.js.map +2 -2
- package/dist/bun/local.js +153 -4
- package/dist/bun/local.js.map +2 -2
- package/dist/node/index.js +153 -4
- package/dist/node/index.js.map +2 -2
- package/dist/node/local.js +153 -4
- package/dist/node/local.js.map +2 -2
- package/dist/types/acp.d.ts +14 -0
- package/dist/types/acp.d.ts.map +1 -1
- package/dist/types/types.d.ts +26 -0
- package/dist/types/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -6797,6 +6797,20 @@ var TEXT_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
|
6797
6797
|
function isRecord2(value) {
|
|
6798
6798
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
6799
6799
|
}
|
|
6800
|
+
var ACP_HARNESS_NOISE_PATTERNS = [
|
|
6801
|
+
/^модель переключена на .+?\.?(?:\s*готов к работе[.!…]*)?$/iu,
|
|
6802
|
+
/^готов к работе[.!…]*$/iu,
|
|
6803
|
+
/^жду (?:вашего вопроса|вопроса или задачи|вашей задачи|вашего ответа|явного запроса)[^]*$/iu,
|
|
6804
|
+
/^это сообщение помечено как локальная команда[^]*$/iu,
|
|
6805
|
+
/^<local-command-(?:caveat|stdout|name|message|args)[^>]*>[^]*$/iu
|
|
6806
|
+
];
|
|
6807
|
+
function isHarnessNoiseLine(line) {
|
|
6808
|
+
const trimmed = line.trim();
|
|
6809
|
+
if (trimmed.length === 0) {
|
|
6810
|
+
return false;
|
|
6811
|
+
}
|
|
6812
|
+
return ACP_HARNESS_NOISE_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
6813
|
+
}
|
|
6800
6814
|
function splitCommandLine(commandLine) {
|
|
6801
6815
|
const matches = commandLine.match(/"[^"]*"|'[^']*'|[^\s]+/g) ?? [];
|
|
6802
6816
|
const parts = matches.map((part) => {
|
|
@@ -7633,6 +7647,7 @@ function buildAcpLifecycle(route, authRequest, mode) {
|
|
|
7633
7647
|
}
|
|
7634
7648
|
steps.push("session/new");
|
|
7635
7649
|
if (mode === "prompt") {
|
|
7650
|
+
steps.push("session/set_model");
|
|
7636
7651
|
steps.push("session/prompt");
|
|
7637
7652
|
}
|
|
7638
7653
|
return { steps, keys };
|
|
@@ -7720,6 +7735,9 @@ var AcpConnection = class {
|
|
|
7720
7735
|
env;
|
|
7721
7736
|
timeoutMs;
|
|
7722
7737
|
permissionMode;
|
|
7738
|
+
selectModel;
|
|
7739
|
+
suppressHarnessNoise;
|
|
7740
|
+
failOnHarnessOnlyTurn;
|
|
7723
7741
|
command;
|
|
7724
7742
|
args;
|
|
7725
7743
|
child;
|
|
@@ -7741,6 +7759,9 @@ var AcpConnection = class {
|
|
|
7741
7759
|
this.env = options.env;
|
|
7742
7760
|
this.timeoutMs = options.timeoutMs;
|
|
7743
7761
|
this.permissionMode = options.permissionMode;
|
|
7762
|
+
this.selectModel = options.selectModel;
|
|
7763
|
+
this.suppressHarnessNoise = options.suppressHarnessNoise;
|
|
7764
|
+
this.failOnHarnessOnlyTurn = options.failOnHarnessOnlyTurn;
|
|
7744
7765
|
const resolved = splitCommandLine(options.commandLine);
|
|
7745
7766
|
this.command = resolved.command;
|
|
7746
7767
|
this.args = resolved.args;
|
|
@@ -7773,8 +7794,18 @@ var AcpConnection = class {
|
|
|
7773
7794
|
usage: void 0,
|
|
7774
7795
|
attachments: [],
|
|
7775
7796
|
warnings: [],
|
|
7797
|
+
suppressNoise: this.suppressHarnessNoise,
|
|
7798
|
+
lineBuffer: "",
|
|
7799
|
+
harnessMarkers: [],
|
|
7776
7800
|
...onDelta ? { onDelta } : {}
|
|
7777
7801
|
};
|
|
7802
|
+
await this.selectSessionModel(
|
|
7803
|
+
sessionId,
|
|
7804
|
+
context.route,
|
|
7805
|
+
session,
|
|
7806
|
+
transport.phases ?? [],
|
|
7807
|
+
this.activePrompt.warnings
|
|
7808
|
+
);
|
|
7778
7809
|
let stopReason;
|
|
7779
7810
|
const abortSignal = context.abort.signal;
|
|
7780
7811
|
let abortListener;
|
|
@@ -7817,13 +7848,27 @@ var AcpConnection = class {
|
|
|
7817
7848
|
}
|
|
7818
7849
|
this.bumpIdleTimer();
|
|
7819
7850
|
}
|
|
7851
|
+
this.flushHarnessLineBuffer();
|
|
7820
7852
|
const stderrSlice = this.stderr.slice(stderrOffset).trim();
|
|
7821
7853
|
const warnings = [...this.activePrompt.warnings];
|
|
7854
|
+
if (this.activePrompt.harnessMarkers.length > 0) {
|
|
7855
|
+
warnings.push(
|
|
7856
|
+
`ACP: filtered ${this.activePrompt.harnessMarkers.length} interactive-harness line(s) from the response.`
|
|
7857
|
+
);
|
|
7858
|
+
}
|
|
7822
7859
|
if (stderrSlice.length > 0) {
|
|
7823
7860
|
warnings.push(stderrSlice);
|
|
7824
7861
|
}
|
|
7862
|
+
const text = this.activePrompt.text.trim();
|
|
7863
|
+
if (this.failOnHarnessOnlyTurn && this.activePrompt.harnessMarkers.length > 0 && text.length === 0) {
|
|
7864
|
+
this.activePrompt = void 0;
|
|
7865
|
+
throw new AiConnectError(
|
|
7866
|
+
"temporary_unavailable",
|
|
7867
|
+
"ACP turn returned only interactive-harness output (no task output)."
|
|
7868
|
+
);
|
|
7869
|
+
}
|
|
7825
7870
|
const result = {
|
|
7826
|
-
text
|
|
7871
|
+
text,
|
|
7827
7872
|
attachments: [...this.activePrompt.attachments],
|
|
7828
7873
|
warnings,
|
|
7829
7874
|
...this.activePrompt.usage ? { usage: this.activePrompt.usage } : {},
|
|
@@ -8130,6 +8175,108 @@ var AcpConnection = class {
|
|
|
8130
8175
|
}
|
|
8131
8176
|
});
|
|
8132
8177
|
}
|
|
8178
|
+
/**
|
|
8179
|
+
* Select the route's model through the ACP protocol (TASK-033 / UR-002).
|
|
8180
|
+
* Best-effort matrix: skip when disabled / no model / no advertised catalog /
|
|
8181
|
+
* already current; warn (not silently default) when the requested model is not
|
|
8182
|
+
* in the agent's `availableModels`; otherwise `session/set_model` and surface
|
|
8183
|
+
* any error as a warning. Never throws — a failed protocol selection must not
|
|
8184
|
+
* fail the generation.
|
|
8185
|
+
*/
|
|
8186
|
+
async selectSessionModel(sessionId, route, sessionResult, phases, warnings) {
|
|
8187
|
+
if (!this.selectModel) {
|
|
8188
|
+
return;
|
|
8189
|
+
}
|
|
8190
|
+
const desiredModel = route.model?.trim();
|
|
8191
|
+
if (!desiredModel) {
|
|
8192
|
+
return;
|
|
8193
|
+
}
|
|
8194
|
+
const catalog = modelCatalogFromSession(sessionResult);
|
|
8195
|
+
if (!catalog) {
|
|
8196
|
+
return;
|
|
8197
|
+
}
|
|
8198
|
+
if (catalog.currentModelId === desiredModel) {
|
|
8199
|
+
return;
|
|
8200
|
+
}
|
|
8201
|
+
const available = catalog.availableModels ?? [];
|
|
8202
|
+
if (available.length > 0 && !available.some((entry) => entry.modelId === desiredModel)) {
|
|
8203
|
+
warnings.push(
|
|
8204
|
+
`ACP agent's available models [${available.map((entry) => entry.modelId).join(", ")}] do not include route model "${desiredModel}"; model not switched via protocol.`
|
|
8205
|
+
);
|
|
8206
|
+
return;
|
|
8207
|
+
}
|
|
8208
|
+
try {
|
|
8209
|
+
await measurePhase(
|
|
8210
|
+
phases,
|
|
8211
|
+
"session/set_model",
|
|
8212
|
+
async () => this.request("session/set_model", {
|
|
8213
|
+
sessionId,
|
|
8214
|
+
modelId: desiredModel
|
|
8215
|
+
})
|
|
8216
|
+
);
|
|
8217
|
+
} catch (error) {
|
|
8218
|
+
const message = error instanceof Error ? error.message : isRecord2(error) && typeof error.message === "string" ? error.message : String(error);
|
|
8219
|
+
warnings.push(
|
|
8220
|
+
`ACP session/set_model("${desiredModel}") failed: ${message}`
|
|
8221
|
+
);
|
|
8222
|
+
}
|
|
8223
|
+
}
|
|
8224
|
+
/**
|
|
8225
|
+
* Append `agent_message_chunk` text (TASK-033 / UR-003). With suppression off
|
|
8226
|
+
* (legacy) the chunk streams + accumulates raw. With suppression on, the chunk
|
|
8227
|
+
* is line-buffered: each COMPLETE line is classified and either dropped (a
|
|
8228
|
+
* harness marker — no delta, no accumulation) or emitted; the trailing partial
|
|
8229
|
+
* line waits in `lineBuffer` for the next chunk or the end-of-turn flush.
|
|
8230
|
+
*/
|
|
8231
|
+
appendAgentText(chunk) {
|
|
8232
|
+
const state = this.activePrompt;
|
|
8233
|
+
if (!state) {
|
|
8234
|
+
return;
|
|
8235
|
+
}
|
|
8236
|
+
if (!state.suppressNoise) {
|
|
8237
|
+
state.onDelta?.(chunk);
|
|
8238
|
+
state.text += chunk;
|
|
8239
|
+
return;
|
|
8240
|
+
}
|
|
8241
|
+
state.lineBuffer += chunk;
|
|
8242
|
+
let newlineIndex = state.lineBuffer.indexOf("\n");
|
|
8243
|
+
while (newlineIndex !== -1) {
|
|
8244
|
+
const line = state.lineBuffer.slice(0, newlineIndex + 1);
|
|
8245
|
+
state.lineBuffer = state.lineBuffer.slice(newlineIndex + 1);
|
|
8246
|
+
this.emitAgentLine(line);
|
|
8247
|
+
newlineIndex = state.lineBuffer.indexOf("\n");
|
|
8248
|
+
}
|
|
8249
|
+
}
|
|
8250
|
+
/** Flush any trailing partial line through the harness-noise classifier. */
|
|
8251
|
+
flushHarnessLineBuffer() {
|
|
8252
|
+
const state = this.activePrompt;
|
|
8253
|
+
if (!state || !state.suppressNoise) {
|
|
8254
|
+
return;
|
|
8255
|
+
}
|
|
8256
|
+
const remaining = state.lineBuffer;
|
|
8257
|
+
state.lineBuffer = "";
|
|
8258
|
+
if (remaining.length > 0) {
|
|
8259
|
+
this.emitAgentLine(remaining);
|
|
8260
|
+
}
|
|
8261
|
+
}
|
|
8262
|
+
/**
|
|
8263
|
+
* Emit one classified line: a curated harness marker is recorded + dropped
|
|
8264
|
+
* (no delta, no accumulation); any other line streams + accumulates. `line`
|
|
8265
|
+
* may carry a trailing newline — classification runs on the content.
|
|
8266
|
+
*/
|
|
8267
|
+
emitAgentLine(line) {
|
|
8268
|
+
const state = this.activePrompt;
|
|
8269
|
+
if (!state) {
|
|
8270
|
+
return;
|
|
8271
|
+
}
|
|
8272
|
+
const content = line.endsWith("\n") ? line.slice(0, -1) : line;
|
|
8273
|
+
if (isHarnessNoiseLine(content)) {
|
|
8274
|
+
state.harnessMarkers.push(content.trim());
|
|
8275
|
+
return;
|
|
8276
|
+
}
|
|
8277
|
+
state.onDelta?.(line);
|
|
8278
|
+
state.text += line;
|
|
8279
|
+
}
|
|
8133
8280
|
handleNotification(message) {
|
|
8134
8281
|
if (message.method !== "session/update" || !this.activePrompt) {
|
|
8135
8282
|
return;
|
|
@@ -8144,8 +8291,7 @@ var AcpConnection = class {
|
|
|
8144
8291
|
}
|
|
8145
8292
|
const chunk = extractTextChunk(update);
|
|
8146
8293
|
if (update.sessionUpdate === "agent_message_chunk" && chunk) {
|
|
8147
|
-
this.
|
|
8148
|
-
this.activePrompt.text += chunk;
|
|
8294
|
+
this.appendAgentText(chunk);
|
|
8149
8295
|
}
|
|
8150
8296
|
if (update.sessionUpdate === "agent_thought_chunk" && chunk) {
|
|
8151
8297
|
this.activePrompt.warnings.push(chunk);
|
|
@@ -8332,7 +8478,10 @@ function createAcpTransportManager(options) {
|
|
|
8332
8478
|
cwd: runtime.cwd,
|
|
8333
8479
|
env: runtime.env,
|
|
8334
8480
|
timeoutMs: promptTimeout(options),
|
|
8335
|
-
permissionMode: options?.permissionMode ?? "deny-all"
|
|
8481
|
+
permissionMode: options?.permissionMode ?? "deny-all",
|
|
8482
|
+
selectModel: options?.selectModel ?? true,
|
|
8483
|
+
suppressHarnessNoise: options?.suppressHarnessNoise ?? true,
|
|
8484
|
+
failOnHarnessOnlyTurn: options?.failOnHarnessOnlyTurn ?? true
|
|
8336
8485
|
};
|
|
8337
8486
|
}
|
|
8338
8487
|
function getPool(key) {
|