@get-bb/plugin-sdk 0.4.17 → 0.4.20
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/bundled-types/bb-plugin-sdk-internal-host-policy.d.ts +4 -3
- package/bundled-types/bb-plugin-sdk.d.ts +5 -3
- package/dist/internal/host-policy.js +13 -1
- package/dist/provider-bridge-acp.js +1191 -1077
- package/dist/provider-bridge-testing.js +2 -2
- package/dist/testing/index.js +14 -6
- package/package.json +1 -1
|
@@ -6802,1162 +6802,1190 @@ function resolveAcpPermissionDecision(args) {
|
|
|
6802
6802
|
|
|
6803
6803
|
// ../provider-bridge-acp/src/session-params.ts
|
|
6804
6804
|
import path4 from "node:path";
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
return void 0;
|
|
6805
|
+
|
|
6806
|
+
// ../provider-bridge-acp/src/bridge/model-catalog.ts
|
|
6807
|
+
var ACP_NATIVE_REASONING_EFFORTS = [
|
|
6808
|
+
{
|
|
6809
|
+
reasoningEffort: "medium",
|
|
6810
|
+
description: "Reasoning effort is managed by the connected ACP agent."
|
|
6812
6811
|
}
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6812
|
+
];
|
|
6813
|
+
var MODEL_LINE_PATTERN = /^(\S+) - (.+)$/;
|
|
6814
|
+
var BARE_PROVIDER_MODEL_LINE_PATTERN = /^\S+\/\S+$/;
|
|
6815
|
+
var BULLETED_MODEL_LINE_PATTERN = /^[*-]\s+(\S+)(?:\s+\([^)]*\))?$/u;
|
|
6816
|
+
var EFFORT_TOKENS = [
|
|
6817
|
+
["extra-high", "xhigh"],
|
|
6818
|
+
["medium", "medium"],
|
|
6819
|
+
["xhigh", "xhigh"],
|
|
6820
|
+
["high", "high"],
|
|
6821
|
+
["low", "low"],
|
|
6822
|
+
["max", "max"],
|
|
6823
|
+
["none", "none"]
|
|
6824
|
+
];
|
|
6825
|
+
var FAST_TAIL = "-fast";
|
|
6826
|
+
var THINKING_TOKEN = "thinking";
|
|
6827
|
+
function parseAgentModelLines(stdout) {
|
|
6828
|
+
const models = [];
|
|
6829
|
+
for (const line of stdout.split("\n")) {
|
|
6830
|
+
const trimmed = line.trim();
|
|
6831
|
+
const match = MODEL_LINE_PATTERN.exec(trimmed);
|
|
6832
|
+
if (!match) {
|
|
6833
|
+
const bulletMatch = BULLETED_MODEL_LINE_PATTERN.exec(trimmed);
|
|
6834
|
+
if (bulletMatch) {
|
|
6835
|
+
const [, id2] = bulletMatch;
|
|
6836
|
+
models.push({ id: id2, displayName: id2 });
|
|
6837
|
+
continue;
|
|
6838
|
+
}
|
|
6839
|
+
if (BARE_PROVIDER_MODEL_LINE_PATTERN.test(trimmed)) {
|
|
6840
|
+
models.push({ id: trimmed, displayName: trimmed });
|
|
6841
|
+
}
|
|
6842
|
+
continue;
|
|
6843
|
+
}
|
|
6844
|
+
const [, id, displayName] = match;
|
|
6845
|
+
models.push({ id, displayName });
|
|
6825
6846
|
}
|
|
6826
|
-
return
|
|
6827
|
-
"bb skills are reusable instruction folders. When the current task matches a listed skill description, read that skill's SKILL.md at the absolute path before proceeding; you may read supporting files in the same skill directory that SKILL.md references. If a listed path does not exist, the list is stale and should be ignored.",
|
|
6828
|
-
"",
|
|
6829
|
-
"Available bb skills:",
|
|
6830
|
-
...skillLines
|
|
6831
|
-
].join("\n");
|
|
6847
|
+
return models;
|
|
6832
6848
|
}
|
|
6833
|
-
function
|
|
6834
|
-
const
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6849
|
+
function findAcpModelConfigOption(configOptions) {
|
|
6850
|
+
const options = configOptions ?? [];
|
|
6851
|
+
return options.find((option) => option.category === "model") ?? options.find((option) => option.id === "model");
|
|
6852
|
+
}
|
|
6853
|
+
function findAcpThoughtLevelConfigOption(configOptions) {
|
|
6854
|
+
return (configOptions ?? []).find(
|
|
6855
|
+
(option) => option.category === "thought_level"
|
|
6838
6856
|
);
|
|
6839
|
-
return instructions.length > 0 ? instructions.join("\n\n") : void 0;
|
|
6840
6857
|
}
|
|
6841
|
-
|
|
6842
|
-
|
|
6858
|
+
var ACP_NATIVE_REASONING_LEVEL_BY_VALUE = {
|
|
6859
|
+
none: "none",
|
|
6860
|
+
minimal: "low",
|
|
6861
|
+
low: "low",
|
|
6862
|
+
medium: "medium",
|
|
6863
|
+
high: "high",
|
|
6864
|
+
xhigh: "xhigh",
|
|
6865
|
+
ultracode: "ultracode",
|
|
6866
|
+
max: "max",
|
|
6867
|
+
ultra: "ultra"
|
|
6868
|
+
};
|
|
6869
|
+
var ACP_NATIVE_REASONING_VALUE_CANDIDATES_BY_LEVEL = {
|
|
6870
|
+
none: ["none"],
|
|
6871
|
+
low: ["low", "minimal"],
|
|
6872
|
+
medium: ["medium"],
|
|
6873
|
+
high: ["high"],
|
|
6874
|
+
xhigh: ["xhigh"],
|
|
6875
|
+
ultracode: ["ultracode", "xhigh"],
|
|
6876
|
+
max: ["max", "xhigh"],
|
|
6877
|
+
ultra: ["ultra", "max"]
|
|
6878
|
+
};
|
|
6879
|
+
function acpNativeValueToReasoningLevel(value) {
|
|
6880
|
+
return value === void 0 ? void 0 : ACP_NATIVE_REASONING_LEVEL_BY_VALUE[value];
|
|
6843
6881
|
}
|
|
6844
|
-
function
|
|
6845
|
-
|
|
6882
|
+
function acpNativeReasoningLevelToValue(level, thoughtLevelOption) {
|
|
6883
|
+
const candidateValues = ACP_NATIVE_REASONING_VALUE_CANDIDATES_BY_LEVEL[level];
|
|
6884
|
+
if (candidateValues === void 0) {
|
|
6846
6885
|
return void 0;
|
|
6847
6886
|
}
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
...launchEnvVars(launchSpec)
|
|
6853
|
-
};
|
|
6887
|
+
const values = new Set(
|
|
6888
|
+
(thoughtLevelOption.options ?? []).map((o) => o.value)
|
|
6889
|
+
);
|
|
6890
|
+
return candidateValues.find((value) => values.has(value));
|
|
6854
6891
|
}
|
|
6855
|
-
function
|
|
6856
|
-
|
|
6857
|
-
|
|
6892
|
+
function buildAcpNativeReasoningSupport(thoughtLevelOption) {
|
|
6893
|
+
const options = thoughtLevelOption?.options ?? [];
|
|
6894
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6895
|
+
const matchedValueByLevel = /* @__PURE__ */ new Map();
|
|
6896
|
+
const supportedReasoningEfforts = [];
|
|
6897
|
+
for (const option of options) {
|
|
6898
|
+
const level = acpNativeValueToReasoningLevel(option.value);
|
|
6899
|
+
if (level === void 0) {
|
|
6900
|
+
continue;
|
|
6901
|
+
}
|
|
6902
|
+
if (seen.has(level)) {
|
|
6903
|
+
const previousValue = matchedValueByLevel.get(level);
|
|
6904
|
+
if (previousValue !== level && option.value === level) {
|
|
6905
|
+
const effort = supportedReasoningEfforts.find(
|
|
6906
|
+
(candidate) => candidate.reasoningEffort === level
|
|
6907
|
+
);
|
|
6908
|
+
if (effort) {
|
|
6909
|
+
effort.description = option.name ?? option.value;
|
|
6910
|
+
}
|
|
6911
|
+
matchedValueByLevel.set(level, option.value);
|
|
6912
|
+
}
|
|
6913
|
+
continue;
|
|
6914
|
+
}
|
|
6915
|
+
seen.add(level);
|
|
6916
|
+
matchedValueByLevel.set(level, option.value);
|
|
6917
|
+
supportedReasoningEfforts.push({
|
|
6918
|
+
reasoningEffort: level,
|
|
6919
|
+
description: option.name ?? option.value
|
|
6920
|
+
});
|
|
6858
6921
|
}
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6922
|
+
supportedReasoningEfforts.sort(
|
|
6923
|
+
(a, b) => reasoningLevelValues.indexOf(a.reasoningEffort) - reasoningLevelValues.indexOf(b.reasoningEffort)
|
|
6924
|
+
);
|
|
6925
|
+
if (supportedReasoningEfforts.length === 0) {
|
|
6926
|
+
return {
|
|
6927
|
+
// An omitted option preserves the legacy agent-managed fallback. A
|
|
6928
|
+
// declared option is authoritative, even when bb cannot map its values.
|
|
6929
|
+
supportedReasoningEfforts: thoughtLevelOption === void 0 ? ACP_NATIVE_REASONING_EFFORTS : [],
|
|
6930
|
+
defaultReasoningEffort: "medium"
|
|
6931
|
+
};
|
|
6869
6932
|
}
|
|
6870
|
-
const
|
|
6871
|
-
|
|
6933
|
+
const currentLevel = acpNativeValueToReasoningLevel(
|
|
6934
|
+
thoughtLevelOption?.currentValue
|
|
6935
|
+
);
|
|
6936
|
+
const supportedLevels = supportedReasoningEfforts.map(
|
|
6937
|
+
(effort) => effort.reasoningEffort
|
|
6938
|
+
);
|
|
6872
6939
|
return {
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
primaryModels: [...launchSpec.modelCli?.primaryModels ?? []],
|
|
6876
|
-
...launchSpec.reasoningCli !== void 0 ? { reasoningCli: launchSpec.reasoningCli } : {},
|
|
6877
|
-
...launchSpec.nativeReasoning !== void 0 ? { nativeReasoning: launchSpec.nativeReasoning } : {}
|
|
6940
|
+
supportedReasoningEfforts,
|
|
6941
|
+
defaultReasoningEffort: currentLevel !== void 0 && supportedLevels.includes(currentLevel) ? currentLevel : supportedReasoningEfforts[0].reasoningEffort
|
|
6878
6942
|
};
|
|
6879
6943
|
}
|
|
6880
|
-
function
|
|
6881
|
-
const
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
return {};
|
|
6944
|
+
function buildModelCatalogFromConfigOptions(modelOption, reasoningByModel) {
|
|
6945
|
+
const options = modelOption?.options ?? [];
|
|
6946
|
+
if (options.length === 0) {
|
|
6947
|
+
return [];
|
|
6885
6948
|
}
|
|
6886
|
-
|
|
6949
|
+
const currentValue = modelOption?.currentValue;
|
|
6950
|
+
const models = options.map((option, index) => {
|
|
6951
|
+
const isDefault = currentValue !== void 0 ? option.value === currentValue : index === 0;
|
|
6952
|
+
const reasoning = reasoningByModel?.get(option.value) ?? {
|
|
6953
|
+
supportedReasoningEfforts: ACP_NATIVE_REASONING_EFFORTS,
|
|
6954
|
+
defaultReasoningEffort: "medium"
|
|
6955
|
+
};
|
|
6887
6956
|
return {
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6957
|
+
id: option.value,
|
|
6958
|
+
model: option.value,
|
|
6959
|
+
displayName: option.name ?? option.value,
|
|
6960
|
+
description: "",
|
|
6961
|
+
supportedReasoningEfforts: reasoning.supportedReasoningEfforts,
|
|
6962
|
+
defaultReasoningEffort: reasoning.defaultReasoningEffort,
|
|
6963
|
+
isDefault
|
|
6892
6964
|
};
|
|
6893
|
-
}
|
|
6894
|
-
return
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
selectFlag: launchSpec.modelCli.selectFlag,
|
|
6898
|
-
model,
|
|
6899
|
-
...options.reasoningLevel !== void 0 ? { reasoningLevel: options.reasoningLevel } : {},
|
|
6900
|
-
// Only "fast" changes resolution; "default" is the catalog's normal id.
|
|
6901
|
-
...options.serviceTier === "fast" ? { serviceTier: options.serviceTier } : {}
|
|
6902
|
-
}
|
|
6903
|
-
};
|
|
6965
|
+
});
|
|
6966
|
+
return models.some((model) => model.isDefault) ? models : models.map(
|
|
6967
|
+
(model, index) => index === 0 ? { ...model, isDefault: true } : model
|
|
6968
|
+
);
|
|
6904
6969
|
}
|
|
6905
|
-
function
|
|
6906
|
-
const
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
const envVars = {
|
|
6910
|
-
...launchSpec.env,
|
|
6911
|
-
...options.envVars ?? {}
|
|
6912
|
-
};
|
|
6913
|
-
if (options.permissionMode === "auto") {
|
|
6914
|
-
throw new Error(
|
|
6915
|
-
`Provider "${args.providerLabel}" does not support permission mode "auto".`
|
|
6916
|
-
);
|
|
6970
|
+
function buildModelCatalogFromSessionModels(sessionModels) {
|
|
6971
|
+
const availableModels = sessionModels?.availableModels ?? [];
|
|
6972
|
+
if (availableModels.length === 0) {
|
|
6973
|
+
return [];
|
|
6917
6974
|
}
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
...instructions ? { instructions } : {},
|
|
6935
|
-
...args.dynamicTools && args.dynamicTools.length > 0 ? { dynamicTools: args.dynamicTools } : {}
|
|
6936
|
-
};
|
|
6937
|
-
}
|
|
6938
|
-
|
|
6939
|
-
// ../provider-bridge-acp/src/bridge/agent-connection.ts
|
|
6940
|
-
import { spawn } from "node:child_process";
|
|
6941
|
-
import { createInterface } from "node:readline";
|
|
6942
|
-
var STDERR_TAIL_MAX_CHUNKS = 40;
|
|
6943
|
-
var CLOSED_STDIN_ERROR_CODES = /* @__PURE__ */ new Set(["EPIPE", "ERR_STREAM_DESTROYED"]);
|
|
6944
|
-
var AcpAgentExitedError = class extends Error {
|
|
6945
|
-
constructor(message) {
|
|
6946
|
-
super(message);
|
|
6947
|
-
this.name = "AcpAgentExitedError";
|
|
6948
|
-
}
|
|
6949
|
-
};
|
|
6950
|
-
var AcpAgentResponseError = class extends Error {
|
|
6951
|
-
code;
|
|
6952
|
-
constructor(message, code) {
|
|
6953
|
-
super(message);
|
|
6954
|
-
this.name = "AcpAgentResponseError";
|
|
6955
|
-
this.code = code;
|
|
6956
|
-
}
|
|
6957
|
-
};
|
|
6958
|
-
function isClosedAgentStdinError(error) {
|
|
6959
|
-
return "code" in error && typeof error.code === "string" && CLOSED_STDIN_ERROR_CODES.has(error.code);
|
|
6960
|
-
}
|
|
6961
|
-
function formatAgentError(error) {
|
|
6962
|
-
const message = error.message ?? `ACP agent returned error code ${error.code ?? "unknown"}`;
|
|
6963
|
-
const details = formatAgentErrorData(error.data);
|
|
6964
|
-
return details === void 0 ? message : `${message}: ${details}`;
|
|
6975
|
+
const currentModelId = sessionModels?.currentModelId;
|
|
6976
|
+
const models = availableModels.map((model, index) => {
|
|
6977
|
+
const isDefault = currentModelId !== void 0 ? model.modelId === currentModelId : index === 0;
|
|
6978
|
+
return {
|
|
6979
|
+
id: model.modelId,
|
|
6980
|
+
model: model.modelId,
|
|
6981
|
+
displayName: model.name ?? model.modelId,
|
|
6982
|
+
description: model.description ?? "",
|
|
6983
|
+
supportedReasoningEfforts: ACP_NATIVE_REASONING_EFFORTS,
|
|
6984
|
+
defaultReasoningEffort: "medium",
|
|
6985
|
+
isDefault
|
|
6986
|
+
};
|
|
6987
|
+
});
|
|
6988
|
+
return models.some((model) => model.isDefault) ? models : models.map(
|
|
6989
|
+
(model, index) => index === 0 ? { ...model, isDefault: true } : model
|
|
6990
|
+
);
|
|
6965
6991
|
}
|
|
6966
|
-
function
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6992
|
+
function splitVariant(id) {
|
|
6993
|
+
let rest = id;
|
|
6994
|
+
let fast = false;
|
|
6995
|
+
if (rest.endsWith(FAST_TAIL)) {
|
|
6996
|
+
fast = true;
|
|
6997
|
+
rest = rest.slice(0, -FAST_TAIL.length);
|
|
6972
6998
|
}
|
|
6973
|
-
|
|
6974
|
-
|
|
6999
|
+
let thinking = false;
|
|
7000
|
+
if (rest.endsWith(`-${THINKING_TOKEN}`)) {
|
|
7001
|
+
thinking = true;
|
|
7002
|
+
rest = rest.slice(0, -(THINKING_TOKEN.length + 1));
|
|
7003
|
+
} else if (rest.includes(`-${THINKING_TOKEN}-`)) {
|
|
7004
|
+
thinking = true;
|
|
7005
|
+
rest = rest.replace(`-${THINKING_TOKEN}-`, "-");
|
|
6975
7006
|
}
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
7007
|
+
for (const [token, effort] of EFFORT_TOKENS) {
|
|
7008
|
+
if (rest.endsWith(`-${token}`)) {
|
|
7009
|
+
return {
|
|
7010
|
+
familyKey: rest.slice(0, -(token.length + 1)),
|
|
7011
|
+
effort,
|
|
7012
|
+
effortToken: token,
|
|
7013
|
+
fast,
|
|
7014
|
+
thinking
|
|
7015
|
+
};
|
|
7016
|
+
}
|
|
6980
7017
|
}
|
|
7018
|
+
return {
|
|
7019
|
+
familyKey: rest,
|
|
7020
|
+
effort: "medium",
|
|
7021
|
+
effortToken: void 0,
|
|
7022
|
+
fast,
|
|
7023
|
+
thinking
|
|
7024
|
+
};
|
|
6981
7025
|
}
|
|
6982
|
-
function
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
7026
|
+
function agentModelFamilyId(id) {
|
|
7027
|
+
return splitVariant(id).familyKey;
|
|
7028
|
+
}
|
|
7029
|
+
var EFFORT_DISPLAY_WORDS = {
|
|
7030
|
+
"extra-high": "Extra High",
|
|
7031
|
+
medium: "Medium",
|
|
7032
|
+
xhigh: "Extra High",
|
|
7033
|
+
high: "High",
|
|
7034
|
+
low: "Low",
|
|
7035
|
+
max: "Max",
|
|
7036
|
+
ultra: "Ultra",
|
|
7037
|
+
none: "None"
|
|
7038
|
+
};
|
|
7039
|
+
function familyDisplayName(displayName, effortToken) {
|
|
7040
|
+
const word = effortToken ? EFFORT_DISPLAY_WORDS[effortToken] : void 0;
|
|
7041
|
+
if (!word) {
|
|
7042
|
+
return cleanDisplayName(displayName);
|
|
6986
7043
|
}
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
7044
|
+
return cleanDisplayName(
|
|
7045
|
+
displayName.replace(new RegExp(`(^|\\s)${word}(?=\\s|$)`), "$1")
|
|
7046
|
+
);
|
|
7047
|
+
}
|
|
7048
|
+
function cleanDisplayName(name) {
|
|
7049
|
+
return name.replace(/\s*\((?:NO ZDR|default|current)\)/gi, "").replace(/(^|\s)(?:1M|Thinking)(?=\s|$)/g, "$1").replace(/\s{2,}/g, " ").trim();
|
|
7050
|
+
}
|
|
7051
|
+
function buildAgentModelCatalog(rawModels) {
|
|
7052
|
+
const families = /* @__PURE__ */ new Map();
|
|
7053
|
+
for (const raw of rawModels) {
|
|
7054
|
+
const { familyKey, effort, effortToken, fast, thinking } = splitVariant(
|
|
7055
|
+
raw.id
|
|
7056
|
+
);
|
|
7057
|
+
const members = families.get(familyKey) ?? [];
|
|
7058
|
+
members.push({ ...raw, effort, effortToken, fast, thinking });
|
|
7059
|
+
families.set(familyKey, members);
|
|
6992
7060
|
}
|
|
6993
|
-
if (
|
|
7061
|
+
if (families.size === 0) {
|
|
6994
7062
|
return null;
|
|
6995
7063
|
}
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
const
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
function closeForAgentStdin(error) {
|
|
7018
|
-
if (exited) {
|
|
7019
|
-
return;
|
|
7064
|
+
const models = [];
|
|
7065
|
+
const variantsByFamilyId = /* @__PURE__ */ new Map();
|
|
7066
|
+
const defaultEffortByFamilyId = /* @__PURE__ */ new Map();
|
|
7067
|
+
for (const members of families.values()) {
|
|
7068
|
+
const hasThinking = members.some((m) => m.thinking);
|
|
7069
|
+
const leveled = members.map((member) => ({
|
|
7070
|
+
member,
|
|
7071
|
+
level: member.thinking ? member.effort : hasThinking ? "none" : member.effort
|
|
7072
|
+
}));
|
|
7073
|
+
const byLevel = /* @__PURE__ */ new Map();
|
|
7074
|
+
const repEffortByCell = /* @__PURE__ */ new Map();
|
|
7075
|
+
for (const { member, level } of leveled) {
|
|
7076
|
+
const slot = member.fast ? "fast" : "normal";
|
|
7077
|
+
const tier = byLevel.get(level) ?? {};
|
|
7078
|
+
const cellKey = `${level}:${slot}`;
|
|
7079
|
+
const upgradesNoneRep = level === "none" && member.effort === "medium" && repEffortByCell.get(cellKey) !== "medium";
|
|
7080
|
+
if (tier[slot] === void 0 || upgradesNoneRep) {
|
|
7081
|
+
tier[slot] = member.id;
|
|
7082
|
+
repEffortByCell.set(cellKey, member.effort);
|
|
7083
|
+
byLevel.set(level, tier);
|
|
7084
|
+
}
|
|
7020
7085
|
}
|
|
7021
|
-
|
|
7022
|
-
const
|
|
7023
|
-
const
|
|
7024
|
-
|
|
7025
|
-
|
|
7086
|
+
const nonFast = leveled.filter((entry) => !entry.member.fast);
|
|
7087
|
+
const pool = nonFast.length > 0 ? nonFast : leveled;
|
|
7088
|
+
const defaultEntry = pool.find((entry) => entry.level === "medium") ?? pool.find((entry) => entry.level !== "none") ?? pool[0];
|
|
7089
|
+
const defaultVariant = defaultEntry.member;
|
|
7090
|
+
const levelsInLadderOrder = [...byLevel.keys()].sort(
|
|
7091
|
+
(a, b) => reasoningLevelValues.indexOf(a) - reasoningLevelValues.indexOf(b)
|
|
7026
7092
|
);
|
|
7027
|
-
|
|
7028
|
-
const
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
const stdin = child.stdin;
|
|
7033
|
-
if (!stdin || stdin.destroyed || !stdin.writable) {
|
|
7034
|
-
closeForAgentStdin(new Error("stdin is not writable"));
|
|
7035
|
-
return;
|
|
7093
|
+
const nameByLevel = /* @__PURE__ */ new Map();
|
|
7094
|
+
for (const { member, level } of leveled) {
|
|
7095
|
+
if (!nameByLevel.has(level)) {
|
|
7096
|
+
nameByLevel.set(level, member.displayName);
|
|
7097
|
+
}
|
|
7036
7098
|
}
|
|
7037
|
-
|
|
7099
|
+
models.push({
|
|
7100
|
+
id: defaultVariant.id,
|
|
7101
|
+
model: defaultVariant.id,
|
|
7102
|
+
displayName: familyDisplayName(
|
|
7103
|
+
defaultVariant.displayName,
|
|
7104
|
+
defaultVariant.effortToken
|
|
7105
|
+
),
|
|
7106
|
+
description: "",
|
|
7107
|
+
supportedReasoningEfforts: levelsInLadderOrder.map((level) => ({
|
|
7108
|
+
reasoningEffort: level,
|
|
7109
|
+
description: nameByLevel.get(level) ?? ""
|
|
7110
|
+
})),
|
|
7111
|
+
defaultReasoningEffort: defaultEntry.level,
|
|
7112
|
+
// The agent lists its default model first.
|
|
7113
|
+
isDefault: models.length === 0
|
|
7114
|
+
});
|
|
7115
|
+
variantsByFamilyId.set(defaultVariant.id, byLevel);
|
|
7116
|
+
defaultEffortByFamilyId.set(defaultVariant.id, defaultEntry.level);
|
|
7038
7117
|
}
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7118
|
+
return {
|
|
7119
|
+
models,
|
|
7120
|
+
resolveVariant({ model, reasoningLevel, serviceTier }) {
|
|
7121
|
+
const byLevel = variantsByFamilyId.get(model);
|
|
7122
|
+
if (!byLevel) {
|
|
7123
|
+
return void 0;
|
|
7124
|
+
}
|
|
7125
|
+
const level = reasoningLevel ?? defaultEffortByFamilyId.get(model);
|
|
7126
|
+
const tier = level === void 0 ? void 0 : byLevel.get(level);
|
|
7127
|
+
if (!tier) {
|
|
7128
|
+
return void 0;
|
|
7129
|
+
}
|
|
7130
|
+
if (serviceTier === "fast" && tier.fast !== void 0) {
|
|
7131
|
+
return tier.fast;
|
|
7132
|
+
}
|
|
7133
|
+
return tier.normal ?? tier.fast;
|
|
7042
7134
|
}
|
|
7043
|
-
|
|
7135
|
+
};
|
|
7136
|
+
}
|
|
7137
|
+
function splitPrimaryModels(catalogModels, primaryModels) {
|
|
7138
|
+
const primaryIds = new Set(primaryModels);
|
|
7139
|
+
const modelsById = new Map(catalogModels.map((model) => [model.id, model]));
|
|
7140
|
+
const models = primaryModels.flatMap((id) => {
|
|
7141
|
+
const model = modelsById.get(id);
|
|
7142
|
+
return model ? [model] : [];
|
|
7044
7143
|
});
|
|
7045
|
-
if (
|
|
7046
|
-
|
|
7047
|
-
input: child.stdout,
|
|
7048
|
-
terminal: false
|
|
7049
|
-
});
|
|
7050
|
-
stdoutLines.on("line", (line) => {
|
|
7051
|
-
const message = parseAgentLine(line);
|
|
7052
|
-
if (!message) {
|
|
7053
|
-
return;
|
|
7054
|
-
}
|
|
7055
|
-
const id = message.id;
|
|
7056
|
-
if ((typeof id === "string" || typeof id === "number") && message.method === void 0) {
|
|
7057
|
-
const numericId = typeof id === "number" ? id : Number(id);
|
|
7058
|
-
const request = pending.get(numericId);
|
|
7059
|
-
if (!request) {
|
|
7060
|
-
return;
|
|
7061
|
-
}
|
|
7062
|
-
pending.delete(numericId);
|
|
7063
|
-
if (message.error) {
|
|
7064
|
-
request.reject(
|
|
7065
|
-
new AcpAgentResponseError(
|
|
7066
|
-
formatAgentError(message.error),
|
|
7067
|
-
message.error.code
|
|
7068
|
-
)
|
|
7069
|
-
);
|
|
7070
|
-
} else {
|
|
7071
|
-
request.resolve(message.result);
|
|
7072
|
-
}
|
|
7073
|
-
return;
|
|
7074
|
-
}
|
|
7075
|
-
if (typeof message.method !== "string") {
|
|
7076
|
-
return;
|
|
7077
|
-
}
|
|
7078
|
-
if (typeof id === "string" || typeof id === "number") {
|
|
7079
|
-
let settled = false;
|
|
7080
|
-
options.onRequest(message.method, message.params, {
|
|
7081
|
-
result(value) {
|
|
7082
|
-
if (settled) return;
|
|
7083
|
-
settled = true;
|
|
7084
|
-
writeLine({ jsonrpc: "2.0", id, result: value ?? null });
|
|
7085
|
-
},
|
|
7086
|
-
error(code, errorMessage) {
|
|
7087
|
-
if (settled) return;
|
|
7088
|
-
settled = true;
|
|
7089
|
-
writeLine({
|
|
7090
|
-
jsonrpc: "2.0",
|
|
7091
|
-
id,
|
|
7092
|
-
error: { code, message: errorMessage }
|
|
7093
|
-
});
|
|
7094
|
-
}
|
|
7095
|
-
});
|
|
7096
|
-
return;
|
|
7097
|
-
}
|
|
7098
|
-
options.onNotification(message.method, message.params);
|
|
7099
|
-
});
|
|
7100
|
-
}
|
|
7101
|
-
if (child.stderr) {
|
|
7102
|
-
const stderrLines = createInterface({
|
|
7103
|
-
input: child.stderr,
|
|
7104
|
-
terminal: false
|
|
7105
|
-
});
|
|
7106
|
-
stderrLines.on("line", (line) => {
|
|
7107
|
-
stderrChunks.push(line);
|
|
7108
|
-
if (stderrChunks.length > STDERR_TAIL_MAX_CHUNKS) {
|
|
7109
|
-
stderrChunks.shift();
|
|
7110
|
-
}
|
|
7111
|
-
});
|
|
7144
|
+
if (models.length === 0) {
|
|
7145
|
+
return { models: [...catalogModels], selectedOnlyModels: [] };
|
|
7112
7146
|
}
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
)
|
|
7122
|
-
);
|
|
7123
|
-
options.onExit({ code: null, signal: null, stderrTail: error.message });
|
|
7124
|
-
});
|
|
7125
|
-
child.on("exit", (code, signal) => {
|
|
7126
|
-
if (exited) {
|
|
7127
|
-
return;
|
|
7128
|
-
}
|
|
7129
|
-
exited = true;
|
|
7130
|
-
const stderrTail = stderrChunks.join("\n");
|
|
7131
|
-
rejectAllPending(
|
|
7132
|
-
new AcpAgentExitedError(
|
|
7133
|
-
`ACP agent "${options.command}" exited (code ${code ?? "null"}, signal ${signal ?? "null"})${stderrTail ? `: ${stderrTail}` : ""}`
|
|
7147
|
+
const selectedOnlyModels = catalogModels.filter(
|
|
7148
|
+
(model) => !primaryIds.has(model.id)
|
|
7149
|
+
);
|
|
7150
|
+
if (models.some((model) => model.isDefault)) {
|
|
7151
|
+
return {
|
|
7152
|
+
models,
|
|
7153
|
+
selectedOnlyModels: selectedOnlyModels.map(
|
|
7154
|
+
(model) => model.isDefault ? { ...model, isDefault: false } : model
|
|
7134
7155
|
)
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
});
|
|
7156
|
+
};
|
|
7157
|
+
}
|
|
7138
7158
|
return {
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
new AcpAgentExitedError(
|
|
7146
|
-
`ACP agent "${options.command}" is not running`
|
|
7147
|
-
)
|
|
7148
|
-
);
|
|
7149
|
-
}
|
|
7150
|
-
const id = nextRequestId;
|
|
7151
|
-
nextRequestId += 1;
|
|
7152
|
-
return new Promise((resolve4, reject) => {
|
|
7153
|
-
pending.set(id, {
|
|
7154
|
-
resolve: (value) => {
|
|
7155
|
-
const parsed = resultSchema.safeParse(value);
|
|
7156
|
-
if (parsed.success) {
|
|
7157
|
-
resolve4(parsed.data);
|
|
7158
|
-
} else {
|
|
7159
|
-
reject(
|
|
7160
|
-
new Error(
|
|
7161
|
-
`ACP agent returned an unexpected ${method} result: ${parsed.error.message}`
|
|
7162
|
-
)
|
|
7163
|
-
);
|
|
7164
|
-
}
|
|
7165
|
-
},
|
|
7166
|
-
reject
|
|
7167
|
-
});
|
|
7168
|
-
writeLine({ jsonrpc: "2.0", id, method, params });
|
|
7169
|
-
});
|
|
7170
|
-
},
|
|
7171
|
-
notify(method, params) {
|
|
7172
|
-
if (exited) {
|
|
7173
|
-
return;
|
|
7174
|
-
}
|
|
7175
|
-
writeLine({ jsonrpc: "2.0", method, params });
|
|
7176
|
-
},
|
|
7177
|
-
kill() {
|
|
7178
|
-
if (exited) {
|
|
7179
|
-
return;
|
|
7180
|
-
}
|
|
7181
|
-
child.kill("SIGTERM");
|
|
7182
|
-
}
|
|
7159
|
+
models: models.map(
|
|
7160
|
+
(model, index) => index === 0 ? { ...model, isDefault: true } : model
|
|
7161
|
+
),
|
|
7162
|
+
selectedOnlyModels: selectedOnlyModels.map(
|
|
7163
|
+
(model) => model.isDefault ? { ...model, isDefault: false } : model
|
|
7164
|
+
)
|
|
7183
7165
|
};
|
|
7184
7166
|
}
|
|
7185
7167
|
|
|
7186
|
-
// ../provider-bridge-acp/src/
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
import { homedir } from "node:os";
|
|
7191
|
-
import { basename as basename2, dirname, join as join2, resolve as resolve2 } from "node:path";
|
|
7192
|
-
|
|
7193
|
-
// ../provider-bridge-acp/src/bridge/tool-proxy-mcp.ts
|
|
7194
|
-
import { createConnection } from "node:net";
|
|
7195
|
-
import { createInterface as createInterface2 } from "node:readline";
|
|
7196
|
-
import { z as z38 } from "zod";
|
|
7197
|
-
var ACP_BRIDGE_MCP_SERVER_NAME = "bb-bridge";
|
|
7198
|
-
var ENV_HOST = "BB_ACP_DYNAMIC_TOOL_HOST";
|
|
7199
|
-
var ENV_PORT = "BB_ACP_DYNAMIC_TOOL_PORT";
|
|
7200
|
-
var ENV_TOKEN = "BB_ACP_DYNAMIC_TOOL_TOKEN";
|
|
7201
|
-
var ENV_THREAD_ID = "BB_ACP_DYNAMIC_TOOL_THREAD_ID";
|
|
7202
|
-
var ENV_TOOLS = "BB_ACP_DYNAMIC_TOOLS";
|
|
7203
|
-
var ENV_PROGRESS_INTERVAL_MS = "BB_ACP_DYNAMIC_TOOL_PROGRESS_INTERVAL_MS";
|
|
7204
|
-
var bridgeToolCallResponseSchema = z38.union([
|
|
7205
|
-
z38.object({
|
|
7206
|
-
ok: z38.literal(true),
|
|
7207
|
-
content: z38.string(),
|
|
7208
|
-
contentBlocks: z38.array(
|
|
7209
|
-
z38.discriminatedUnion("type", [
|
|
7210
|
-
z38.object({ type: z38.literal("text"), text: z38.string() }),
|
|
7211
|
-
z38.object({
|
|
7212
|
-
type: z38.literal("image"),
|
|
7213
|
-
data: z38.string(),
|
|
7214
|
-
mimeType: z38.string()
|
|
7215
|
-
})
|
|
7216
|
-
])
|
|
7217
|
-
).optional(),
|
|
7218
|
-
// The initialized response and older text-only responses omit images.
|
|
7219
|
-
// Parsing them as an empty list keeps the re-executed packaged artifact
|
|
7220
|
-
// compatible with that legacy socket shape.
|
|
7221
|
-
images: z38.array(z38.object({ data: z38.string(), mimeType: z38.string() })).default([]),
|
|
7222
|
-
isError: z38.boolean().optional()
|
|
7223
|
-
}),
|
|
7224
|
-
z38.object({ ok: z38.literal(false), error: z38.string() })
|
|
7225
|
-
]);
|
|
7226
|
-
var nextMcpToolCallId = 0;
|
|
7227
|
-
var TOOL_CALL_PROGRESS_INTERVAL_MS = 15e3;
|
|
7228
|
-
function buildAcpMcpServerConfig(args) {
|
|
7229
|
-
return {
|
|
7230
|
-
name: ACP_BRIDGE_MCP_SERVER_NAME,
|
|
7231
|
-
command: args.command,
|
|
7232
|
-
args: args.bridgeArgs,
|
|
7233
|
-
env: [
|
|
7234
|
-
...args.runtimeEnv,
|
|
7235
|
-
{ name: ENV_HOST, value: args.host },
|
|
7236
|
-
{ name: ENV_PORT, value: String(args.port) },
|
|
7237
|
-
{ name: ENV_TOKEN, value: args.token },
|
|
7238
|
-
{ name: ENV_THREAD_ID, value: args.threadId },
|
|
7239
|
-
{ name: ENV_TOOLS, value: JSON.stringify(args.dynamicTools) }
|
|
7240
|
-
]
|
|
7241
|
-
};
|
|
7168
|
+
// ../provider-bridge-acp/src/session-params.ts
|
|
7169
|
+
function sanitizeAcpSkillDescription(description) {
|
|
7170
|
+
const sanitized = description.replace(/[\r\n]+/gu, " ").replace(/\s+/gu, " ").replace(/[<>]/gu, "").trim();
|
|
7171
|
+
return sanitized.length > 0 ? sanitized : "(description unavailable)";
|
|
7242
7172
|
}
|
|
7243
|
-
function
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
throw new Error(`${ENV_PORT} must be a positive integer`);
|
|
7173
|
+
function buildAcpSkillsInstructions(skillRoots) {
|
|
7174
|
+
if (!skillRoots || skillRoots.length === 0) {
|
|
7175
|
+
return void 0;
|
|
7247
7176
|
}
|
|
7248
|
-
const
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7177
|
+
const skillLines = skillRoots.flatMap((skillRoot) => {
|
|
7178
|
+
return skillRoot.skills.map((skill) => {
|
|
7179
|
+
const skillFilePath = path4.join(
|
|
7180
|
+
skillRoot.skillDirectoryRootPath,
|
|
7181
|
+
skill.name,
|
|
7182
|
+
"SKILL.md"
|
|
7183
|
+
);
|
|
7184
|
+
return `- ${skill.name}: ${sanitizeAcpSkillDescription(skill.description)} (SKILL.md: ${skillFilePath})`;
|
|
7185
|
+
});
|
|
7186
|
+
});
|
|
7187
|
+
if (skillLines.length === 0) {
|
|
7188
|
+
return void 0;
|
|
7254
7189
|
}
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
port,
|
|
7262
|
-
progressIntervalMs,
|
|
7263
|
-
threadId,
|
|
7264
|
-
token,
|
|
7265
|
-
tools
|
|
7266
|
-
};
|
|
7190
|
+
return [
|
|
7191
|
+
"bb skills are reusable instruction folders. When the current task matches a listed skill description, read that skill's SKILL.md at the absolute path before proceeding; you may read supporting files in the same skill directory that SKILL.md references. If a listed path does not exist, the list is stale and should be ignored.",
|
|
7192
|
+
"",
|
|
7193
|
+
"Available bb skills:",
|
|
7194
|
+
...skillLines
|
|
7195
|
+
].join("\n");
|
|
7267
7196
|
}
|
|
7268
|
-
function
|
|
7269
|
-
|
|
7270
|
-
|
|
7197
|
+
function buildAcpSessionInstructions(options) {
|
|
7198
|
+
const baseInstructions = options.instructions?.trim();
|
|
7199
|
+
const skillsInstructions = buildAcpSkillsInstructions(options.skillRoots);
|
|
7200
|
+
const instructions = [baseInstructions, skillsInstructions].filter(
|
|
7201
|
+
(value) => value !== void 0 && value.length > 0
|
|
7202
|
+
);
|
|
7203
|
+
return instructions.length > 0 ? instructions.join("\n\n") : void 0;
|
|
7271
7204
|
}
|
|
7272
|
-
function
|
|
7273
|
-
|
|
7274
|
-
}
|
|
7275
|
-
function writeError(id, code, message) {
|
|
7276
|
-
writeJson({ jsonrpc: "2.0", id, error: { code, message } });
|
|
7277
|
-
}
|
|
7278
|
-
function mcpToolCallId(toolName) {
|
|
7279
|
-
nextMcpToolCallId += 1;
|
|
7280
|
-
return `acp-mcp-${toolName}-${Date.now()}-${nextMcpToolCallId}`;
|
|
7205
|
+
function launchEnvVars(launchSpec) {
|
|
7206
|
+
return Object.keys(launchSpec.env).length > 0 ? { envVars: launchSpec.env } : {};
|
|
7281
7207
|
}
|
|
7282
|
-
function
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
};
|
|
7293
|
-
socket.write(`${JSON.stringify(payload)}
|
|
7294
|
-
`);
|
|
7295
|
-
});
|
|
7296
|
-
socket.on("data", (chunk) => {
|
|
7297
|
-
buffer += chunk;
|
|
7298
|
-
const newlineIndex = buffer.indexOf("\n");
|
|
7299
|
-
if (newlineIndex === -1) {
|
|
7300
|
-
return;
|
|
7301
|
-
}
|
|
7302
|
-
const line = buffer.slice(0, newlineIndex);
|
|
7303
|
-
socket.end();
|
|
7304
|
-
try {
|
|
7305
|
-
resolve4(bridgeToolCallResponseSchema.parse(JSON.parse(line)));
|
|
7306
|
-
} catch (error) {
|
|
7307
|
-
reject(error);
|
|
7308
|
-
}
|
|
7309
|
-
});
|
|
7310
|
-
socket.on("error", reject);
|
|
7311
|
-
socket.on("end", () => {
|
|
7312
|
-
if (!buffer.includes("\n")) {
|
|
7313
|
-
reject(new Error("ACP dynamic tool bridge closed without a response"));
|
|
7314
|
-
}
|
|
7315
|
-
});
|
|
7316
|
-
});
|
|
7208
|
+
function buildAcpModelListCommand(launchSpec) {
|
|
7209
|
+
if (!launchSpec.modelCli || launchSpec.modelCli.listArgs.length === 0) {
|
|
7210
|
+
return void 0;
|
|
7211
|
+
}
|
|
7212
|
+
return {
|
|
7213
|
+
command: launchSpec.command,
|
|
7214
|
+
args: [...launchSpec.modelCli.listArgs],
|
|
7215
|
+
...launchSpec.cwd !== void 0 ? { cwd: launchSpec.cwd } : {},
|
|
7216
|
+
...launchEnvVars(launchSpec)
|
|
7217
|
+
};
|
|
7317
7218
|
}
|
|
7318
|
-
function
|
|
7319
|
-
|
|
7219
|
+
function buildAcpModelDiscoveryAgentCommand(launchSpec) {
|
|
7220
|
+
if (buildAcpModelListCommand(launchSpec) !== void 0) {
|
|
7221
|
+
return void 0;
|
|
7222
|
+
}
|
|
7223
|
+
return {
|
|
7224
|
+
command: launchSpec.command,
|
|
7225
|
+
args: [...launchSpec.args],
|
|
7226
|
+
...launchSpec.cwd !== void 0 ? { cwd: launchSpec.cwd } : {},
|
|
7227
|
+
...launchEnvVars(launchSpec)
|
|
7228
|
+
};
|
|
7320
7229
|
}
|
|
7321
|
-
function
|
|
7322
|
-
const
|
|
7323
|
-
|
|
7230
|
+
function buildAcpModelListParams(launchSpec, options) {
|
|
7231
|
+
const primaryModels = [
|
|
7232
|
+
...options.primaryModels ?? launchSpec?.modelCli?.primaryModels ?? []
|
|
7233
|
+
];
|
|
7234
|
+
const reasoningProbePriorityModelIds = [
|
|
7235
|
+
...options.reasoningProbePriorityModelIds
|
|
7236
|
+
];
|
|
7237
|
+
if (launchSpec === null) {
|
|
7238
|
+
return {
|
|
7239
|
+
primaryModels,
|
|
7240
|
+
reasoningProbePriorityModelIds,
|
|
7241
|
+
parameterizedModelPicker: options.parameterizedModelPicker
|
|
7242
|
+
};
|
|
7243
|
+
}
|
|
7244
|
+
const listCommand = buildAcpModelListCommand(launchSpec);
|
|
7245
|
+
const agent = buildAcpModelDiscoveryAgentCommand(launchSpec);
|
|
7246
|
+
return {
|
|
7247
|
+
...listCommand !== void 0 ? { listCommand } : {},
|
|
7248
|
+
...agent !== void 0 ? { agent } : {},
|
|
7249
|
+
primaryModels,
|
|
7250
|
+
reasoningProbePriorityModelIds,
|
|
7251
|
+
parameterizedModelPicker: options.parameterizedModelPicker,
|
|
7252
|
+
...launchSpec.reasoningCli !== void 0 ? { reasoningCli: launchSpec.reasoningCli } : {},
|
|
7253
|
+
...launchSpec.nativeReasoning !== void 0 ? { nativeReasoning: launchSpec.nativeReasoning } : {}
|
|
7254
|
+
};
|
|
7324
7255
|
}
|
|
7325
|
-
function
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
progress += 1;
|
|
7329
|
-
writeJson({
|
|
7330
|
-
jsonrpc: "2.0",
|
|
7331
|
-
method: "notifications/progress",
|
|
7332
|
-
params: { progressToken: args.progressToken, progress }
|
|
7333
|
-
});
|
|
7334
|
-
}, args.intervalMs ?? TOOL_CALL_PROGRESS_INTERVAL_MS);
|
|
7335
|
-
return () => clearInterval(timer);
|
|
7256
|
+
function cursorParameterizedModelId(model) {
|
|
7257
|
+
const familyId = model === "auto" ? "default" : agentModelFamilyId(model);
|
|
7258
|
+
return familyId.startsWith("cursor-") ? familyId.slice("cursor-".length) : familyId;
|
|
7336
7259
|
}
|
|
7337
|
-
|
|
7338
|
-
|
|
7339
|
-
|
|
7260
|
+
function buildAcpModelSelectionParam(launchSpec, options, parameterizedModelPicker, dialectId) {
|
|
7261
|
+
const model = options.model;
|
|
7262
|
+
const listCommand = buildAcpModelListCommand(launchSpec);
|
|
7263
|
+
if (!model || model === ACP_DEFAULT_MODEL_ID) {
|
|
7264
|
+
return {};
|
|
7340
7265
|
}
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7347
|
-
});
|
|
7348
|
-
void callBridge(env, {
|
|
7349
|
-
kind: "initialized",
|
|
7350
|
-
toolCount: env.tools.length
|
|
7351
|
-
}).catch((error) => {
|
|
7352
|
-
process.stderr.write(
|
|
7353
|
-
`bb-bridge MCP: failed to report initialize: ${error instanceof Error ? error.message : String(error)}
|
|
7354
|
-
`
|
|
7355
|
-
);
|
|
7356
|
-
});
|
|
7357
|
-
return;
|
|
7358
|
-
case "tools/list":
|
|
7359
|
-
writeResult(message.id, {
|
|
7360
|
-
tools: env.tools.map((tool) => ({
|
|
7361
|
-
name: tool.name,
|
|
7362
|
-
description: tool.description,
|
|
7363
|
-
inputSchema: tool.inputSchema
|
|
7364
|
-
}))
|
|
7365
|
-
});
|
|
7366
|
-
return;
|
|
7367
|
-
case "tools/call": {
|
|
7368
|
-
const params = objectParams(message.params);
|
|
7369
|
-
const name = typeof params.name === "string" ? params.name : "";
|
|
7370
|
-
const tool = env.tools.find((candidate) => candidate.name === name);
|
|
7371
|
-
if (!tool) {
|
|
7372
|
-
writeError(message.id, -32602, `Unknown tool: ${name}`);
|
|
7373
|
-
return;
|
|
7374
|
-
}
|
|
7375
|
-
const rawArguments = params.arguments;
|
|
7376
|
-
const toolArguments = rawArguments && typeof rawArguments === "object" && !Array.isArray(rawArguments) ? rawArguments : {};
|
|
7377
|
-
const progressToken = readProgressToken(message.params);
|
|
7378
|
-
const stopHeartbeat = progressToken === null ? () => {
|
|
7379
|
-
} : startProgressHeartbeat({
|
|
7380
|
-
intervalMs: env.progressIntervalMs,
|
|
7381
|
-
progressToken
|
|
7382
|
-
});
|
|
7383
|
-
try {
|
|
7384
|
-
const result = await callBridge(env, {
|
|
7385
|
-
kind: "toolCall",
|
|
7386
|
-
arguments: toolArguments,
|
|
7387
|
-
callId: mcpToolCallId(tool.name),
|
|
7388
|
-
tool: tool.name
|
|
7389
|
-
});
|
|
7390
|
-
stopHeartbeat();
|
|
7391
|
-
if (!result.ok) {
|
|
7392
|
-
writeResult(message.id, {
|
|
7393
|
-
content: [{ type: "text", text: result.error }],
|
|
7394
|
-
isError: true
|
|
7395
|
-
});
|
|
7396
|
-
return;
|
|
7397
|
-
}
|
|
7398
|
-
writeResult(message.id, {
|
|
7399
|
-
content: buildBridgeToolCallContent(result),
|
|
7400
|
-
...result.isError ? { isError: true } : {}
|
|
7401
|
-
});
|
|
7402
|
-
} catch (error) {
|
|
7403
|
-
stopHeartbeat();
|
|
7404
|
-
writeResult(message.id, {
|
|
7405
|
-
content: [
|
|
7406
|
-
{
|
|
7407
|
-
type: "text",
|
|
7408
|
-
text: error instanceof Error ? error.message : String(error)
|
|
7409
|
-
}
|
|
7410
|
-
],
|
|
7411
|
-
isError: true
|
|
7412
|
-
});
|
|
7266
|
+
if (parameterizedModelPicker || !listCommand || !launchSpec.modelCli?.selectFlag) {
|
|
7267
|
+
return {
|
|
7268
|
+
modelSelection: {
|
|
7269
|
+
modelId: parameterizedModelPicker && dialectId === "cursor" ? cursorParameterizedModelId(model) : model,
|
|
7270
|
+
...options.reasoningLevel !== void 0 ? { reasoningLevel: options.reasoningLevel } : {},
|
|
7271
|
+
...parameterizedModelPicker && options.serviceTier !== void 0 ? { serviceTier: options.serviceTier } : {}
|
|
7413
7272
|
}
|
|
7414
|
-
|
|
7415
|
-
}
|
|
7416
|
-
default:
|
|
7417
|
-
writeError(
|
|
7418
|
-
message.id,
|
|
7419
|
-
-32601,
|
|
7420
|
-
`Unsupported MCP method: ${message.method}`
|
|
7421
|
-
);
|
|
7273
|
+
};
|
|
7422
7274
|
}
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
}
|
|
7432
|
-
let message;
|
|
7433
|
-
try {
|
|
7434
|
-
message = JSON.parse(trimmed);
|
|
7435
|
-
} catch {
|
|
7436
|
-
return;
|
|
7275
|
+
return {
|
|
7276
|
+
modelSelection: {
|
|
7277
|
+
listCommand,
|
|
7278
|
+
selectFlag: launchSpec.modelCli.selectFlag,
|
|
7279
|
+
model,
|
|
7280
|
+
...options.reasoningLevel !== void 0 ? { reasoningLevel: options.reasoningLevel } : {},
|
|
7281
|
+
// Only "fast" changes launch resolution; "default" is the normal id.
|
|
7282
|
+
...options.serviceTier === "fast" ? { serviceTier: options.serviceTier } : {}
|
|
7437
7283
|
}
|
|
7438
|
-
|
|
7439
|
-
});
|
|
7440
|
-
}
|
|
7441
|
-
|
|
7442
|
-
// ../provider-bridge-acp/src/bridge/cursor-mcp-approval.ts
|
|
7443
|
-
var CURSOR_MCP_APPROVAL_FILE = "mcp-approvals.json";
|
|
7444
|
-
var CURSOR_APPROVAL_LOCK_STALE_MS = 3e4;
|
|
7445
|
-
var CURSOR_APPROVAL_LOCK_TIMEOUT_MS = 5e3;
|
|
7446
|
-
function errorCode(error) {
|
|
7447
|
-
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
7448
|
-
}
|
|
7449
|
-
function cursorAgentCommand(command) {
|
|
7450
|
-
return basename2(command).toLowerCase().replace(/\.(?:bat|cmd|exe)$/u, "") === "cursor-agent";
|
|
7451
|
-
}
|
|
7452
|
-
function cursorProjectSlug(projectRoot) {
|
|
7453
|
-
return projectRoot.replace(/[^a-zA-Z0-9]/gu, "-").replace(/-+/gu, "-").replace(/^-+|-+$/gu, "");
|
|
7284
|
+
};
|
|
7454
7285
|
}
|
|
7455
|
-
function
|
|
7456
|
-
const
|
|
7457
|
-
|
|
7458
|
-
|
|
7286
|
+
function buildAcpSessionParams(args) {
|
|
7287
|
+
const { options, launchSpec } = args;
|
|
7288
|
+
const instructions = buildAcpSessionInstructions(options);
|
|
7289
|
+
const cwd = launchSpec.cwd ?? args.cwd;
|
|
7290
|
+
const envVars = {
|
|
7291
|
+
...launchSpec.env,
|
|
7292
|
+
...options.envVars ?? {}
|
|
7293
|
+
};
|
|
7294
|
+
if (options.permissionMode === "auto") {
|
|
7295
|
+
throw new Error(
|
|
7296
|
+
`Provider "${args.providerLabel}" does not support permission mode "auto".`
|
|
7297
|
+
);
|
|
7459
7298
|
}
|
|
7460
|
-
const home = env.HOME?.trim() || env.USERPROFILE?.trim() || homedir();
|
|
7461
|
-
return join2(home, ".cursor");
|
|
7462
|
-
}
|
|
7463
|
-
function cursorMcpServerConfig(config) {
|
|
7464
7299
|
return {
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
);
|
|
7490
|
-
});
|
|
7300
|
+
threadId: args.threadId,
|
|
7301
|
+
cwd,
|
|
7302
|
+
agent: {
|
|
7303
|
+
command: launchSpec.command,
|
|
7304
|
+
args: [...launchSpec.args]
|
|
7305
|
+
},
|
|
7306
|
+
...args.dialectId === void 0 ? {} : { dialectId: args.dialectId },
|
|
7307
|
+
...buildAcpModelSelectionParam(
|
|
7308
|
+
launchSpec,
|
|
7309
|
+
options,
|
|
7310
|
+
args.parameterizedModelPicker,
|
|
7311
|
+
args.dialectId
|
|
7312
|
+
),
|
|
7313
|
+
parameterizedModelPicker: args.parameterizedModelPicker,
|
|
7314
|
+
...launchSpec.reasoningCli !== void 0 ? { reasoningCli: launchSpec.reasoningCli } : {},
|
|
7315
|
+
...launchSpec.nativeReasoning !== void 0 ? { nativeReasoning: launchSpec.nativeReasoning } : {},
|
|
7316
|
+
...launchSpec.permissionCli !== void 0 ? { permissionCli: launchSpec.permissionCli } : {},
|
|
7317
|
+
...launchSpec.reasoningCli !== void 0 && options.reasoningLevel !== void 0 ? { launchReasoningLevel: options.reasoningLevel } : {},
|
|
7318
|
+
permissionMode: options.permissionMode,
|
|
7319
|
+
workspaceWriteRoots: [cwd, ...args.additionalWorkspaceWriteRoots],
|
|
7320
|
+
...Object.keys(envVars).length > 0 ? { envVars } : {},
|
|
7321
|
+
...instructions ? { instructions } : {},
|
|
7322
|
+
...args.dynamicTools && args.dynamicTools.length > 0 ? { dynamicTools: args.dynamicTools } : {}
|
|
7323
|
+
};
|
|
7491
7324
|
}
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7325
|
+
|
|
7326
|
+
// ../provider-bridge-acp/src/bridge/agent-connection.ts
|
|
7327
|
+
import { spawn } from "node:child_process";
|
|
7328
|
+
import { createInterface } from "node:readline";
|
|
7329
|
+
var STDERR_TAIL_MAX_CHUNKS = 40;
|
|
7330
|
+
var CLOSED_STDIN_ERROR_CODES = /* @__PURE__ */ new Set(["EPIPE", "ERR_STREAM_DESTROYED"]);
|
|
7331
|
+
var AcpAgentExitedError = class extends Error {
|
|
7332
|
+
constructor(message) {
|
|
7333
|
+
super(message);
|
|
7334
|
+
this.name = "AcpAgentExitedError";
|
|
7501
7335
|
}
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7336
|
+
};
|
|
7337
|
+
var AcpAgentResponseError = class extends Error {
|
|
7338
|
+
code;
|
|
7339
|
+
constructor(message, code) {
|
|
7340
|
+
super(message);
|
|
7341
|
+
this.name = "AcpAgentResponseError";
|
|
7342
|
+
this.code = code;
|
|
7505
7343
|
}
|
|
7506
|
-
|
|
7344
|
+
};
|
|
7345
|
+
function isClosedAgentStdinError(error) {
|
|
7346
|
+
return "code" in error && typeof error.code === "string" && CLOSED_STDIN_ERROR_CODES.has(error.code);
|
|
7507
7347
|
}
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
const
|
|
7348
|
+
function formatAgentError(error) {
|
|
7349
|
+
const message = error.message ?? `ACP agent returned error code ${error.code ?? "unknown"}`;
|
|
7350
|
+
const details = formatAgentErrorData(error.data);
|
|
7351
|
+
return details === void 0 ? message : `${message}: ${details}`;
|
|
7352
|
+
}
|
|
7353
|
+
function formatAgentErrorData(data) {
|
|
7354
|
+
if (data === void 0 || data === null) {
|
|
7355
|
+
return void 0;
|
|
7356
|
+
}
|
|
7357
|
+
if (typeof data === "string") {
|
|
7358
|
+
return data.trim() === "" ? void 0 : data;
|
|
7359
|
+
}
|
|
7360
|
+
if (typeof data === "object" && "details" in data && typeof data.details === "string" && data.details.trim() !== "") {
|
|
7361
|
+
return data.details;
|
|
7362
|
+
}
|
|
7511
7363
|
try {
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
mode: 384
|
|
7516
|
-
});
|
|
7517
|
-
await rename(tempPath, path5);
|
|
7518
|
-
} catch (error) {
|
|
7519
|
-
await rm(tempPath, { force: true });
|
|
7520
|
-
throw error;
|
|
7364
|
+
return JSON.stringify(data);
|
|
7365
|
+
} catch {
|
|
7366
|
+
return void 0;
|
|
7521
7367
|
}
|
|
7522
7368
|
}
|
|
7523
|
-
|
|
7524
|
-
const
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
for (; ; ) {
|
|
7528
|
-
try {
|
|
7529
|
-
await mkdir(lockPath, { mode: 448 });
|
|
7530
|
-
return () => rm(lockPath, { recursive: true, force: true });
|
|
7531
|
-
} catch (error) {
|
|
7532
|
-
if (errorCode(error) !== "EEXIST") {
|
|
7533
|
-
throw error;
|
|
7534
|
-
}
|
|
7535
|
-
}
|
|
7536
|
-
try {
|
|
7537
|
-
const lockStat = await stat(lockPath);
|
|
7538
|
-
if (Date.now() - lockStat.mtimeMs > CURSOR_APPROVAL_LOCK_STALE_MS) {
|
|
7539
|
-
await rm(lockPath, { recursive: true, force: true });
|
|
7540
|
-
continue;
|
|
7541
|
-
}
|
|
7542
|
-
} catch (error) {
|
|
7543
|
-
if (errorCode(error) === "ENOENT") {
|
|
7544
|
-
continue;
|
|
7545
|
-
}
|
|
7546
|
-
throw error;
|
|
7547
|
-
}
|
|
7548
|
-
if (Date.now() >= deadline) {
|
|
7549
|
-
throw new Error(`Timed out updating Cursor MCP approvals: ${path5}`);
|
|
7550
|
-
}
|
|
7551
|
-
await new Promise((resolveDelay) => setTimeout(resolveDelay, 25));
|
|
7369
|
+
function parseAgentLine(line) {
|
|
7370
|
+
const trimmed = line.trim();
|
|
7371
|
+
if (!trimmed) {
|
|
7372
|
+
return null;
|
|
7552
7373
|
}
|
|
7553
|
-
|
|
7554
|
-
async function mutateApprovals(path5, mutate) {
|
|
7555
|
-
const releaseLock = await acquireApprovalLock(path5);
|
|
7374
|
+
let parsed;
|
|
7556
7375
|
try {
|
|
7557
|
-
|
|
7558
|
-
|
|
7559
|
-
|
|
7560
|
-
await writeApprovals(path5, nextApprovals);
|
|
7561
|
-
}
|
|
7562
|
-
} finally {
|
|
7563
|
-
await releaseLock();
|
|
7376
|
+
parsed = JSON.parse(trimmed);
|
|
7377
|
+
} catch {
|
|
7378
|
+
return null;
|
|
7564
7379
|
}
|
|
7565
|
-
|
|
7566
|
-
|
|
7567
|
-
if (!cursorAgentCommand(args.agentCommand) || args.config.name !== ACP_BRIDGE_MCP_SERVER_NAME) {
|
|
7568
|
-
return void 0;
|
|
7380
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
7381
|
+
return null;
|
|
7569
7382
|
}
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7383
|
+
return parsed;
|
|
7384
|
+
}
|
|
7385
|
+
function createAcpAgentConnection(options) {
|
|
7386
|
+
const child = spawn(options.command, options.args, {
|
|
7387
|
+
cwd: options.cwd,
|
|
7388
|
+
env: options.env,
|
|
7389
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
7573
7390
|
});
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
"projects",
|
|
7577
|
-
cursorProjectSlug(projectRoot),
|
|
7578
|
-
CURSOR_MCP_APPROVAL_FILE
|
|
7579
|
-
);
|
|
7580
|
-
const approval = buildCursorMcpApprovalIdentifier({
|
|
7581
|
-
config: args.config,
|
|
7582
|
-
projectRoot
|
|
7391
|
+
experimental_recordProviderChildIo(child, {
|
|
7392
|
+
threadId: options.recordThreadId
|
|
7583
7393
|
});
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7394
|
+
const pending = /* @__PURE__ */ new Map();
|
|
7395
|
+
const stderrChunks = [];
|
|
7396
|
+
let nextRequestId = 1;
|
|
7397
|
+
let exited = false;
|
|
7398
|
+
function rejectAllPending(error) {
|
|
7399
|
+
for (const [, request] of pending) {
|
|
7400
|
+
request.reject(error);
|
|
7588
7401
|
}
|
|
7589
|
-
|
|
7590
|
-
return [...approvals, approval];
|
|
7591
|
-
});
|
|
7592
|
-
return { approval, installedByBb, path: path5 };
|
|
7593
|
-
}
|
|
7594
|
-
async function revokeCursorSessionMcpServer(approval) {
|
|
7595
|
-
if (!approval.installedByBb) {
|
|
7596
|
-
return;
|
|
7402
|
+
pending.clear();
|
|
7597
7403
|
}
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7404
|
+
function closeForAgentStdin(error) {
|
|
7405
|
+
if (exited) {
|
|
7406
|
+
return;
|
|
7407
|
+
}
|
|
7408
|
+
exited = true;
|
|
7409
|
+
const code = "code" in error && typeof error.code === "string" ? ` (${error.code})` : "";
|
|
7410
|
+
const detail = `stdin closed${code}: ${error.message}`;
|
|
7411
|
+
rejectAllPending(
|
|
7412
|
+
new AcpAgentExitedError(`ACP agent "${options.command}" ${detail}`)
|
|
7413
|
+
);
|
|
7414
|
+
child.kill("SIGKILL");
|
|
7415
|
+
const stderrTail = [...stderrChunks, detail].join("\n");
|
|
7416
|
+
options.onExit({ code: null, signal: null, stderrTail });
|
|
7609
7417
|
}
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
["extra-high", "xhigh"],
|
|
7616
|
-
["medium", "medium"],
|
|
7617
|
-
["xhigh", "xhigh"],
|
|
7618
|
-
["high", "high"],
|
|
7619
|
-
["low", "low"],
|
|
7620
|
-
["max", "max"],
|
|
7621
|
-
["none", "none"]
|
|
7622
|
-
];
|
|
7623
|
-
var FAST_TAIL = "-fast";
|
|
7624
|
-
var THINKING_TOKEN = "thinking";
|
|
7625
|
-
function parseAgentModelLines(stdout) {
|
|
7626
|
-
const models = [];
|
|
7627
|
-
for (const line of stdout.split("\n")) {
|
|
7628
|
-
const trimmed = line.trim();
|
|
7629
|
-
const match = MODEL_LINE_PATTERN.exec(trimmed);
|
|
7630
|
-
if (!match) {
|
|
7631
|
-
const bulletMatch = BULLETED_MODEL_LINE_PATTERN.exec(trimmed);
|
|
7632
|
-
if (bulletMatch) {
|
|
7633
|
-
const [, id2] = bulletMatch;
|
|
7634
|
-
models.push({ id: id2, displayName: id2 });
|
|
7635
|
-
continue;
|
|
7636
|
-
}
|
|
7637
|
-
if (BARE_PROVIDER_MODEL_LINE_PATTERN.test(trimmed)) {
|
|
7638
|
-
models.push({ id: trimmed, displayName: trimmed });
|
|
7639
|
-
}
|
|
7640
|
-
continue;
|
|
7418
|
+
function writeLine(message) {
|
|
7419
|
+
const stdin = child.stdin;
|
|
7420
|
+
if (!stdin || stdin.destroyed || !stdin.writable) {
|
|
7421
|
+
closeForAgentStdin(new Error("stdin is not writable"));
|
|
7422
|
+
return;
|
|
7641
7423
|
}
|
|
7642
|
-
|
|
7643
|
-
models.push({ id, displayName });
|
|
7424
|
+
stdin.write(JSON.stringify(message) + "\n");
|
|
7644
7425
|
}
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
const options = configOptions ?? [];
|
|
7649
|
-
return options.find((option) => option.category === "model") ?? options.find((option) => option.id === "model");
|
|
7650
|
-
}
|
|
7651
|
-
function findAcpThoughtLevelConfigOption(configOptions) {
|
|
7652
|
-
return (configOptions ?? []).find(
|
|
7653
|
-
(option) => option.category === "thought_level"
|
|
7654
|
-
);
|
|
7655
|
-
}
|
|
7656
|
-
var ACP_NATIVE_REASONING_LEVEL_BY_VALUE = {
|
|
7657
|
-
none: "none",
|
|
7658
|
-
minimal: "low",
|
|
7659
|
-
low: "low",
|
|
7660
|
-
medium: "medium",
|
|
7661
|
-
high: "high",
|
|
7662
|
-
xhigh: "xhigh",
|
|
7663
|
-
ultracode: "ultracode",
|
|
7664
|
-
max: "max",
|
|
7665
|
-
ultra: "ultra"
|
|
7666
|
-
};
|
|
7667
|
-
var ACP_NATIVE_REASONING_VALUE_CANDIDATES_BY_LEVEL = {
|
|
7668
|
-
none: ["none"],
|
|
7669
|
-
low: ["low", "minimal"],
|
|
7670
|
-
medium: ["medium"],
|
|
7671
|
-
high: ["high"],
|
|
7672
|
-
xhigh: ["xhigh"],
|
|
7673
|
-
ultracode: ["ultracode", "xhigh"],
|
|
7674
|
-
max: ["max", "xhigh"],
|
|
7675
|
-
ultra: ["ultra", "max"]
|
|
7676
|
-
};
|
|
7677
|
-
function acpNativeValueToReasoningLevel(value) {
|
|
7678
|
-
return value === void 0 ? void 0 : ACP_NATIVE_REASONING_LEVEL_BY_VALUE[value];
|
|
7679
|
-
}
|
|
7680
|
-
function acpNativeReasoningLevelToValue(level, thoughtLevelOption) {
|
|
7681
|
-
const candidateValues = ACP_NATIVE_REASONING_VALUE_CANDIDATES_BY_LEVEL[level];
|
|
7682
|
-
if (candidateValues === void 0) {
|
|
7683
|
-
return void 0;
|
|
7684
|
-
}
|
|
7685
|
-
const values = new Set(
|
|
7686
|
-
(thoughtLevelOption.options ?? []).map((o) => o.value)
|
|
7687
|
-
);
|
|
7688
|
-
return candidateValues.find((value) => values.has(value));
|
|
7689
|
-
}
|
|
7690
|
-
function buildAcpNativeReasoningSupport(thoughtLevelOption) {
|
|
7691
|
-
const options = thoughtLevelOption?.options ?? [];
|
|
7692
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7693
|
-
const matchedValueByLevel = /* @__PURE__ */ new Map();
|
|
7694
|
-
const supportedReasoningEfforts = [];
|
|
7695
|
-
for (const option of options) {
|
|
7696
|
-
const level = acpNativeValueToReasoningLevel(option.value);
|
|
7697
|
-
if (level === void 0) {
|
|
7698
|
-
continue;
|
|
7426
|
+
child.stdin?.on("error", (error) => {
|
|
7427
|
+
if (!isClosedAgentStdinError(error)) {
|
|
7428
|
+
throw error;
|
|
7699
7429
|
}
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7430
|
+
closeForAgentStdin(error);
|
|
7431
|
+
});
|
|
7432
|
+
if (child.stdout) {
|
|
7433
|
+
const stdoutLines = createInterface({
|
|
7434
|
+
input: child.stdout,
|
|
7435
|
+
terminal: false
|
|
7436
|
+
});
|
|
7437
|
+
stdoutLines.on("line", (line) => {
|
|
7438
|
+
const message = parseAgentLine(line);
|
|
7439
|
+
if (!message) {
|
|
7440
|
+
return;
|
|
7441
|
+
}
|
|
7442
|
+
const id = message.id;
|
|
7443
|
+
if ((typeof id === "string" || typeof id === "number") && message.method === void 0) {
|
|
7444
|
+
const numericId = typeof id === "number" ? id : Number(id);
|
|
7445
|
+
const request = pending.get(numericId);
|
|
7446
|
+
if (!request) {
|
|
7447
|
+
return;
|
|
7708
7448
|
}
|
|
7709
|
-
|
|
7449
|
+
pending.delete(numericId);
|
|
7450
|
+
if (message.error) {
|
|
7451
|
+
request.reject(
|
|
7452
|
+
new AcpAgentResponseError(
|
|
7453
|
+
formatAgentError(message.error),
|
|
7454
|
+
message.error.code
|
|
7455
|
+
)
|
|
7456
|
+
);
|
|
7457
|
+
} else {
|
|
7458
|
+
request.resolve(message.result);
|
|
7459
|
+
}
|
|
7460
|
+
return;
|
|
7710
7461
|
}
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7716
|
-
|
|
7717
|
-
|
|
7462
|
+
if (typeof message.method !== "string") {
|
|
7463
|
+
return;
|
|
7464
|
+
}
|
|
7465
|
+
if (typeof id === "string" || typeof id === "number") {
|
|
7466
|
+
let settled = false;
|
|
7467
|
+
options.onRequest(message.method, message.params, {
|
|
7468
|
+
result(value) {
|
|
7469
|
+
if (settled) return;
|
|
7470
|
+
settled = true;
|
|
7471
|
+
writeLine({ jsonrpc: "2.0", id, result: value ?? null });
|
|
7472
|
+
},
|
|
7473
|
+
error(code, errorMessage) {
|
|
7474
|
+
if (settled) return;
|
|
7475
|
+
settled = true;
|
|
7476
|
+
writeLine({
|
|
7477
|
+
jsonrpc: "2.0",
|
|
7478
|
+
id,
|
|
7479
|
+
error: { code, message: errorMessage }
|
|
7480
|
+
});
|
|
7481
|
+
}
|
|
7482
|
+
});
|
|
7483
|
+
return;
|
|
7484
|
+
}
|
|
7485
|
+
options.onNotification(message.method, message.params);
|
|
7718
7486
|
});
|
|
7719
7487
|
}
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
const currentLevel = acpNativeValueToReasoningLevel(
|
|
7732
|
-
thoughtLevelOption?.currentValue
|
|
7733
|
-
);
|
|
7734
|
-
const supportedLevels = supportedReasoningEfforts.map(
|
|
7735
|
-
(effort) => effort.reasoningEffort
|
|
7736
|
-
);
|
|
7737
|
-
return {
|
|
7738
|
-
supportedReasoningEfforts,
|
|
7739
|
-
defaultReasoningEffort: currentLevel !== void 0 && supportedLevels.includes(currentLevel) ? currentLevel : supportedReasoningEfforts[0].reasoningEffort
|
|
7740
|
-
};
|
|
7741
|
-
}
|
|
7742
|
-
function buildModelCatalogFromConfigOptions(modelOption, reasoningByModel) {
|
|
7743
|
-
const options = modelOption?.options ?? [];
|
|
7744
|
-
if (options.length === 0) {
|
|
7745
|
-
return [];
|
|
7746
|
-
}
|
|
7747
|
-
const currentValue = modelOption?.currentValue;
|
|
7748
|
-
const models = options.map((option, index) => {
|
|
7749
|
-
const isDefault = currentValue !== void 0 ? option.value === currentValue : index === 0;
|
|
7750
|
-
const reasoning = reasoningByModel?.get(option.value) ?? {
|
|
7751
|
-
supportedReasoningEfforts: ACP_NATIVE_REASONING_EFFORTS,
|
|
7752
|
-
defaultReasoningEffort: "medium"
|
|
7753
|
-
};
|
|
7754
|
-
return {
|
|
7755
|
-
id: option.value,
|
|
7756
|
-
model: option.value,
|
|
7757
|
-
displayName: option.name ?? option.value,
|
|
7758
|
-
description: "",
|
|
7759
|
-
supportedReasoningEfforts: reasoning.supportedReasoningEfforts,
|
|
7760
|
-
defaultReasoningEffort: reasoning.defaultReasoningEffort,
|
|
7761
|
-
isDefault
|
|
7762
|
-
};
|
|
7763
|
-
});
|
|
7764
|
-
return models.some((model) => model.isDefault) ? models : models.map(
|
|
7765
|
-
(model, index) => index === 0 ? { ...model, isDefault: true } : model
|
|
7766
|
-
);
|
|
7767
|
-
}
|
|
7768
|
-
function buildModelCatalogFromSessionModels(sessionModels) {
|
|
7769
|
-
const availableModels = sessionModels?.availableModels ?? [];
|
|
7770
|
-
if (availableModels.length === 0) {
|
|
7771
|
-
return [];
|
|
7488
|
+
if (child.stderr) {
|
|
7489
|
+
const stderrLines = createInterface({
|
|
7490
|
+
input: child.stderr,
|
|
7491
|
+
terminal: false
|
|
7492
|
+
});
|
|
7493
|
+
stderrLines.on("line", (line) => {
|
|
7494
|
+
stderrChunks.push(line);
|
|
7495
|
+
if (stderrChunks.length > STDERR_TAIL_MAX_CHUNKS) {
|
|
7496
|
+
stderrChunks.shift();
|
|
7497
|
+
}
|
|
7498
|
+
});
|
|
7772
7499
|
}
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
};
|
|
7500
|
+
child.on("error", (error) => {
|
|
7501
|
+
if (exited) {
|
|
7502
|
+
return;
|
|
7503
|
+
}
|
|
7504
|
+
exited = true;
|
|
7505
|
+
rejectAllPending(
|
|
7506
|
+
new AcpAgentExitedError(
|
|
7507
|
+
`Failed to launch ACP agent "${options.command}": ${error.message}`
|
|
7508
|
+
)
|
|
7509
|
+
);
|
|
7510
|
+
options.onExit({ code: null, signal: null, stderrTail: error.message });
|
|
7785
7511
|
});
|
|
7786
|
-
|
|
7787
|
-
(
|
|
7788
|
-
|
|
7789
|
-
}
|
|
7790
|
-
function splitVariant(id) {
|
|
7791
|
-
let rest = id;
|
|
7792
|
-
let fast = false;
|
|
7793
|
-
if (rest.endsWith(FAST_TAIL)) {
|
|
7794
|
-
fast = true;
|
|
7795
|
-
rest = rest.slice(0, -FAST_TAIL.length);
|
|
7796
|
-
}
|
|
7797
|
-
let thinking = false;
|
|
7798
|
-
if (rest.endsWith(`-${THINKING_TOKEN}`)) {
|
|
7799
|
-
thinking = true;
|
|
7800
|
-
rest = rest.slice(0, -(THINKING_TOKEN.length + 1));
|
|
7801
|
-
} else if (rest.includes(`-${THINKING_TOKEN}-`)) {
|
|
7802
|
-
thinking = true;
|
|
7803
|
-
rest = rest.replace(`-${THINKING_TOKEN}-`, "-");
|
|
7804
|
-
}
|
|
7805
|
-
for (const [token, effort] of EFFORT_TOKENS) {
|
|
7806
|
-
if (rest.endsWith(`-${token}`)) {
|
|
7807
|
-
return {
|
|
7808
|
-
familyKey: rest.slice(0, -(token.length + 1)),
|
|
7809
|
-
effort,
|
|
7810
|
-
effortToken: token,
|
|
7811
|
-
fast,
|
|
7812
|
-
thinking
|
|
7813
|
-
};
|
|
7512
|
+
child.on("exit", (code, signal) => {
|
|
7513
|
+
if (exited) {
|
|
7514
|
+
return;
|
|
7814
7515
|
}
|
|
7815
|
-
|
|
7516
|
+
exited = true;
|
|
7517
|
+
const stderrTail = stderrChunks.join("\n");
|
|
7518
|
+
rejectAllPending(
|
|
7519
|
+
new AcpAgentExitedError(
|
|
7520
|
+
`ACP agent "${options.command}" exited (code ${code ?? "null"}, signal ${signal ?? "null"})${stderrTail ? `: ${stderrTail}` : ""}`
|
|
7521
|
+
)
|
|
7522
|
+
);
|
|
7523
|
+
options.onExit({ code, signal, stderrTail });
|
|
7524
|
+
});
|
|
7816
7525
|
return {
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
|
|
7830
|
-
|
|
7831
|
-
|
|
7832
|
-
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
7526
|
+
get exited() {
|
|
7527
|
+
return exited;
|
|
7528
|
+
},
|
|
7529
|
+
request({ method, params, resultSchema }) {
|
|
7530
|
+
if (exited) {
|
|
7531
|
+
return Promise.reject(
|
|
7532
|
+
new AcpAgentExitedError(
|
|
7533
|
+
`ACP agent "${options.command}" is not running`
|
|
7534
|
+
)
|
|
7535
|
+
);
|
|
7536
|
+
}
|
|
7537
|
+
const id = nextRequestId;
|
|
7538
|
+
nextRequestId += 1;
|
|
7539
|
+
return new Promise((resolve4, reject) => {
|
|
7540
|
+
pending.set(id, {
|
|
7541
|
+
resolve: (value) => {
|
|
7542
|
+
const parsed = resultSchema.safeParse(value);
|
|
7543
|
+
if (parsed.success) {
|
|
7544
|
+
resolve4(parsed.data);
|
|
7545
|
+
} else {
|
|
7546
|
+
reject(
|
|
7547
|
+
new Error(
|
|
7548
|
+
`ACP agent returned an unexpected ${method} result: ${parsed.error.message}`
|
|
7549
|
+
)
|
|
7550
|
+
);
|
|
7551
|
+
}
|
|
7552
|
+
},
|
|
7553
|
+
reject
|
|
7554
|
+
});
|
|
7555
|
+
writeLine({ jsonrpc: "2.0", id, method, params });
|
|
7556
|
+
});
|
|
7557
|
+
},
|
|
7558
|
+
notify(method, params) {
|
|
7559
|
+
if (exited) {
|
|
7560
|
+
return;
|
|
7561
|
+
}
|
|
7562
|
+
writeLine({ jsonrpc: "2.0", method, params });
|
|
7563
|
+
},
|
|
7564
|
+
kill() {
|
|
7565
|
+
if (exited) {
|
|
7566
|
+
return;
|
|
7567
|
+
}
|
|
7568
|
+
child.kill("SIGTERM");
|
|
7569
|
+
}
|
|
7570
|
+
};
|
|
7571
|
+
}
|
|
7572
|
+
|
|
7573
|
+
// ../provider-bridge-acp/src/bridge/cursor-mcp-approval.ts
|
|
7574
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
7575
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
7576
|
+
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
7577
|
+
import { homedir } from "node:os";
|
|
7578
|
+
import { basename as basename2, dirname, join as join2, resolve as resolve2 } from "node:path";
|
|
7579
|
+
|
|
7580
|
+
// ../provider-bridge-acp/src/bridge/tool-proxy-mcp.ts
|
|
7581
|
+
import { createConnection } from "node:net";
|
|
7582
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
7583
|
+
import { z as z38 } from "zod";
|
|
7584
|
+
var ACP_BRIDGE_MCP_SERVER_NAME = "bb-bridge";
|
|
7585
|
+
var ENV_HOST = "BB_ACP_DYNAMIC_TOOL_HOST";
|
|
7586
|
+
var ENV_PORT = "BB_ACP_DYNAMIC_TOOL_PORT";
|
|
7587
|
+
var ENV_TOKEN = "BB_ACP_DYNAMIC_TOOL_TOKEN";
|
|
7588
|
+
var ENV_THREAD_ID = "BB_ACP_DYNAMIC_TOOL_THREAD_ID";
|
|
7589
|
+
var ENV_TOOLS = "BB_ACP_DYNAMIC_TOOLS";
|
|
7590
|
+
var ENV_PROGRESS_INTERVAL_MS = "BB_ACP_DYNAMIC_TOOL_PROGRESS_INTERVAL_MS";
|
|
7591
|
+
var bridgeToolCallResponseSchema = z38.union([
|
|
7592
|
+
z38.object({
|
|
7593
|
+
ok: z38.literal(true),
|
|
7594
|
+
content: z38.string(),
|
|
7595
|
+
contentBlocks: z38.array(
|
|
7596
|
+
z38.discriminatedUnion("type", [
|
|
7597
|
+
z38.object({ type: z38.literal("text"), text: z38.string() }),
|
|
7598
|
+
z38.object({
|
|
7599
|
+
type: z38.literal("image"),
|
|
7600
|
+
data: z38.string(),
|
|
7601
|
+
mimeType: z38.string()
|
|
7602
|
+
})
|
|
7603
|
+
])
|
|
7604
|
+
).optional(),
|
|
7605
|
+
// The initialized response and older text-only responses omit images.
|
|
7606
|
+
// Parsing them as an empty list keeps the re-executed packaged artifact
|
|
7607
|
+
// compatible with that legacy socket shape.
|
|
7608
|
+
images: z38.array(z38.object({ data: z38.string(), mimeType: z38.string() })).default([]),
|
|
7609
|
+
isError: z38.boolean().optional()
|
|
7610
|
+
}),
|
|
7611
|
+
z38.object({ ok: z38.literal(false), error: z38.string() })
|
|
7612
|
+
]);
|
|
7613
|
+
var nextMcpToolCallId = 0;
|
|
7614
|
+
var TOOL_CALL_PROGRESS_INTERVAL_MS = 15e3;
|
|
7615
|
+
function buildAcpMcpServerConfig(args) {
|
|
7616
|
+
return {
|
|
7617
|
+
name: ACP_BRIDGE_MCP_SERVER_NAME,
|
|
7618
|
+
command: args.command,
|
|
7619
|
+
args: args.bridgeArgs,
|
|
7620
|
+
env: [
|
|
7621
|
+
...args.runtimeEnv,
|
|
7622
|
+
{ name: ENV_HOST, value: args.host },
|
|
7623
|
+
{ name: ENV_PORT, value: String(args.port) },
|
|
7624
|
+
{ name: ENV_TOKEN, value: args.token },
|
|
7625
|
+
{ name: ENV_THREAD_ID, value: args.threadId },
|
|
7626
|
+
{ name: ENV_TOOLS, value: JSON.stringify(args.dynamicTools) }
|
|
7627
|
+
]
|
|
7628
|
+
};
|
|
7629
|
+
}
|
|
7630
|
+
function readEnvironment() {
|
|
7631
|
+
const port = Number(process.env[ENV_PORT]);
|
|
7632
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
7633
|
+
throw new Error(`${ENV_PORT} must be a positive integer`);
|
|
7838
7634
|
}
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7635
|
+
const host = process.env[ENV_HOST];
|
|
7636
|
+
const token = process.env[ENV_TOKEN];
|
|
7637
|
+
const threadId = process.env[ENV_THREAD_ID];
|
|
7638
|
+
const toolsJson = process.env[ENV_TOOLS];
|
|
7639
|
+
if (!host || !token || !threadId || !toolsJson) {
|
|
7640
|
+
throw new Error("Missing ACP dynamic tool MCP server environment");
|
|
7641
|
+
}
|
|
7642
|
+
const parsedTools = JSON.parse(toolsJson);
|
|
7643
|
+
const tools = dynamicToolSchema.array().parse(parsedTools);
|
|
7644
|
+
const rawProgressInterval = process.env[ENV_PROGRESS_INTERVAL_MS];
|
|
7645
|
+
const progressIntervalMs = rawProgressInterval !== void 0 && Number(rawProgressInterval) > 0 ? Number(rawProgressInterval) : void 0;
|
|
7646
|
+
return {
|
|
7647
|
+
host,
|
|
7648
|
+
port,
|
|
7649
|
+
progressIntervalMs,
|
|
7650
|
+
threadId,
|
|
7651
|
+
token,
|
|
7652
|
+
tools
|
|
7653
|
+
};
|
|
7842
7654
|
}
|
|
7843
|
-
function
|
|
7844
|
-
|
|
7655
|
+
function writeJson(message) {
|
|
7656
|
+
process.stdout.write(`${JSON.stringify(message)}
|
|
7657
|
+
`);
|
|
7845
7658
|
}
|
|
7846
|
-
function
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7659
|
+
function writeResult(id, result) {
|
|
7660
|
+
writeJson({ jsonrpc: "2.0", id, result });
|
|
7661
|
+
}
|
|
7662
|
+
function writeError(id, code, message) {
|
|
7663
|
+
writeJson({ jsonrpc: "2.0", id, error: { code, message } });
|
|
7664
|
+
}
|
|
7665
|
+
function mcpToolCallId(toolName) {
|
|
7666
|
+
nextMcpToolCallId += 1;
|
|
7667
|
+
return `acp-mcp-${toolName}-${Date.now()}-${nextMcpToolCallId}`;
|
|
7668
|
+
}
|
|
7669
|
+
function callBridge(env, request) {
|
|
7670
|
+
return new Promise((resolve4, reject) => {
|
|
7671
|
+
const socket = createConnection({ host: env.host, port: env.port });
|
|
7672
|
+
let buffer = "";
|
|
7673
|
+
socket.setEncoding("utf8");
|
|
7674
|
+
socket.on("connect", () => {
|
|
7675
|
+
const payload = {
|
|
7676
|
+
...request,
|
|
7677
|
+
threadId: env.threadId,
|
|
7678
|
+
token: env.token
|
|
7679
|
+
};
|
|
7680
|
+
socket.write(`${JSON.stringify(payload)}
|
|
7681
|
+
`);
|
|
7682
|
+
});
|
|
7683
|
+
socket.on("data", (chunk) => {
|
|
7684
|
+
buffer += chunk;
|
|
7685
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
7686
|
+
if (newlineIndex === -1) {
|
|
7687
|
+
return;
|
|
7688
|
+
}
|
|
7689
|
+
const line = buffer.slice(0, newlineIndex);
|
|
7690
|
+
socket.end();
|
|
7691
|
+
try {
|
|
7692
|
+
resolve4(bridgeToolCallResponseSchema.parse(JSON.parse(line)));
|
|
7693
|
+
} catch (error) {
|
|
7694
|
+
reject(error);
|
|
7695
|
+
}
|
|
7696
|
+
});
|
|
7697
|
+
socket.on("error", reject);
|
|
7698
|
+
socket.on("end", () => {
|
|
7699
|
+
if (!buffer.includes("\n")) {
|
|
7700
|
+
reject(new Error("ACP dynamic tool bridge closed without a response"));
|
|
7701
|
+
}
|
|
7702
|
+
});
|
|
7703
|
+
});
|
|
7704
|
+
}
|
|
7705
|
+
function objectParams(params) {
|
|
7706
|
+
return params && typeof params === "object" && !Array.isArray(params) ? params : {};
|
|
7707
|
+
}
|
|
7708
|
+
function readProgressToken(params) {
|
|
7709
|
+
const meta = objectParams(objectParams(params)._meta).progressToken;
|
|
7710
|
+
return typeof meta === "string" || typeof meta === "number" ? meta : null;
|
|
7711
|
+
}
|
|
7712
|
+
function startProgressHeartbeat(args) {
|
|
7713
|
+
let progress = 0;
|
|
7714
|
+
const timer = setInterval(() => {
|
|
7715
|
+
progress += 1;
|
|
7716
|
+
writeJson({
|
|
7717
|
+
jsonrpc: "2.0",
|
|
7718
|
+
method: "notifications/progress",
|
|
7719
|
+
params: { progressToken: args.progressToken, progress }
|
|
7720
|
+
});
|
|
7721
|
+
}, args.intervalMs ?? TOOL_CALL_PROGRESS_INTERVAL_MS);
|
|
7722
|
+
return () => clearInterval(timer);
|
|
7723
|
+
}
|
|
7724
|
+
async function handleRequest(env, message) {
|
|
7725
|
+
if (message.id === void 0 || message.method === void 0) {
|
|
7726
|
+
return;
|
|
7855
7727
|
}
|
|
7856
|
-
|
|
7857
|
-
|
|
7728
|
+
switch (message.method) {
|
|
7729
|
+
case "initialize":
|
|
7730
|
+
writeResult(message.id, {
|
|
7731
|
+
protocolVersion: typeof objectParams(message.params).protocolVersion === "string" ? objectParams(message.params).protocolVersion : "2024-11-05",
|
|
7732
|
+
capabilities: { tools: {} },
|
|
7733
|
+
serverInfo: { name: ACP_BRIDGE_MCP_SERVER_NAME, version: "1.0.0" }
|
|
7734
|
+
});
|
|
7735
|
+
void callBridge(env, {
|
|
7736
|
+
kind: "initialized",
|
|
7737
|
+
toolCount: env.tools.length
|
|
7738
|
+
}).catch((error) => {
|
|
7739
|
+
process.stderr.write(
|
|
7740
|
+
`bb-bridge MCP: failed to report initialize: ${error instanceof Error ? error.message : String(error)}
|
|
7741
|
+
`
|
|
7742
|
+
);
|
|
7743
|
+
});
|
|
7744
|
+
return;
|
|
7745
|
+
case "tools/list":
|
|
7746
|
+
writeResult(message.id, {
|
|
7747
|
+
tools: env.tools.map((tool) => ({
|
|
7748
|
+
name: tool.name,
|
|
7749
|
+
description: tool.description,
|
|
7750
|
+
inputSchema: tool.inputSchema
|
|
7751
|
+
}))
|
|
7752
|
+
});
|
|
7753
|
+
return;
|
|
7754
|
+
case "tools/call": {
|
|
7755
|
+
const params = objectParams(message.params);
|
|
7756
|
+
const name = typeof params.name === "string" ? params.name : "";
|
|
7757
|
+
const tool = env.tools.find((candidate) => candidate.name === name);
|
|
7758
|
+
if (!tool) {
|
|
7759
|
+
writeError(message.id, -32602, `Unknown tool: ${name}`);
|
|
7760
|
+
return;
|
|
7761
|
+
}
|
|
7762
|
+
const rawArguments = params.arguments;
|
|
7763
|
+
const toolArguments = rawArguments && typeof rawArguments === "object" && !Array.isArray(rawArguments) ? rawArguments : {};
|
|
7764
|
+
const progressToken = readProgressToken(message.params);
|
|
7765
|
+
const stopHeartbeat = progressToken === null ? () => {
|
|
7766
|
+
} : startProgressHeartbeat({
|
|
7767
|
+
intervalMs: env.progressIntervalMs,
|
|
7768
|
+
progressToken
|
|
7769
|
+
});
|
|
7770
|
+
try {
|
|
7771
|
+
const result = await callBridge(env, {
|
|
7772
|
+
kind: "toolCall",
|
|
7773
|
+
arguments: toolArguments,
|
|
7774
|
+
callId: mcpToolCallId(tool.name),
|
|
7775
|
+
tool: tool.name
|
|
7776
|
+
});
|
|
7777
|
+
stopHeartbeat();
|
|
7778
|
+
if (!result.ok) {
|
|
7779
|
+
writeResult(message.id, {
|
|
7780
|
+
content: [{ type: "text", text: result.error }],
|
|
7781
|
+
isError: true
|
|
7782
|
+
});
|
|
7783
|
+
return;
|
|
7784
|
+
}
|
|
7785
|
+
writeResult(message.id, {
|
|
7786
|
+
content: buildBridgeToolCallContent(result),
|
|
7787
|
+
...result.isError ? { isError: true } : {}
|
|
7788
|
+
});
|
|
7789
|
+
} catch (error) {
|
|
7790
|
+
stopHeartbeat();
|
|
7791
|
+
writeResult(message.id, {
|
|
7792
|
+
content: [
|
|
7793
|
+
{
|
|
7794
|
+
type: "text",
|
|
7795
|
+
text: error instanceof Error ? error.message : String(error)
|
|
7796
|
+
}
|
|
7797
|
+
],
|
|
7798
|
+
isError: true
|
|
7799
|
+
});
|
|
7800
|
+
}
|
|
7801
|
+
return;
|
|
7802
|
+
}
|
|
7803
|
+
default:
|
|
7804
|
+
writeError(
|
|
7805
|
+
message.id,
|
|
7806
|
+
-32601,
|
|
7807
|
+
`Unsupported MCP method: ${message.method}`
|
|
7808
|
+
);
|
|
7858
7809
|
}
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
const
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
const
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
}
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7810
|
+
}
|
|
7811
|
+
function runAcpDynamicToolMcpServer() {
|
|
7812
|
+
const env = readEnvironment();
|
|
7813
|
+
const rl = createInterface2({ input: process.stdin, terminal: false });
|
|
7814
|
+
rl.on("line", (line) => {
|
|
7815
|
+
const trimmed = line.trim();
|
|
7816
|
+
if (!trimmed) {
|
|
7817
|
+
return;
|
|
7818
|
+
}
|
|
7819
|
+
let message;
|
|
7820
|
+
try {
|
|
7821
|
+
message = JSON.parse(trimmed);
|
|
7822
|
+
} catch {
|
|
7823
|
+
return;
|
|
7824
|
+
}
|
|
7825
|
+
void handleRequest(env, message);
|
|
7826
|
+
});
|
|
7827
|
+
}
|
|
7828
|
+
|
|
7829
|
+
// ../provider-bridge-acp/src/bridge/cursor-mcp-approval.ts
|
|
7830
|
+
var CURSOR_MCP_APPROVAL_FILE = "mcp-approvals.json";
|
|
7831
|
+
var CURSOR_APPROVAL_LOCK_STALE_MS = 3e4;
|
|
7832
|
+
var CURSOR_APPROVAL_LOCK_TIMEOUT_MS = 5e3;
|
|
7833
|
+
function errorCode(error) {
|
|
7834
|
+
return error instanceof Error && "code" in error ? error.code : void 0;
|
|
7835
|
+
}
|
|
7836
|
+
function cursorAgentCommand(command) {
|
|
7837
|
+
return basename2(command).toLowerCase().replace(/\.(?:bat|cmd|exe)$/u, "") === "cursor-agent";
|
|
7838
|
+
}
|
|
7839
|
+
function cursorProjectSlug(projectRoot) {
|
|
7840
|
+
return projectRoot.replace(/[^a-zA-Z0-9]/gu, "-").replace(/-+/gu, "-").replace(/^-+|-+$/gu, "");
|
|
7841
|
+
}
|
|
7842
|
+
function cursorDataDirectory(env) {
|
|
7843
|
+
const configured = env.CURSOR_DATA_DIR?.trim();
|
|
7844
|
+
if (configured) {
|
|
7845
|
+
return configured;
|
|
7846
|
+
}
|
|
7847
|
+
const home = env.HOME?.trim() || env.USERPROFILE?.trim() || homedir();
|
|
7848
|
+
return join2(home, ".cursor");
|
|
7849
|
+
}
|
|
7850
|
+
function cursorMcpServerConfig(config) {
|
|
7851
|
+
return {
|
|
7852
|
+
command: config.command,
|
|
7853
|
+
args: config.args,
|
|
7854
|
+
env: Object.fromEntries(config.env.map(({ name, value }) => [name, value]))
|
|
7855
|
+
};
|
|
7856
|
+
}
|
|
7857
|
+
function buildCursorMcpApprovalIdentifier(args) {
|
|
7858
|
+
const fingerprint = createHash("sha256").update(
|
|
7859
|
+
JSON.stringify({
|
|
7860
|
+
path: args.projectRoot,
|
|
7861
|
+
server: cursorMcpServerConfig(args.config)
|
|
7862
|
+
})
|
|
7863
|
+
).digest("hex").slice(0, 16);
|
|
7864
|
+
return `${args.config.name}-${fingerprint}`;
|
|
7865
|
+
}
|
|
7866
|
+
async function resolveCursorProjectRoot(args) {
|
|
7867
|
+
return new Promise((resolveRoot) => {
|
|
7868
|
+
execFile3(
|
|
7869
|
+
"git",
|
|
7870
|
+
["rev-parse", "--show-toplevel"],
|
|
7871
|
+
{ cwd: args.cwd, env: args.env, windowsHide: true },
|
|
7872
|
+
(error, stdout) => {
|
|
7873
|
+
const root = stdout.trim();
|
|
7874
|
+
resolveRoot(error === null && root !== "" ? root : resolve2(args.cwd));
|
|
7879
7875
|
}
|
|
7880
|
-
}
|
|
7881
|
-
const nonFast = leveled.filter((entry) => !entry.member.fast);
|
|
7882
|
-
const pool = nonFast.length > 0 ? nonFast : leveled;
|
|
7883
|
-
const defaultEntry = pool.find((entry) => entry.level === "medium") ?? pool.find((entry) => entry.level !== "none") ?? pool[0];
|
|
7884
|
-
const defaultVariant = defaultEntry.member;
|
|
7885
|
-
const levelsInLadderOrder = [...byLevel.keys()].sort(
|
|
7886
|
-
(a, b) => reasoningLevelValues.indexOf(a) - reasoningLevelValues.indexOf(b)
|
|
7887
7876
|
);
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7877
|
+
});
|
|
7878
|
+
}
|
|
7879
|
+
async function readApprovals(path5) {
|
|
7880
|
+
let text;
|
|
7881
|
+
try {
|
|
7882
|
+
text = await readFile(path5, "utf8");
|
|
7883
|
+
} catch (error) {
|
|
7884
|
+
if (errorCode(error) === "ENOENT") {
|
|
7885
|
+
return [];
|
|
7893
7886
|
}
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7887
|
+
throw error;
|
|
7888
|
+
}
|
|
7889
|
+
const value = JSON.parse(text);
|
|
7890
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
|
|
7891
|
+
throw new Error(`Cursor MCP approval file is not a string array: ${path5}`);
|
|
7892
|
+
}
|
|
7893
|
+
return value;
|
|
7894
|
+
}
|
|
7895
|
+
async function writeApprovals(path5, approvals) {
|
|
7896
|
+
await mkdir(dirname(path5), { recursive: true });
|
|
7897
|
+
const tempPath = `${path5}.bb-${process.pid}-${randomBytes(6).toString("hex")}.tmp`;
|
|
7898
|
+
try {
|
|
7899
|
+
await writeFile(tempPath, `${JSON.stringify(approvals, null, 2)}
|
|
7900
|
+
`, {
|
|
7901
|
+
encoding: "utf8",
|
|
7902
|
+
mode: 384
|
|
7909
7903
|
});
|
|
7910
|
-
|
|
7911
|
-
|
|
7904
|
+
await rename(tempPath, path5);
|
|
7905
|
+
} catch (error) {
|
|
7906
|
+
await rm(tempPath, { force: true });
|
|
7907
|
+
throw error;
|
|
7912
7908
|
}
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7909
|
+
}
|
|
7910
|
+
async function acquireApprovalLock(path5) {
|
|
7911
|
+
const lockPath = `${path5}.bb-lock`;
|
|
7912
|
+
const deadline = Date.now() + CURSOR_APPROVAL_LOCK_TIMEOUT_MS;
|
|
7913
|
+
await mkdir(dirname(path5), { recursive: true });
|
|
7914
|
+
for (; ; ) {
|
|
7915
|
+
try {
|
|
7916
|
+
await mkdir(lockPath, { mode: 448 });
|
|
7917
|
+
return () => rm(lockPath, { recursive: true, force: true });
|
|
7918
|
+
} catch (error) {
|
|
7919
|
+
if (errorCode(error) !== "EEXIST") {
|
|
7920
|
+
throw error;
|
|
7919
7921
|
}
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7922
|
+
}
|
|
7923
|
+
try {
|
|
7924
|
+
const lockStat = await stat(lockPath);
|
|
7925
|
+
if (Date.now() - lockStat.mtimeMs > CURSOR_APPROVAL_LOCK_STALE_MS) {
|
|
7926
|
+
await rm(lockPath, { recursive: true, force: true });
|
|
7927
|
+
continue;
|
|
7924
7928
|
}
|
|
7925
|
-
|
|
7926
|
-
|
|
7929
|
+
} catch (error) {
|
|
7930
|
+
if (errorCode(error) === "ENOENT") {
|
|
7931
|
+
continue;
|
|
7927
7932
|
}
|
|
7928
|
-
|
|
7933
|
+
throw error;
|
|
7929
7934
|
}
|
|
7930
|
-
|
|
7935
|
+
if (Date.now() >= deadline) {
|
|
7936
|
+
throw new Error(`Timed out updating Cursor MCP approvals: ${path5}`);
|
|
7937
|
+
}
|
|
7938
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, 25));
|
|
7939
|
+
}
|
|
7931
7940
|
}
|
|
7932
|
-
function
|
|
7933
|
-
const
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
const
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
+
async function mutateApprovals(path5, mutate) {
|
|
7942
|
+
const releaseLock = await acquireApprovalLock(path5);
|
|
7943
|
+
try {
|
|
7944
|
+
const approvals = await readApprovals(path5);
|
|
7945
|
+
const nextApprovals = mutate(approvals);
|
|
7946
|
+
if (approvals.length !== nextApprovals.length || approvals.some((approval, index) => approval !== nextApprovals[index])) {
|
|
7947
|
+
await writeApprovals(path5, nextApprovals);
|
|
7948
|
+
}
|
|
7949
|
+
} finally {
|
|
7950
|
+
await releaseLock();
|
|
7941
7951
|
}
|
|
7942
|
-
|
|
7943
|
-
|
|
7952
|
+
}
|
|
7953
|
+
async function approveCursorSessionMcpServer(args) {
|
|
7954
|
+
if (!cursorAgentCommand(args.agentCommand) || args.config.name !== ACP_BRIDGE_MCP_SERVER_NAME) {
|
|
7955
|
+
return void 0;
|
|
7956
|
+
}
|
|
7957
|
+
const projectRoot = await resolveCursorProjectRoot({
|
|
7958
|
+
cwd: args.cwd,
|
|
7959
|
+
env: args.env
|
|
7960
|
+
});
|
|
7961
|
+
const path5 = join2(
|
|
7962
|
+
cursorDataDirectory(args.env),
|
|
7963
|
+
"projects",
|
|
7964
|
+
cursorProjectSlug(projectRoot),
|
|
7965
|
+
CURSOR_MCP_APPROVAL_FILE
|
|
7944
7966
|
);
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7967
|
+
const approval = buildCursorMcpApprovalIdentifier({
|
|
7968
|
+
config: args.config,
|
|
7969
|
+
projectRoot
|
|
7970
|
+
});
|
|
7971
|
+
let installedByBb = false;
|
|
7972
|
+
await mutateApprovals(path5, (approvals) => {
|
|
7973
|
+
if (approvals.includes(approval)) {
|
|
7974
|
+
return approvals;
|
|
7975
|
+
}
|
|
7976
|
+
installedByBb = true;
|
|
7977
|
+
return [...approvals, approval];
|
|
7978
|
+
});
|
|
7979
|
+
return { approval, installedByBb, path: path5 };
|
|
7980
|
+
}
|
|
7981
|
+
async function revokeCursorSessionMcpServer(approval) {
|
|
7982
|
+
if (!approval.installedByBb) {
|
|
7983
|
+
return;
|
|
7952
7984
|
}
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
selectedOnlyModels: selectedOnlyModels.map(
|
|
7958
|
-
(model) => model.isDefault ? { ...model, isDefault: false } : model
|
|
7959
|
-
)
|
|
7960
|
-
};
|
|
7985
|
+
await mutateApprovals(
|
|
7986
|
+
approval.path,
|
|
7987
|
+
(approvals) => approvals.filter((candidate) => candidate !== approval.approval)
|
|
7988
|
+
);
|
|
7961
7989
|
}
|
|
7962
7990
|
|
|
7963
7991
|
// ../provider-bridge-acp/src/bridge/bridge.ts
|
|
@@ -8315,6 +8343,13 @@ async function authenticateAcpAgent(args) {
|
|
|
8315
8343
|
);
|
|
8316
8344
|
}
|
|
8317
8345
|
}
|
|
8346
|
+
function acpClientCapabilities(parameterizedModelPicker, fsAccess = false) {
|
|
8347
|
+
return {
|
|
8348
|
+
fs: { readTextFile: fsAccess, writeTextFile: fsAccess },
|
|
8349
|
+
terminal: false,
|
|
8350
|
+
...parameterizedModelPicker === true ? { _meta: { parameterizedModelPicker: true } } : {}
|
|
8351
|
+
};
|
|
8352
|
+
}
|
|
8318
8353
|
async function loadAgentModelCatalog(listCommand) {
|
|
8319
8354
|
const stdout = await new Promise((resolveExec, rejectExec) => {
|
|
8320
8355
|
execFile4(
|
|
@@ -8364,8 +8399,12 @@ async function loadAgentModelCatalog(listCommand) {
|
|
|
8364
8399
|
cachedModelCatalog = { key, catalog };
|
|
8365
8400
|
return catalog;
|
|
8366
8401
|
}
|
|
8367
|
-
async function loadSessionDiscoveredModels(agent) {
|
|
8368
|
-
const key = JSON.stringify(
|
|
8402
|
+
async function loadSessionDiscoveredModels(agent, reasoningProbePriorityModelIds, parameterizedModelPicker) {
|
|
8403
|
+
const key = JSON.stringify({
|
|
8404
|
+
agent,
|
|
8405
|
+
reasoningProbePriorityModelIds,
|
|
8406
|
+
parameterizedModelPicker
|
|
8407
|
+
});
|
|
8369
8408
|
if (cachedSessionDiscoveredModels?.key === key && Date.now() - cachedSessionDiscoveredModels.fetchedAt < SESSION_MODEL_DISCOVERY_TTL_MS) {
|
|
8370
8409
|
return cachedSessionDiscoveredModels.models;
|
|
8371
8410
|
}
|
|
@@ -8406,10 +8445,7 @@ async function loadSessionDiscoveredModels(agent) {
|
|
|
8406
8445
|
params: {
|
|
8407
8446
|
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
8408
8447
|
clientInfo: { name: "bb", version: "1.0.0" },
|
|
8409
|
-
clientCapabilities:
|
|
8410
|
-
fs: { readTextFile: false, writeTextFile: false },
|
|
8411
|
-
terminal: false
|
|
8412
|
-
}
|
|
8448
|
+
clientCapabilities: acpClientCapabilities(parameterizedModelPicker)
|
|
8413
8449
|
},
|
|
8414
8450
|
resultSchema: acpInitializeResultSchema
|
|
8415
8451
|
});
|
|
@@ -8447,7 +8483,8 @@ async function loadSessionDiscoveredModels(agent) {
|
|
|
8447
8483
|
const reasoningByModel = await discoverAcpNativeReasoningByModel({
|
|
8448
8484
|
connection,
|
|
8449
8485
|
sessionId: newSession.sessionId,
|
|
8450
|
-
modelOption
|
|
8486
|
+
modelOption,
|
|
8487
|
+
reasoningProbePriorityModelIds
|
|
8451
8488
|
});
|
|
8452
8489
|
const models = reasoningByModel === null ? configOptionModels : buildModelCatalogFromConfigOptions(modelOption, reasoningByModel);
|
|
8453
8490
|
cachedSessionDiscoveredModels = {
|
|
@@ -8475,6 +8512,23 @@ async function discoverAcpNativeReasoningByModel(args) {
|
|
|
8475
8512
|
return null;
|
|
8476
8513
|
}
|
|
8477
8514
|
const modelOption = args.modelOption;
|
|
8515
|
+
const modelByValue = new Map(
|
|
8516
|
+
modelOptions.map((model) => [model.value, model])
|
|
8517
|
+
);
|
|
8518
|
+
const modelsToProbe = [];
|
|
8519
|
+
const addedModels = /* @__PURE__ */ new Set();
|
|
8520
|
+
for (const value of args.reasoningProbePriorityModelIds) {
|
|
8521
|
+
const model = modelByValue.get(value);
|
|
8522
|
+
if (model && !addedModels.has(model.value)) {
|
|
8523
|
+
modelsToProbe.push(model);
|
|
8524
|
+
addedModels.add(model.value);
|
|
8525
|
+
}
|
|
8526
|
+
}
|
|
8527
|
+
for (const model of modelOptions) {
|
|
8528
|
+
if (!addedModels.has(model.value)) {
|
|
8529
|
+
modelsToProbe.push(model);
|
|
8530
|
+
}
|
|
8531
|
+
}
|
|
8478
8532
|
const supportByModel = /* @__PURE__ */ new Map();
|
|
8479
8533
|
let timeout;
|
|
8480
8534
|
const timeoutReached = new Promise((resolve4) => {
|
|
@@ -8486,7 +8540,7 @@ async function discoverAcpNativeReasoningByModel(args) {
|
|
|
8486
8540
|
try {
|
|
8487
8541
|
return await Promise.race([
|
|
8488
8542
|
(async () => {
|
|
8489
|
-
for (const model of
|
|
8543
|
+
for (const model of modelsToProbe) {
|
|
8490
8544
|
const configState = await args.connection.request({
|
|
8491
8545
|
method: "session/set_config_option",
|
|
8492
8546
|
params: {
|
|
@@ -8646,6 +8700,12 @@ async function selectAcpNativeModel(args) {
|
|
|
8646
8700
|
modelSelection: selection,
|
|
8647
8701
|
nativeReasoning: args.nativeReasoning
|
|
8648
8702
|
});
|
|
8703
|
+
await selectAcpNativeServiceTier({
|
|
8704
|
+
connection: args.connection,
|
|
8705
|
+
sessionId: args.sessionId,
|
|
8706
|
+
configOptions,
|
|
8707
|
+
modelSelection: selection
|
|
8708
|
+
});
|
|
8649
8709
|
}
|
|
8650
8710
|
async function selectAcpNativeReasoning(args) {
|
|
8651
8711
|
const reasoningLevel = args.modelSelection.reasoningLevel;
|
|
@@ -8676,6 +8736,28 @@ async function selectAcpNativeReasoning(args) {
|
|
|
8676
8736
|
} catch {
|
|
8677
8737
|
}
|
|
8678
8738
|
}
|
|
8739
|
+
async function selectAcpNativeServiceTier(args) {
|
|
8740
|
+
const serviceTier = args.modelSelection.serviceTier;
|
|
8741
|
+
if (serviceTier === void 0) {
|
|
8742
|
+
return;
|
|
8743
|
+
}
|
|
8744
|
+
const fastOption = (args.configOptions ?? []).find(
|
|
8745
|
+
(option) => option.id === "fast" && option.type === "select"
|
|
8746
|
+
);
|
|
8747
|
+
const value = serviceTier === "fast" ? "true" : "false";
|
|
8748
|
+
if (!fastOption?.options?.some((option) => option.value === value)) {
|
|
8749
|
+
return;
|
|
8750
|
+
}
|
|
8751
|
+
await args.connection.request({
|
|
8752
|
+
method: "session/set_config_option",
|
|
8753
|
+
params: {
|
|
8754
|
+
sessionId: args.sessionId,
|
|
8755
|
+
configId: fastOption.id,
|
|
8756
|
+
value
|
|
8757
|
+
},
|
|
8758
|
+
resultSchema: acpConfigStateResultSchema
|
|
8759
|
+
});
|
|
8760
|
+
}
|
|
8679
8761
|
function buildPromptContentBlocks(session, input) {
|
|
8680
8762
|
const blocks = [];
|
|
8681
8763
|
const instructions = session.pendingInstructions;
|
|
@@ -9041,10 +9123,10 @@ async function startAgentSession(request) {
|
|
|
9041
9123
|
params: {
|
|
9042
9124
|
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
9043
9125
|
clientInfo: { name: "bb", version: "1.0.0" },
|
|
9044
|
-
clientCapabilities:
|
|
9045
|
-
|
|
9046
|
-
|
|
9047
|
-
|
|
9126
|
+
clientCapabilities: acpClientCapabilities(
|
|
9127
|
+
params.parameterizedModelPicker,
|
|
9128
|
+
true
|
|
9129
|
+
)
|
|
9048
9130
|
},
|
|
9049
9131
|
resultSchema: acpInitializeResultSchema
|
|
9050
9132
|
});
|
|
@@ -9514,15 +9596,22 @@ async function handleModelList(id, params) {
|
|
|
9514
9596
|
);
|
|
9515
9597
|
return;
|
|
9516
9598
|
}
|
|
9517
|
-
const sessionDiscoveredModels = params.listCommand === void 0 && params.agent ? await loadSessionDiscoveredModels(
|
|
9599
|
+
const sessionDiscoveredModels = params.listCommand === void 0 && params.agent ? await loadSessionDiscoveredModels(
|
|
9600
|
+
params.agent,
|
|
9601
|
+
params.reasoningProbePriorityModelIds,
|
|
9602
|
+
params.parameterizedModelPicker
|
|
9603
|
+
) : null;
|
|
9518
9604
|
if (sessionDiscoveredModels) {
|
|
9519
|
-
sendResult(
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9605
|
+
sendResult(
|
|
9606
|
+
id,
|
|
9607
|
+
splitPrimaryModels(
|
|
9608
|
+
applyConfiguredReasoningToModels(sessionDiscoveredModels, {
|
|
9609
|
+
reasoningCli: params.reasoningCli,
|
|
9610
|
+
nativeReasoning: params.nativeReasoning
|
|
9611
|
+
}),
|
|
9612
|
+
params.primaryModels
|
|
9613
|
+
)
|
|
9614
|
+
);
|
|
9526
9615
|
return;
|
|
9527
9616
|
}
|
|
9528
9617
|
sendResult(id, {
|
|
@@ -9554,8 +9643,24 @@ var acpProviderOptionsSchema = z39.object({
|
|
|
9554
9643
|
* the provider, so a third-party registration of a known agent gets the
|
|
9555
9644
|
* same reporting fidelity a first-party one does.
|
|
9556
9645
|
*/
|
|
9557
|
-
acpDialect: z39.string().min(1).optional()
|
|
9646
|
+
acpDialect: z39.string().min(1).optional(),
|
|
9647
|
+
/** Enables an agent's separate model configuration options. */
|
|
9648
|
+
parameterizedModelPicker: z39.boolean().optional(),
|
|
9649
|
+
/** Bare model ids shown before the collapsed "More models" pool. */
|
|
9650
|
+
primaryModels: z39.array(z39.string().min(1)).optional(),
|
|
9651
|
+
/** Model ids to probe first during bounded native discovery. */
|
|
9652
|
+
reasoningProbePriorityModelIds: z39.array(z39.string().min(1)).optional()
|
|
9558
9653
|
}).passthrough();
|
|
9654
|
+
function decodeAcpModelPickerOptions(providerOptions) {
|
|
9655
|
+
const parsed = acpProviderOptionsSchema.parse(providerOptions ?? {});
|
|
9656
|
+
return {
|
|
9657
|
+
parameterizedModelPicker: parsed.parameterizedModelPicker === true,
|
|
9658
|
+
...parsed.primaryModels === void 0 ? {} : { primaryModels: [...parsed.primaryModels] },
|
|
9659
|
+
reasoningProbePriorityModelIds: [
|
|
9660
|
+
...parsed.reasoningProbePriorityModelIds ?? []
|
|
9661
|
+
]
|
|
9662
|
+
};
|
|
9663
|
+
}
|
|
9559
9664
|
function decodeAdditionalWorkspaceWriteRoots(providerOptions) {
|
|
9560
9665
|
return acpProviderOptionsSchema.parse(providerOptions ?? {}).additionalWorkspaceWriteRoots ?? [];
|
|
9561
9666
|
}
|
|
@@ -9597,14 +9702,19 @@ async function handleRequest2(request) {
|
|
|
9597
9702
|
};
|
|
9598
9703
|
sendResult(request.id, result);
|
|
9599
9704
|
return;
|
|
9600
|
-
case "model/list":
|
|
9705
|
+
case "model/list": {
|
|
9706
|
+
const modelPicker = decodeAcpModelPickerOptions(
|
|
9707
|
+
request.params.providerOptions
|
|
9708
|
+
);
|
|
9601
9709
|
await handleModelList(
|
|
9602
9710
|
request.id,
|
|
9603
9711
|
buildAcpModelListParams(
|
|
9604
|
-
decodeLaunchSpec(request.params.providerOptions)
|
|
9712
|
+
decodeLaunchSpec(request.params.providerOptions),
|
|
9713
|
+
modelPicker
|
|
9605
9714
|
)
|
|
9606
9715
|
);
|
|
9607
9716
|
return;
|
|
9717
|
+
}
|
|
9608
9718
|
case "provider/health": {
|
|
9609
9719
|
const launchSpec = decodeLaunchSpec(request.params.providerOptions);
|
|
9610
9720
|
sendResult(
|
|
@@ -9683,6 +9793,9 @@ async function handleRequest2(request) {
|
|
|
9683
9793
|
);
|
|
9684
9794
|
return;
|
|
9685
9795
|
}
|
|
9796
|
+
const modelPicker = decodeAcpModelPickerOptions(
|
|
9797
|
+
params.options.providerOptions
|
|
9798
|
+
);
|
|
9686
9799
|
const sessionParams = buildAcpSessionParams({
|
|
9687
9800
|
additionalWorkspaceWriteRoots: decodeAdditionalWorkspaceWriteRoots(
|
|
9688
9801
|
params.options.providerOptions
|
|
@@ -9694,6 +9807,7 @@ async function handleRequest2(request) {
|
|
|
9694
9807
|
...params.options,
|
|
9695
9808
|
skillRoots: configuredSkillRoots ?? void 0
|
|
9696
9809
|
},
|
|
9810
|
+
parameterizedModelPicker: modelPicker.parameterizedModelPicker,
|
|
9697
9811
|
launchSpec,
|
|
9698
9812
|
providerLabel: launchSpec.displayName,
|
|
9699
9813
|
threadId: params.threadId
|