@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/local.js
CHANGED
|
@@ -6547,6 +6547,20 @@ var TEXT_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
|
6547
6547
|
function isRecord2(value) {
|
|
6548
6548
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
6549
6549
|
}
|
|
6550
|
+
var ACP_HARNESS_NOISE_PATTERNS = [
|
|
6551
|
+
/^модель переключена на .+?\.?(?:\s*готов к работе[.!…]*)?$/iu,
|
|
6552
|
+
/^готов к работе[.!…]*$/iu,
|
|
6553
|
+
/^жду (?:вашего вопроса|вопроса или задачи|вашей задачи|вашего ответа|явного запроса)[^]*$/iu,
|
|
6554
|
+
/^это сообщение помечено как локальная команда[^]*$/iu,
|
|
6555
|
+
/^<local-command-(?:caveat|stdout|name|message|args)[^>]*>[^]*$/iu
|
|
6556
|
+
];
|
|
6557
|
+
function isHarnessNoiseLine(line) {
|
|
6558
|
+
const trimmed = line.trim();
|
|
6559
|
+
if (trimmed.length === 0) {
|
|
6560
|
+
return false;
|
|
6561
|
+
}
|
|
6562
|
+
return ACP_HARNESS_NOISE_PATTERNS.some((pattern) => pattern.test(trimmed));
|
|
6563
|
+
}
|
|
6550
6564
|
function splitCommandLine(commandLine) {
|
|
6551
6565
|
const matches = commandLine.match(/"[^"]*"|'[^']*'|[^\s]+/g) ?? [];
|
|
6552
6566
|
const parts = matches.map((part) => {
|
|
@@ -7383,6 +7397,7 @@ function buildAcpLifecycle(route, authRequest, mode) {
|
|
|
7383
7397
|
}
|
|
7384
7398
|
steps.push("session/new");
|
|
7385
7399
|
if (mode === "prompt") {
|
|
7400
|
+
steps.push("session/set_model");
|
|
7386
7401
|
steps.push("session/prompt");
|
|
7387
7402
|
}
|
|
7388
7403
|
return { steps, keys };
|
|
@@ -7470,6 +7485,9 @@ var AcpConnection = class {
|
|
|
7470
7485
|
env;
|
|
7471
7486
|
timeoutMs;
|
|
7472
7487
|
permissionMode;
|
|
7488
|
+
selectModel;
|
|
7489
|
+
suppressHarnessNoise;
|
|
7490
|
+
failOnHarnessOnlyTurn;
|
|
7473
7491
|
command;
|
|
7474
7492
|
args;
|
|
7475
7493
|
child;
|
|
@@ -7491,6 +7509,9 @@ var AcpConnection = class {
|
|
|
7491
7509
|
this.env = options.env;
|
|
7492
7510
|
this.timeoutMs = options.timeoutMs;
|
|
7493
7511
|
this.permissionMode = options.permissionMode;
|
|
7512
|
+
this.selectModel = options.selectModel;
|
|
7513
|
+
this.suppressHarnessNoise = options.suppressHarnessNoise;
|
|
7514
|
+
this.failOnHarnessOnlyTurn = options.failOnHarnessOnlyTurn;
|
|
7494
7515
|
const resolved = splitCommandLine(options.commandLine);
|
|
7495
7516
|
this.command = resolved.command;
|
|
7496
7517
|
this.args = resolved.args;
|
|
@@ -7523,8 +7544,18 @@ var AcpConnection = class {
|
|
|
7523
7544
|
usage: void 0,
|
|
7524
7545
|
attachments: [],
|
|
7525
7546
|
warnings: [],
|
|
7547
|
+
suppressNoise: this.suppressHarnessNoise,
|
|
7548
|
+
lineBuffer: "",
|
|
7549
|
+
harnessMarkers: [],
|
|
7526
7550
|
...onDelta ? { onDelta } : {}
|
|
7527
7551
|
};
|
|
7552
|
+
await this.selectSessionModel(
|
|
7553
|
+
sessionId,
|
|
7554
|
+
context.route,
|
|
7555
|
+
session,
|
|
7556
|
+
transport.phases ?? [],
|
|
7557
|
+
this.activePrompt.warnings
|
|
7558
|
+
);
|
|
7528
7559
|
let stopReason;
|
|
7529
7560
|
const abortSignal = context.abort.signal;
|
|
7530
7561
|
let abortListener;
|
|
@@ -7567,13 +7598,27 @@ var AcpConnection = class {
|
|
|
7567
7598
|
}
|
|
7568
7599
|
this.bumpIdleTimer();
|
|
7569
7600
|
}
|
|
7601
|
+
this.flushHarnessLineBuffer();
|
|
7570
7602
|
const stderrSlice = this.stderr.slice(stderrOffset).trim();
|
|
7571
7603
|
const warnings = [...this.activePrompt.warnings];
|
|
7604
|
+
if (this.activePrompt.harnessMarkers.length > 0) {
|
|
7605
|
+
warnings.push(
|
|
7606
|
+
`ACP: filtered ${this.activePrompt.harnessMarkers.length} interactive-harness line(s) from the response.`
|
|
7607
|
+
);
|
|
7608
|
+
}
|
|
7572
7609
|
if (stderrSlice.length > 0) {
|
|
7573
7610
|
warnings.push(stderrSlice);
|
|
7574
7611
|
}
|
|
7612
|
+
const text = this.activePrompt.text.trim();
|
|
7613
|
+
if (this.failOnHarnessOnlyTurn && this.activePrompt.harnessMarkers.length > 0 && text.length === 0) {
|
|
7614
|
+
this.activePrompt = void 0;
|
|
7615
|
+
throw new AiConnectError(
|
|
7616
|
+
"temporary_unavailable",
|
|
7617
|
+
"ACP turn returned only interactive-harness output (no task output)."
|
|
7618
|
+
);
|
|
7619
|
+
}
|
|
7575
7620
|
const result = {
|
|
7576
|
-
text
|
|
7621
|
+
text,
|
|
7577
7622
|
attachments: [...this.activePrompt.attachments],
|
|
7578
7623
|
warnings,
|
|
7579
7624
|
...this.activePrompt.usage ? { usage: this.activePrompt.usage } : {},
|
|
@@ -7880,6 +7925,108 @@ var AcpConnection = class {
|
|
|
7880
7925
|
}
|
|
7881
7926
|
});
|
|
7882
7927
|
}
|
|
7928
|
+
/**
|
|
7929
|
+
* Select the route's model through the ACP protocol (TASK-033 / UR-002).
|
|
7930
|
+
* Best-effort matrix: skip when disabled / no model / no advertised catalog /
|
|
7931
|
+
* already current; warn (not silently default) when the requested model is not
|
|
7932
|
+
* in the agent's `availableModels`; otherwise `session/set_model` and surface
|
|
7933
|
+
* any error as a warning. Never throws — a failed protocol selection must not
|
|
7934
|
+
* fail the generation.
|
|
7935
|
+
*/
|
|
7936
|
+
async selectSessionModel(sessionId, route, sessionResult, phases, warnings) {
|
|
7937
|
+
if (!this.selectModel) {
|
|
7938
|
+
return;
|
|
7939
|
+
}
|
|
7940
|
+
const desiredModel = route.model?.trim();
|
|
7941
|
+
if (!desiredModel) {
|
|
7942
|
+
return;
|
|
7943
|
+
}
|
|
7944
|
+
const catalog = modelCatalogFromSession(sessionResult);
|
|
7945
|
+
if (!catalog) {
|
|
7946
|
+
return;
|
|
7947
|
+
}
|
|
7948
|
+
if (catalog.currentModelId === desiredModel) {
|
|
7949
|
+
return;
|
|
7950
|
+
}
|
|
7951
|
+
const available = catalog.availableModels ?? [];
|
|
7952
|
+
if (available.length > 0 && !available.some((entry) => entry.modelId === desiredModel)) {
|
|
7953
|
+
warnings.push(
|
|
7954
|
+
`ACP agent's available models [${available.map((entry) => entry.modelId).join(", ")}] do not include route model "${desiredModel}"; model not switched via protocol.`
|
|
7955
|
+
);
|
|
7956
|
+
return;
|
|
7957
|
+
}
|
|
7958
|
+
try {
|
|
7959
|
+
await measurePhase(
|
|
7960
|
+
phases,
|
|
7961
|
+
"session/set_model",
|
|
7962
|
+
async () => this.request("session/set_model", {
|
|
7963
|
+
sessionId,
|
|
7964
|
+
modelId: desiredModel
|
|
7965
|
+
})
|
|
7966
|
+
);
|
|
7967
|
+
} catch (error) {
|
|
7968
|
+
const message = error instanceof Error ? error.message : isRecord2(error) && typeof error.message === "string" ? error.message : String(error);
|
|
7969
|
+
warnings.push(
|
|
7970
|
+
`ACP session/set_model("${desiredModel}") failed: ${message}`
|
|
7971
|
+
);
|
|
7972
|
+
}
|
|
7973
|
+
}
|
|
7974
|
+
/**
|
|
7975
|
+
* Append `agent_message_chunk` text (TASK-033 / UR-003). With suppression off
|
|
7976
|
+
* (legacy) the chunk streams + accumulates raw. With suppression on, the chunk
|
|
7977
|
+
* is line-buffered: each COMPLETE line is classified and either dropped (a
|
|
7978
|
+
* harness marker — no delta, no accumulation) or emitted; the trailing partial
|
|
7979
|
+
* line waits in `lineBuffer` for the next chunk or the end-of-turn flush.
|
|
7980
|
+
*/
|
|
7981
|
+
appendAgentText(chunk) {
|
|
7982
|
+
const state = this.activePrompt;
|
|
7983
|
+
if (!state) {
|
|
7984
|
+
return;
|
|
7985
|
+
}
|
|
7986
|
+
if (!state.suppressNoise) {
|
|
7987
|
+
state.onDelta?.(chunk);
|
|
7988
|
+
state.text += chunk;
|
|
7989
|
+
return;
|
|
7990
|
+
}
|
|
7991
|
+
state.lineBuffer += chunk;
|
|
7992
|
+
let newlineIndex = state.lineBuffer.indexOf("\n");
|
|
7993
|
+
while (newlineIndex !== -1) {
|
|
7994
|
+
const line = state.lineBuffer.slice(0, newlineIndex + 1);
|
|
7995
|
+
state.lineBuffer = state.lineBuffer.slice(newlineIndex + 1);
|
|
7996
|
+
this.emitAgentLine(line);
|
|
7997
|
+
newlineIndex = state.lineBuffer.indexOf("\n");
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
8000
|
+
/** Flush any trailing partial line through the harness-noise classifier. */
|
|
8001
|
+
flushHarnessLineBuffer() {
|
|
8002
|
+
const state = this.activePrompt;
|
|
8003
|
+
if (!state || !state.suppressNoise) {
|
|
8004
|
+
return;
|
|
8005
|
+
}
|
|
8006
|
+
const remaining = state.lineBuffer;
|
|
8007
|
+
state.lineBuffer = "";
|
|
8008
|
+
if (remaining.length > 0) {
|
|
8009
|
+
this.emitAgentLine(remaining);
|
|
8010
|
+
}
|
|
8011
|
+
}
|
|
8012
|
+
/**
|
|
8013
|
+
* Emit one classified line: a curated harness marker is recorded + dropped
|
|
8014
|
+
* (no delta, no accumulation); any other line streams + accumulates. `line`
|
|
8015
|
+
* may carry a trailing newline — classification runs on the content.
|
|
8016
|
+
*/
|
|
8017
|
+
emitAgentLine(line) {
|
|
8018
|
+
const state = this.activePrompt;
|
|
8019
|
+
if (!state) {
|
|
8020
|
+
return;
|
|
8021
|
+
}
|
|
8022
|
+
const content = line.endsWith("\n") ? line.slice(0, -1) : line;
|
|
8023
|
+
if (isHarnessNoiseLine(content)) {
|
|
8024
|
+
state.harnessMarkers.push(content.trim());
|
|
8025
|
+
return;
|
|
8026
|
+
}
|
|
8027
|
+
state.onDelta?.(line);
|
|
8028
|
+
state.text += line;
|
|
8029
|
+
}
|
|
7883
8030
|
handleNotification(message) {
|
|
7884
8031
|
if (message.method !== "session/update" || !this.activePrompt) {
|
|
7885
8032
|
return;
|
|
@@ -7894,8 +8041,7 @@ var AcpConnection = class {
|
|
|
7894
8041
|
}
|
|
7895
8042
|
const chunk = extractTextChunk(update);
|
|
7896
8043
|
if (update.sessionUpdate === "agent_message_chunk" && chunk) {
|
|
7897
|
-
this.
|
|
7898
|
-
this.activePrompt.text += chunk;
|
|
8044
|
+
this.appendAgentText(chunk);
|
|
7899
8045
|
}
|
|
7900
8046
|
if (update.sessionUpdate === "agent_thought_chunk" && chunk) {
|
|
7901
8047
|
this.activePrompt.warnings.push(chunk);
|
|
@@ -8082,7 +8228,10 @@ function createAcpTransportManager(options) {
|
|
|
8082
8228
|
cwd: runtime.cwd,
|
|
8083
8229
|
env: runtime.env,
|
|
8084
8230
|
timeoutMs: promptTimeout(options),
|
|
8085
|
-
permissionMode: options?.permissionMode ?? "deny-all"
|
|
8231
|
+
permissionMode: options?.permissionMode ?? "deny-all",
|
|
8232
|
+
selectModel: options?.selectModel ?? true,
|
|
8233
|
+
suppressHarnessNoise: options?.suppressHarnessNoise ?? true,
|
|
8234
|
+
failOnHarnessOnlyTurn: options?.failOnHarnessOnlyTurn ?? true
|
|
8086
8235
|
};
|
|
8087
8236
|
}
|
|
8088
8237
|
function getPool(key) {
|