cascade-ai 0.80.0 → 0.81.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/dist/cli.cjs +310 -11
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +310 -11
- package/dist/cli.js.map +1 -1
- package/dist/desktop-core.cjs +530 -29
- package/dist/index.cjs +530 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +328 -7
- package/dist/index.d.ts +328 -7
- package/dist/index.js +527 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11623,7 +11623,7 @@ function reconcilePrice(model, live) {
|
|
|
11623
11623
|
}
|
|
11624
11624
|
|
|
11625
11625
|
// src/constants.ts
|
|
11626
|
-
var CASCADE_VERSION = "0.
|
|
11626
|
+
var CASCADE_VERSION = "0.81.0";
|
|
11627
11627
|
var CASCADE_CONFIG_DIR = ".cascade";
|
|
11628
11628
|
var CASCADE_MD_FILE = "CASCADE.md";
|
|
11629
11629
|
var CASCADE_IGNORE_FILE = ".cascadeignore";
|
|
@@ -30861,8 +30861,95 @@ function requiredFieldFor(kind, input) {
|
|
|
30861
30861
|
}
|
|
30862
30862
|
}
|
|
30863
30863
|
|
|
30864
|
+
// src/tools/ask-user.ts
|
|
30865
|
+
var MAX_QUESTIONS = 5;
|
|
30866
|
+
var MAX_OPTIONS = 6;
|
|
30867
|
+
var AskUserTool = class extends BaseTool {
|
|
30868
|
+
name = "ask_user";
|
|
30869
|
+
description = "Ask the person a short questionnaire when their request is genuinely ambiguous, instead of guessing. Use it when two readings of the request would produce materially different work \u2014 which account, which date range, whether to include drafts \u2014 and NOT for anything you can settle yourself or from the conversation. Ask everything you need in ONE call: several questions together read as a form, the same questions one per turn read as an interrogation. You may get no answer (nobody is watching, or they did not reply); if so, proceed on your best reading and say which assumption you made.";
|
|
30870
|
+
inputSchema = {
|
|
30871
|
+
type: "object",
|
|
30872
|
+
properties: {
|
|
30873
|
+
questions: {
|
|
30874
|
+
type: "array",
|
|
30875
|
+
minItems: 1,
|
|
30876
|
+
maxItems: MAX_QUESTIONS,
|
|
30877
|
+
description: `The questions to ask together (at most ${MAX_QUESTIONS}).`,
|
|
30878
|
+
items: {
|
|
30879
|
+
type: "object",
|
|
30880
|
+
properties: {
|
|
30881
|
+
prompt: { type: "string", description: "The question, as you would say it to them." },
|
|
30882
|
+
kind: {
|
|
30883
|
+
type: "string",
|
|
30884
|
+
enum: ["choice", "multi", "text"],
|
|
30885
|
+
description: "choice = pick one, multi = pick any that apply, text = free-form answer."
|
|
30886
|
+
},
|
|
30887
|
+
options: {
|
|
30888
|
+
type: "array",
|
|
30889
|
+
items: { type: "string" },
|
|
30890
|
+
description: `The answers to offer, for choice and multi (at most ${MAX_OPTIONS}). Omit for text.`
|
|
30891
|
+
}
|
|
30892
|
+
},
|
|
30893
|
+
required: ["prompt", "kind"]
|
|
30894
|
+
}
|
|
30895
|
+
}
|
|
30896
|
+
},
|
|
30897
|
+
required: ["questions"]
|
|
30898
|
+
};
|
|
30899
|
+
ask;
|
|
30900
|
+
constructor(ask) {
|
|
30901
|
+
super();
|
|
30902
|
+
this.ask = ask;
|
|
30903
|
+
}
|
|
30904
|
+
// Asking a question changes nothing, so it needs no approval gate: a prompt
|
|
30905
|
+
// asking permission to show a prompt is a tax on the behaviour we want.
|
|
30906
|
+
isDangerous() {
|
|
30907
|
+
return false;
|
|
30908
|
+
}
|
|
30909
|
+
async execute(input, options) {
|
|
30910
|
+
const raw = Array.isArray(input["questions"]) ? input["questions"] : [];
|
|
30911
|
+
const questions = [];
|
|
30912
|
+
for (const [i, q] of raw.slice(0, MAX_QUESTIONS).entries()) {
|
|
30913
|
+
const item = q ?? {};
|
|
30914
|
+
const prompt = typeof item["prompt"] === "string" ? item["prompt"].trim() : "";
|
|
30915
|
+
if (!prompt) continue;
|
|
30916
|
+
const kind = item["kind"] === "multi" || item["kind"] === "text" ? item["kind"] : "choice";
|
|
30917
|
+
const options_ = Array.isArray(item["options"]) ? item["options"].filter((o) => typeof o === "string" && o.trim() !== "").slice(0, MAX_OPTIONS) : [];
|
|
30918
|
+
const resolved = kind !== "text" && options_.length < 2 ? "text" : kind;
|
|
30919
|
+
questions.push({
|
|
30920
|
+
// Positional, and assigned HERE. Letting the model supply ids invites
|
|
30921
|
+
// two questions sharing one, and the second answer would overwrite the
|
|
30922
|
+
// first with nothing to say it had.
|
|
30923
|
+
id: `q${i + 1}`,
|
|
30924
|
+
prompt,
|
|
30925
|
+
kind: resolved,
|
|
30926
|
+
...resolved === "text" ? {} : { options: options_ }
|
|
30927
|
+
});
|
|
30928
|
+
}
|
|
30929
|
+
if (questions.length === 0) {
|
|
30930
|
+
return "Error: ask_user needs at least one question with a prompt.";
|
|
30931
|
+
}
|
|
30932
|
+
const result = await this.ask(questions, options.signal);
|
|
30933
|
+
if (result.outcome !== "answered" || result.answers.length === 0) {
|
|
30934
|
+
const why = result.outcome === "no-listener" ? "There is nobody watching this run to answer" : result.outcome === "aborted" ? "The run was stopped while the question was open" : result.outcome === "answered" ? "They saw the questions and chose not to answer" : "They did not answer in time";
|
|
30935
|
+
return `${why}. Proceed on your best reading of the request, and say plainly which assumption you made.`;
|
|
30936
|
+
}
|
|
30937
|
+
const byId = new Map(result.answers.map((a) => [a.id, a.value]));
|
|
30938
|
+
const lines = questions.map((q) => {
|
|
30939
|
+
const value = byId.get(q.id);
|
|
30940
|
+
const said = Array.isArray(value) ? value.join(", ") : value;
|
|
30941
|
+
return `${q.prompt}
|
|
30942
|
+
\u2192 ${said && said.length > 0 ? said : "(no answer given)"}`;
|
|
30943
|
+
});
|
|
30944
|
+
return `They answered:
|
|
30945
|
+
|
|
30946
|
+
${lines.join("\n\n")}`;
|
|
30947
|
+
}
|
|
30948
|
+
};
|
|
30949
|
+
|
|
30864
30950
|
// src/core/cascade.ts
|
|
30865
30951
|
var ESCALATION_DECISION_TIMEOUT_MS = 5 * 6e4;
|
|
30952
|
+
var CLARIFICATION_TIMEOUT_MS = 2 * 6e4;
|
|
30866
30953
|
function buildContextualPrompt(prompt, history = []) {
|
|
30867
30954
|
const recent = history.slice(-6);
|
|
30868
30955
|
if (recent.length === 0) return prompt;
|
|
@@ -31141,6 +31228,112 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
31141
31228
|
// timeout. Same class of bug as the twelve-failover dead-model race: a wave
|
|
31142
31229
|
// is concurrent, so per-run singletons are never safe inside it.
|
|
31143
31230
|
pendingEscalations = /* @__PURE__ */ new Map();
|
|
31231
|
+
/**
|
|
31232
|
+
* Questionnaires waiting on a person, keyed by request id.
|
|
31233
|
+
*
|
|
31234
|
+
* Exactly the shape `pendingEscalations` uses, and for the same reason: the
|
|
31235
|
+
* answer, the timeout and the abort all race, and one settle path guarded by
|
|
31236
|
+
* the map delete is what makes the first of them win.
|
|
31237
|
+
*/
|
|
31238
|
+
pendingClarifications = /* @__PURE__ */ new Map();
|
|
31239
|
+
/**
|
|
31240
|
+
* Put a gate's opening question to its listeners, and NOTICE when one fails.
|
|
31241
|
+
*
|
|
31242
|
+
* `emit` cannot do this job. It calls listeners synchronously and discards
|
|
31243
|
+
* what they return, so an `async` listener — the ordinary shape for anything
|
|
31244
|
+
* that has to reach a socket or a UI — does not fail in a way `emit` reports:
|
|
31245
|
+
* it returns a REJECTED PROMISE that nobody is holding. The `try` around the
|
|
31246
|
+
* emit sees nothing, the gate is never told delivery failed, and it parks for
|
|
31247
|
+
* its full timeout while Node raises an unhandled rejection that can take the
|
|
31248
|
+
* process down.
|
|
31249
|
+
*
|
|
31250
|
+
* `onFailed` is called for either shape, and it is safe to call more than
|
|
31251
|
+
* once: both gates route it to `settle`, which is guarded by a map delete, so
|
|
31252
|
+
* the first failure wins and the rest are no-ops.
|
|
31253
|
+
*
|
|
31254
|
+
* PER LISTENER, not around the loop. `emit` stops dispatching at the first
|
|
31255
|
+
* throw, so one broken host used to cost a working one its notification —
|
|
31256
|
+
* the same reason `announceLiveView` delivers its two listeners separately.
|
|
31257
|
+
* A synchronous failure settles the gate once the whole snapshot has been
|
|
31258
|
+
* delivered; an asynchronous one settles it when the rejection arrives, which
|
|
31259
|
+
* is still far better than the window-long park it replaces.
|
|
31260
|
+
*
|
|
31261
|
+
* SETTLED AFTER THE LOOP, not inside it, and that is not tidiness. `onFailed`
|
|
31262
|
+
* settles the gate, and settling emits the gate's CLOSURE — so failing
|
|
31263
|
+
* mid-dispatch announced "this request is over" and then went on handing the
|
|
31264
|
+
* OPENING event to the listeners after it. A host later in the list would
|
|
31265
|
+
* draw a form whose only closure notification had already gone past, and it
|
|
31266
|
+
* would stand there forever. Deliver to everyone, then decide.
|
|
31267
|
+
*
|
|
31268
|
+
* `rawListeners`, NOT `listeners`. Bypassing `emit` means taking on what
|
|
31269
|
+
* `emit` was doing, and `once` is the part that bites: `listeners()` hands
|
|
31270
|
+
* back the UNWRAPPED callback, so calling it never runs the wrapper that
|
|
31271
|
+
* deregisters it. A host that asked to be told once would be told every
|
|
31272
|
+
* time — and told through a transport it had set up for one gate only.
|
|
31273
|
+
* `rawListeners()` returns the wrapper, which removes the registration and
|
|
31274
|
+
* passes the underlying listener's return value straight through, so the
|
|
31275
|
+
* promise below is still the one being observed. Verified against Node.
|
|
31276
|
+
*
|
|
31277
|
+
* `.call(this, …)`, which is the third thing `emit` was doing. EventEmitter
|
|
31278
|
+
* invokes listeners with the emitter as the receiver, so
|
|
31279
|
+
* `function () { this.resolveClarification(...) }` is a legitimate host — and
|
|
31280
|
+
* calling it bare gave it `this === undefined`, which throws, which this
|
|
31281
|
+
* would then have read as the host failing to receive the question and
|
|
31282
|
+
* settled the gate unanswered. A working listener turned into a delivery
|
|
31283
|
+
* failure by the thing delivering it.
|
|
31284
|
+
*/
|
|
31285
|
+
deliverGate(event, payload, onFailed) {
|
|
31286
|
+
let delivered = false;
|
|
31287
|
+
let threw = false;
|
|
31288
|
+
const pending = [];
|
|
31289
|
+
for (const listener of this.rawListeners(event)) {
|
|
31290
|
+
try {
|
|
31291
|
+
const out = listener.call(this, payload);
|
|
31292
|
+
if (out && typeof out.then === "function") {
|
|
31293
|
+
pending.push(Promise.resolve(out).then(() => true, () => false));
|
|
31294
|
+
} else {
|
|
31295
|
+
delivered = true;
|
|
31296
|
+
}
|
|
31297
|
+
} catch {
|
|
31298
|
+
threw = true;
|
|
31299
|
+
}
|
|
31300
|
+
}
|
|
31301
|
+
if (delivered) return;
|
|
31302
|
+
if (pending.length === 0) {
|
|
31303
|
+
if (threw) onFailed();
|
|
31304
|
+
return;
|
|
31305
|
+
}
|
|
31306
|
+
void Promise.all(pending).then((results) => {
|
|
31307
|
+
if (!results.some(Boolean)) onFailed();
|
|
31308
|
+
});
|
|
31309
|
+
}
|
|
31310
|
+
/**
|
|
31311
|
+
* Tell listeners something that is over, and let none of them make it worse.
|
|
31312
|
+
*
|
|
31313
|
+
* The closing half of the gate family — `clarification:closed`,
|
|
31314
|
+
* `clarification:timeout`, `escalation:closed`, `escalation:timeout`. Each
|
|
31315
|
+
* was already wrapped in a `try` for the synchronous case, and each had the
|
|
31316
|
+
* same hole `deliverGate` had before last round: `emit` discards what a
|
|
31317
|
+
* listener returns, so an `async` host fails by returning a rejected promise
|
|
31318
|
+
* nobody is holding and Node raises an unhandled rejection.
|
|
31319
|
+
*
|
|
31320
|
+
* There is nothing to settle here — the gate is already closed, which is the
|
|
31321
|
+
* whole message — so unlike `deliverGate` this reports to no one. It exists
|
|
31322
|
+
* so that the four informational emits cannot take the process down, and so
|
|
31323
|
+
* the rule is written once rather than four times.
|
|
31324
|
+
*/
|
|
31325
|
+
announceGateClosed(event, payload) {
|
|
31326
|
+
for (const listener of this.rawListeners(event)) {
|
|
31327
|
+
try {
|
|
31328
|
+
const out = listener.call(this, payload);
|
|
31329
|
+
if (out && typeof out.then === "function") {
|
|
31330
|
+
void Promise.resolve(out).catch(() => {
|
|
31331
|
+
});
|
|
31332
|
+
}
|
|
31333
|
+
} catch {
|
|
31334
|
+
}
|
|
31335
|
+
}
|
|
31336
|
+
}
|
|
31144
31337
|
async requestEscalationDecision(ctx, taskId, signal) {
|
|
31145
31338
|
if (this.config.autonomy === "auto") return { action: "skip", automatic: true };
|
|
31146
31339
|
if (this.listenerCount("escalation:decision-required") === 0) return { action: "skip", automatic: true };
|
|
@@ -31153,23 +31346,28 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
31153
31346
|
if (timeout) clearTimeout(timeout);
|
|
31154
31347
|
signal?.removeEventListener("abort", onAbort);
|
|
31155
31348
|
resolve2(decision);
|
|
31349
|
+
this.announceGateClosed("escalation:closed", { taskId, requestId, sectionId: ctx.sectionId });
|
|
31156
31350
|
};
|
|
31157
31351
|
const onAbort = () => settle({ action: "skip", automatic: true });
|
|
31158
31352
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
31159
31353
|
timeout = setTimeout(() => {
|
|
31160
|
-
this.emit("escalation:timeout", { taskId, requestId, sectionId: ctx.sectionId });
|
|
31161
31354
|
settle({ action: "timeout" });
|
|
31355
|
+
this.announceGateClosed("escalation:timeout", { taskId, requestId, sectionId: ctx.sectionId });
|
|
31162
31356
|
}, ESCALATION_DECISION_TIMEOUT_MS);
|
|
31163
31357
|
this.pendingEscalations.set(requestId, settle);
|
|
31164
|
-
this.
|
|
31165
|
-
|
|
31166
|
-
|
|
31167
|
-
|
|
31168
|
-
|
|
31169
|
-
|
|
31170
|
-
|
|
31171
|
-
|
|
31172
|
-
|
|
31358
|
+
this.deliverGate(
|
|
31359
|
+
"escalation:decision-required",
|
|
31360
|
+
{
|
|
31361
|
+
taskId,
|
|
31362
|
+
requestId,
|
|
31363
|
+
sectionId: ctx.sectionId,
|
|
31364
|
+
sectionTitle: ctx.sectionTitle,
|
|
31365
|
+
issues: ctx.issues,
|
|
31366
|
+
summary: ctx.summary,
|
|
31367
|
+
timeoutMs: ESCALATION_DECISION_TIMEOUT_MS
|
|
31368
|
+
},
|
|
31369
|
+
() => settle({ action: "skip", automatic: true })
|
|
31370
|
+
);
|
|
31173
31371
|
});
|
|
31174
31372
|
}
|
|
31175
31373
|
/**
|
|
@@ -31206,6 +31404,73 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
31206
31404
|
releasePendingEscalations(action = "skip") {
|
|
31207
31405
|
for (const settle of Array.from(this.pendingEscalations.values())) settle({ action, automatic: true });
|
|
31208
31406
|
}
|
|
31407
|
+
// ── Clarification: asking instead of assuming ───────────────────────
|
|
31408
|
+
// The same gate shape as the escalation above, and for the same reasons. The
|
|
31409
|
+
// difference that matters: an unanswered escalation SKIPS a section, while an
|
|
31410
|
+
// unanswered question just means the model proceeds on its own reading — so
|
|
31411
|
+
// every non-answer here is benign, and none of them may park the run.
|
|
31412
|
+
/**
|
|
31413
|
+
* Put a questionnaire to whoever is watching, if anybody is.
|
|
31414
|
+
*
|
|
31415
|
+
* Returns `no-listener` rather than waiting when there is nothing attached to
|
|
31416
|
+
* answer — a scheduled run, an API caller with no socket, an autonomous run
|
|
31417
|
+
* that has already said it wants no prompts. That check is the whole reason
|
|
31418
|
+
* this can be offered to the model at all: a tool that might hang a headless
|
|
31419
|
+
* run forever is a tool that cannot be registered.
|
|
31420
|
+
*/
|
|
31421
|
+
async askUser(questions, signal) {
|
|
31422
|
+
const none = (outcome) => ({ outcome, answers: [] });
|
|
31423
|
+
if (this.unattended) return none("no-listener");
|
|
31424
|
+
if (this.config.autonomy === "auto") return none("no-listener");
|
|
31425
|
+
if (this.listenerCount("clarification:required") === 0) return none("no-listener");
|
|
31426
|
+
if (signal?.aborted) return none("aborted");
|
|
31427
|
+
const requestId = randomUUID();
|
|
31428
|
+
return await new Promise((resolve2) => {
|
|
31429
|
+
let timeout;
|
|
31430
|
+
const settle = (result) => {
|
|
31431
|
+
if (!this.pendingClarifications.delete(requestId)) return;
|
|
31432
|
+
if (timeout) clearTimeout(timeout);
|
|
31433
|
+
signal?.removeEventListener("abort", onAbort);
|
|
31434
|
+
resolve2(result);
|
|
31435
|
+
this.announceGateClosed("clarification:closed", { requestId });
|
|
31436
|
+
};
|
|
31437
|
+
const onAbort = () => settle(none("aborted"));
|
|
31438
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
31439
|
+
timeout = setTimeout(() => {
|
|
31440
|
+
settle(none("timeout"));
|
|
31441
|
+
this.announceGateClosed("clarification:timeout", { requestId });
|
|
31442
|
+
}, CLARIFICATION_TIMEOUT_MS);
|
|
31443
|
+
this.pendingClarifications.set(requestId, settle);
|
|
31444
|
+
this.deliverGate(
|
|
31445
|
+
"clarification:required",
|
|
31446
|
+
{ requestId, questions, timeoutMs: CLARIFICATION_TIMEOUT_MS },
|
|
31447
|
+
() => settle(none("no-listener"))
|
|
31448
|
+
);
|
|
31449
|
+
});
|
|
31450
|
+
}
|
|
31451
|
+
/**
|
|
31452
|
+
* Answer a questionnaire from a REPL / dashboard / cloud listener.
|
|
31453
|
+
*
|
|
31454
|
+
* `requestId` comes back on the `clarification:required` event and is what
|
|
31455
|
+
* makes an answer land on the question that asked. Optional for a host with
|
|
31456
|
+
* only one in flight, matching `resolveEscalation`: without it the oldest
|
|
31457
|
+
* outstanding request is answered, which is correct whenever there is one.
|
|
31458
|
+
*/
|
|
31459
|
+
resolveClarification(answers, requestId) {
|
|
31460
|
+
const result = { outcome: "answered", answers };
|
|
31461
|
+
if (requestId) {
|
|
31462
|
+
this.pendingClarifications.get(requestId)?.(result);
|
|
31463
|
+
return;
|
|
31464
|
+
}
|
|
31465
|
+
const oldest = this.pendingClarifications.keys().next();
|
|
31466
|
+
if (!oldest.done) this.pendingClarifications.get(oldest.value)?.(result);
|
|
31467
|
+
}
|
|
31468
|
+
/** Release every parked questionnaire — run teardown, so none outlive the run. */
|
|
31469
|
+
releasePendingClarifications() {
|
|
31470
|
+
for (const settle of Array.from(this.pendingClarifications.values())) {
|
|
31471
|
+
settle({ outcome: "aborted", answers: [] });
|
|
31472
|
+
}
|
|
31473
|
+
}
|
|
31209
31474
|
/**
|
|
31210
31475
|
* Resolve a pending boardroom plan approval from a REPL / dashboard listener.
|
|
31211
31476
|
* An optional `note` re-plans and re-asks; an optional `editedPlan` is applied
|
|
@@ -31230,12 +31495,14 @@ var Cascade = class _Cascade extends EventEmitter {
|
|
|
31230
31495
|
const timeout = setTimeout(() => {
|
|
31231
31496
|
if (this.pendingContextApproval) {
|
|
31232
31497
|
this.pendingContextApproval = void 0;
|
|
31498
|
+
this.announceGateClosed("context:approval-closed", {});
|
|
31233
31499
|
resolve2(true);
|
|
31234
31500
|
}
|
|
31235
31501
|
}, 12e4);
|
|
31236
31502
|
this.pendingContextApproval = (approved) => {
|
|
31237
31503
|
clearTimeout(timeout);
|
|
31238
31504
|
this.pendingContextApproval = void 0;
|
|
31505
|
+
this.announceGateClosed("context:approval-closed", {});
|
|
31239
31506
|
resolve2(approved);
|
|
31240
31507
|
};
|
|
31241
31508
|
this.emit("context:approval-required", info);
|
|
@@ -31426,6 +31693,34 @@ ${input}` }],
|
|
|
31426
31693
|
if ((this.config.tools?.disabledTools ?? []).includes("browser_control")) return;
|
|
31427
31694
|
this.toolRegistry.register(new BrowserControlTool(controller, release));
|
|
31428
31695
|
}
|
|
31696
|
+
/**
|
|
31697
|
+
* Declare that this host can put a questionnaire to a person and answer it.
|
|
31698
|
+
*
|
|
31699
|
+
* Explicit, and NOT done at construction, because registering a tool is a
|
|
31700
|
+
* promise the host has to keep. A host that registers `ask_user` without
|
|
31701
|
+
* listening for `clarification:required` gives the model a tool that always
|
|
31702
|
+
* answers "there is nobody watching this run" — while a person sits at the
|
|
31703
|
+
* terminal looking at it. That is worse than not offering the tool at all:
|
|
31704
|
+
* it costs a round trip and then tells the model something false.
|
|
31705
|
+
*
|
|
31706
|
+
* Only `cloud/server` bridges the protocol today. The CLI REPL and the
|
|
31707
|
+
* dashboard do not, so they do not call this, and their models are not shown
|
|
31708
|
+
* a capability nobody can serve. Wiring either of them is a matter of
|
|
31709
|
+
* listening for the event and calling `resolveClarification`, then calling
|
|
31710
|
+
* this.
|
|
31711
|
+
*
|
|
31712
|
+
* Still gated on the same conditions as the call itself, and `askUser`
|
|
31713
|
+
* re-checks them: `setUnattended` can land after this, so the tool can be
|
|
31714
|
+
* registered for a run that later turns out to have nobody on it. Then it
|
|
31715
|
+
* answers `no-listener` and the model proceeds on its own reading, which is
|
|
31716
|
+
* the same defence-in-depth `BrowserControlTool.revoke` provides.
|
|
31717
|
+
*/
|
|
31718
|
+
enableClarification() {
|
|
31719
|
+
if (this.unattended) return;
|
|
31720
|
+
if (this.config.autonomy === "auto") return;
|
|
31721
|
+
if ((this.config.tools?.disabledTools ?? []).includes("ask_user")) return;
|
|
31722
|
+
this.toolRegistry.register(new AskUserTool((questions, signal) => this.askUser(questions, signal)));
|
|
31723
|
+
}
|
|
31429
31724
|
registerMediaTools(workspacePath) {
|
|
31430
31725
|
const denied = new Set(this.config.tools?.disabledTools ?? []);
|
|
31431
31726
|
const permitted = (name) => !denied.has(name);
|
|
@@ -32371,6 +32666,10 @@ ${finalOutput}` : ""
|
|
|
32371
32666
|
this.releasePendingEscalations();
|
|
32372
32667
|
} catch {
|
|
32373
32668
|
}
|
|
32669
|
+
try {
|
|
32670
|
+
this.releasePendingClarifications();
|
|
32671
|
+
} catch {
|
|
32672
|
+
}
|
|
32374
32673
|
this.router.restoreTierModels();
|
|
32375
32674
|
this.router.setRunSignal(void 0);
|
|
32376
32675
|
if (this.taskAnalyzer) {
|
|
@@ -35445,6 +35744,13 @@ var RESTORE_FRAME_MS = 2e3;
|
|
|
35445
35744
|
var MAX_HUMAN_INPUT_QUEUE = 64;
|
|
35446
35745
|
var MAX_CAPTURE_TRANSITION_QUEUE = 16;
|
|
35447
35746
|
var MAX_WATCH_LIFECYCLE_QUEUE = 16;
|
|
35747
|
+
function notify(deliver) {
|
|
35748
|
+
try {
|
|
35749
|
+
void Promise.resolve(deliver()).catch(() => {
|
|
35750
|
+
});
|
|
35751
|
+
} catch {
|
|
35752
|
+
}
|
|
35753
|
+
}
|
|
35448
35754
|
var RemoteBrowserController = class {
|
|
35449
35755
|
provider;
|
|
35450
35756
|
maxSessions;
|
|
@@ -35470,6 +35776,36 @@ var RemoteBrowserController = class {
|
|
|
35470
35776
|
controlAnnounced = /* @__PURE__ */ new Map();
|
|
35471
35777
|
/** An embedder that wants every run's live view, told which run each is. */
|
|
35472
35778
|
onLiveViewAll;
|
|
35779
|
+
/** Told when a provider session could not be handed back. See `disposeRun`. */
|
|
35780
|
+
onReleaseFailed;
|
|
35781
|
+
/**
|
|
35782
|
+
* Tell the observer a session leaked, without letting it become the leak.
|
|
35783
|
+
*
|
|
35784
|
+
* Guarded, because this runs inside a `.catch` on the release: an observer
|
|
35785
|
+
* that throws — a logging or telemetry sink that is momentarily unavailable
|
|
35786
|
+
* is the ordinary case — would turn its own failure into a fresh rejection
|
|
35787
|
+
* from `disposeRun`, so `endRun` would reject before `forgetRun` and the
|
|
35788
|
+
* fire-and-forget `stopRun` path would raise an unhandled rejection.
|
|
35789
|
+
*
|
|
35790
|
+
* That is precisely the guarantee this whole change claims to preserve: a
|
|
35791
|
+
* release that fails must never fail the run. Reporting it cannot be the
|
|
35792
|
+
* thing that breaks it.
|
|
35793
|
+
*
|
|
35794
|
+
* TWO WAYS TO FAIL, not one. The `try` catches a synchronous throw; an
|
|
35795
|
+
* `async` sink — which is what a telemetry or logging callback usually is —
|
|
35796
|
+
* fails by returning a REJECTED PROMISE, which no `try` around a call that is
|
|
35797
|
+
* never awaited can see. Node then raises an unhandled rejection and can take
|
|
35798
|
+
* the process down: the observer would not merely have failed to report the
|
|
35799
|
+
* leak, it would have killed the run, which is the one outcome this function
|
|
35800
|
+
* exists to prevent, reached through the door the guard did not cover.
|
|
35801
|
+
*
|
|
35802
|
+
* Not awaited, though. The caller is a `.catch` on the release and is not
|
|
35803
|
+
* going to wait for a telemetry round trip; attaching a handler is what makes
|
|
35804
|
+
* the rejection observed, which is the whole requirement.
|
|
35805
|
+
*/
|
|
35806
|
+
reportReleaseFailure(runId, sessionId, err, expiresInMs) {
|
|
35807
|
+
notify(() => this.onReleaseFailed?.(runId, sessionId, err, expiresInMs));
|
|
35808
|
+
}
|
|
35473
35809
|
runs = /* @__PURE__ */ new Map();
|
|
35474
35810
|
/**
|
|
35475
35811
|
* Runs that have a pool slot but no browser yet.
|
|
@@ -35528,6 +35864,7 @@ var RemoteBrowserController = class {
|
|
|
35528
35864
|
const asked = Math.max(1, options.maxSessions ?? 1);
|
|
35529
35865
|
this.maxSessions = options.provider.isolatesSessions ? asked : 1;
|
|
35530
35866
|
this.onLiveViewAll = options.onLiveView;
|
|
35867
|
+
this.onReleaseFailed = options.onReleaseFailed;
|
|
35531
35868
|
this.ready = options.ready;
|
|
35532
35869
|
}
|
|
35533
35870
|
/**
|
|
@@ -35612,7 +35949,7 @@ var RemoteBrowserController = class {
|
|
|
35612
35949
|
const key = `${state.human}:${state.capturing}:${state.confirmed}`;
|
|
35613
35950
|
if (!force && this.controlAnnounced.get(runId) === key) return;
|
|
35614
35951
|
this.controlAnnounced.set(runId, key);
|
|
35615
|
-
listener(state);
|
|
35952
|
+
notify(() => listener(state));
|
|
35616
35953
|
}
|
|
35617
35954
|
/**
|
|
35618
35955
|
* Tell a run's listener what its browser situation is.
|
|
@@ -35623,9 +35960,32 @@ var RemoteBrowserController = class {
|
|
|
35623
35960
|
* apart — and would drop the Stop control for the first as if it were the
|
|
35624
35961
|
* second.
|
|
35625
35962
|
*/
|
|
35963
|
+
/*
|
|
35964
|
+
* Guarded HERE rather than at the call sites, which is the point.
|
|
35965
|
+
*
|
|
35966
|
+
* This is the fifth place in this changeset where a notification could take
|
|
35967
|
+
* down the thing it was notifying about — after the release observer,
|
|
35968
|
+
* `clarification:closed`, `clarification:timeout` and `escalation:timeout`.
|
|
35969
|
+
* The first four were fixed one door at a time, which is how a fifth door
|
|
35970
|
+
* came to exist: the announcement added on the reuse path propagated out of
|
|
35971
|
+
* `open()`, `act()` caught it as an action failure, and every later action
|
|
35972
|
+
* against a perfectly healthy browser was skipped.
|
|
35973
|
+
*
|
|
35974
|
+
* Putting the guard at the source closes all four call sites at once and
|
|
35975
|
+
* leaves no door for a sixth. The worst of them is not the reported one:
|
|
35976
|
+
* `disposeRun` announces `active: false` as its FIRST statement, so a
|
|
35977
|
+
* throwing listener aborted teardown before the screencast was stopped, the
|
|
35978
|
+
* context closed, or the session handed back — leaking the provider session
|
|
35979
|
+
* and never reaching `reportReleaseFailure`. The leak report would have been
|
|
35980
|
+
* skipped by exactly the failure it exists to report.
|
|
35981
|
+
*
|
|
35982
|
+
* Two separate guards, not one around both: these are different listeners —
|
|
35983
|
+
* the per-run panel and the global observer — and one failing must not cost
|
|
35984
|
+
* the other its notification.
|
|
35985
|
+
*/
|
|
35626
35986
|
announceLiveView(runId, liveViewUrl, active) {
|
|
35627
|
-
this.liveViewListeners.get(runId)?.({ active, ...liveViewUrl ? { liveViewUrl } : {} });
|
|
35628
|
-
this.onLiveViewAll?.(runId, liveViewUrl);
|
|
35987
|
+
notify(() => this.liveViewListeners.get(runId)?.({ active, ...liveViewUrl ? { liveViewUrl } : {} }));
|
|
35988
|
+
notify(() => this.onLiveViewAll?.(runId, liveViewUrl));
|
|
35629
35989
|
}
|
|
35630
35990
|
/**
|
|
35631
35991
|
* Hand back a session the run turned out not to want.
|
|
@@ -35836,7 +36196,8 @@ var RemoteBrowserController = class {
|
|
|
35836
36196
|
ping?.();
|
|
35837
36197
|
const deliver = held.onFrame;
|
|
35838
36198
|
if (deliver) {
|
|
35839
|
-
|
|
36199
|
+
const frame = { data: e.data, width, height, generation: held.watchGen ?? 0 };
|
|
36200
|
+
notify(() => deliver(frame));
|
|
35840
36201
|
}
|
|
35841
36202
|
}
|
|
35842
36203
|
void cdp.send("Page.screencastFrameAck", { sessionId: e?.sessionId }).catch(() => {
|
|
@@ -36365,8 +36726,7 @@ var RemoteBrowserController = class {
|
|
|
36365
36726
|
});
|
|
36366
36727
|
await held.browser.close().catch(() => {
|
|
36367
36728
|
});
|
|
36368
|
-
await this.provider.endSession(held.session.id).catch(() =>
|
|
36369
|
-
});
|
|
36729
|
+
await this.provider.endSession(held.session.id).catch((err) => this.reportReleaseFailure(runId, held.session.id, err, held.session.expiresInMs));
|
|
36370
36730
|
}
|
|
36371
36731
|
/**
|
|
36372
36732
|
* Run `disposeRun`, with the run id counted in `closing` until it settles.
|
|
@@ -36525,11 +36885,17 @@ var RemoteBrowserController = class {
|
|
|
36525
36885
|
if (this.ready === settling) this.ready = void 0;
|
|
36526
36886
|
}
|
|
36527
36887
|
const existing = this.runs.get(runId);
|
|
36528
|
-
if (existing && !existing.page.isClosed())
|
|
36888
|
+
if (existing && !existing.page.isClosed()) {
|
|
36889
|
+
this.announceLiveView(runId, existing.session.liveViewUrl, true);
|
|
36890
|
+
return existing;
|
|
36891
|
+
}
|
|
36529
36892
|
if (existing && existing.page.isClosed()) {
|
|
36530
36893
|
const fallback = existing.page.context().pages().filter((p) => !p.isClosed()).at(-1);
|
|
36531
36894
|
if (fallback) {
|
|
36532
36895
|
await this.adoptPage(runId, existing, fallback);
|
|
36896
|
+
if (this.runs.get(runId) === existing && !existing.abort.signal.aborted) {
|
|
36897
|
+
this.announceLiveView(runId, existing.session.liveViewUrl, true);
|
|
36898
|
+
}
|
|
36533
36899
|
return existing;
|
|
36534
36900
|
}
|
|
36535
36901
|
}
|
|
@@ -36578,8 +36944,7 @@ var RemoteBrowserController = class {
|
|
|
36578
36944
|
});
|
|
36579
36945
|
await browser?.close().catch(() => {
|
|
36580
36946
|
});
|
|
36581
|
-
await this.provider.endSession(session.id).catch(() =>
|
|
36582
|
-
});
|
|
36947
|
+
await this.provider.endSession(session.id).catch((releaseErr) => this.reportReleaseFailure(runId, session.id, releaseErr, session.expiresInMs));
|
|
36583
36948
|
throw err;
|
|
36584
36949
|
}
|
|
36585
36950
|
this.announceLiveView(runId, session.liveViewUrl, true);
|
|
@@ -36789,6 +37154,139 @@ function isCdpEndpoint(url) {
|
|
|
36789
37154
|
|
|
36790
37155
|
// src/browser/remote/steel.ts
|
|
36791
37156
|
var DEFAULT_BASE = "https://api.steel.dev";
|
|
37157
|
+
function isHostedSteel(url) {
|
|
37158
|
+
if (!url) return true;
|
|
37159
|
+
try {
|
|
37160
|
+
return hostKey(new URL(url).hostname) === hostKey(new URL(DEFAULT_BASE).hostname);
|
|
37161
|
+
} catch {
|
|
37162
|
+
return false;
|
|
37163
|
+
}
|
|
37164
|
+
}
|
|
37165
|
+
function isUsableSteelBase(url) {
|
|
37166
|
+
try {
|
|
37167
|
+
const u = new URL(url);
|
|
37168
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") return false;
|
|
37169
|
+
if (u.username !== "" || u.password !== "") return false;
|
|
37170
|
+
const built = new URL(withoutTrailingSlashes(url) + PROBE_PATH);
|
|
37171
|
+
if (FETCH_BLOCKED_PORTS.has(built.port)) return false;
|
|
37172
|
+
if (built.search !== "" || built.hash !== "") return false;
|
|
37173
|
+
if (!built.pathname.endsWith(PROBE_PATH)) return false;
|
|
37174
|
+
if (isHostedSteel(url)) {
|
|
37175
|
+
if (built.pathname !== PROBE_PATH) return false;
|
|
37176
|
+
if (u.protocol !== "https:") return false;
|
|
37177
|
+
if (built.port !== "") return false;
|
|
37178
|
+
}
|
|
37179
|
+
return true;
|
|
37180
|
+
} catch {
|
|
37181
|
+
return false;
|
|
37182
|
+
}
|
|
37183
|
+
}
|
|
37184
|
+
function isUsableSteelKey(apiKey) {
|
|
37185
|
+
for (const ch of apiKey) {
|
|
37186
|
+
const c = ch.codePointAt(0) ?? 0;
|
|
37187
|
+
if (c === 9) continue;
|
|
37188
|
+
if (c >= 32 && c <= 126) continue;
|
|
37189
|
+
if (c >= 128 && c <= 255) continue;
|
|
37190
|
+
return false;
|
|
37191
|
+
}
|
|
37192
|
+
return true;
|
|
37193
|
+
}
|
|
37194
|
+
var API_KEY_HEADER = "steel-api-key";
|
|
37195
|
+
var FETCH_BLOCKED_PORTS = /* @__PURE__ */ new Set([
|
|
37196
|
+
"1",
|
|
37197
|
+
"7",
|
|
37198
|
+
"9",
|
|
37199
|
+
"11",
|
|
37200
|
+
"13",
|
|
37201
|
+
"15",
|
|
37202
|
+
"17",
|
|
37203
|
+
"19",
|
|
37204
|
+
"20",
|
|
37205
|
+
"21",
|
|
37206
|
+
"22",
|
|
37207
|
+
"23",
|
|
37208
|
+
"25",
|
|
37209
|
+
"37",
|
|
37210
|
+
"42",
|
|
37211
|
+
"43",
|
|
37212
|
+
"53",
|
|
37213
|
+
"69",
|
|
37214
|
+
"77",
|
|
37215
|
+
"79",
|
|
37216
|
+
"87",
|
|
37217
|
+
"95",
|
|
37218
|
+
"101",
|
|
37219
|
+
"102",
|
|
37220
|
+
"103",
|
|
37221
|
+
"104",
|
|
37222
|
+
"109",
|
|
37223
|
+
"110",
|
|
37224
|
+
"111",
|
|
37225
|
+
"113",
|
|
37226
|
+
"115",
|
|
37227
|
+
"117",
|
|
37228
|
+
"119",
|
|
37229
|
+
"123",
|
|
37230
|
+
"135",
|
|
37231
|
+
"137",
|
|
37232
|
+
"139",
|
|
37233
|
+
"143",
|
|
37234
|
+
"161",
|
|
37235
|
+
"179",
|
|
37236
|
+
"389",
|
|
37237
|
+
"427",
|
|
37238
|
+
"465",
|
|
37239
|
+
"512",
|
|
37240
|
+
"513",
|
|
37241
|
+
"514",
|
|
37242
|
+
"515",
|
|
37243
|
+
"526",
|
|
37244
|
+
"530",
|
|
37245
|
+
"531",
|
|
37246
|
+
"532",
|
|
37247
|
+
"540",
|
|
37248
|
+
"548",
|
|
37249
|
+
"554",
|
|
37250
|
+
"556",
|
|
37251
|
+
"563",
|
|
37252
|
+
"587",
|
|
37253
|
+
"601",
|
|
37254
|
+
"636",
|
|
37255
|
+
"989",
|
|
37256
|
+
"990",
|
|
37257
|
+
"993",
|
|
37258
|
+
"995",
|
|
37259
|
+
"1719",
|
|
37260
|
+
"1720",
|
|
37261
|
+
"1723",
|
|
37262
|
+
"2049",
|
|
37263
|
+
"3659",
|
|
37264
|
+
"4045",
|
|
37265
|
+
"4190",
|
|
37266
|
+
"5060",
|
|
37267
|
+
"5061",
|
|
37268
|
+
"6000",
|
|
37269
|
+
"6566",
|
|
37270
|
+
"6665",
|
|
37271
|
+
"6666",
|
|
37272
|
+
"6667",
|
|
37273
|
+
"6668",
|
|
37274
|
+
"6669",
|
|
37275
|
+
"6679",
|
|
37276
|
+
"6697",
|
|
37277
|
+
"10080"
|
|
37278
|
+
]);
|
|
37279
|
+
var PROBE_PATH = "/v1/sessions";
|
|
37280
|
+
function withoutTrailingSlashes(value) {
|
|
37281
|
+
let out = value;
|
|
37282
|
+
while (out.endsWith("/")) out = out.slice(0, -1);
|
|
37283
|
+
return out;
|
|
37284
|
+
}
|
|
37285
|
+
function hostKey(hostname) {
|
|
37286
|
+
let host = hostname.toLowerCase();
|
|
37287
|
+
while (host.endsWith(".")) host = host.slice(0, -1);
|
|
37288
|
+
return host;
|
|
37289
|
+
}
|
|
36792
37290
|
var CREATE_TIMEOUT_MS = 6e4;
|
|
36793
37291
|
var SteelProvider = class {
|
|
36794
37292
|
name = "Steel";
|
|
@@ -36798,9 +37296,7 @@ var SteelProvider = class {
|
|
|
36798
37296
|
base;
|
|
36799
37297
|
apiKey;
|
|
36800
37298
|
constructor(opts = {}) {
|
|
36801
|
-
|
|
36802
|
-
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
36803
|
-
this.base = base;
|
|
37299
|
+
this.base = withoutTrailingSlashes(opts.url || DEFAULT_BASE);
|
|
36804
37300
|
this.apiKey = opts.apiKey;
|
|
36805
37301
|
}
|
|
36806
37302
|
async createSession(signal) {
|
|
@@ -36811,14 +37307,15 @@ var SteelProvider = class {
|
|
|
36811
37307
|
return {
|
|
36812
37308
|
id: details.id,
|
|
36813
37309
|
cdpUrl: details.websocketUrl,
|
|
36814
|
-
...details.debugUrl ? { liveViewUrl: details.debugUrl } : {}
|
|
37310
|
+
...details.debugUrl ? { liveViewUrl: details.debugUrl } : {},
|
|
37311
|
+
// Carried through because it explains an otherwise mysterious death. A
|
|
37312
|
+
// session nobody released dies at exactly this number, and without it a
|
|
37313
|
+
// leak looks identical to an orderly shutdown.
|
|
37314
|
+
...typeof details.timeout === "number" ? { expiresInMs: details.timeout } : {}
|
|
36815
37315
|
};
|
|
36816
37316
|
}
|
|
36817
37317
|
async endSession(id) {
|
|
36818
|
-
|
|
36819
|
-
await this.call("POST", `/v1/sessions/${encodeURIComponent(id)}/release`, void 0, {});
|
|
36820
|
-
} catch {
|
|
36821
|
-
}
|
|
37318
|
+
await this.call("POST", `/v1/sessions/${encodeURIComponent(id)}/release`, void 0, {});
|
|
36822
37319
|
}
|
|
36823
37320
|
async call(method, path30, signal, body) {
|
|
36824
37321
|
const timeout = AbortSignal.timeout(CREATE_TIMEOUT_MS);
|
|
@@ -36829,7 +37326,7 @@ var SteelProvider = class {
|
|
|
36829
37326
|
"content-type": "application/json",
|
|
36830
37327
|
// Sent only when configured — the self-hosted API takes no key, and an
|
|
36831
37328
|
// empty header is worse than none.
|
|
36832
|
-
...this.apiKey ? {
|
|
37329
|
+
...this.apiKey ? { [API_KEY_HEADER]: this.apiKey } : {}
|
|
36833
37330
|
},
|
|
36834
37331
|
body: JSON.stringify(body),
|
|
36835
37332
|
signal: composed
|
|
@@ -37493,6 +37990,6 @@ function applySyncBundle(bundle, config, cleanup) {
|
|
|
37493
37990
|
return next;
|
|
37494
37991
|
}
|
|
37495
37992
|
|
|
37496
|
-
export { AZURE_BASE_MODELS, AZURE_BASE_URL_TEMPLATE, AuditLogger, BrowserControlTool, BrowserLease, CASCADE_AUDIT_FILE, CASCADE_CONFIG_DIR, CASCADE_CONFIG_FILE, CASCADE_DASHBOARD_SECRET_FILE, CASCADE_DB_FILE, CASCADE_IGNORE_FILE, CASCADE_KEYSTORE_FILE, CASCADE_MD_FILE, CASCADE_VERSION, CHARS_PER_TOKEN2 as CHARS_PER_TOKEN, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, CascadeConfigSchema, CascadeIgnore, CascadeRouter, CascadeToolError, CloudClient, CodeSearchTool, ConfigManager, CurrentPageTool, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CLOUD_URL, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, DOCUMENT_MIME, DashboardServer, DependencyScheduler, FileMcpOAuthStore, GLOBAL_CONFIG_DIR, GLOBAL_CREDENTIALS_FILE, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, GenerateDocumentTool, GenericCdpProvider, GraphRetriever, GraphSearchTool, HooksRunner, Keystore, LLMReranker, LM_STUDIO_BASE_URL, MAX_PAGE_TEXT_CHARS, MCP_TOOL_PREFIX, MODELS, McpClient, McpOAuthProvider, MemoryStore, OLLAMA_BASE_URL, OpenAICompatibleEmbedder, PROVIDER_DISPLAY_NAMES, RESUME_SCHEMA_VERSION, RemoteBrowserController, ResumeStore, Retriever, SqliteVectorStore, SteelProvider, T1Administrator, T1_MODEL_PRIORITY, T2Manager, T2_MODEL_PRIORITY, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, TaskGraphValidationError, TaskScheduler, Telemetry, ToolRegistry, VISION_MODEL_PRIORITY, WorkspaceIndex, applyEndpointEdit, applyProviderApiKey, applyProviderCredential, applySettingsCredentials, applySettingsPayload, applySyncBundle, azureModelForDeployment, beginMcpOAuth, buildDocumentTools, buildManifest, buildSessionTranscript, bytesToBase64, cagCharBudget, chartKind, chartToTableRows, chatCompleterFromProviders, chunkCode, chunkText2 as chunkText, commitSettings, compileSectionGraph, compileSubtaskGraph, compileTaskGraph, completeMcpOAuth, connectMcpWithLoopbackOAuth, createCascade, credentialDispositionForEdit, credentialEndpointIdentity, decryptJSON as decryptSyncBlob, diffManifest, disambiguateMcpServerNames, discoverMcpAuthServer, discoverMcpTools, distillSessionFacts, embedderFromProviders, encryptJSON as encryptSyncBlob, endpointFromSettingsPayload, evaluateAcceptance, explainRefusal, extractCharts, failures, fileExt, fileOAuthProvider, gatherSyncBundle, hasDefaultEndpoint, hasProviderCredential, hasUsableProvider, hashContent, heuristicCodeChunker, inferAzureBaseModel, inlineRuns, isCdpEndpoint, isDocumentFormat, isMcpToolName, matchImageLine, mcpServerPrefix, mcpToolName, nodeHttpFetch, normalizeEndpoint, parseBlocks, parseChartSpec, parseDelimited, parseRankOrder, parseSlide, planRetrieval, preferIpv4Host, priorAzureRow, reciprocalRankFusion, refreshMcpToken, removeMcpServerDenials, renderDocument, renderDocx, renderPptx, renderXlsx, runCascade, sameAzureEndpoint, sameCredentialEndpoint, sameEndpoint, sessionWorthRemembering, settingsSnapshot, sniffImage, splitSlides, streamCascade, stripInline, summarizeCompleted, undecided, uniqueMcpServerName };
|
|
37993
|
+
export { AZURE_BASE_MODELS, AZURE_BASE_URL_TEMPLATE, AskUserTool, AuditLogger, BrowserControlTool, BrowserLease, CASCADE_AUDIT_FILE, CASCADE_CONFIG_DIR, CASCADE_CONFIG_FILE, CASCADE_DASHBOARD_SECRET_FILE, CASCADE_DB_FILE, CASCADE_IGNORE_FILE, CASCADE_KEYSTORE_FILE, CASCADE_MD_FILE, CASCADE_VERSION, CHARS_PER_TOKEN2 as CHARS_PER_TOKEN, COMPLEXITY_T2_COUNT, Cascade, CascadeCancelledError, CascadeConfigSchema, CascadeIgnore, CascadeRouter, CascadeToolError, CloudClient, CodeSearchTool, ConfigManager, CurrentPageTool, DEFAULT_API_PORT, DEFAULT_APPROVAL_REQUIRED, DEFAULT_AUTO_SUMMARIZE_AT, DEFAULT_CLOUD_URL, DEFAULT_CONTEXT_LIMIT, DEFAULT_DASHBOARD_PORT, DEFAULT_MAX_SESSION_MESSAGES, DEFAULT_RETENTION_DAYS, DEFAULT_THEME, DOCUMENT_MIME, DashboardServer, DependencyScheduler, FileMcpOAuthStore, GLOBAL_CONFIG_DIR, GLOBAL_CREDENTIALS_FILE, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_RUNTIME_DB_FILE, GenerateDocumentTool, GenericCdpProvider, GraphRetriever, GraphSearchTool, HooksRunner, Keystore, LLMReranker, LM_STUDIO_BASE_URL, MAX_PAGE_TEXT_CHARS, MCP_TOOL_PREFIX, MODELS, McpClient, McpOAuthProvider, MemoryStore, OLLAMA_BASE_URL, OpenAICompatibleEmbedder, PROVIDER_DISPLAY_NAMES, RESUME_SCHEMA_VERSION, RemoteBrowserController, ResumeStore, Retriever, SqliteVectorStore, SteelProvider, T1Administrator, T1_MODEL_PRIORITY, T2Manager, T2_MODEL_PRIORITY, T3Worker, T3_MODEL_PRIORITY, THEME_NAMES, TOOL_NAMES, TaskGraphValidationError, TaskScheduler, Telemetry, ToolRegistry, VISION_MODEL_PRIORITY, WorkspaceIndex, applyEndpointEdit, applyProviderApiKey, applyProviderCredential, applySettingsCredentials, applySettingsPayload, applySyncBundle, azureModelForDeployment, beginMcpOAuth, buildDocumentTools, buildManifest, buildSessionTranscript, bytesToBase64, cagCharBudget, chartKind, chartToTableRows, chatCompleterFromProviders, chunkCode, chunkText2 as chunkText, commitSettings, compileSectionGraph, compileSubtaskGraph, compileTaskGraph, completeMcpOAuth, connectMcpWithLoopbackOAuth, createCascade, credentialDispositionForEdit, credentialEndpointIdentity, decryptJSON as decryptSyncBlob, diffManifest, disambiguateMcpServerNames, discoverMcpAuthServer, discoverMcpTools, distillSessionFacts, embedderFromProviders, encryptJSON as encryptSyncBlob, endpointFromSettingsPayload, evaluateAcceptance, explainRefusal, extractCharts, failures, fileExt, fileOAuthProvider, gatherSyncBundle, hasDefaultEndpoint, hasProviderCredential, hasUsableProvider, hashContent, heuristicCodeChunker, inferAzureBaseModel, inlineRuns, isCdpEndpoint, isDocumentFormat, isHostedSteel, isMcpToolName, isUsableSteelBase, isUsableSteelKey, matchImageLine, mcpServerPrefix, mcpToolName, nodeHttpFetch, normalizeEndpoint, parseBlocks, parseChartSpec, parseDelimited, parseRankOrder, parseSlide, planRetrieval, preferIpv4Host, priorAzureRow, reciprocalRankFusion, refreshMcpToken, removeMcpServerDenials, renderDocument, renderDocx, renderPptx, renderXlsx, runCascade, sameAzureEndpoint, sameCredentialEndpoint, sameEndpoint, sessionWorthRemembering, settingsSnapshot, sniffImage, splitSlides, streamCascade, stripInline, summarizeCompleted, undecided, uniqueMcpServerName };
|
|
37497
37994
|
//# sourceMappingURL=index.js.map
|
|
37498
37995
|
//# sourceMappingURL=index.js.map
|