@bike4mind/cli 1.2.0 → 2.1.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 +3 -1
- package/dist/{AgentHistoryStore-B2NEOvSW.mjs → AgentHistoryStore-DdYKfx7C.mjs} +599 -363
- package/dist/{ApiClient-D0fQ2FT6.mjs → ApiClient-dIB3YQc2.mjs} +44 -5
- package/dist/{ConfigStore-qV7NrCgZ.mjs → ConfigStore-BygzEI6H.mjs} +12830 -9263
- package/dist/{WorkItemsClient-Cow6nXx7.mjs → WorkItemsClient-ClBC49y0.mjs} +52 -8
- package/dist/{buildAgent-C-C-VGff.mjs → buildAgent-B7cMwRAy.mjs} +146 -10
- package/dist/commands/acpCommand.mjs +5 -4
- package/dist/commands/apiCommand.mjs +1 -1
- package/dist/commands/doctorCommand.mjs +1 -1
- package/dist/commands/envCommand.mjs +1 -1
- package/dist/commands/headlessCommand.mjs +5 -4
- package/dist/commands/mcpCommand.mjs +3 -3
- package/dist/commands/pluginCommand.mjs +1 -1
- package/dist/commands/updateCommand.mjs +1 -1
- package/dist/index.mjs +592 -52
- package/dist/{package-CGZIoxcs.mjs → package-CRNnNXxq.mjs} +1 -1
- package/dist/serve-DM7ld3-o.mjs +1365 -0
- package/package.json +14 -14
- package/dist/serve-CPXqcEZr.mjs +0 -774
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { bt as tokenEstimateMultiplier } from "./ConfigStore-BygzEI6H.mjs";
|
|
2
3
|
import { v4 } from "uuid";
|
|
3
4
|
import { get_encoding } from "tiktoken";
|
|
5
|
+
//#region ../../b4m-core/utils/dist/calibratedTokenizer.mjs
|
|
6
|
+
/**
|
|
7
|
+
* Scale a raw cl100k_base count by `multiplier`, rounded up to the nearest whole token. Paired with
|
|
8
|
+
* tokenEstimateMultiplier (@bike4mind/common) to bring a raw count up to a Claude model's tokenizer.
|
|
9
|
+
* The sync counterpart of withTokenEstimateMultiplier, for callers whose counter is synchronous.
|
|
10
|
+
*/
|
|
11
|
+
function scaleTokenEstimate(count, multiplier) {
|
|
12
|
+
if (multiplier === 1) return count;
|
|
13
|
+
const hundredths = Math.round(multiplier * 100);
|
|
14
|
+
return Math.ceil(count * hundredths / 100);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
4
17
|
//#region src/utils/tokenCounter.ts
|
|
5
18
|
const DEFAULT_CONTEXT_WINDOW = 2e5;
|
|
6
19
|
const IMAGE_BLOCK_TOKEN_ESTIMATE = 1600;
|
|
7
20
|
/**
|
|
8
21
|
* Token counting utility for context window management.
|
|
9
|
-
* Uses tiktoken (cl100k_base encoding)
|
|
22
|
+
* Uses tiktoken (cl100k_base encoding), the encoding GPT-4 reports. Claude's tokenizers spend more
|
|
23
|
+
* tokens on the same text, so call `forModel(modelId)` before comparing a count against a model's
|
|
24
|
+
* context window (see tokenEstimateMultiplier in @bike4mind/common).
|
|
10
25
|
*/
|
|
11
26
|
var TokenCounter = class {
|
|
12
27
|
constructor() {
|
|
@@ -17,6 +32,16 @@ var TokenCounter = class {
|
|
|
17
32
|
return this.encoder;
|
|
18
33
|
}
|
|
19
34
|
/**
|
|
35
|
+
* A view of this counter whose counts are scaled to `modelId`'s own tokenizer, or `this` when the
|
|
36
|
+
* model needs no scaling (non-Claude, or a Claude version tokenEstimateMultiplier leaves at 1). Use
|
|
37
|
+
* it wherever a count is compared against a model's context window, so a Claude session compacts
|
|
38
|
+
* and reports against real token usage rather than a cl100k_base undercount.
|
|
39
|
+
*/
|
|
40
|
+
forModel(modelId) {
|
|
41
|
+
const multiplier = tokenEstimateMultiplier(modelId);
|
|
42
|
+
return multiplier === 1 ? this : new CalibratedTokenCounter(this, multiplier);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
20
45
|
* Count tokens in a text string
|
|
21
46
|
*/
|
|
22
47
|
countTokens(text) {
|
|
@@ -80,6 +105,24 @@ var TokenCounter = class {
|
|
|
80
105
|
}
|
|
81
106
|
}
|
|
82
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* A calibrated view over a raw `TokenCounter`. `countTokens` is the one primitive every other count
|
|
110
|
+
* routes through, so overriding it calibrates message, session and tool-schema counts at once. The
|
|
111
|
+
* flat image estimate stays unscaled because it is not a tiktoken count. The view holds no encoder of
|
|
112
|
+
* its own - it reads through `raw` - so `dispose` is a no-op and disposing the view never frees the
|
|
113
|
+
* shared encoder.
|
|
114
|
+
*/
|
|
115
|
+
var CalibratedTokenCounter = class extends TokenCounter {
|
|
116
|
+
constructor(raw, multiplier) {
|
|
117
|
+
super();
|
|
118
|
+
this.raw = raw;
|
|
119
|
+
this.multiplier = multiplier;
|
|
120
|
+
}
|
|
121
|
+
countTokens(text) {
|
|
122
|
+
return scaleTokenEstimate(this.raw.countTokens(text), this.multiplier);
|
|
123
|
+
}
|
|
124
|
+
dispose() {}
|
|
125
|
+
};
|
|
83
126
|
let tokenCounter = null;
|
|
84
127
|
/**
|
|
85
128
|
* Get the singleton TokenCounter instance
|
|
@@ -151,7 +194,8 @@ var ConversationContext = class ConversationContext {
|
|
|
151
194
|
* rendering each turn's bounded tool trace - plus the system prompt, and
|
|
152
195
|
* compares against `thresholdRatio` of the context window. Rich-content aware:
|
|
153
196
|
* replaces the old string-only `content` sum so a session whose weight lives
|
|
154
|
-
* in tool traces still triggers compaction.
|
|
197
|
+
* in tool traces still triggers compaction. Counts are calibrated to
|
|
198
|
+
* `opts.model`, so `systemPromptTokens` must be too (the caller owns it).
|
|
155
199
|
*/
|
|
156
200
|
needsCompaction(systemPromptTokens, opts, thresholdRatio = .8) {
|
|
157
201
|
return this.estimateSessionTokens(systemPromptTokens, opts) >= opts.contextWindow * thresholdRatio;
|
|
@@ -162,7 +206,7 @@ var ConversationContext = class ConversationContext {
|
|
|
162
206
|
* system prompt. Used by `needsCompaction`.
|
|
163
207
|
*/
|
|
164
208
|
estimateSessionTokens(systemPromptTokens, opts) {
|
|
165
|
-
return systemPromptTokens + this.messages.filter((m) => m.role === "user" || m.role === "assistant").reduce((sum, m) => sum + this.estimateTokens(this.renderHistoryMessage(m, opts)), 0);
|
|
209
|
+
return systemPromptTokens + this.messages.filter((m) => m.role === "user" || m.role === "assistant").reduce((sum, m) => sum + this.estimateTokens(this.renderHistoryMessage(m, opts), opts), 0);
|
|
166
210
|
}
|
|
167
211
|
/** Serialize back to a Session for on-disk persistence (rich content preserved). */
|
|
168
212
|
toSession() {
|
|
@@ -181,12 +225,12 @@ var ConversationContext = class ConversationContext {
|
|
|
181
225
|
*/
|
|
182
226
|
windowedHistory(newInput, opts) {
|
|
183
227
|
const reserved = opts.reservedTokens ?? 8e3;
|
|
184
|
-
const currentTokens = this.estimateTokens(this.inputToIMessage(newInput));
|
|
228
|
+
const currentTokens = this.estimateTokens(this.inputToIMessage(newInput), opts);
|
|
185
229
|
const history = this.messages.filter((m) => m.role === "user" || m.role === "assistant").map((m) => this.renderHistoryMessage(m, opts));
|
|
186
230
|
let remaining = opts.contextWindow - reserved - currentTokens;
|
|
187
231
|
const kept = [];
|
|
188
232
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
189
|
-
const cost = this.estimateTokens(history[i]);
|
|
233
|
+
const cost = this.estimateTokens(history[i], opts);
|
|
190
234
|
if (cost > remaining) break;
|
|
191
235
|
remaining -= cost;
|
|
192
236
|
kept.unshift(history[i]);
|
|
@@ -250,7 +294,7 @@ var ConversationContext = class ConversationContext {
|
|
|
250
294
|
if (b.type !== "tool_use") continue;
|
|
251
295
|
const resultText = b.id && results.get(b.id) || "";
|
|
252
296
|
const line = `[tool ${b.name}] ${this.brief(JSON.stringify(b.input ?? {}))} -> ${this.brief(resultText)}`;
|
|
253
|
-
const cost = this.counter.countTokens(line);
|
|
297
|
+
const cost = this.counter.forModel(opts.model).countTokens(line);
|
|
254
298
|
if (used + cost > budget) {
|
|
255
299
|
omitted++;
|
|
256
300
|
continue;
|
|
@@ -272,8 +316,8 @@ var ConversationContext = class ConversationContext {
|
|
|
272
316
|
content: input
|
|
273
317
|
};
|
|
274
318
|
}
|
|
275
|
-
estimateTokens(message) {
|
|
276
|
-
return this.counter.countMessageContent(message.content);
|
|
319
|
+
estimateTokens(message, opts) {
|
|
320
|
+
return this.counter.forModel(opts.model).countMessageContent(message.content);
|
|
277
321
|
}
|
|
278
322
|
};
|
|
279
323
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { I as generateCliTools, J as setWebSocketToolExecutor, L as wrapTools, N as ReActAgent, X as buildSystemPrompt, Y as getPlanModeFilePath, a as loadProjectContext, c as createSseBackend, i as buildProjectAgentStore, it as Logger, l as ServerLlmBackend, n as BackgroundAgentManager, o as McpManager, r as SubagentOrchestrator, t as AgentHistoryStore } from "./AgentHistoryStore-
|
|
3
|
-
import {
|
|
2
|
+
import { I as generateCliTools, J as setWebSocketToolExecutor, L as wrapTools, N as ReActAgent, X as buildSystemPrompt, Y as getPlanModeFilePath, a as loadProjectContext, c as createSseBackend, i as buildProjectAgentStore, it as Logger, l as ServerLlmBackend, n as BackgroundAgentManager, o as McpManager, r as SubagentOrchestrator, t as AgentHistoryStore } from "./AgentHistoryStore-DdYKfx7C.mjs";
|
|
3
|
+
import { $ as escapeThinkMarkers, A as ChatModels, C as ARTIFACT_REMOVED_PLACEHOLDER, L as MODEL_INFO_FIELD_GROUP_OF, O as CONTEXT_WINDOW_SAFETY_BUFFER_TOKENS, Q as createThinkMarkerEscaper, S as ARTIFACT_DELIVERED_PLACEHOLDER, W as PermissionDeniedError, _t as stripDeliveredArtifactBlocks, at as hasDeliverablePinnedArtifact, et as filterToolArtifactMarkup, lt as isUserInitiatedAbort, n as logger, rt as getQuestErrorCode, vt as stripToolArtifactMarkup, z as ModelBackend } from "./ConfigStore-BygzEI6H.mjs";
|
|
4
4
|
import "crypto";
|
|
5
5
|
import { v4 } from "uuid";
|
|
6
6
|
import { z as z$1 } from "zod";
|
|
@@ -24,6 +24,23 @@ import WebSocket from "ws";
|
|
|
24
24
|
function isTerminalToolError(error) {
|
|
25
25
|
return error instanceof PermissionDeniedError || getQuestErrorCode(error) !== void 0;
|
|
26
26
|
}
|
|
27
|
+
/** Whether the named tool is flagged `endsTurnAfterText` in the offered tool list. */
|
|
28
|
+
function isTurnEndingTool(name, tools) {
|
|
29
|
+
return tools?.find((tool) => tool.toolSchema.name === name)?.endsTurnAfterText === true;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Whether the tool loop should end the turn after this round's tool batch instead of making
|
|
33
|
+
* the follow-up model call. True only when the round already streamed non-empty answer text
|
|
34
|
+
* AND every tool it called is flagged `endsTurnAfterText`: the follow-up round would only
|
|
35
|
+
* repeat the answer. A tool-only round still recurses so the model gets to answer.
|
|
36
|
+
*
|
|
37
|
+
* The single decision point for every adapter's tool loop - keep them from drifting.
|
|
38
|
+
*/
|
|
39
|
+
function shouldEndTurnAfterTools(calledToolNames, tools, roundText) {
|
|
40
|
+
const names = calledToolNames.filter((name) => Boolean(name));
|
|
41
|
+
if (names.length === 0 || !roundText?.trim()) return false;
|
|
42
|
+
return names.every((name) => isTurnEndingTool(name, tools));
|
|
43
|
+
}
|
|
27
44
|
/**
|
|
28
45
|
* Execute an array of async tasks either in parallel (with concurrency limiting)
|
|
29
46
|
* or sequentially, returning outcomes in the original order.
|
|
@@ -135,6 +152,96 @@ function attachFullToolResult(entry, observation) {
|
|
|
135
152
|
writable: true
|
|
136
153
|
});
|
|
137
154
|
}
|
|
155
|
+
/** The `artifactType` the named tool declared at registration, for the helpers below. */
|
|
156
|
+
function declaredArtifactType(tools, toolName) {
|
|
157
|
+
return tools?.find((t) => t.toolSchema.name === toolName)?.artifactType;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Helper function to handle tool result streaming for artifact-generating tools
|
|
161
|
+
* This ensures tools like recharts that generate artifacts are streamed immediately
|
|
162
|
+
* rather than waiting for recursive completion calls.
|
|
163
|
+
*
|
|
164
|
+
* Only the emitters in TOOL_ARTIFACT_EMITTERS (or a tool that declared `artifactType`, see
|
|
165
|
+
* declaredArtifactType) stream, and only their pinned artifact type: streamed text is parsed
|
|
166
|
+
* into reply artifacts, so any other tool's markup would render.
|
|
167
|
+
*
|
|
168
|
+
* What does stream is still a raw tool artifact rather than reply prose, so `streamCallback`
|
|
169
|
+
* receives the channel tag and a public surface drops the text on that tag alone.
|
|
170
|
+
*/
|
|
171
|
+
async function handleToolResultStreaming(toolName, toolResult, streamCallback, artifactType) {
|
|
172
|
+
const filtered = filterToolArtifactMarkup(toolName, String(toolResult), artifactType);
|
|
173
|
+
if (filtered !== null) await streamCallback([filtered], { channel: "tool-artifact" });
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Strips artifact markup from a tool result before it re-enters history, so the model cannot echo
|
|
177
|
+
* it into a second card. Live-emitting backends pass `delivered` = whether their tool-artifact
|
|
178
|
+
* emit fired. The `hasDeliverablePinnedArtifact` fallback is for the OpenAI Responses path, whose
|
|
179
|
+
* artifact reaches the client through sharedToolBuilder extraction instead.
|
|
180
|
+
*
|
|
181
|
+
* The delivered/removed choice is made once per result and stamped on every block it contains.
|
|
182
|
+
* That holds because each emitter emits one pinned block; a result mixing a foreign-type block
|
|
183
|
+
* with a pinned one would label both DELIVERED.
|
|
184
|
+
*/
|
|
185
|
+
function stripUnstreamedToolResult(toolName, result, delivered) {
|
|
186
|
+
return stripToolArtifactMarkup(result, delivered ?? hasDeliverablePinnedArtifact(toolName, result) ? ARTIFACT_DELIVERED_PLACEHOLDER : ARTIFACT_REMOVED_PLACEHOLDER);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Buffers a recursive completion's text instead of streaming it live, so an <artifact> tag the
|
|
190
|
+
* model echoes back (after seeing its own tool result, even sanitized) can be stripped before the
|
|
191
|
+
* client ever renders a second, empty card for it. Only removes blocks whose `identifier` matches
|
|
192
|
+
* one already delivered this turn (stripDeliveredArtifactBlocks) - a stray "<artifact" the model's
|
|
193
|
+
* prose merely mentions, or a genuinely NEW artifact the model composes with a different
|
|
194
|
+
* identifier, must not cost the rest of a legitimate reply, unlike the tool-output-facing
|
|
195
|
+
* stripToolArtifactMarkup.
|
|
196
|
+
*
|
|
197
|
+
* One instance is created lazily by whichever level first streams an artifact in a recursive
|
|
198
|
+
* chain, and reused UNCHANGED by every deeper level (never recreated per level) - see each
|
|
199
|
+
* backend's `_internal.artifactGuard`. A chained tool call's artifact goes through `emitArtifact`
|
|
200
|
+
* on this same shared instance, which flushes any text already buffered ahead of it before
|
|
201
|
+
* sending the artifact through - so ordering survives even when the chained call happens several
|
|
202
|
+
* recursion levels below where the guard was created.
|
|
203
|
+
*/
|
|
204
|
+
function createRecursiveArtifactGuard(cb) {
|
|
205
|
+
let buffer = "";
|
|
206
|
+
let deliveredMarkup = "";
|
|
207
|
+
let meta = {};
|
|
208
|
+
const callback = (async (text, info) => {
|
|
209
|
+
for (const chunk of text) if (chunk != null) buffer += chunk;
|
|
210
|
+
if (info?.inputTokens || info?.outputTokens) meta = { ...info };
|
|
211
|
+
});
|
|
212
|
+
const emitArtifact = async (results, info) => {
|
|
213
|
+
if (buffer) {
|
|
214
|
+
const pending = buffer;
|
|
215
|
+
buffer = "";
|
|
216
|
+
const stripped = stripDeliveredArtifactBlocks(pending, deliveredMarkup);
|
|
217
|
+
if (stripped.trim()) await cb([stripped], {});
|
|
218
|
+
}
|
|
219
|
+
deliveredMarkup += results.join("");
|
|
220
|
+
await cb(results, info);
|
|
221
|
+
};
|
|
222
|
+
const markDelivered = (markup) => {
|
|
223
|
+
deliveredMarkup += markup;
|
|
224
|
+
};
|
|
225
|
+
let flushPromise = null;
|
|
226
|
+
const flush = () => {
|
|
227
|
+
if (flushPromise) return flushPromise;
|
|
228
|
+
const cleaned = stripDeliveredArtifactBlocks(buffer, deliveredMarkup).trim();
|
|
229
|
+
let resolve;
|
|
230
|
+
let reject;
|
|
231
|
+
flushPromise = new Promise((res, rej) => {
|
|
232
|
+
resolve = res;
|
|
233
|
+
reject = rej;
|
|
234
|
+
});
|
|
235
|
+
(async () => cb(cleaned ? [cleaned] : [], meta))().then(() => resolve(), reject);
|
|
236
|
+
return flushPromise;
|
|
237
|
+
};
|
|
238
|
+
return {
|
|
239
|
+
callback,
|
|
240
|
+
emitArtifact,
|
|
241
|
+
markDelivered,
|
|
242
|
+
flush
|
|
243
|
+
};
|
|
244
|
+
}
|
|
138
245
|
/**
|
|
139
246
|
* Drops the messages whose instructions assume a tool is attached (see `IMessage.requiresTool`).
|
|
140
247
|
*
|
|
@@ -850,20 +957,32 @@ var OllamaBackend = class OllamaBackend {
|
|
|
850
957
|
parallel: options.parallelToolExecution !== false,
|
|
851
958
|
maxConcurrency: options.maxParallelTools
|
|
852
959
|
});
|
|
960
|
+
const inheritedArtifactGuard = options._internal?.artifactGuard;
|
|
961
|
+
let artifactGuard = inheritedArtifactGuard;
|
|
853
962
|
const observations = [];
|
|
854
|
-
outcomes.
|
|
963
|
+
for (let i = 0; i < outcomes.length; i++) {
|
|
964
|
+
const outcome = outcomes[i];
|
|
855
965
|
const { tc } = resolved[i];
|
|
856
966
|
const params = tc.arguments || "{}";
|
|
857
967
|
if (outcome.ok) {
|
|
858
|
-
|
|
968
|
+
let emitted = false;
|
|
969
|
+
await handleToolResultStreaming(tc.name, outcome.result, async (results, artifactInfo) => {
|
|
970
|
+
emitted = true;
|
|
971
|
+
if (!artifactGuard) artifactGuard = createRecursiveArtifactGuard(callback);
|
|
972
|
+
await artifactGuard.emitArtifact(results, {
|
|
973
|
+
toolsUsed,
|
|
974
|
+
...artifactInfo
|
|
975
|
+
});
|
|
976
|
+
}, declaredArtifactType(options.tools, tc.name));
|
|
977
|
+
observations[i] = stripUnstreamedToolResult(tc.name, outcome.result, emitted);
|
|
859
978
|
this.pushToolMessages(messages, {
|
|
860
979
|
id: tc.id,
|
|
861
980
|
name: tc.name,
|
|
862
981
|
parameters: params
|
|
863
|
-
},
|
|
982
|
+
}, observations[i]);
|
|
864
983
|
} else {
|
|
865
984
|
if (outcome.error instanceof PermissionDeniedError) throw outcome.error;
|
|
866
|
-
const errorMsg = `Error running ${tc.name}: ${outcome.error instanceof Error ? outcome.error.message : "Unknown error"}
|
|
985
|
+
const errorMsg = stripToolArtifactMarkup(`Error running ${tc.name}: ${outcome.error instanceof Error ? outcome.error.message : "Unknown error"}`, ARTIFACT_REMOVED_PLACEHOLDER);
|
|
867
986
|
observations[i] = errorMsg;
|
|
868
987
|
this.pushToolMessages(messages, {
|
|
869
988
|
id: tc.id,
|
|
@@ -871,7 +990,7 @@ var OllamaBackend = class OllamaBackend {
|
|
|
871
990
|
parameters: params
|
|
872
991
|
}, errorMsg);
|
|
873
992
|
}
|
|
874
|
-
}
|
|
993
|
+
}
|
|
875
994
|
const executedToolsUsed = [...priorToolsUsed, ...resolved.map(({ tc }, i) => {
|
|
876
995
|
const entry = {
|
|
877
996
|
name: tc.name,
|
|
@@ -884,11 +1003,26 @@ var OllamaBackend = class OllamaBackend {
|
|
|
884
1003
|
return entry;
|
|
885
1004
|
})];
|
|
886
1005
|
if (options.abortSignal?.aborted) {
|
|
887
|
-
await callback([""], {
|
|
1006
|
+
await (artifactGuard?.callback ?? callback)([""], {
|
|
888
1007
|
inputTokens,
|
|
889
1008
|
outputTokens,
|
|
890
1009
|
toolsUsed: executedToolsUsed
|
|
891
1010
|
});
|
|
1011
|
+
if (!inheritedArtifactGuard && artifactGuard) await artifactGuard.flush();
|
|
1012
|
+
return;
|
|
1013
|
+
}
|
|
1014
|
+
if (round.toolCalls.length > 0 && shouldEndTurnAfterTools(toolCalls.map((tc) => tc.name), options.tools, round.content)) {
|
|
1015
|
+
this._logger.info("[Tool Execution] Ending turn: answer already produced, only end-of-turn tools ran", {
|
|
1016
|
+
model,
|
|
1017
|
+
toolsExecuted: toolCalls.map((tc) => tc.name)
|
|
1018
|
+
});
|
|
1019
|
+
await (artifactGuard?.callback ?? callback)([round.content], {
|
|
1020
|
+
inputTokens,
|
|
1021
|
+
outputTokens,
|
|
1022
|
+
toolsUsed: executedToolsUsed,
|
|
1023
|
+
stopReason: "tool_use"
|
|
1024
|
+
});
|
|
1025
|
+
if (!inheritedArtifactGuard && artifactGuard) await artifactGuard.flush();
|
|
892
1026
|
return;
|
|
893
1027
|
}
|
|
894
1028
|
await this.complete(model, messages, {
|
|
@@ -898,9 +1032,11 @@ var OllamaBackend = class OllamaBackend {
|
|
|
898
1032
|
toolCallCount: toolCallCount + 1,
|
|
899
1033
|
accumToolsUsed: executedToolsUsed,
|
|
900
1034
|
accumInputTokens: inputTokens,
|
|
901
|
-
accumOutputTokens: outputTokens
|
|
1035
|
+
accumOutputTokens: outputTokens,
|
|
1036
|
+
artifactGuard
|
|
902
1037
|
}
|
|
903
|
-
}, callback);
|
|
1038
|
+
}, artifactGuard?.callback ?? callback);
|
|
1039
|
+
if (!inheritedArtifactGuard && artifactGuard) await artifactGuard.flush();
|
|
904
1040
|
} catch (error) {
|
|
905
1041
|
if (error instanceof Error && isUserInitiatedAbort(error, options.abortSignal)) this._logger.debug("[OllamaBackend] Ollama request cancelled by the caller");
|
|
906
1042
|
else this._logger.error("[OllamaBackend] Error during Ollama API call:", error);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, J as setWebSocketToolExecutor, L as wrapTools, O as createResumeAgentTool, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, b as createGetFileStructureTool, et as CheckpointStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, s as buildSandbox, tt as SessionStore, w as createWriteTodosTool } from "../AgentHistoryStore-
|
|
3
|
-
import {
|
|
4
|
-
import { a as deferredToolRegistry, i as createToolSearchTool, n as buildSupportingStores, o as NotifyingLlmBackend, r as buildLlmBackend, t as buildAgent } from "../buildAgent-
|
|
5
|
-
import { t as ApiClient } from "../ApiClient-
|
|
2
|
+
import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, J as setWebSocketToolExecutor, L as wrapTools, O as createResumeAgentTool, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, b as createGetFileStructureTool, et as CheckpointStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, s as buildSandbox, tt as SessionStore, w as createWriteTodosTool } from "../AgentHistoryStore-DdYKfx7C.mjs";
|
|
3
|
+
import { _ as requireApiUrl, d as isReadOnlyTool, n as logger, t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
|
|
4
|
+
import { a as deferredToolRegistry, i as createToolSearchTool, n as buildSupportingStores, o as NotifyingLlmBackend, r as buildLlmBackend, t as buildAgent } from "../buildAgent-B7cMwRAy.mjs";
|
|
5
|
+
import { t as ApiClient } from "../ApiClient-dIB3YQc2.mjs";
|
|
6
6
|
import { randomUUID } from "crypto";
|
|
7
7
|
import { existsSync, realpathSync, statSync } from "fs";
|
|
8
8
|
import { isAbsolute } from "path";
|
|
@@ -575,6 +575,7 @@ var AcpServer = class {
|
|
|
575
575
|
}
|
|
576
576
|
async buildStack() {
|
|
577
577
|
const config = await this.configStore.load();
|
|
578
|
+
this.configStore.warnPendingMcpApprovals();
|
|
578
579
|
await this.loadCustomCommands();
|
|
579
580
|
const authTokens = await this.configStore.getAuthTokens();
|
|
580
581
|
if (!authTokens) throw RequestError.authRequired(void 0, "Not authenticated. Run `b4m /login` first.");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { g as
|
|
2
|
+
import { g as parseApiUrl, t as ConfigStore, v as resolveApiEndpoint } from "../ConfigStore-BygzEI6H.mjs";
|
|
3
3
|
//#region src/commands/apiCommand.ts
|
|
4
4
|
/**
|
|
5
5
|
* External API config command (--api-url / --reset-api)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "../package-
|
|
2
|
+
import { t as version } from "../package-CRNnNXxq.mjs";
|
|
3
3
|
import { a as fetchLatestVersion, c as isNpmPrefixWritable, i as compareSemver } from "../updateChecker-CQW8bxo6.mjs";
|
|
4
4
|
import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
|
|
5
5
|
import { execSync } from "child_process";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, G as classifyCommandRisk, I as generateCliTools, J as setWebSocketToolExecutor, L as wrapTools, N as ReActAgent, O as createResumeAgentTool, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, X as buildSystemPrompt, a as loadProjectContext, b as createGetFileStructureTool, c as createSseBackend, et as CheckpointStore, i as buildProjectAgentStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, n as BackgroundAgentManager, o as McpManager, r as SubagentOrchestrator, s as buildSandbox, t as AgentHistoryStore, tt as SessionStore, w as createWriteTodosTool, x as createWorkItemTools, z as SHELL_LIKE_TOOL_COMMAND_FIELDS } from "../AgentHistoryStore-
|
|
3
|
-
import {
|
|
4
|
-
import { t as
|
|
5
|
-
import {
|
|
2
|
+
import { $ as CustomCommandStore, A as createAgentDelegateTool, C as createTodoStore, D as createCoordinateTaskTool, F as PermissionManager, G as classifyCommandRisk, I as generateCliTools, J as setWebSocketToolExecutor, L as wrapTools, N as ReActAgent, O as createResumeAgentTool, Q as RemoteSkillSource, S as createFindDefinitionTool, T as createSkillTool, X as buildSystemPrompt, a as loadProjectContext, b as createGetFileStructureTool, c as createSseBackend, et as CheckpointStore, i as buildProjectAgentStore, j as FallbackLlmBackend, k as createBackgroundAgentTools, n as BackgroundAgentManager, o as McpManager, r as SubagentOrchestrator, s as buildSandbox, t as AgentHistoryStore, tt as SessionStore, w as createWriteTodosTool, x as createWorkItemTools, z as SHELL_LIKE_TOOL_COMMAND_FIELDS } from "../AgentHistoryStore-DdYKfx7C.mjs";
|
|
3
|
+
import { _ as requireApiUrl, d as isReadOnlyTool, n as logger, t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
|
|
4
|
+
import { r as reconstructTurnBlocks, t as WorkItemsClient } from "../WorkItemsClient-ClBC49y0.mjs";
|
|
5
|
+
import { t as ApiClient } from "../ApiClient-dIB3YQc2.mjs";
|
|
6
6
|
import { randomBytes } from "crypto";
|
|
7
7
|
import { v4 } from "uuid";
|
|
8
8
|
import { readFile } from "fs/promises";
|
|
@@ -250,6 +250,7 @@ async function handleHeadlessCommand(options) {
|
|
|
250
250
|
const runId = v4();
|
|
251
251
|
try {
|
|
252
252
|
const config = await configStore.load();
|
|
253
|
+
configStore.warnPendingMcpApprovals();
|
|
253
254
|
const configDirs = await configStore.getAdditionalDirectories();
|
|
254
255
|
const flagDirs = process.env.B4M_ADDITIONAL_DIRS ? parseStringArray(process.env.B4M_ADDITIONAL_DIRS, "B4M_ADDITIONAL_DIRS") : [];
|
|
255
256
|
const additionalDirectories = [.../* @__PURE__ */ new Set([
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as ConfigStore } from "../ConfigStore-
|
|
3
|
-
import { t as version } from "../package-
|
|
2
|
+
import { t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
|
|
3
|
+
import { t as version } from "../package-CRNnNXxq.mjs";
|
|
4
4
|
//#region src/commands/mcpCommand.ts
|
|
5
5
|
/**
|
|
6
6
|
* External MCP commands (b4m mcp list, b4m mcp add, etc.)
|
|
@@ -70,7 +70,7 @@ async function handleMcpCommand(subcommand, argv) {
|
|
|
70
70
|
await handleDisable(config, argv.name, configStore);
|
|
71
71
|
break;
|
|
72
72
|
case "serve": {
|
|
73
|
-
const { handleMcpServeCommand } = await import("../serve-
|
|
73
|
+
const { handleMcpServeCommand } = await import("../serve-DM7ld3-o.mjs");
|
|
74
74
|
await handleMcpServeCommand({
|
|
75
75
|
http: Boolean(argv.http),
|
|
76
76
|
port: typeof argv.port === "number" ? argv.port : void 0,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { n as getDefaultPluginsDir, r as isFeatureEnabled, t as PluginStore } from "../PluginStore-DwvOJ-G3.mjs";
|
|
3
|
-
import { t as ConfigStore } from "../ConfigStore-
|
|
3
|
+
import { t as ConfigStore } from "../ConfigStore-BygzEI6H.mjs";
|
|
4
4
|
import { execFileSync } from "child_process";
|
|
5
5
|
import { promises } from "fs";
|
|
6
6
|
import path from "path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { t as version } from "../package-
|
|
2
|
+
import { t as version } from "../package-CRNnNXxq.mjs";
|
|
3
3
|
import { c as isNpmPrefixWritable, l as setAutoUpdatePreference, n as REEXEC_GUARD_ENV, o as forceCheckForUpdate, r as checkForUpdate, s as getAutoUpdatePreference, t as INSTALL_CMD, u as shouldAttemptAutoUpdate } from "../updateChecker-CQW8bxo6.mjs";
|
|
4
4
|
import { t as checkRipgrep } from "../ripgrepCheck-BmkyTK2i.mjs";
|
|
5
5
|
import { execSync, spawnSync } from "child_process";
|