@wrongstack/core 0.300.0 → 0.301.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/chronicle/index.d.ts +2 -0
- package/dist/chronicle/index.js +297 -10
- package/dist/chronicle/project-server.js +253 -15
- package/dist/chronicle/sqlite-compaction.d.ts +20 -0
- package/dist/chronicle/sqlite-journal.d.ts +57 -0
- package/dist/coordination/agents/capability-manifest.d.ts +7 -0
- package/dist/coordination/agents/index.d.ts +3 -2
- package/dist/coordination/agents/index.js +818 -570
- package/dist/coordination/agents/project-agent-identity.d.ts +6 -6
- package/dist/coordination/agents/role-skills.d.ts +1 -1
- package/dist/coordination/agents/types.d.ts +6 -0
- package/dist/coordination/director.d.ts +2 -2
- package/dist/coordination/index.js +6778 -6438
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-project-server.js +3 -4
- package/dist/coordination/mailbox-types.d.ts +6 -0
- package/dist/core/agent-response.d.ts +5 -1
- package/dist/core/agent-tools.d.ts +3 -0
- package/dist/core/context.d.ts +20 -0
- package/dist/core/index.d.ts +8 -7
- package/dist/core/index.js +893 -284
- package/dist/core/instruction-template.d.ts +6 -3
- package/dist/core/next-steps-slot.d.ts +88 -0
- package/dist/core/system-prompt-builder.d.ts +5 -3
- package/dist/core/system-prompt-memory-skills.d.ts +1 -0
- package/dist/core/system-prompt-skill-bodies.d.ts +3 -3
- package/dist/defaults/index.js +9796 -8897
- package/dist/design/index.js +11 -3
- package/dist/execution/auto-compaction-middleware.d.ts +17 -0
- package/dist/execution/autonomy-brain.d.ts +8 -2
- package/dist/execution/brain-runtime.d.ts +3 -1
- package/dist/execution/compaction-core.d.ts +41 -2
- package/dist/execution/council-brain.d.ts +37 -2
- package/dist/execution/council-orchestrator.d.ts +2 -2
- package/dist/execution/index.d.ts +11 -10
- package/dist/execution/index.js +5178 -4077
- package/dist/execution/tool-executor.d.ts +4 -1
- package/dist/execution/topic-shift-advisor.d.ts +53 -0
- package/dist/extension/index.js +8 -2
- package/dist/extension/registry.d.ts +8 -1
- package/dist/goal/index.js +11 -3
- package/dist/hooks/index.js +42 -9
- package/dist/hooks/runner.d.ts +12 -1
- package/dist/hq/index.js +41 -17
- package/dist/hq/publisher.d.ts +21 -3
- package/dist/index.d.ts +21 -20
- package/dist/index.js +10887 -8053
- package/dist/infrastructure/index.js +108 -21
- package/dist/kernel/events/session-events.d.ts +13 -0
- package/dist/kernel/events/tool-events.d.ts +3 -3
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +17 -0
- package/dist/models/provider-credentials.d.ts +54 -0
- package/dist/plugin/index.d.ts +1 -0
- package/dist/plugin/index.js +2024 -502
- package/dist/plugins/auto-review-plugin.d.ts +3 -0
- package/dist/plugins/cloud-config-sync-plugin.d.ts +22 -0
- package/dist/plugins/review-claim-registry.d.ts +23 -8
- package/dist/plugins/review-types.d.ts +2 -0
- package/dist/registry/index.js +109 -74
- package/dist/registry/tool-registry.d.ts +15 -0
- package/dist/security/capabilities.d.ts +2 -0
- package/dist/security/index.d.ts +1 -1
- package/dist/security/index.js +9 -2
- package/dist/security/readonly-permission-policy.d.ts +20 -0
- package/dist/session-registry-atomic-file.d.ts +32 -5
- package/dist/skills/frontmatter.d.ts +6 -0
- package/dist/skills/index.js +22 -5
- package/dist/storage/cloud-config-sync/sanitize.d.ts +54 -0
- package/dist/storage/cloud-config-sync.d.ts +87 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +854 -66
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +511 -234
- package/dist/tools/one-shot-llm-tool.d.ts +1 -0
- package/dist/tools/plugin-manager.d.ts +27 -0
- package/dist/types/config/mcp-features.d.ts +18 -11
- package/dist/types/config/root.d.ts +8 -1
- package/dist/types/config/runtime.d.ts +20 -6
- package/dist/types/config/skills-fleet-brain.d.ts +12 -4
- package/dist/types/config/tools.d.ts +16 -0
- package/dist/types/context-window.d.ts +1 -0
- package/dist/types/hooks.d.ts +14 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +1 -0
- package/dist/types/multi-agent.d.ts +2 -0
- package/dist/types/one-shot-llm.d.ts +16 -0
- package/dist/types/provider.d.ts +16 -0
- package/dist/types/runtime-capability-manifest.d.ts +168 -0
- package/dist/types/skill.d.ts +5 -0
- package/dist/types/system-prompt.d.ts +3 -1
- package/dist/types/tool-executor.d.ts +8 -1
- package/dist/utils/context-breakdown.d.ts +8 -2
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +141 -31
- package/dist/utils/regex-guard.d.ts +16 -2
- package/dist/utils/sage-output-block.d.ts +7 -10
- package/dist/utils/wstack-paths.d.ts +11 -3
- package/instructions/agents/browser.md +1 -4
- package/instructions/agents/e2e.md +17 -15
- package/instructions/agents/ios.md +3 -3
- package/instructions/agents/search.md +1 -1
- package/instructions/autonomy/goal-preamble.md +4 -4
- package/instructions/coordination/director-preamble.md +2 -3
- package/instructions/coordination/subagent-baseline.md +3 -1
- package/instructions/leader-after-task.md +12 -0
- package/instructions/llm/chimera-review.md +1 -1
- package/instructions/modes/audit-lite.md +1 -1
- package/instructions/sections/tool/common-patterns.md +18 -2
- package/instructions/sections/tool/mailbox-compact.md +1 -1
- package/instructions/sections/tool/mailbox-full.md +1 -1
- package/instructions/system-lite.md +10 -0
- package/instructions/system-pro.md +23 -14
- package/instructions/system.md +22 -13
- package/package.json +3 -3
- package/skills/api-design/SKILL.md +3 -0
- package/skills/audit-log/SKILL.md +2 -0
- package/skills/auto-review/SKILL.md +6 -1
- package/skills/bug-hunter/SKILL.md +4 -1
- package/skills/chimera/SKILL.md +3 -0
- package/skills/data-governance/SKILL.md +3 -0
- package/skills/design-system/SKILL.md +5 -2
- package/skills/docker-deploy/SKILL.md +2 -0
- package/skills/git-flow/SKILL.md +2 -0
- package/skills/mailbox-bridge/SKILL.md +3 -0
- package/skills/mnemosyne/SKILL.md +2 -0
- package/skills/multi-agent/SKILL.md +4 -1
- package/skills/node-modern/SKILL.md +4 -1
- package/skills/observability/SKILL.md +3 -0
- package/skills/output-standards/SKILL.md +2 -0
- package/skills/plugin-author/SKILL.md +4 -1
- package/skills/prompt-engineering/SKILL.md +3 -1
- package/skills/react-modern/SKILL.md +6 -3
- package/skills/refactor-planner/SKILL.md +2 -0
- package/skills/research-web/SKILL.md +3 -0
- package/skills/sdd/SKILL.md +3 -1
- package/skills/security-scanner/SKILL.md +3 -0
- package/skills/skill-creator/SKILL.md +2 -0
- package/skills/tech-stack/SKILL.md +3 -0
- package/skills/testing/SKILL.md +4 -1
- package/skills/typescript-strict/SKILL.md +4 -1
- package/skills/wrongstack-kanban/SKILL.md +6 -3
- package/skills/wrongstack-mailbox/SKILL.md +4 -1
- package/skills/wrongstack-mailbox-mcp/SKILL.md +10 -8
package/dist/core/index.js
CHANGED
|
@@ -305,9 +305,15 @@ var ExtensionRegistry = class {
|
|
|
305
305
|
* Build a composed provider runner. Extensions with `wrapProviderRunner`
|
|
306
306
|
* form a middleware-style chain: the innermost extension wraps the
|
|
307
307
|
* default runner, each subsequent wrapper wraps the previous.
|
|
308
|
+
*
|
|
309
|
+
* Utility calls may exclude agent-loop-only middleware (notably
|
|
310
|
+
* `fallback-model`) while retaining request-safety wrappers such as the
|
|
311
|
+
* prompt firewall. One-shot orchestration owns its provider and fallback
|
|
312
|
+
* route, so an agent-loop fallback wrapper cannot safely run against it.
|
|
308
313
|
*/
|
|
309
|
-
wrapProviderRunner(inner) {
|
|
310
|
-
const
|
|
314
|
+
wrapProviderRunner(inner, options) {
|
|
315
|
+
const excluded = new Set(options?.exclude);
|
|
316
|
+
const wrappers = this.extensions.filter((e) => e.wrapProviderRunner && !excluded.has(e.name)).map((e) => ({ name: e.name, wrap: expectDefined(e.wrapProviderRunner) }));
|
|
311
317
|
if (wrappers.length === 0) return inner;
|
|
312
318
|
let composed = inner;
|
|
313
319
|
for (let i = wrappers.length - 1; i >= 0; i--) {
|
|
@@ -540,6 +546,9 @@ function canonicalProjectRoot(absRoot) {
|
|
|
540
546
|
const commonDirFile = path.join(gitDir, "commondir");
|
|
541
547
|
if (!fs.statSync(commonDirFile).isFile()) return checkoutRoot;
|
|
542
548
|
const commonDir = path.resolve(gitDir, fs.readFileSync(commonDirFile, "utf8").trim());
|
|
549
|
+
const worktreesDir = path.dirname(gitDir);
|
|
550
|
+
if (path.basename(worktreesDir).toLowerCase() !== "worktrees") return checkoutRoot;
|
|
551
|
+
if (path.resolve(worktreesDir, "..") !== commonDir) return checkoutRoot;
|
|
543
552
|
if (path.basename(commonDir).toLowerCase() !== ".git") return checkoutRoot;
|
|
544
553
|
return path.dirname(commonDir);
|
|
545
554
|
} catch {
|
|
@@ -1647,6 +1656,20 @@ import * as path7 from "node:path";
|
|
|
1647
1656
|
// src/security/file-permissions.ts
|
|
1648
1657
|
var SECRET_FILE_MODE = 384;
|
|
1649
1658
|
|
|
1659
|
+
// src/utils/pid.ts
|
|
1660
|
+
function isPidAlive(pid) {
|
|
1661
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
1662
|
+
if (pid === process.pid) return true;
|
|
1663
|
+
try {
|
|
1664
|
+
process.kill(pid, 0);
|
|
1665
|
+
return true;
|
|
1666
|
+
} catch (err) {
|
|
1667
|
+
const code = err.code;
|
|
1668
|
+
if (code === "EPERM") return true;
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1650
1673
|
// src/hq/auth-store.ts
|
|
1651
1674
|
function defaultHqDataDir() {
|
|
1652
1675
|
return path7.join(wstackGlobalRoot(), "hq");
|
|
@@ -1662,22 +1685,13 @@ function hqAuthFilePath(dataDir) {
|
|
|
1662
1685
|
function hqRuntimeFilePath(dataDir) {
|
|
1663
1686
|
return path7.join(dataDir, "runtime.json");
|
|
1664
1687
|
}
|
|
1665
|
-
function isProcessAlive(pid) {
|
|
1666
|
-
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
1667
|
-
try {
|
|
1668
|
-
process.kill(pid, 0);
|
|
1669
|
-
return true;
|
|
1670
|
-
} catch {
|
|
1671
|
-
return false;
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
1688
|
function readHqRuntimeFileSync(dataDir) {
|
|
1675
1689
|
try {
|
|
1676
1690
|
const parsed = JSON.parse(
|
|
1677
1691
|
syncFs.readFileSync(hqRuntimeFilePath(dataDir), "utf8")
|
|
1678
1692
|
);
|
|
1679
1693
|
if (typeof parsed.url !== "string" || parsed.url.trim().length === 0) return void 0;
|
|
1680
|
-
if (typeof parsed.pid === "number" && !
|
|
1694
|
+
if (typeof parsed.pid === "number" && !isPidAlive(parsed.pid)) return void 0;
|
|
1681
1695
|
return {
|
|
1682
1696
|
url: parsed.url,
|
|
1683
1697
|
updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : "",
|
|
@@ -2303,6 +2317,7 @@ function createMailboxEventPayload(input) {
|
|
|
2303
2317
|
var TRANSCRIPT_EVENT_TYPES = /* @__PURE__ */ new Set(["session.transcript", "agent.message"]);
|
|
2304
2318
|
var OPEN_STATE = 1;
|
|
2305
2319
|
var CONNECT_WARN_AFTER_FAILURES = 5;
|
|
2320
|
+
var DEFAULT_CONNECT_WARN_COOLDOWN_MS = 5 * 6e4;
|
|
2306
2321
|
var DEFAULT_RECONNECT_BASE_MS = 1e3;
|
|
2307
2322
|
var DEFAULT_RECONNECT_MAX_MS = 3e4;
|
|
2308
2323
|
var DEFAULT_DISCOVERY_POLL_MS = 5e3;
|
|
@@ -2314,6 +2329,7 @@ var DEFAULT_MAX_QUEUED_BYTES = Math.min(
|
|
|
2314
2329
|
var DEFAULT_COMMAND_POLL_INTERVAL_MS = 500;
|
|
2315
2330
|
var DEFAULT_COMMAND_POLL_LIMIT = 25;
|
|
2316
2331
|
var DEFAULT_HEARTBEAT_INTERVAL_MS2 = 25e3;
|
|
2332
|
+
var lastConnectWarningAtMs = 0;
|
|
2317
2333
|
function queuedFrameCoalesceKey(frame) {
|
|
2318
2334
|
if (frame.type !== "client.event" || !frame.event.type.endsWith(".snapshot")) {
|
|
2319
2335
|
return void 0;
|
|
@@ -2365,6 +2381,8 @@ var HqPublisher = class {
|
|
|
2365
2381
|
this.reconnect = options.reconnect ?? true;
|
|
2366
2382
|
this.reconnectBaseMs = options.reconnectBaseMs ?? DEFAULT_RECONNECT_BASE_MS;
|
|
2367
2383
|
this.reconnectMaxMs = options.reconnectMaxMs ?? DEFAULT_RECONNECT_MAX_MS;
|
|
2384
|
+
this.connectWarnAfterFailures = options.connectWarnAfterFailures ?? CONNECT_WARN_AFTER_FAILURES;
|
|
2385
|
+
this.connectWarnCooldownMs = options.connectWarnCooldownMs ?? DEFAULT_CONNECT_WARN_COOLDOWN_MS;
|
|
2368
2386
|
this.maxQueuedMessages = options.maxQueuedMessages ?? DEFAULT_MAX_QUEUED_MESSAGES;
|
|
2369
2387
|
this.maxQueuedBytes = options.maxQueuedBytes ?? DEFAULT_MAX_QUEUED_BYTES;
|
|
2370
2388
|
this.resolvedRedactionPolicy = resolveHqRedactionPolicy(options.redactionPolicy);
|
|
@@ -2378,6 +2396,8 @@ var HqPublisher = class {
|
|
|
2378
2396
|
reconnect;
|
|
2379
2397
|
reconnectBaseMs;
|
|
2380
2398
|
reconnectMaxMs;
|
|
2399
|
+
connectWarnAfterFailures;
|
|
2400
|
+
connectWarnCooldownMs;
|
|
2381
2401
|
maxQueuedMessages;
|
|
2382
2402
|
maxQueuedBytes;
|
|
2383
2403
|
resolvedRedactionPolicy;
|
|
@@ -2789,9 +2809,8 @@ var HqPublisher = class {
|
|
|
2789
2809
|
if (this.stopped || !this.reconnect || this.reconnectTimer !== null) return;
|
|
2790
2810
|
const delay2 = Math.min(this.reconnectMaxMs, this.reconnectBaseMs * 2 ** this.reconnectAttempt);
|
|
2791
2811
|
this.reconnectAttempt += 1;
|
|
2792
|
-
if (!this.connectWarningEmitted && this.reconnectAttempt >=
|
|
2793
|
-
this.connectWarningEmitted = true;
|
|
2794
|
-
this.emitConnectWarning();
|
|
2812
|
+
if (!this.connectWarningEmitted && this.reconnectAttempt >= this.connectWarnAfterFailures) {
|
|
2813
|
+
if (this.emitConnectWarning()) this.connectWarningEmitted = true;
|
|
2795
2814
|
}
|
|
2796
2815
|
this.reconnectTimer = setTimeout(() => {
|
|
2797
2816
|
this.reconnectTimer = null;
|
|
@@ -2800,11 +2819,16 @@ var HqPublisher = class {
|
|
|
2800
2819
|
this.reconnectTimer.unref?.();
|
|
2801
2820
|
}
|
|
2802
2821
|
emitConnectWarning() {
|
|
2822
|
+
const nowMs = Date.now();
|
|
2823
|
+
if (nowMs - lastConnectWarningAtMs < this.connectWarnCooldownMs) {
|
|
2824
|
+
return false;
|
|
2825
|
+
}
|
|
2826
|
+
lastConnectWarningAtMs = nowMs;
|
|
2803
2827
|
const attempt = this.lastAttempt;
|
|
2804
2828
|
const message = `WrongStack HQ publisher: ${this.reconnectAttempt} consecutive connection failures${attempt !== null ? ` to ${attempt.url} (client token ${attempt.hadToken ? "present" : "absent"})` : ""}. Either the HQ server is unreachable or it rejected the token (401). If HQ runs in client-token mode, verify WRONGSTACK_HQ_TOKEN / auth.json. Retries continue with backoff.`;
|
|
2805
2829
|
if (this.logger) {
|
|
2806
2830
|
this.logger.warn(message, { event: "hq.publisher.connect_failed" });
|
|
2807
|
-
return;
|
|
2831
|
+
return true;
|
|
2808
2832
|
}
|
|
2809
2833
|
const warn = this.options.warn ?? ((msg) => console.warn(
|
|
2810
2834
|
JSON.stringify({
|
|
@@ -2818,6 +2842,7 @@ var HqPublisher = class {
|
|
|
2818
2842
|
warn(message);
|
|
2819
2843
|
} catch {
|
|
2820
2844
|
}
|
|
2845
|
+
return true;
|
|
2821
2846
|
}
|
|
2822
2847
|
/**
|
|
2823
2848
|
* Dormant re-check while no HQ endpoint is discoverable. Uses a FIXED
|
|
@@ -4826,6 +4851,8 @@ var Context = class _Context {
|
|
|
4826
4851
|
allowOutsideProjectRoot;
|
|
4827
4852
|
model;
|
|
4828
4853
|
tools = [];
|
|
4854
|
+
/** Complete enabled catalog; provider token accounting continues to use `tools`. */
|
|
4855
|
+
catalogTools = [];
|
|
4829
4856
|
meta = {};
|
|
4830
4857
|
/** Agent id performing this run (e.g. 'leader', 'executor'). */
|
|
4831
4858
|
agentId;
|
|
@@ -4906,6 +4933,32 @@ var Context = class _Context {
|
|
|
4906
4933
|
* Cleared after being consumed by agent-tools.
|
|
4907
4934
|
*/
|
|
4908
4935
|
pendingPostToolContext = void 0;
|
|
4936
|
+
/**
|
|
4937
|
+
* Bounded, provider-bound memory evidence kept outside conversation and
|
|
4938
|
+
* tool-result history. Owners replace their own slot instead of appending a
|
|
4939
|
+
* fresh message on every retrieval, so long sessions do not accumulate the
|
|
4940
|
+
* same SAGE hints. Request construction emits these as ephemeral system
|
|
4941
|
+
* suffixes, preserving the stable prompt-cache prefix.
|
|
4942
|
+
*/
|
|
4943
|
+
memoryEvidence = [];
|
|
4944
|
+
setMemoryEvidence(source, text, maxChars = 6e3) {
|
|
4945
|
+
const key = source.trim();
|
|
4946
|
+
if (!key) return;
|
|
4947
|
+
const clean = text?.trim();
|
|
4948
|
+
const retained = this.memoryEvidence.filter((entry) => entry.source !== key);
|
|
4949
|
+
if (clean) {
|
|
4950
|
+
const boundedMax = Number.isFinite(maxChars) ? Math.max(0, Math.floor(maxChars)) : 0;
|
|
4951
|
+
if (boundedMax > 0) retained.push({ source: key, text: clean.slice(0, boundedMax) });
|
|
4952
|
+
}
|
|
4953
|
+
this.memoryEvidence = retained.slice(-8);
|
|
4954
|
+
}
|
|
4955
|
+
clearMemoryEvidence(source) {
|
|
4956
|
+
if (source === void 0) {
|
|
4957
|
+
this.memoryEvidence = [];
|
|
4958
|
+
return;
|
|
4959
|
+
}
|
|
4960
|
+
this.memoryEvidence = this.memoryEvidence.filter((entry) => entry.source !== source);
|
|
4961
|
+
}
|
|
4909
4962
|
/**
|
|
4910
4963
|
* H1: pre-computed total-request token estimate from the most recent
|
|
4911
4964
|
* `estimateRequestTokens()` call in the agent loop's pre-flight step.
|
|
@@ -4941,6 +4994,7 @@ var Context = class _Context {
|
|
|
4941
4994
|
this.allowOutsideProjectRoot = init.allowOutsideProjectRoot ?? false;
|
|
4942
4995
|
this.model = init.model;
|
|
4943
4996
|
this.tools = init.tools ?? [];
|
|
4997
|
+
this.catalogTools = init.catalogTools ?? this.tools;
|
|
4944
4998
|
this.agentId = init.agentId ?? "unknown";
|
|
4945
4999
|
this.agentName = init.agentName ?? "Unknown Agent";
|
|
4946
5000
|
this.traceId = init.traceId;
|
|
@@ -5446,6 +5500,87 @@ function requestLimitExtension(opts) {
|
|
|
5446
5500
|
});
|
|
5447
5501
|
}
|
|
5448
5502
|
|
|
5503
|
+
// src/utils/todos-format.ts
|
|
5504
|
+
function hasOpenTodos(todos) {
|
|
5505
|
+
if (!Array.isArray(todos) || todos.length === 0) return false;
|
|
5506
|
+
return todos.some((t2) => t2.status === "pending" || t2.status === "in_progress");
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
// src/core/next-steps-slot.ts
|
|
5510
|
+
var SLOT_KEY = "nextsteps.pending";
|
|
5511
|
+
var MAX_PENDING_NEXT_STEPS = 4;
|
|
5512
|
+
var NEXT_STEPS_TAG_RE = /<nextsteps\b[^>]*>/i;
|
|
5513
|
+
function writePendingNextSteps(ctx, steps) {
|
|
5514
|
+
const cleaned = [];
|
|
5515
|
+
for (const step of steps) {
|
|
5516
|
+
const text = typeof step?.text === "string" ? step.text.replace(/\s+/g, " ").trim() : "";
|
|
5517
|
+
if (!text) continue;
|
|
5518
|
+
cleaned.push(step.auto === true && cleaned.length === 0 ? { text, auto: true } : { text });
|
|
5519
|
+
if (cleaned.length >= MAX_PENDING_NEXT_STEPS) break;
|
|
5520
|
+
}
|
|
5521
|
+
if (cleaned.length === 0) {
|
|
5522
|
+
clearPendingNextSteps(ctx);
|
|
5523
|
+
return;
|
|
5524
|
+
}
|
|
5525
|
+
ctx.meta[SLOT_KEY] = cleaned;
|
|
5526
|
+
}
|
|
5527
|
+
function readPendingNextSteps(ctx) {
|
|
5528
|
+
const raw = ctx.meta[SLOT_KEY];
|
|
5529
|
+
if (!Array.isArray(raw) || raw.length === 0) return void 0;
|
|
5530
|
+
const steps = raw.filter(
|
|
5531
|
+
(s) => typeof s?.text === "string" && s.text.length > 0
|
|
5532
|
+
);
|
|
5533
|
+
return steps.length > 0 ? steps : void 0;
|
|
5534
|
+
}
|
|
5535
|
+
function clearPendingNextSteps(ctx) {
|
|
5536
|
+
delete ctx.meta[SLOT_KEY];
|
|
5537
|
+
}
|
|
5538
|
+
function hasNextStepsTag(text) {
|
|
5539
|
+
return NEXT_STEPS_TAG_RE.test(text);
|
|
5540
|
+
}
|
|
5541
|
+
function renderNextStepsBlock(steps) {
|
|
5542
|
+
const lines = steps.map((step, i) => {
|
|
5543
|
+
const auto = i === 0 && step.auto === true ? ' auto="true"' : "";
|
|
5544
|
+
return `${i + 1}. ${step.text}${auto}`;
|
|
5545
|
+
});
|
|
5546
|
+
return `<nextsteps>
|
|
5547
|
+
${lines.join("\n")}
|
|
5548
|
+
</nextsteps>`;
|
|
5549
|
+
}
|
|
5550
|
+
function endsTurn(stopReason) {
|
|
5551
|
+
return stopReason !== "tool_use" && stopReason !== "tool_call";
|
|
5552
|
+
}
|
|
5553
|
+
function maybeAppendPendingNextSteps(ctx, res) {
|
|
5554
|
+
if (ctx.agentId !== "leader") return res;
|
|
5555
|
+
if (!endsTurn(res.stopReason)) return res;
|
|
5556
|
+
if (ctx.signal.aborted) return res;
|
|
5557
|
+
const steps = readPendingNextSteps(ctx);
|
|
5558
|
+
if (!steps) return res;
|
|
5559
|
+
if (hasOpenTodos(ctx.todos)) {
|
|
5560
|
+
clearPendingNextSteps(ctx);
|
|
5561
|
+
return res;
|
|
5562
|
+
}
|
|
5563
|
+
const lastTextIndex = res.content.findLastIndex(isTextBlock);
|
|
5564
|
+
if (lastTextIndex >= 0) {
|
|
5565
|
+
const block = res.content[lastTextIndex];
|
|
5566
|
+
if (block && isTextBlock(block) && hasNextStepsTag(block.text)) {
|
|
5567
|
+
clearPendingNextSteps(ctx);
|
|
5568
|
+
return res;
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
const rendered = renderNextStepsBlock(steps);
|
|
5572
|
+
const content = [...res.content];
|
|
5573
|
+
const target = lastTextIndex >= 0 ? content[lastTextIndex] : void 0;
|
|
5574
|
+
if (target && isTextBlock(target)) {
|
|
5575
|
+
const separator = target.text.trim() ? "\n\n" : "";
|
|
5576
|
+
content[lastTextIndex] = { ...target, text: `${target.text}${separator}${rendered}` };
|
|
5577
|
+
} else {
|
|
5578
|
+
content.push({ type: "text", text: rendered });
|
|
5579
|
+
}
|
|
5580
|
+
clearPendingNextSteps(ctx);
|
|
5581
|
+
return { ...res, content };
|
|
5582
|
+
}
|
|
5583
|
+
|
|
5449
5584
|
// src/core/streaming-response-builder.ts
|
|
5450
5585
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
5451
5586
|
|
|
@@ -6279,6 +6414,91 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6279
6414
|
const getFleetPulse = attachFleetPulse(a, fleetPulseCfg);
|
|
6280
6415
|
const pulseEveryN = Math.max(1, fleetPulseCfg?.everyNIterations ?? 5);
|
|
6281
6416
|
const backgroundCoordination = () => a.ctx.meta["coordinationContextMode"] === "background";
|
|
6417
|
+
async function refreshProviderContextLimit(provider, model, opts = {}) {
|
|
6418
|
+
a.ctx.meta ??= {};
|
|
6419
|
+
const routeKey = `${provider.id}/${model}`;
|
|
6420
|
+
const previousRouteKey = a.ctx.meta["contextLimitRouteKey"];
|
|
6421
|
+
const routeChanged = previousRouteKey !== void 0 && previousRouteKey !== routeKey;
|
|
6422
|
+
const previousMaxContext = currentMaxContext();
|
|
6423
|
+
if (routeChanged) {
|
|
6424
|
+
delete a.ctx.meta["providerOverflowMaxContext"];
|
|
6425
|
+
delete a.ctx.meta["contextLimitBaseline"];
|
|
6426
|
+
delete a.ctx.meta["providerLimitEffectiveMaxContext"];
|
|
6427
|
+
delete a.ctx.meta["effectiveMaxContext"];
|
|
6428
|
+
delete a.ctx.meta["effectiveMaxContextSource"];
|
|
6429
|
+
delete a.ctx.meta["contextLimitLastEmittedMaxContext"];
|
|
6430
|
+
delete a.ctx.meta["contextLimitLastEmittedSource"];
|
|
6431
|
+
}
|
|
6432
|
+
a.ctx.meta["contextLimitRouteKey"] = routeKey;
|
|
6433
|
+
const routeMeta = a.ctx.meta["effectiveMaxContext"];
|
|
6434
|
+
const routeProviderCap = provider.capabilities.maxContext;
|
|
6435
|
+
const currentEffective = typeof routeMeta === "number" && routeMeta > 0 ? routeMeta : typeof routeProviderCap === "number" && routeProviderCap > 0 ? routeProviderCap : 2e5;
|
|
6436
|
+
const emitEffectiveLimit = (effective2, source) => {
|
|
6437
|
+
const lastEmitted = a.ctx.meta["contextLimitLastEmittedMaxContext"];
|
|
6438
|
+
const lastEmittedSource = a.ctx.meta["contextLimitLastEmittedSource"];
|
|
6439
|
+
if (lastEmitted === effective2 && lastEmittedSource === source) return;
|
|
6440
|
+
const eventPrevious = typeof lastEmitted === "number" && Number.isFinite(lastEmitted) && lastEmitted > 0 ? Math.floor(lastEmitted) : previousMaxContext;
|
|
6441
|
+
a.ctx.meta["contextLimitLastEmittedMaxContext"] = effective2;
|
|
6442
|
+
a.ctx.meta["contextLimitLastEmittedSource"] = source;
|
|
6443
|
+
a.events.emit("ctx.max_context", {
|
|
6444
|
+
sessionId: resolveEventSessionId(a.ctx),
|
|
6445
|
+
providerId: provider.id,
|
|
6446
|
+
modelId: model,
|
|
6447
|
+
maxContext: effective2,
|
|
6448
|
+
...eventPrevious > 0 ? { previousMaxContext: eventPrevious } : {},
|
|
6449
|
+
source,
|
|
6450
|
+
decreased: eventPrevious > 0 && effective2 < eventPrevious
|
|
6451
|
+
});
|
|
6452
|
+
};
|
|
6453
|
+
const emitNativeAfterRouteChange = () => {
|
|
6454
|
+
if (routeChanged && currentEffective > 0) {
|
|
6455
|
+
a.ctx.meta["effectiveMaxContext"] = currentEffective;
|
|
6456
|
+
a.ctx.meta["effectiveMaxContextSource"] = "configured";
|
|
6457
|
+
emitEffectiveLimit(currentEffective, "configured");
|
|
6458
|
+
}
|
|
6459
|
+
};
|
|
6460
|
+
const refresh = provider.refreshContextLimit;
|
|
6461
|
+
if (opts.probe === false || !refresh) {
|
|
6462
|
+
emitNativeAfterRouteChange();
|
|
6463
|
+
return;
|
|
6464
|
+
}
|
|
6465
|
+
let discovered;
|
|
6466
|
+
try {
|
|
6467
|
+
discovered = await refresh.call(provider, model, { signal: a.ctx.signal });
|
|
6468
|
+
} catch {
|
|
6469
|
+
emitNativeAfterRouteChange();
|
|
6470
|
+
return;
|
|
6471
|
+
}
|
|
6472
|
+
const providerLimit = discovered?.maxContext;
|
|
6473
|
+
if (typeof providerLimit !== "number" || !Number.isFinite(providerLimit) || providerLimit <= 0) {
|
|
6474
|
+
emitNativeAfterRouteChange();
|
|
6475
|
+
return;
|
|
6476
|
+
}
|
|
6477
|
+
const providerLimitFloored = Math.floor(providerLimit);
|
|
6478
|
+
const existingBaseline = a.ctx.meta["contextLimitBaseline"];
|
|
6479
|
+
const lastApplied = a.ctx.meta["providerLimitEffectiveMaxContext"];
|
|
6480
|
+
const existingOverflow = a.ctx.meta["providerOverflowMaxContext"];
|
|
6481
|
+
const effectiveChangedOutsideProbe = typeof lastApplied === "number" && Number.isFinite(lastApplied) && currentEffective !== Math.floor(lastApplied) && currentEffective !== existingOverflow;
|
|
6482
|
+
const baseline = effectiveChangedOutsideProbe || typeof existingBaseline !== "number" || !Number.isFinite(existingBaseline) || existingBaseline <= 0 ? currentEffective : Math.floor(existingBaseline);
|
|
6483
|
+
a.ctx.meta["contextLimitBaseline"] = baseline;
|
|
6484
|
+
const overflowLimit = a.ctx.meta["providerOverflowMaxContext"];
|
|
6485
|
+
const overflowFloored = typeof overflowLimit === "number" && Number.isFinite(overflowLimit) && overflowLimit > 0 ? Math.floor(overflowLimit) : void 0;
|
|
6486
|
+
const ceilings = [baseline, providerLimitFloored];
|
|
6487
|
+
if (overflowFloored !== void 0) ceilings.push(overflowFloored);
|
|
6488
|
+
const effective = Math.min(...ceilings.filter((limit) => limit > 0));
|
|
6489
|
+
let effectiveSource;
|
|
6490
|
+
if (overflowFloored !== void 0 && effective === overflowFloored) {
|
|
6491
|
+
effectiveSource = "provider_overflow";
|
|
6492
|
+
} else if (effective === providerLimitFloored) {
|
|
6493
|
+
effectiveSource = "provider";
|
|
6494
|
+
} else {
|
|
6495
|
+
effectiveSource = "configured";
|
|
6496
|
+
}
|
|
6497
|
+
a.ctx.meta["effectiveMaxContext"] = effective;
|
|
6498
|
+
a.ctx.meta["providerLimitEffectiveMaxContext"] = effective;
|
|
6499
|
+
a.ctx.meta["effectiveMaxContextSource"] = effectiveSource;
|
|
6500
|
+
emitEffectiveLimit(effective, effectiveSource);
|
|
6501
|
+
}
|
|
6282
6502
|
async function compactContextIfNeeded() {
|
|
6283
6503
|
const msgCount = a.ctx.messages.length;
|
|
6284
6504
|
const maxContext = currentMaxContext();
|
|
@@ -6291,13 +6511,14 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6291
6511
|
}
|
|
6292
6512
|
const beforeMessages = a.ctx.messages;
|
|
6293
6513
|
const beforeMsgCount = a.ctx.messages.length;
|
|
6514
|
+
const beforeRevision = a.ctx.state.revision;
|
|
6294
6515
|
await a.pipelines.contextWindow.run(a.ctx);
|
|
6295
6516
|
_lastCompactionMsgCount = a.ctx.messages.length;
|
|
6296
6517
|
_lastCompactionRevision = a.ctx.state.revision;
|
|
6297
6518
|
_lastCompactionToolsRef = a.ctx.tools;
|
|
6298
6519
|
_lastCompactionSystemRef = a.ctx.systemPrompt;
|
|
6299
6520
|
_lastCompactionMaxContext = maxContext;
|
|
6300
|
-
const changed = a.ctx.messages !== beforeMessages || a.ctx.messages.length !== beforeMsgCount;
|
|
6521
|
+
const changed = a.ctx.state.revision !== beforeRevision || a.ctx.messages !== beforeMessages || a.ctx.messages.length !== beforeMsgCount;
|
|
6301
6522
|
const tokens = refreshContextRequestTokenStash({ force: changed });
|
|
6302
6523
|
_lastCompactionRequestTokens = tokens;
|
|
6303
6524
|
const load = maxContext > 0 ? tokens / maxContext : 0;
|
|
@@ -6334,40 +6555,58 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6334
6555
|
);
|
|
6335
6556
|
a.ctx.lastRequestTokens = preFlight.total;
|
|
6336
6557
|
_lastPreFlightMsgCount = req.messages.length;
|
|
6558
|
+
_lastPreFlightToolCount = (req.tools ?? []).length;
|
|
6559
|
+
_lastPreFlightRevision = a.ctx.state.revision;
|
|
6337
6560
|
_cachedSysRef = req.system;
|
|
6338
6561
|
_cachedToolsRef = req.tools ?? [];
|
|
6339
6562
|
_cachedOverheadTokens = preFlight.systemPrompt + preFlight.tools;
|
|
6340
6563
|
a.ctx.meta["lastRequestTokensAt"] = {
|
|
6341
6564
|
msgCount: req.messages.length,
|
|
6342
|
-
toolCount: (req.tools ?? []).length
|
|
6565
|
+
toolCount: (req.tools ?? []).length,
|
|
6566
|
+
revision: a.ctx.state.revision
|
|
6343
6567
|
};
|
|
6344
6568
|
return preFlight;
|
|
6345
6569
|
}
|
|
6346
6570
|
function refreshContextRequestTokenStash(opts = {}) {
|
|
6347
6571
|
const msgCount = a.ctx.messages.length;
|
|
6348
6572
|
const toolCount = (a.ctx.tools ?? []).length;
|
|
6573
|
+
const revision = a.ctx.state.revision;
|
|
6349
6574
|
const stashed = a.ctx.lastRequestTokens;
|
|
6350
6575
|
const stashedAt = a.ctx.meta?.["lastRequestTokensAt"];
|
|
6351
6576
|
if (!opts.force && typeof stashed === "number" && stashed > 0 && typeof stashedAt === "object" && stashedAt !== null) {
|
|
6352
6577
|
const meta = stashedAt;
|
|
6353
|
-
if (meta.msgCount === msgCount &&
|
|
6578
|
+
if (meta.msgCount === msgCount && meta.toolCount === toolCount && meta.revision === revision && _lastPreFlightRevision === revision) {
|
|
6354
6579
|
return stashed;
|
|
6355
6580
|
}
|
|
6356
6581
|
}
|
|
6357
6582
|
const refreshed = estimateMessageTokens(a.ctx.messages) + systemAndToolsOverhead();
|
|
6358
6583
|
a.ctx.lastRequestTokens = refreshed;
|
|
6359
6584
|
_lastPreFlightMsgCount = msgCount;
|
|
6360
|
-
|
|
6585
|
+
_lastPreFlightToolCount = toolCount;
|
|
6586
|
+
_lastPreFlightRevision = revision;
|
|
6587
|
+
a.ctx.meta["lastRequestTokensAt"] = { msgCount, toolCount, revision };
|
|
6361
6588
|
return refreshed;
|
|
6362
6589
|
}
|
|
6363
6590
|
async function buildRequestWithPreflightCompaction(opts) {
|
|
6364
6591
|
let prepared = await handlers.response.buildAndRunRequestPipeline(opts);
|
|
6365
6592
|
let req = prepared.request;
|
|
6366
6593
|
let preFlight = stashRequestTokens(req);
|
|
6594
|
+
let probedRouteKey = `${prepared.provider.id}/${req.model}`;
|
|
6595
|
+
await refreshProviderContextLimit(prepared.provider, req.model);
|
|
6367
6596
|
if (await compactContextIfNeeded()) {
|
|
6368
6597
|
prepared = await handlers.response.buildAndRunRequestPipeline(opts);
|
|
6369
6598
|
req = prepared.request;
|
|
6370
6599
|
preFlight = stashRequestTokens(req);
|
|
6600
|
+
const rebuiltRouteKey = `${prepared.provider.id}/${req.model}`;
|
|
6601
|
+
if (rebuiltRouteKey !== probedRouteKey) {
|
|
6602
|
+
probedRouteKey = rebuiltRouteKey;
|
|
6603
|
+
await refreshProviderContextLimit(prepared.provider, req.model);
|
|
6604
|
+
if (await compactContextIfNeeded()) {
|
|
6605
|
+
prepared = await handlers.response.buildAndRunRequestPipeline(opts);
|
|
6606
|
+
req = prepared.request;
|
|
6607
|
+
preFlight = stashRequestTokens(req);
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6371
6610
|
}
|
|
6372
6611
|
return { req, provider: prepared.provider, preFlight };
|
|
6373
6612
|
}
|
|
@@ -6383,16 +6622,8 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6383
6622
|
_lastEmittedToolCount = toolCount;
|
|
6384
6623
|
_lastEmittedRevision = revision;
|
|
6385
6624
|
_lastEmittedMaxContext = maxContext;
|
|
6386
|
-
if (msgCount !== _lastPreFlightMsgCount) {
|
|
6387
|
-
|
|
6388
|
-
if (typeof stashed2 === "number" && stashed2 > 0 && _lastPreFlightMsgCount >= 0 && _lastPreFlightMsgCount < msgCount) {
|
|
6389
|
-
const delta = estimateMessageTokens(a.ctx.messages.slice(_lastPreFlightMsgCount));
|
|
6390
|
-
a.ctx.lastRequestTokens = stashed2 + delta;
|
|
6391
|
-
} else {
|
|
6392
|
-
a.ctx.lastRequestTokens = estimateMessageTokens(a.ctx.messages) + systemAndToolsOverhead();
|
|
6393
|
-
}
|
|
6394
|
-
_lastPreFlightMsgCount = msgCount;
|
|
6395
|
-
a.ctx.meta["lastRequestTokensAt"] = { msgCount, toolCount };
|
|
6625
|
+
if (msgCount !== _lastPreFlightMsgCount || toolCount !== _lastPreFlightToolCount || revision !== _lastPreFlightRevision) {
|
|
6626
|
+
refreshContextRequestTokenStash({ force: true });
|
|
6396
6627
|
}
|
|
6397
6628
|
let total;
|
|
6398
6629
|
const anchored = realAnchoredInputTokens(
|
|
@@ -6407,9 +6638,7 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6407
6638
|
const cal = getCalibrationState(calibrationKey());
|
|
6408
6639
|
total = cal.calibrated ? Math.round(stashed * Math.min(1.5, Math.max(0.5, cal.ratio))) : stashed;
|
|
6409
6640
|
} else {
|
|
6410
|
-
const raw =
|
|
6411
|
-
a.ctx.lastRequestTokens = raw;
|
|
6412
|
-
_lastPreFlightMsgCount = msgCount;
|
|
6641
|
+
const raw = refreshContextRequestTokenStash({ force: true });
|
|
6413
6642
|
const cal = getCalibrationState(calibrationKey());
|
|
6414
6643
|
total = cal.calibrated ? Math.round(raw * Math.min(1.5, Math.max(0.5, cal.ratio))) : raw;
|
|
6415
6644
|
}
|
|
@@ -6433,6 +6662,8 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6433
6662
|
let _lastEmittedRevision = -1;
|
|
6434
6663
|
let _lastEmittedMaxContext = -1;
|
|
6435
6664
|
let _lastPreFlightMsgCount = -1;
|
|
6665
|
+
let _lastPreFlightToolCount = -1;
|
|
6666
|
+
let _lastPreFlightRevision = -1;
|
|
6436
6667
|
let _lastCompactionMsgCount = -1;
|
|
6437
6668
|
let _lastCompactionRevision = -1;
|
|
6438
6669
|
let _lastCompactionToolsRef = null;
|
|
@@ -6538,6 +6769,7 @@ function createAgentLoopHandler(a, handlers) {
|
|
|
6538
6769
|
} catch (err) {
|
|
6539
6770
|
(a.logger.debug ?? a.logger.warn)?.(`session boundary flush failed: ${toErrorMessage(err)}`);
|
|
6540
6771
|
}
|
|
6772
|
+
clearPendingNextSteps(a.ctx);
|
|
6541
6773
|
let finalText = "";
|
|
6542
6774
|
let iterations = 0;
|
|
6543
6775
|
const delegateSummaries = [];
|
|
@@ -6625,7 +6857,11 @@ ${text}` : text;
|
|
|
6625
6857
|
return { ...limitCheck.exit, finalText };
|
|
6626
6858
|
}
|
|
6627
6859
|
await a.extensions.runBeforeIteration(a.ctx, i);
|
|
6628
|
-
a.events.emit("iteration.started", {
|
|
6860
|
+
a.events.emit("iteration.started", {
|
|
6861
|
+
sessionId: resolveEventSessionId(a.ctx),
|
|
6862
|
+
ctx: a.ctx,
|
|
6863
|
+
index: i
|
|
6864
|
+
});
|
|
6629
6865
|
injectPendingBtwNotes((block) => pendingMailboxBlocks.push(block));
|
|
6630
6866
|
injectQueueAwareness();
|
|
6631
6867
|
if (pendingLoopSteer) {
|
|
@@ -6775,11 +7011,9 @@ ${text}` : text;
|
|
|
6775
7011
|
res = recovered.response;
|
|
6776
7012
|
}
|
|
6777
7013
|
clearEvaluatedMailboxBlocks();
|
|
6778
|
-
const
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
providerBoundToRequest(req) ?? requestProvider
|
|
6782
|
-
);
|
|
7014
|
+
const responseProvider = providerBoundToRequest(req) ?? requestProvider;
|
|
7015
|
+
const responseResult = await handlers.response.processResponse(res, req, responseProvider);
|
|
7016
|
+
await refreshProviderContextLimit(responseProvider, req.model, { probe: false });
|
|
6783
7017
|
if (responseResult.aborted) {
|
|
6784
7018
|
return {
|
|
6785
7019
|
status: "aborted",
|
|
@@ -6937,7 +7171,11 @@ ${text}` : text;
|
|
|
6937
7171
|
}
|
|
6938
7172
|
await compactContextIfNeeded();
|
|
6939
7173
|
emitContextPct();
|
|
6940
|
-
a.events.emit("iteration.completed", {
|
|
7174
|
+
a.events.emit("iteration.completed", {
|
|
7175
|
+
sessionId: resolveEventSessionId(a.ctx),
|
|
7176
|
+
ctx: a.ctx,
|
|
7177
|
+
index: i
|
|
7178
|
+
});
|
|
6941
7179
|
await a.extensions.runAfterIteration(a.ctx, i);
|
|
6942
7180
|
if (autonomousContinue && responseResult.directive === "continue") {
|
|
6943
7181
|
continue;
|
|
@@ -7091,6 +7329,9 @@ function buildLiveNextStepsGateBlock(ctx) {
|
|
|
7091
7329
|
(todo) => todo.status === "pending" || todo.status === "in_progress"
|
|
7092
7330
|
);
|
|
7093
7331
|
if (openTodos.length === 0) {
|
|
7332
|
+
const toolRoute = ctx.tools?.some((t2) => t2.name === "nextsteps") ? [
|
|
7333
|
+
"Calling the `nextsteps` tool with the same items satisfies branch 1 as well; if you both call it and write the block, the block wins."
|
|
7334
|
+
] : [];
|
|
7094
7335
|
return {
|
|
7095
7336
|
type: "text",
|
|
7096
7337
|
text: [
|
|
@@ -7099,6 +7340,7 @@ function buildLiveNextStepsGateBlock(ctx) {
|
|
|
7099
7340
|
"On the final response, you MUST take exactly one branch:",
|
|
7100
7341
|
"1. If at least one genuinely useful follow-on action exists, include a balanced <nextsteps> block containing 1-4 exact prompt messages that can be submitted back to you through the current TUI or WebUI input.",
|
|
7101
7342
|
"Every item must ask the agent to perform work. Never put a human-only chore or an instruction addressed to the user inside <nextsteps>; natural-language agent-directed imperatives are valid and need not be shell commands.",
|
|
7343
|
+
...toolRoute,
|
|
7102
7344
|
"2. If no useful follow-on action truly exists, omit <nextsteps> and explicitly tell the user in normal prose that no further steps are needed for this task.",
|
|
7103
7345
|
"Silently omitting both is invalid. Do not decide by chance, tone, or response length, and do not invent filler suggestions.",
|
|
7104
7346
|
"[/nextsteps_gate]"
|
|
@@ -7126,6 +7368,27 @@ function buildLiveNextStepsGateBlock(ctx) {
|
|
|
7126
7368
|
cache_control: { type: "ephemeral" }
|
|
7127
7369
|
};
|
|
7128
7370
|
}
|
|
7371
|
+
var MAX_MEMORY_EVIDENCE_CHARS = 12e3;
|
|
7372
|
+
function buildMemoryEvidenceBlocks(ctx) {
|
|
7373
|
+
const blocks = [];
|
|
7374
|
+
let remaining = MAX_MEMORY_EVIDENCE_CHARS;
|
|
7375
|
+
for (const entry of ctx.memoryEvidence) {
|
|
7376
|
+
if (remaining <= 0) break;
|
|
7377
|
+
const text = entry.text.trim();
|
|
7378
|
+
if (!text) continue;
|
|
7379
|
+
const source = entry.source.replace(/[^a-z0-9_.-]+/gi, "-").slice(0, 80) || "memory";
|
|
7380
|
+
const bounded = text.slice(0, remaining);
|
|
7381
|
+
remaining -= bounded.length;
|
|
7382
|
+
blocks.push({
|
|
7383
|
+
type: "text",
|
|
7384
|
+
text: `[memory_evidence source="${source}"]
|
|
7385
|
+
${bounded}
|
|
7386
|
+
[/memory_evidence]`,
|
|
7387
|
+
cache_control: { type: "ephemeral" }
|
|
7388
|
+
});
|
|
7389
|
+
}
|
|
7390
|
+
return blocks;
|
|
7391
|
+
}
|
|
7129
7392
|
function createAgentResponseHandler(a) {
|
|
7130
7393
|
const stabilizedPromptEpochs = /* @__PURE__ */ new WeakSet();
|
|
7131
7394
|
function stabilizePromptEpoch() {
|
|
@@ -7157,7 +7420,8 @@ function createAgentResponseHandler(a) {
|
|
|
7157
7420
|
stabilizePromptEpoch();
|
|
7158
7421
|
const volatileLedger = buildCompletedWorkLedgerBlock(a.ctx);
|
|
7159
7422
|
const liveNextStepsGate = buildLiveNextStepsGateBlock(a.ctx);
|
|
7160
|
-
const
|
|
7423
|
+
const memoryEvidence = buildMemoryEvidenceBlocks(a.ctx);
|
|
7424
|
+
const volatileBlocks = [volatileLedger, liveNextStepsGate, ...memoryEvidence].filter(
|
|
7161
7425
|
(block) => block !== void 0
|
|
7162
7426
|
);
|
|
7163
7427
|
const system = volatileBlocks.length > 0 ? [...a.ctx.systemPrompt, ...volatileBlocks] : a.ctx.systemPrompt;
|
|
@@ -7167,7 +7431,7 @@ function createAgentResponseHandler(a) {
|
|
|
7167
7431
|
model: opts.model ?? a.ctx.model,
|
|
7168
7432
|
system,
|
|
7169
7433
|
messages: a.ctx.messages,
|
|
7170
|
-
tools: a.tools.
|
|
7434
|
+
tools: a.tools.listForProvider(),
|
|
7171
7435
|
// `maxTokens` is deliberately NOT set here. The provider adapter
|
|
7172
7436
|
// resolves the ceiling from the catalog entry for the model in
|
|
7173
7437
|
// `req.model`, which is the only source that stays correct across a
|
|
@@ -7190,6 +7454,7 @@ function createAgentResponseHandler(a) {
|
|
|
7190
7454
|
async function processResponse(raw, req, requestProvider = a.ctx.provider) {
|
|
7191
7455
|
let res = raw;
|
|
7192
7456
|
res = await a.pipelines.response.run(res);
|
|
7457
|
+
res = maybeAppendPendingNextSteps(a.ctx, res);
|
|
7193
7458
|
a.events.emit("provider.response", {
|
|
7194
7459
|
sessionId: resolveEventSessionId(a.ctx),
|
|
7195
7460
|
ctx: a.ctx,
|
|
@@ -7330,7 +7595,7 @@ var DIFF_TOOL_NAMES = /* @__PURE__ */ new Set(["edit", "write", "replace", "patc
|
|
|
7330
7595
|
var DIFF_TOOL_EVENT_PREVIEW_MAX = 16e3;
|
|
7331
7596
|
var SAGE_EVENT_MAX = 2e3;
|
|
7332
7597
|
function createAgentToolHandler(a) {
|
|
7333
|
-
async function executeSingleWithDecision(tool, use) {
|
|
7598
|
+
async function executeSingleWithDecision(tool, use, preToolContext) {
|
|
7334
7599
|
const start = Date.now();
|
|
7335
7600
|
try {
|
|
7336
7601
|
const result = await a.toolExecutor.executeTool(
|
|
@@ -7342,7 +7607,8 @@ function createAgentToolHandler(a) {
|
|
|
7342
7607
|
input: use.input
|
|
7343
7608
|
},
|
|
7344
7609
|
a.ctx,
|
|
7345
|
-
a.perIterationOutputCapBytes
|
|
7610
|
+
a.perIterationOutputCapBytes,
|
|
7611
|
+
preToolContext
|
|
7346
7612
|
);
|
|
7347
7613
|
return { result: result.block, durationMs: Date.now() - start };
|
|
7348
7614
|
} catch (err) {
|
|
@@ -7486,11 +7752,15 @@ function createAgentToolHandler(a) {
|
|
|
7486
7752
|
const p = a.permission;
|
|
7487
7753
|
p.denyOnce?.({ tool: tool.name, pattern: result.suggestedPattern });
|
|
7488
7754
|
}
|
|
7489
|
-
const reRunResult = decision === "yes" || decision === "always" ? await executeSingleWithDecision(
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7755
|
+
const reRunResult = decision === "yes" || decision === "always" ? await executeSingleWithDecision(
|
|
7756
|
+
tool,
|
|
7757
|
+
{
|
|
7758
|
+
id: result.toolUseId,
|
|
7759
|
+
name: tool.name,
|
|
7760
|
+
input: result.input
|
|
7761
|
+
},
|
|
7762
|
+
result.preToolContext
|
|
7763
|
+
) : {
|
|
7494
7764
|
result: {
|
|
7495
7765
|
type: "tool_result",
|
|
7496
7766
|
tool_use_id: result.toolUseId,
|
|
@@ -7924,7 +8194,8 @@ var Agent = class {
|
|
|
7924
8194
|
await sessionWriter.flush().catch(() => {
|
|
7925
8195
|
});
|
|
7926
8196
|
});
|
|
7927
|
-
this.ctx.tools = this.tools.
|
|
8197
|
+
this.ctx.tools = this.tools.listForProvider();
|
|
8198
|
+
this.ctx.catalogTools = this.tools.list();
|
|
7928
8199
|
const span = this.tracer?.startSpan("agent.run", {
|
|
7929
8200
|
"agent.model": opts.model ?? this.ctx.model,
|
|
7930
8201
|
"agent.executionStrategy": opts.executionStrategy ?? this.executionStrategy
|
|
@@ -8011,165 +8282,6 @@ var Agent = class {
|
|
|
8011
8282
|
// ── Tool + response execution handled by AgentToolHandler / AgentResponseHandler ──
|
|
8012
8283
|
};
|
|
8013
8284
|
|
|
8014
|
-
// src/core/input-builder.ts
|
|
8015
|
-
var InputBuilder = class {
|
|
8016
|
-
store;
|
|
8017
|
-
pasteLineThreshold;
|
|
8018
|
-
pasteCharThreshold;
|
|
8019
|
-
display = "";
|
|
8020
|
-
refs = [];
|
|
8021
|
-
constructor(opts) {
|
|
8022
|
-
this.store = opts.store;
|
|
8023
|
-
this.pasteLineThreshold = opts.pasteLineThreshold ?? 8;
|
|
8024
|
-
this.pasteCharThreshold = opts.pasteCharThreshold ?? 2e3;
|
|
8025
|
-
}
|
|
8026
|
-
get text() {
|
|
8027
|
-
return this.display;
|
|
8028
|
-
}
|
|
8029
|
-
get attachments() {
|
|
8030
|
-
return [...this.refs];
|
|
8031
|
-
}
|
|
8032
|
-
get isEmpty() {
|
|
8033
|
-
return this.display.trim().length === 0;
|
|
8034
|
-
}
|
|
8035
|
-
appendText(text) {
|
|
8036
|
-
this.display += text;
|
|
8037
|
-
}
|
|
8038
|
-
/**
|
|
8039
|
-
* Decide whether a chunk of pasted text is "big" enough to collapse.
|
|
8040
|
-
* If yes, store it and append a placeholder. If no, inline it.
|
|
8041
|
-
* Returns the placeholder string actually appended (or `null` if inlined).
|
|
8042
|
-
*/
|
|
8043
|
-
async appendPaste(text) {
|
|
8044
|
-
if (this.shouldCollapse(text)) {
|
|
8045
|
-
const ref = await this.store.add({
|
|
8046
|
-
kind: "text",
|
|
8047
|
-
data: text,
|
|
8048
|
-
meta: { label: paragraphLabel(text) }
|
|
8049
|
-
});
|
|
8050
|
-
const placeholder = `[pasted #${ref.seq}]`;
|
|
8051
|
-
this.display += placeholder;
|
|
8052
|
-
this.refs.push(ref);
|
|
8053
|
-
return placeholder;
|
|
8054
|
-
}
|
|
8055
|
-
this.display += text;
|
|
8056
|
-
return null;
|
|
8057
|
-
}
|
|
8058
|
-
/**
|
|
8059
|
-
* Always collapses to `[image #N]` — images are never inlined.
|
|
8060
|
-
* `dataBase64` is the raw base64 payload (no data: prefix).
|
|
8061
|
-
*/
|
|
8062
|
-
async appendImage(dataBase64, mediaType) {
|
|
8063
|
-
const ref = await this.store.add({
|
|
8064
|
-
kind: "image",
|
|
8065
|
-
data: dataBase64,
|
|
8066
|
-
meta: { mediaType, label: `${mediaType.split("/")[1]?.toUpperCase() ?? "IMG"}` }
|
|
8067
|
-
});
|
|
8068
|
-
const placeholder = `[image #${ref.seq}]`;
|
|
8069
|
-
this.display += placeholder;
|
|
8070
|
-
this.refs.push(ref);
|
|
8071
|
-
return placeholder;
|
|
8072
|
-
}
|
|
8073
|
-
async appendFile(input) {
|
|
8074
|
-
const ref = await this.store.add({ ...input, kind: "file" });
|
|
8075
|
-
const placeholder = `[file #${ref.seq}]`;
|
|
8076
|
-
this.display += placeholder;
|
|
8077
|
-
this.refs.push(ref);
|
|
8078
|
-
return placeholder;
|
|
8079
|
-
}
|
|
8080
|
-
/**
|
|
8081
|
-
* Register-only variant of `appendPaste`. Always stores the paste and
|
|
8082
|
-
* returns the inline `[pasted #N, L lines]` token WITHOUT mutating
|
|
8083
|
-
* `display` — the caller (TUI) owns its own editable buffer as the single
|
|
8084
|
-
* source of truth, inserts the token there, and expands the buffer at
|
|
8085
|
-
* submit. The collapse decision is the caller's (it gates this call); use
|
|
8086
|
-
* `wouldCollapse()` for that.
|
|
8087
|
-
*/
|
|
8088
|
-
async registerPaste(text) {
|
|
8089
|
-
const ref = await this.store.add({
|
|
8090
|
-
kind: "text",
|
|
8091
|
-
data: text,
|
|
8092
|
-
meta: { label: paragraphLabel(text) }
|
|
8093
|
-
});
|
|
8094
|
-
this.refs.push(ref);
|
|
8095
|
-
const lines = text.split(/\r?\n|\r/).length;
|
|
8096
|
-
return `[pasted #${ref.seq}, ${lines} lines]`;
|
|
8097
|
-
}
|
|
8098
|
-
/**
|
|
8099
|
-
* Register-only variant of `appendImage` — see `registerPaste`. Returns a
|
|
8100
|
-
* seq-keyed `[image #N, LABEL]` token; does not touch `display`.
|
|
8101
|
-
*/
|
|
8102
|
-
async registerImage(dataBase64, mediaType) {
|
|
8103
|
-
const label = `${mediaType.split("/")[1]?.toUpperCase() ?? "IMG"}`;
|
|
8104
|
-
const ref = await this.store.add({
|
|
8105
|
-
kind: "image",
|
|
8106
|
-
data: dataBase64,
|
|
8107
|
-
meta: { mediaType, label }
|
|
8108
|
-
});
|
|
8109
|
-
this.refs.push(ref);
|
|
8110
|
-
return `[image #${ref.seq}, ${label}]`;
|
|
8111
|
-
}
|
|
8112
|
-
/**
|
|
8113
|
-
* Register-only variant of `appendFile` — see `registerPaste`. Returns a
|
|
8114
|
-
* path-keyed `[file:<path>]` token (resolved by path at expand time); does
|
|
8115
|
-
* not touch `display`. The path is read from `meta.filename` (falling back
|
|
8116
|
-
* to `meta.label`).
|
|
8117
|
-
*/
|
|
8118
|
-
async registerFile(input) {
|
|
8119
|
-
const ref = await this.store.add({ ...input, kind: "file" });
|
|
8120
|
-
this.refs.push(ref);
|
|
8121
|
-
const path15 = ref.meta.filename ?? ref.meta.label ?? String(ref.seq);
|
|
8122
|
-
return `[file:${path15}]`;
|
|
8123
|
-
}
|
|
8124
|
-
/**
|
|
8125
|
-
* Whether `appendPaste(text)` would collapse the text to a placeholder
|
|
8126
|
-
* (rather than inlining it). Lets a frontend decide where to route a paste
|
|
8127
|
-
* — e.g. collapsed pastes become a pill, while inlined ones can be shown
|
|
8128
|
-
* in the editable input row — without calling `appendPaste` first (which
|
|
8129
|
-
* mutates the display buffer).
|
|
8130
|
-
*/
|
|
8131
|
-
wouldCollapse(text) {
|
|
8132
|
-
return this.shouldCollapse(text);
|
|
8133
|
-
}
|
|
8134
|
-
/** Reset display and ref list. Does NOT clear the store itself. */
|
|
8135
|
-
reset() {
|
|
8136
|
-
this.display = "";
|
|
8137
|
-
this.refs.length = 0;
|
|
8138
|
-
}
|
|
8139
|
-
/**
|
|
8140
|
-
* Resolve the current display string into ContentBlock[]. Empty
|
|
8141
|
-
* input returns an empty array — caller decides what to do.
|
|
8142
|
-
*/
|
|
8143
|
-
async submit() {
|
|
8144
|
-
const text = this.display;
|
|
8145
|
-
this.reset();
|
|
8146
|
-
return text ? this.store.expand(text) : [];
|
|
8147
|
-
}
|
|
8148
|
-
shouldCollapse(text) {
|
|
8149
|
-
if (text.length >= this.pasteCharThreshold) return true;
|
|
8150
|
-
let lines = 1;
|
|
8151
|
-
for (let i = 0; i < text.length; i++) {
|
|
8152
|
-
const c = text.charCodeAt(i);
|
|
8153
|
-
if (c === 10) lines++;
|
|
8154
|
-
else if (c === 13 && text.charCodeAt(i + 1) !== 10) lines++;
|
|
8155
|
-
if (lines >= this.pasteLineThreshold) return true;
|
|
8156
|
-
}
|
|
8157
|
-
return false;
|
|
8158
|
-
}
|
|
8159
|
-
};
|
|
8160
|
-
function paragraphLabel(text) {
|
|
8161
|
-
const lines = text.split(/\r?\n|\r/).length;
|
|
8162
|
-
const bytes = Buffer.byteLength(text, "utf8");
|
|
8163
|
-
if (bytes < 1024) return `${lines} lines, ${bytes} B`;
|
|
8164
|
-
return `${lines} lines, ${(bytes / 1024).toFixed(1)} KB`;
|
|
8165
|
-
}
|
|
8166
|
-
|
|
8167
|
-
// src/utils/todos-format.ts
|
|
8168
|
-
function hasOpenTodos(todos) {
|
|
8169
|
-
if (!Array.isArray(todos) || todos.length === 0) return false;
|
|
8170
|
-
return todos.some((t2) => t2.status === "pending" || t2.status === "in_progress");
|
|
8171
|
-
}
|
|
8172
|
-
|
|
8173
8285
|
// src/core/continue-intent.ts
|
|
8174
8286
|
var CONTINUE_PHRASES = /* @__PURE__ */ new Set([
|
|
8175
8287
|
// ── English ──
|
|
@@ -9101,34 +9213,157 @@ function createFallbackModelExtension(deps) {
|
|
|
9101
9213
|
};
|
|
9102
9214
|
}
|
|
9103
9215
|
|
|
9104
|
-
// src/
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9216
|
+
// src/core/input-builder.ts
|
|
9217
|
+
var InputBuilder = class {
|
|
9218
|
+
store;
|
|
9219
|
+
pasteLineThreshold;
|
|
9220
|
+
pasteCharThreshold;
|
|
9221
|
+
display = "";
|
|
9222
|
+
refs = [];
|
|
9223
|
+
constructor(opts) {
|
|
9224
|
+
this.store = opts.store;
|
|
9225
|
+
this.pasteLineThreshold = opts.pasteLineThreshold ?? 8;
|
|
9226
|
+
this.pasteCharThreshold = opts.pasteCharThreshold ?? 2e3;
|
|
9227
|
+
}
|
|
9228
|
+
get text() {
|
|
9229
|
+
return this.display;
|
|
9230
|
+
}
|
|
9231
|
+
get attachments() {
|
|
9232
|
+
return [...this.refs];
|
|
9233
|
+
}
|
|
9234
|
+
get isEmpty() {
|
|
9235
|
+
return this.display.trim().length === 0;
|
|
9236
|
+
}
|
|
9237
|
+
appendText(text) {
|
|
9238
|
+
this.display += text;
|
|
9239
|
+
}
|
|
9240
|
+
/**
|
|
9241
|
+
* Decide whether a chunk of pasted text is "big" enough to collapse.
|
|
9242
|
+
* If yes, store it and append a placeholder. If no, inline it.
|
|
9243
|
+
* Returns the placeholder string actually appended (or `null` if inlined).
|
|
9244
|
+
*/
|
|
9245
|
+
async appendPaste(text) {
|
|
9246
|
+
if (this.shouldCollapse(text)) {
|
|
9247
|
+
const ref = await this.store.add({
|
|
9248
|
+
kind: "text",
|
|
9249
|
+
data: text,
|
|
9250
|
+
meta: { label: paragraphLabel(text) }
|
|
9251
|
+
});
|
|
9252
|
+
const placeholder = `[pasted #${ref.seq}]`;
|
|
9253
|
+
this.display += placeholder;
|
|
9254
|
+
this.refs.push(ref);
|
|
9255
|
+
return placeholder;
|
|
9121
9256
|
}
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
return "minimal";
|
|
9257
|
+
this.display += text;
|
|
9258
|
+
return null;
|
|
9125
9259
|
}
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9260
|
+
/**
|
|
9261
|
+
* Always collapses to `[image #N]` — images are never inlined.
|
|
9262
|
+
* `dataBase64` is the raw base64 payload (no data: prefix).
|
|
9263
|
+
*/
|
|
9264
|
+
async appendImage(dataBase64, mediaType) {
|
|
9265
|
+
const ref = await this.store.add({
|
|
9266
|
+
kind: "image",
|
|
9267
|
+
data: dataBase64,
|
|
9268
|
+
meta: { mediaType, label: `${mediaType.split("/")[1]?.toUpperCase() ?? "IMG"}` }
|
|
9269
|
+
});
|
|
9270
|
+
const placeholder = `[image #${ref.seq}]`;
|
|
9271
|
+
this.display += placeholder;
|
|
9272
|
+
this.refs.push(ref);
|
|
9273
|
+
return placeholder;
|
|
9274
|
+
}
|
|
9275
|
+
async appendFile(input) {
|
|
9276
|
+
const ref = await this.store.add({ ...input, kind: "file" });
|
|
9277
|
+
const placeholder = `[file #${ref.seq}]`;
|
|
9278
|
+
this.display += placeholder;
|
|
9279
|
+
this.refs.push(ref);
|
|
9280
|
+
return placeholder;
|
|
9281
|
+
}
|
|
9282
|
+
/**
|
|
9283
|
+
* Register-only variant of `appendPaste`. Always stores the paste and
|
|
9284
|
+
* returns the inline `[pasted #N, L lines]` token WITHOUT mutating
|
|
9285
|
+
* `display` — the caller (TUI) owns its own editable buffer as the single
|
|
9286
|
+
* source of truth, inserts the token there, and expands the buffer at
|
|
9287
|
+
* submit. The collapse decision is the caller's (it gates this call); use
|
|
9288
|
+
* `wouldCollapse()` for that.
|
|
9289
|
+
*/
|
|
9290
|
+
async registerPaste(text) {
|
|
9291
|
+
const ref = await this.store.add({
|
|
9292
|
+
kind: "text",
|
|
9293
|
+
data: text,
|
|
9294
|
+
meta: { label: paragraphLabel(text) }
|
|
9295
|
+
});
|
|
9296
|
+
this.refs.push(ref);
|
|
9297
|
+
const lines = text.split(/\r?\n|\r/).length;
|
|
9298
|
+
return `[pasted #${ref.seq}, ${lines} lines]`;
|
|
9299
|
+
}
|
|
9300
|
+
/**
|
|
9301
|
+
* Register-only variant of `appendImage` — see `registerPaste`. Returns a
|
|
9302
|
+
* seq-keyed `[image #N, LABEL]` token; does not touch `display`.
|
|
9303
|
+
*/
|
|
9304
|
+
async registerImage(dataBase64, mediaType) {
|
|
9305
|
+
const label = `${mediaType.split("/")[1]?.toUpperCase() ?? "IMG"}`;
|
|
9306
|
+
const ref = await this.store.add({
|
|
9307
|
+
kind: "image",
|
|
9308
|
+
data: dataBase64,
|
|
9309
|
+
meta: { mediaType, label }
|
|
9310
|
+
});
|
|
9311
|
+
this.refs.push(ref);
|
|
9312
|
+
return `[image #${ref.seq}, ${label}]`;
|
|
9313
|
+
}
|
|
9314
|
+
/**
|
|
9315
|
+
* Register-only variant of `appendFile` — see `registerPaste`. Returns a
|
|
9316
|
+
* path-keyed `[file:<path>]` token (resolved by path at expand time); does
|
|
9317
|
+
* not touch `display`. The path is read from `meta.filename` (falling back
|
|
9318
|
+
* to `meta.label`).
|
|
9319
|
+
*/
|
|
9320
|
+
async registerFile(input) {
|
|
9321
|
+
const ref = await this.store.add({ ...input, kind: "file" });
|
|
9322
|
+
this.refs.push(ref);
|
|
9323
|
+
const path15 = ref.meta.filename ?? ref.meta.label ?? String(ref.seq);
|
|
9324
|
+
return `[file:${path15}]`;
|
|
9325
|
+
}
|
|
9326
|
+
/**
|
|
9327
|
+
* Whether `appendPaste(text)` would collapse the text to a placeholder
|
|
9328
|
+
* (rather than inlining it). Lets a frontend decide where to route a paste
|
|
9329
|
+
* — e.g. collapsed pastes become a pill, while inlined ones can be shown
|
|
9330
|
+
* in the editable input row — without calling `appendPaste` first (which
|
|
9331
|
+
* mutates the display buffer).
|
|
9332
|
+
*/
|
|
9333
|
+
wouldCollapse(text) {
|
|
9334
|
+
return this.shouldCollapse(text);
|
|
9335
|
+
}
|
|
9336
|
+
/** Reset display and ref list. Does NOT clear the store itself. */
|
|
9337
|
+
reset() {
|
|
9338
|
+
this.display = "";
|
|
9339
|
+
this.refs.length = 0;
|
|
9340
|
+
}
|
|
9341
|
+
/**
|
|
9342
|
+
* Resolve the current display string into ContentBlock[]. Empty
|
|
9343
|
+
* input returns an empty array — caller decides what to do.
|
|
9344
|
+
*/
|
|
9345
|
+
async submit() {
|
|
9346
|
+
const text = this.display;
|
|
9347
|
+
this.reset();
|
|
9348
|
+
return text ? this.store.expand(text) : [];
|
|
9349
|
+
}
|
|
9350
|
+
shouldCollapse(text) {
|
|
9351
|
+
if (text.length >= this.pasteCharThreshold) return true;
|
|
9352
|
+
let lines = 1;
|
|
9353
|
+
for (let i = 0; i < text.length; i++) {
|
|
9354
|
+
const c = text.charCodeAt(i);
|
|
9355
|
+
if (c === 10) lines++;
|
|
9356
|
+
else if (c === 13 && text.charCodeAt(i + 1) !== 10) lines++;
|
|
9357
|
+
if (lines >= this.pasteLineThreshold) return true;
|
|
9358
|
+
}
|
|
9359
|
+
return false;
|
|
9360
|
+
}
|
|
9361
|
+
};
|
|
9362
|
+
function paragraphLabel(text) {
|
|
9363
|
+
const lines = text.split(/\r?\n|\r/).length;
|
|
9364
|
+
const bytes = Buffer.byteLength(text, "utf8");
|
|
9365
|
+
if (bytes < 1024) return `${lines} lines, ${bytes} B`;
|
|
9366
|
+
return `${lines} lines, ${(bytes / 1024).toFixed(1)} KB`;
|
|
9132
9367
|
}
|
|
9133
9368
|
|
|
9134
9369
|
// src/core/instruction-bundle.ts
|
|
@@ -9306,7 +9541,281 @@ function firstExistingDirSync(candidates) {
|
|
|
9306
9541
|
return candidates[0] ?? "";
|
|
9307
9542
|
}
|
|
9308
9543
|
|
|
9544
|
+
// src/types/runtime-capability-manifest.ts
|
|
9545
|
+
var PLAYWRIGHT_ALIASES = {
|
|
9546
|
+
playwright_navigate: "browser_navigate",
|
|
9547
|
+
playwright_screenshot: "browser_screenshot",
|
|
9548
|
+
playwright_click: "browser_click",
|
|
9549
|
+
playwright_type: "browser_type",
|
|
9550
|
+
playwright_evaluate: "browser_evaluate",
|
|
9551
|
+
playwright_select_option: "browser_select",
|
|
9552
|
+
playwright_hover: "browser_hover",
|
|
9553
|
+
playwright_fill_form: "browser_type",
|
|
9554
|
+
playwright_wait_for: "browser_wait",
|
|
9555
|
+
playwright_press_key: "browser_press",
|
|
9556
|
+
playwright_drag: "browser_drag"
|
|
9557
|
+
};
|
|
9558
|
+
var RUNTIME_CAPABILITY_MANIFEST = [
|
|
9559
|
+
{
|
|
9560
|
+
id: "filesystem.read",
|
|
9561
|
+
pack: "core",
|
|
9562
|
+
exposure: "direct",
|
|
9563
|
+
tools: ["read", "grep", "glob", "tree"]
|
|
9564
|
+
},
|
|
9565
|
+
{
|
|
9566
|
+
id: "code.inspect",
|
|
9567
|
+
pack: "core",
|
|
9568
|
+
exposure: "direct",
|
|
9569
|
+
tools: [
|
|
9570
|
+
"codebase-stats",
|
|
9571
|
+
"codebase-search",
|
|
9572
|
+
"codebase-incoming-calls",
|
|
9573
|
+
"codebase-outgoing-calls",
|
|
9574
|
+
"codebase-index",
|
|
9575
|
+
"dead-code-scan",
|
|
9576
|
+
"diff",
|
|
9577
|
+
"json",
|
|
9578
|
+
"logs"
|
|
9579
|
+
]
|
|
9580
|
+
},
|
|
9581
|
+
{
|
|
9582
|
+
id: "filesystem.write",
|
|
9583
|
+
pack: "development",
|
|
9584
|
+
exposure: "direct",
|
|
9585
|
+
tools: ["write", "edit", "replace", "patch"]
|
|
9586
|
+
},
|
|
9587
|
+
{
|
|
9588
|
+
id: "execution.shell",
|
|
9589
|
+
pack: "development",
|
|
9590
|
+
exposure: "direct",
|
|
9591
|
+
tools: ["bash", "exec", "language", "language_info", "language_package"]
|
|
9592
|
+
},
|
|
9593
|
+
{
|
|
9594
|
+
id: "verification.run",
|
|
9595
|
+
pack: "development",
|
|
9596
|
+
exposure: "direct",
|
|
9597
|
+
tools: ["lint", "format", "typecheck", "test", "e2e_plan"]
|
|
9598
|
+
},
|
|
9599
|
+
{
|
|
9600
|
+
id: "version-control.manage",
|
|
9601
|
+
pack: "development",
|
|
9602
|
+
exposure: "direct",
|
|
9603
|
+
tools: ["git"]
|
|
9604
|
+
},
|
|
9605
|
+
{
|
|
9606
|
+
id: "dependencies.manage",
|
|
9607
|
+
pack: "development",
|
|
9608
|
+
exposure: "on-demand",
|
|
9609
|
+
tools: ["install", "outdated", "audit"]
|
|
9610
|
+
},
|
|
9611
|
+
{
|
|
9612
|
+
id: "documentation.author",
|
|
9613
|
+
pack: "development",
|
|
9614
|
+
exposure: "on-demand",
|
|
9615
|
+
tools: ["document", "design", "scaffold"]
|
|
9616
|
+
},
|
|
9617
|
+
{
|
|
9618
|
+
id: "web.research",
|
|
9619
|
+
pack: "core",
|
|
9620
|
+
exposure: "direct",
|
|
9621
|
+
tools: ["search", "fetch"]
|
|
9622
|
+
},
|
|
9623
|
+
{
|
|
9624
|
+
id: "work.plan",
|
|
9625
|
+
pack: "core",
|
|
9626
|
+
exposure: "direct",
|
|
9627
|
+
tools: ["todo", "plan", "task", "kanban", "nextsteps"]
|
|
9628
|
+
},
|
|
9629
|
+
{
|
|
9630
|
+
id: "coordination.mailbox",
|
|
9631
|
+
pack: "fleet",
|
|
9632
|
+
exposure: "direct",
|
|
9633
|
+
tools: ["mailbox", "mail_send", "mail_inbox", "fleet_status"]
|
|
9634
|
+
},
|
|
9635
|
+
{
|
|
9636
|
+
id: "fleet.delegate",
|
|
9637
|
+
pack: "fleet",
|
|
9638
|
+
exposure: "on-demand",
|
|
9639
|
+
tools: [
|
|
9640
|
+
"delegate",
|
|
9641
|
+
"spawn_subagent",
|
|
9642
|
+
"assign_task",
|
|
9643
|
+
"kanban_queue",
|
|
9644
|
+
"await_tasks",
|
|
9645
|
+
"ask_subagent",
|
|
9646
|
+
"ask_result",
|
|
9647
|
+
"roll_up",
|
|
9648
|
+
"quality_gate",
|
|
9649
|
+
"terminate_subagent",
|
|
9650
|
+
"terminate_all",
|
|
9651
|
+
"work_complete",
|
|
9652
|
+
"collab_debug",
|
|
9653
|
+
"fleet_emit",
|
|
9654
|
+
"fleet"
|
|
9655
|
+
]
|
|
9656
|
+
},
|
|
9657
|
+
{
|
|
9658
|
+
id: "reasoning.oneshot",
|
|
9659
|
+
pack: "core",
|
|
9660
|
+
exposure: "on-demand",
|
|
9661
|
+
tools: ["llm", "council"]
|
|
9662
|
+
},
|
|
9663
|
+
{
|
|
9664
|
+
id: "memory.manage",
|
|
9665
|
+
pack: "memory",
|
|
9666
|
+
exposure: "on-demand",
|
|
9667
|
+
tools: ["remember", "search_memory", "find_related_memories", "forget"]
|
|
9668
|
+
},
|
|
9669
|
+
{
|
|
9670
|
+
id: "memory.curate",
|
|
9671
|
+
pack: "memory",
|
|
9672
|
+
exposure: "on-demand",
|
|
9673
|
+
tools: [
|
|
9674
|
+
"memory_candidates",
|
|
9675
|
+
"memory_update",
|
|
9676
|
+
"memory_delete",
|
|
9677
|
+
"memory_recover",
|
|
9678
|
+
"memory_backfill_recoverable",
|
|
9679
|
+
"memory_for_file",
|
|
9680
|
+
"memory_for_path",
|
|
9681
|
+
"memory_search",
|
|
9682
|
+
"memory_graph",
|
|
9683
|
+
"memory_gather_batch",
|
|
9684
|
+
"memory_verify",
|
|
9685
|
+
"memory_hygiene"
|
|
9686
|
+
]
|
|
9687
|
+
},
|
|
9688
|
+
{
|
|
9689
|
+
id: "browser.interact",
|
|
9690
|
+
pack: "browser",
|
|
9691
|
+
exposure: "on-demand",
|
|
9692
|
+
tools: [
|
|
9693
|
+
"browser_open",
|
|
9694
|
+
"browser_status",
|
|
9695
|
+
"browser_list",
|
|
9696
|
+
"browser_navigate",
|
|
9697
|
+
"browser_snapshot",
|
|
9698
|
+
"browser_screenshot",
|
|
9699
|
+
"browser_click",
|
|
9700
|
+
"browser_type",
|
|
9701
|
+
"browser_select",
|
|
9702
|
+
"browser_press",
|
|
9703
|
+
"browser_hover",
|
|
9704
|
+
"browser_drag",
|
|
9705
|
+
"browser_wait",
|
|
9706
|
+
"browser_evaluate",
|
|
9707
|
+
"browser_upload",
|
|
9708
|
+
"browser_close"
|
|
9709
|
+
],
|
|
9710
|
+
aliases: PLAYWRIGHT_ALIASES
|
|
9711
|
+
},
|
|
9712
|
+
{
|
|
9713
|
+
id: "mcp.dynamic",
|
|
9714
|
+
pack: "mcp",
|
|
9715
|
+
exposure: "on-demand",
|
|
9716
|
+
tools: ["mcp_use"]
|
|
9717
|
+
},
|
|
9718
|
+
{
|
|
9719
|
+
id: "automation.manage",
|
|
9720
|
+
pack: "admin",
|
|
9721
|
+
exposure: "on-demand",
|
|
9722
|
+
tools: ["cron_schedule", "cron_list", "cron_cancel", "watch_start", "watch_list", "watch_stop"]
|
|
9723
|
+
},
|
|
9724
|
+
{
|
|
9725
|
+
id: "context.pin",
|
|
9726
|
+
pack: "admin",
|
|
9727
|
+
exposure: "on-demand",
|
|
9728
|
+
tools: ["pin_add", "pin_list", "pin_remove"]
|
|
9729
|
+
},
|
|
9730
|
+
{
|
|
9731
|
+
id: "quality.analyze",
|
|
9732
|
+
pack: "development",
|
|
9733
|
+
exposure: "on-demand",
|
|
9734
|
+
tools: ["dead_code_scan", "detect_duplicate_code", "secret_scanner_test", "error_lens_history"]
|
|
9735
|
+
},
|
|
9736
|
+
{
|
|
9737
|
+
id: "release.manage",
|
|
9738
|
+
pack: "development",
|
|
9739
|
+
exposure: "on-demand",
|
|
9740
|
+
tools: ["git_autocommit", "semver_current", "semver_bump", "semver_changelog"]
|
|
9741
|
+
},
|
|
9742
|
+
{
|
|
9743
|
+
id: "messaging.telegram",
|
|
9744
|
+
pack: "fleet",
|
|
9745
|
+
exposure: "on-demand",
|
|
9746
|
+
tools: ["telegram_send", "telegram_read", "telegram_approve"]
|
|
9747
|
+
},
|
|
9748
|
+
{
|
|
9749
|
+
id: "tools.discover",
|
|
9750
|
+
pack: "admin",
|
|
9751
|
+
exposure: "direct",
|
|
9752
|
+
tools: ["tool_search", "tool_use", "tool_help", "batch_tool_use"]
|
|
9753
|
+
},
|
|
9754
|
+
{
|
|
9755
|
+
id: "runtime.admin",
|
|
9756
|
+
pack: "admin",
|
|
9757
|
+
exposure: "internal",
|
|
9758
|
+
tools: ["set_working_dir", "context_manager", "mode", "skill", "mcp_control"]
|
|
9759
|
+
}
|
|
9760
|
+
];
|
|
9761
|
+
var CAPABILITY_BY_ID = new Map(
|
|
9762
|
+
RUNTIME_CAPABILITY_MANIFEST.map((definition) => [definition.id, definition])
|
|
9763
|
+
);
|
|
9764
|
+
var CAPABILITY_BY_TOOL = /* @__PURE__ */ new Map();
|
|
9765
|
+
var TOOL_ALIASES = /* @__PURE__ */ new Map();
|
|
9766
|
+
for (const definition of RUNTIME_CAPABILITY_MANIFEST) {
|
|
9767
|
+
for (const tool of definition.tools) {
|
|
9768
|
+
CAPABILITY_BY_TOOL.set(tool, definition.id);
|
|
9769
|
+
}
|
|
9770
|
+
for (const [alias, tool] of Object.entries(definition.aliases ?? {})) {
|
|
9771
|
+
TOOL_ALIASES.set(alias, tool);
|
|
9772
|
+
}
|
|
9773
|
+
}
|
|
9774
|
+
function normalizeRuntimeToolName(name) {
|
|
9775
|
+
return TOOL_ALIASES.get(name) ?? name;
|
|
9776
|
+
}
|
|
9777
|
+
function runtimeCapabilityForTool(name) {
|
|
9778
|
+
return CAPABILITY_BY_TOOL.get(normalizeRuntimeToolName(name));
|
|
9779
|
+
}
|
|
9780
|
+
function inferRuntimeCapabilities(toolNames) {
|
|
9781
|
+
const ids = /* @__PURE__ */ new Set();
|
|
9782
|
+
for (const rawName of toolNames) {
|
|
9783
|
+
const id = runtimeCapabilityForTool(rawName);
|
|
9784
|
+
if (id) ids.add(id);
|
|
9785
|
+
}
|
|
9786
|
+
return [...ids];
|
|
9787
|
+
}
|
|
9788
|
+
function missingRuntimeCapabilities(required, toolNames) {
|
|
9789
|
+
if (!required || required.length === 0) return [];
|
|
9790
|
+
const available = new Set(inferRuntimeCapabilities(toolNames));
|
|
9791
|
+
return required.filter((id) => !CAPABILITY_BY_ID.has(id) || !available.has(id));
|
|
9792
|
+
}
|
|
9793
|
+
function missingRequiredRuntimeTools(required, toolNames) {
|
|
9794
|
+
if (!required || required.length === 0) return [];
|
|
9795
|
+
const available = new Set(toolNames.map(normalizeRuntimeToolName));
|
|
9796
|
+
return required.map(normalizeRuntimeToolName).filter((name) => !CAPABILITY_BY_TOOL.has(name) || !available.has(name));
|
|
9797
|
+
}
|
|
9798
|
+
function runtimeToolReferencesFromText(text) {
|
|
9799
|
+
const references = /* @__PURE__ */ new Set();
|
|
9800
|
+
for (const match of text.matchAll(/`([a-z][a-z0-9_-]+)`/gi)) {
|
|
9801
|
+
const name = normalizeRuntimeToolName(match[1] ?? "");
|
|
9802
|
+
if (CAPABILITY_BY_TOOL.has(name)) references.add(name);
|
|
9803
|
+
}
|
|
9804
|
+
for (const pattern of [
|
|
9805
|
+
/\b(?:call|use|invoke|run)\s+`([a-z][a-z0-9_-]+)`/gi,
|
|
9806
|
+
/`([a-z][a-z0-9_-]+)`\s+tool\b/gi
|
|
9807
|
+
]) {
|
|
9808
|
+
for (const match of text.matchAll(pattern)) {
|
|
9809
|
+
references.add(normalizeRuntimeToolName(match[1] ?? ""));
|
|
9810
|
+
}
|
|
9811
|
+
}
|
|
9812
|
+
return [...references];
|
|
9813
|
+
}
|
|
9814
|
+
|
|
9309
9815
|
// src/core/instruction-template.ts
|
|
9816
|
+
var CANONICAL_TOOL_NAMES = new Set(
|
|
9817
|
+
RUNTIME_CAPABILITY_MANIFEST.flatMap((entry) => [...entry.tools])
|
|
9818
|
+
);
|
|
9310
9819
|
var DIRECTIVE_RE = /[ \t]*<!--\s*ws:(if|else|end)\b([^>]*?)-->[ \t]*(?:\r?\n)?/g;
|
|
9311
9820
|
var PLACEHOLDER_RE = /\{\{\s*(tools:)?\s*([a-zA-Z0-9_.,\s-]+?)\s*\}\}/g;
|
|
9312
9821
|
function renderInstructionLayer(text, ctx) {
|
|
@@ -9316,7 +9825,41 @@ function renderInstructionLayer(text, ctx) {
|
|
|
9316
9825
|
if (!hasDirectives && !hasPlaceholders) return text;
|
|
9317
9826
|
const rendered = hasDirectives ? emit(parse(text), ctx) : text;
|
|
9318
9827
|
const substituted = hasPlaceholders ? substitute(rendered, ctx) : rendered;
|
|
9319
|
-
|
|
9828
|
+
const guarded = ctx?.strictToolReferences ? dropLinesWithUnavailableToolReferences(
|
|
9829
|
+
substituted,
|
|
9830
|
+
ctx,
|
|
9831
|
+
/* @__PURE__ */ new Set([...CANONICAL_TOOL_NAMES, ...declaredToolNames(text)])
|
|
9832
|
+
) : substituted;
|
|
9833
|
+
return tidy(guarded);
|
|
9834
|
+
}
|
|
9835
|
+
function declaredToolNames(text) {
|
|
9836
|
+
const names = /* @__PURE__ */ new Set();
|
|
9837
|
+
for (const marker of text.matchAll(/<!--\s*ws:if\b([^>]*?)-->/g)) {
|
|
9838
|
+
for (const attr of (marker[1] ?? "").matchAll(/!?tool=([A-Za-z0-9_.,-]+)/g)) {
|
|
9839
|
+
for (const name of (attr[1] ?? "").split(",")) if (name.trim()) names.add(name.trim());
|
|
9840
|
+
}
|
|
9841
|
+
}
|
|
9842
|
+
for (const placeholder of text.matchAll(/\{\{\s*tools:\s*([^}]+)}}/g)) {
|
|
9843
|
+
for (const name of (placeholder[1] ?? "").split(",")) if (name.trim()) names.add(name.trim());
|
|
9844
|
+
}
|
|
9845
|
+
return names;
|
|
9846
|
+
}
|
|
9847
|
+
function dropLinesWithUnavailableToolReferences(text, ctx, declared) {
|
|
9848
|
+
const unavailable = [...declared].filter((name) => !ctx.toolNames.has(name));
|
|
9849
|
+
if (unavailable.length === 0) return text;
|
|
9850
|
+
return text.split(/(?<=\n)/).filter((line) => !unavailable.some((name) => formattedToolMention(line, name))).join("");
|
|
9851
|
+
}
|
|
9852
|
+
function formattedToolMention(line, name) {
|
|
9853
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9854
|
+
const token = new RegExp(`(?<![\\w-])${escaped}(?![\\w-])`);
|
|
9855
|
+
if (line.split("`").some((segment, index) => {
|
|
9856
|
+
if (index % 2 !== 1) return false;
|
|
9857
|
+
if (segment.includes(`<${name}`) || segment.includes(`</${name}`)) return false;
|
|
9858
|
+
return token.test(segment);
|
|
9859
|
+
})) {
|
|
9860
|
+
return true;
|
|
9861
|
+
}
|
|
9862
|
+
return line.split("**").some((segment, index) => index % 2 === 1 && segment.trim() === name);
|
|
9320
9863
|
}
|
|
9321
9864
|
function parse(text) {
|
|
9322
9865
|
const root = [];
|
|
@@ -9401,6 +9944,37 @@ function tidy(text) {
|
|
|
9401
9944
|
return text.replace(/(\r?\n){3,}/g, "$1$1");
|
|
9402
9945
|
}
|
|
9403
9946
|
|
|
9947
|
+
// src/types/config/runtime.ts
|
|
9948
|
+
function normalizeTokenSavingTier(val) {
|
|
9949
|
+
if (val === void 0) return "off";
|
|
9950
|
+
if (typeof val === "boolean") return val ? "medium" : "off";
|
|
9951
|
+
if (val === "auto") return "medium";
|
|
9952
|
+
const validTiers = /* @__PURE__ */ new Set([
|
|
9953
|
+
"off",
|
|
9954
|
+
"minimal",
|
|
9955
|
+
"light",
|
|
9956
|
+
"medium",
|
|
9957
|
+
"aggressive"
|
|
9958
|
+
]);
|
|
9959
|
+
return validTiers.has(val) ? val : "off";
|
|
9960
|
+
}
|
|
9961
|
+
function resolveTokenSavingTier(val, maxContext) {
|
|
9962
|
+
if (val === "auto") {
|
|
9963
|
+
if (typeof maxContext !== "number" || !Number.isFinite(maxContext) || maxContext <= 0) {
|
|
9964
|
+
return "off";
|
|
9965
|
+
}
|
|
9966
|
+
if (maxContext < 32e3) return "medium";
|
|
9967
|
+
if (maxContext < 128e3) return "light";
|
|
9968
|
+
return "minimal";
|
|
9969
|
+
}
|
|
9970
|
+
return normalizeTokenSavingTier(val);
|
|
9971
|
+
}
|
|
9972
|
+
|
|
9973
|
+
// src/types/system-prompt.ts
|
|
9974
|
+
function flattenSystemPromptRegions(regions) {
|
|
9975
|
+
return [...regions.core, ...regions.session, ...regions.volatile];
|
|
9976
|
+
}
|
|
9977
|
+
|
|
9404
9978
|
// src/core/modes/default.ts
|
|
9405
9979
|
import { readFileSync as readFileSync6, statSync as statSync3 } from "node:fs";
|
|
9406
9980
|
import * as path12 from "node:path";
|
|
@@ -9795,7 +10369,8 @@ async function buildEnvironment(ctx, env) {
|
|
|
9795
10369
|
modelCapabilities?.maxContextTokens ?? 0,
|
|
9796
10370
|
modelCapabilities?.supportsTools ? 1 : 0,
|
|
9797
10371
|
modelCapabilities?.supportsVision ? 1 : 0,
|
|
9798
|
-
modelCapabilities?.supportsReasoning ? 1 : 0
|
|
10372
|
+
modelCapabilities?.supportsReasoning ? 1 : 0,
|
|
10373
|
+
env.skillCache ?? ""
|
|
9799
10374
|
].join("\0");
|
|
9800
10375
|
const cached = env.envCacheByRoot.get(cacheKey);
|
|
9801
10376
|
if (cached) {
|
|
@@ -9854,7 +10429,7 @@ async function buildEnvironment(ctx, env) {
|
|
|
9854
10429
|
lines.push(`- Mode: ${env.modeId}`);
|
|
9855
10430
|
}
|
|
9856
10431
|
}
|
|
9857
|
-
if (effShell !== "posix" && tier !== "minimal") {
|
|
10432
|
+
if (ctx.tools.some((tool) => tool.name === "bash") && effShell !== "posix" && tier !== "minimal") {
|
|
9858
10433
|
const guide = shellGuidanceBlock(effShell, tier === "light" ? "short" : "full");
|
|
9859
10434
|
if (guide) lines.push("", guide);
|
|
9860
10435
|
}
|
|
@@ -10028,7 +10603,7 @@ function foreignProvenanceTag(source, originTool) {
|
|
|
10028
10603
|
const origin = source === "foreign" && originTool ? originTool : source;
|
|
10029
10604
|
return ` [foreign skill: ${origin}]`;
|
|
10030
10605
|
}
|
|
10031
|
-
async function buildProgressiveSkillManifestText(loader) {
|
|
10606
|
+
async function buildProgressiveSkillManifestText(loader, availableToolNames = []) {
|
|
10032
10607
|
try {
|
|
10033
10608
|
const entries = await loader.listEntries();
|
|
10034
10609
|
if (entries.length === 0) return "";
|
|
@@ -10038,7 +10613,12 @@ async function buildProgressiveSkillManifestText(loader) {
|
|
|
10038
10613
|
"| Skill | Use when |",
|
|
10039
10614
|
"|---|---|"
|
|
10040
10615
|
];
|
|
10616
|
+
const manifests = new Map((await loader.list()).map((manifest) => [manifest.name, manifest]));
|
|
10041
10617
|
for (const e of entries) {
|
|
10618
|
+
const manifest = manifests.get(e.name);
|
|
10619
|
+
if (manifest && (missingRuntimeCapabilities(manifest.requiredCapabilities, availableToolNames).length > 0 || missingRequiredRuntimeTools(manifest.requiredTools, availableToolNames).length > 0)) {
|
|
10620
|
+
continue;
|
|
10621
|
+
}
|
|
10042
10622
|
const trigger = (e.trigger ?? "").replace(/\|/g, "\\|").replace(/\n+/g, " ").trim();
|
|
10043
10623
|
lines.push(`| \`${e.name}\`${foreignProvenanceTag(e.source, e.originTool)} | ${trigger} |`);
|
|
10044
10624
|
}
|
|
@@ -10047,7 +10627,7 @@ async function buildProgressiveSkillManifestText(loader) {
|
|
|
10047
10627
|
return "";
|
|
10048
10628
|
}
|
|
10049
10629
|
}
|
|
10050
|
-
async function buildFullSkillBodiesText(loader, budget = SKILL_LIMITS.EAGER_DEFAULT_MAX_CHARS) {
|
|
10630
|
+
async function buildFullSkillBodiesText(loader, budget = SKILL_LIMITS.EAGER_DEFAULT_MAX_CHARS, availableToolNames = []) {
|
|
10051
10631
|
try {
|
|
10052
10632
|
const skills = await loader.list();
|
|
10053
10633
|
if (skills.length === 0) return "";
|
|
@@ -10055,10 +10635,16 @@ async function buildFullSkillBodiesText(loader, budget = SKILL_LIMITS.EAGER_DEFA
|
|
|
10055
10635
|
const overflow = [];
|
|
10056
10636
|
let used = 0;
|
|
10057
10637
|
for (const s of skills) {
|
|
10638
|
+
if (missingRuntimeCapabilities(s.requiredCapabilities, availableToolNames).length > 0 || missingRequiredRuntimeTools(s.requiredTools, availableToolNames).length > 0) {
|
|
10639
|
+
continue;
|
|
10640
|
+
}
|
|
10058
10641
|
try {
|
|
10059
10642
|
const raw = await loader.readBody(s.name);
|
|
10060
10643
|
const trimmed = stripFrontmatter(raw).trim();
|
|
10061
10644
|
if (!trimmed) continue;
|
|
10645
|
+
if (missingRequiredRuntimeTools(runtimeToolReferencesFromText(trimmed), availableToolNames).length > 0) {
|
|
10646
|
+
continue;
|
|
10647
|
+
}
|
|
10062
10648
|
const entry = `## Skill: ${s.name}${foreignProvenanceTag(s.source, s.originTool)}
|
|
10063
10649
|
|
|
10064
10650
|
${capSkillBody(trimmed)}`;
|
|
@@ -10082,7 +10668,7 @@ ${overflow.join("\n")}`;
|
|
|
10082
10668
|
return "";
|
|
10083
10669
|
}
|
|
10084
10670
|
}
|
|
10085
|
-
async function buildCompactSkillBodiesText(loader, budget = SKILL_LIMITS.COMPACT_DEFAULT_MAX_CHARS) {
|
|
10671
|
+
async function buildCompactSkillBodiesText(loader, budget = SKILL_LIMITS.COMPACT_DEFAULT_MAX_CHARS, availableToolNames = []) {
|
|
10086
10672
|
try {
|
|
10087
10673
|
const skills = await loader.list();
|
|
10088
10674
|
if (skills.length === 0) return "";
|
|
@@ -10090,10 +10676,16 @@ async function buildCompactSkillBodiesText(loader, budget = SKILL_LIMITS.COMPACT
|
|
|
10090
10676
|
const overflow = [];
|
|
10091
10677
|
let used = 0;
|
|
10092
10678
|
for (const s of skills) {
|
|
10679
|
+
if (missingRuntimeCapabilities(s.requiredCapabilities, availableToolNames).length > 0 || missingRequiredRuntimeTools(s.requiredTools, availableToolNames).length > 0) {
|
|
10680
|
+
continue;
|
|
10681
|
+
}
|
|
10093
10682
|
try {
|
|
10094
10683
|
const saveBody = await loader.readSaveBody(s.name);
|
|
10095
10684
|
const clean = stripFrontmatter(saveBody).trim();
|
|
10096
10685
|
if (!clean) continue;
|
|
10686
|
+
if (missingRequiredRuntimeTools(runtimeToolReferencesFromText(clean), availableToolNames).length > 0) {
|
|
10687
|
+
continue;
|
|
10688
|
+
}
|
|
10097
10689
|
const entry = `## Skill: ${s.name}${foreignProvenanceTag(s.source, s.originTool)}
|
|
10098
10690
|
|
|
10099
10691
|
${clean}`;
|
|
@@ -10191,11 +10783,22 @@ ${memText}`);
|
|
|
10191
10783
|
}
|
|
10192
10784
|
if (mem.skillLoader) {
|
|
10193
10785
|
if (mem.skillMode === "progressive") {
|
|
10194
|
-
skillBodyCache = await buildProgressiveSkillManifestText(
|
|
10786
|
+
skillBodyCache = await buildProgressiveSkillManifestText(
|
|
10787
|
+
mem.skillLoader,
|
|
10788
|
+
mem.catalogTools?.map((tool) => tool.name) ?? []
|
|
10789
|
+
);
|
|
10195
10790
|
} else if (mem.isCompact) {
|
|
10196
|
-
skillBodyCache = await buildCompactSkillBodiesText(
|
|
10791
|
+
skillBodyCache = await buildCompactSkillBodiesText(
|
|
10792
|
+
mem.skillLoader,
|
|
10793
|
+
void 0,
|
|
10794
|
+
mem.catalogTools?.map((tool) => tool.name) ?? []
|
|
10795
|
+
);
|
|
10197
10796
|
} else {
|
|
10198
|
-
skillBodyCache = await buildFullSkillBodiesText(
|
|
10797
|
+
skillBodyCache = await buildFullSkillBodiesText(
|
|
10798
|
+
mem.skillLoader,
|
|
10799
|
+
mem.skillEagerMaxChars,
|
|
10800
|
+
mem.catalogTools?.map((tool) => tool.name) ?? []
|
|
10801
|
+
);
|
|
10199
10802
|
}
|
|
10200
10803
|
}
|
|
10201
10804
|
if (skillBodyCache) {
|
|
@@ -10282,6 +10885,8 @@ var DefaultSystemPromptBuilder = class {
|
|
|
10282
10885
|
skillBodyCache;
|
|
10283
10886
|
/** Tools from last build — used for memory relevance scoring. */
|
|
10284
10887
|
_lastBuildTools;
|
|
10888
|
+
/** Full executable catalog used to capability-gate progressive skills. */
|
|
10889
|
+
_lastCatalogTools;
|
|
10285
10890
|
/** Cached rendered online agents string, keyed by content fingerprint. */
|
|
10286
10891
|
_lastOnlineAgents;
|
|
10287
10892
|
/** Cached full buildToolUsage output — keyed by tools array ref + agents fingerprint + tier. */
|
|
@@ -10341,12 +10946,26 @@ var DefaultSystemPromptBuilder = class {
|
|
|
10341
10946
|
}
|
|
10342
10947
|
async buildRegions(ctx) {
|
|
10343
10948
|
this._lastBuildTools = ctx.tools;
|
|
10949
|
+
this._lastCatalogTools = ctx.catalogTools ?? ctx.tools;
|
|
10344
10950
|
if (this.opts.skillLoader) {
|
|
10345
10951
|
try {
|
|
10346
10952
|
const entries = await this.opts.skillLoader.listEntries();
|
|
10953
|
+
const manifests = new Map(
|
|
10954
|
+
(await this.opts.skillLoader.list()).map((manifest) => [manifest.name, manifest])
|
|
10955
|
+
);
|
|
10347
10956
|
if (entries.length > 0) {
|
|
10348
10957
|
const lines = [];
|
|
10349
10958
|
for (const e of entries) {
|
|
10959
|
+
const manifest = manifests.get(e.name);
|
|
10960
|
+
if (manifest && (missingRuntimeCapabilities(
|
|
10961
|
+
manifest.requiredCapabilities,
|
|
10962
|
+
this._lastCatalogTools?.map((tool) => tool.name) ?? []
|
|
10963
|
+
).length > 0 || missingRequiredRuntimeTools(
|
|
10964
|
+
manifest.requiredTools,
|
|
10965
|
+
this._lastCatalogTools?.map((tool) => tool.name) ?? []
|
|
10966
|
+
).length > 0)) {
|
|
10967
|
+
continue;
|
|
10968
|
+
}
|
|
10350
10969
|
const shortTrigger = compactTrigger(e.trigger);
|
|
10351
10970
|
lines.push(`- **${e.name}** (${shortTrigger})`);
|
|
10352
10971
|
}
|
|
@@ -10371,14 +10990,8 @@ var DefaultSystemPromptBuilder = class {
|
|
|
10371
10990
|
const layer5 = await this.buildMode();
|
|
10372
10991
|
const layer6 = ctx.subagent ? "" : await this.buildActivePlan();
|
|
10373
10992
|
const core = [
|
|
10374
|
-
tagBlock(
|
|
10375
|
-
|
|
10376
|
-
"identity"
|
|
10377
|
-
),
|
|
10378
|
-
tagBlock(
|
|
10379
|
-
{ type: "text", text: layer2, cache_control: { type: "ephemeral" } },
|
|
10380
|
-
"tool-usage"
|
|
10381
|
-
)
|
|
10993
|
+
tagBlock({ type: "text", text: layer1, cache_control: { type: "ephemeral" } }, "identity"),
|
|
10994
|
+
tagBlock({ type: "text", text: layer2, cache_control: { type: "ephemeral" } }, "tool-usage")
|
|
10382
10995
|
];
|
|
10383
10996
|
const session = [
|
|
10384
10997
|
tagBlock(
|
|
@@ -10389,18 +11002,12 @@ var DefaultSystemPromptBuilder = class {
|
|
|
10389
11002
|
const volatile = [];
|
|
10390
11003
|
if (layer4.trim()) {
|
|
10391
11004
|
session.push(
|
|
10392
|
-
tagBlock(
|
|
10393
|
-
{ type: "text", text: layer4, cache_control: { type: "ephemeral" } },
|
|
10394
|
-
"skills"
|
|
10395
|
-
)
|
|
11005
|
+
tagBlock({ type: "text", text: layer4, cache_control: { type: "ephemeral" } }, "skills")
|
|
10396
11006
|
);
|
|
10397
11007
|
}
|
|
10398
11008
|
if (layer5.trim()) {
|
|
10399
11009
|
session.push(
|
|
10400
|
-
tagBlock(
|
|
10401
|
-
{ type: "text", text: layer5, cache_control: { type: "ephemeral" } },
|
|
10402
|
-
"mode"
|
|
10403
|
-
)
|
|
11010
|
+
tagBlock({ type: "text", text: layer5, cache_control: { type: "ephemeral" } }, "mode")
|
|
10404
11011
|
);
|
|
10405
11012
|
}
|
|
10406
11013
|
if (this.opts.modeStore && this.opts.skillLoader) {
|
|
@@ -10428,10 +11035,7 @@ var DefaultSystemPromptBuilder = class {
|
|
|
10428
11035
|
}
|
|
10429
11036
|
if (layer6.trim()) {
|
|
10430
11037
|
volatile.push(
|
|
10431
|
-
tagBlock(
|
|
10432
|
-
{ type: "text", text: layer6, cache_control: { type: "ephemeral" } },
|
|
10433
|
-
"plan"
|
|
10434
|
-
)
|
|
11038
|
+
tagBlock({ type: "text", text: layer6, cache_control: { type: "ephemeral" } }, "plan")
|
|
10435
11039
|
);
|
|
10436
11040
|
}
|
|
10437
11041
|
if (this.opts.contributors && this.opts.contributors.length > 0) {
|
|
@@ -10469,7 +11073,8 @@ var DefaultSystemPromptBuilder = class {
|
|
|
10469
11073
|
return {
|
|
10470
11074
|
toolNames: new Set(ctx.tools.map((t2) => t2.name)),
|
|
10471
11075
|
tier: this.tier,
|
|
10472
|
-
subagent: ctx.subagent === true
|
|
11076
|
+
subagent: ctx.subagent === true,
|
|
11077
|
+
strictToolReferences: true
|
|
10473
11078
|
};
|
|
10474
11079
|
}
|
|
10475
11080
|
/**
|
|
@@ -10582,7 +11187,15 @@ ${hint.trim()}`);
|
|
|
10582
11187
|
}
|
|
10583
11188
|
if (this.tier !== "minimal" && this.tier !== "aggressive") {
|
|
10584
11189
|
const commonPatterns = section("tool.common.patterns");
|
|
10585
|
-
if (commonPatterns)
|
|
11190
|
+
if (commonPatterns) {
|
|
11191
|
+
lines.push(
|
|
11192
|
+
renderInstructionLayer(commonPatterns, {
|
|
11193
|
+
toolNames: new Set(tools.map((tool) => tool.name)),
|
|
11194
|
+
tier: this.tier,
|
|
11195
|
+
subagent: ctx.subagent === true
|
|
11196
|
+
})
|
|
11197
|
+
);
|
|
11198
|
+
}
|
|
10586
11199
|
}
|
|
10587
11200
|
const hasDelegate = tools.some((t2) => t2.name === "delegate");
|
|
10588
11201
|
if (hasDelegate) {
|
|
@@ -10621,10 +11234,7 @@ ${hint.trim()}`);
|
|
|
10621
11234
|
mailSendCommand
|
|
10622
11235
|
};
|
|
10623
11236
|
if (this.tier !== "off") {
|
|
10624
|
-
const mailbox = section(
|
|
10625
|
-
"tool.mailbox.compact",
|
|
10626
|
-
mailboxVars
|
|
10627
|
-
);
|
|
11237
|
+
const mailbox = section("tool.mailbox.compact", mailboxVars);
|
|
10628
11238
|
if (mailbox) lines.push(mailbox);
|
|
10629
11239
|
} else {
|
|
10630
11240
|
const mailbox = section("tool.mailbox.full", mailboxVars);
|
|
@@ -10640,14 +11250,10 @@ ${hint.trim()}`);
|
|
|
10640
11250
|
const hasMcpUse = tools.some((t2) => t2.name === "mcp_use");
|
|
10641
11251
|
if (hasMcpControl) {
|
|
10642
11252
|
if (this.tier === "minimal" || this.tier === "light" || this.tier === "aggressive") {
|
|
10643
|
-
const mcp = section(
|
|
10644
|
-
hasMcpUse ? "tool.mcp.compact.use" : "tool.mcp.compact.control"
|
|
10645
|
-
);
|
|
11253
|
+
const mcp = section(hasMcpUse ? "tool.mcp.compact.use" : "tool.mcp.compact.control");
|
|
10646
11254
|
if (mcp) lines.push(mcp);
|
|
10647
11255
|
} else {
|
|
10648
|
-
const mcp = section(
|
|
10649
|
-
hasMcpUse ? "tool.mcp.full.use" : "tool.mcp.full.control"
|
|
10650
|
-
);
|
|
11256
|
+
const mcp = section(hasMcpUse ? "tool.mcp.full.use" : "tool.mcp.full.control");
|
|
10651
11257
|
if (mcp) lines.push(mcp);
|
|
10652
11258
|
}
|
|
10653
11259
|
}
|
|
@@ -10655,17 +11261,12 @@ ${hint.trim()}`);
|
|
|
10655
11261
|
if (hasContextManager) {
|
|
10656
11262
|
if (this.tier === "minimal" || this.tier === "light") {
|
|
10657
11263
|
} else if (this.tier === "medium") {
|
|
10658
|
-
const contextManagement = section(
|
|
10659
|
-
"tool.context.management.compact"
|
|
10660
|
-
);
|
|
11264
|
+
const contextManagement = section("tool.context.management.compact");
|
|
10661
11265
|
if (contextManagement) lines.push(contextManagement);
|
|
10662
11266
|
} else {
|
|
10663
11267
|
const maxCtx = this.modelCapabilities()?.maxContextTokens ?? 0;
|
|
10664
11268
|
const threshold = maxCtx <= 32e3 ? "50" : "70";
|
|
10665
|
-
const contextManagement = section(
|
|
10666
|
-
"tool.context.management.full",
|
|
10667
|
-
{ threshold }
|
|
10668
|
-
);
|
|
11269
|
+
const contextManagement = section("tool.context.management.full", { threshold });
|
|
10669
11270
|
if (contextManagement) lines.push(contextManagement);
|
|
10670
11271
|
}
|
|
10671
11272
|
}
|
|
@@ -10704,6 +11305,7 @@ ${hint.trim()}`);
|
|
|
10704
11305
|
skillMode: this.opts.skillMode,
|
|
10705
11306
|
skillEagerMaxChars: this.opts.skillEagerMaxChars,
|
|
10706
11307
|
lastBuildTools: this._lastBuildTools,
|
|
11308
|
+
catalogTools: this._lastCatalogTools,
|
|
10707
11309
|
skillBodyCache: this.skillBodyCache
|
|
10708
11310
|
});
|
|
10709
11311
|
this.skillBodyCache = result.skillBodyCache;
|
|
@@ -10724,7 +11326,9 @@ export {
|
|
|
10724
11326
|
DefaultSystemPromptBuilder,
|
|
10725
11327
|
FallbackProfileManager,
|
|
10726
11328
|
InputBuilder,
|
|
11329
|
+
MAX_PENDING_NEXT_STEPS,
|
|
10727
11330
|
buildBtwBlock,
|
|
11331
|
+
clearPendingNextSteps,
|
|
10728
11332
|
consumeBtwNotes,
|
|
10729
11333
|
createDefaultPipelines,
|
|
10730
11334
|
createFallbackModelExtension,
|
|
@@ -10732,16 +11336,21 @@ export {
|
|
|
10732
11336
|
effectiveFallbackChain,
|
|
10733
11337
|
fallbackProfileChain,
|
|
10734
11338
|
formatModelRef,
|
|
11339
|
+
hasNextStepsTag,
|
|
10735
11340
|
loadInstructionBundle,
|
|
11341
|
+
maybeAppendPendingNextSteps,
|
|
10736
11342
|
normalizeModelRef,
|
|
10737
11343
|
parseModelRef,
|
|
10738
11344
|
pendingBtwCount,
|
|
11345
|
+
readPendingNextSteps,
|
|
10739
11346
|
renderInstructionLayer,
|
|
11347
|
+
renderNextStepsBlock,
|
|
10740
11348
|
resolveContinuation,
|
|
10741
11349
|
runProviderWithRetry,
|
|
10742
11350
|
setBtwNote,
|
|
10743
11351
|
setQueuedMessagesSnapshot,
|
|
10744
11352
|
smartDefaultFallbackChain,
|
|
10745
|
-
wrapAsState
|
|
11353
|
+
wrapAsState,
|
|
11354
|
+
writePendingNextSteps
|
|
10746
11355
|
};
|
|
10747
11356
|
//# sourceMappingURL=index.js.map
|