@wrongstack/core 0.303.0 → 0.305.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/coordination/agents/index.js +530 -130
- package/dist/coordination/agents/project-agent-consolidation.d.ts +5 -0
- package/dist/coordination/agents/project-agent-directive-outcome.d.ts +57 -0
- package/dist/coordination/agents/project-agent-identity.d.ts +26 -12
- package/dist/coordination/agents/project-agent-learning-policy.d.ts +22 -1
- package/dist/coordination/agents/project-agent-learning-structured.d.ts +46 -1
- package/dist/coordination/agents/project-agent-quarantine.d.ts +63 -0
- package/dist/coordination/agents/project-agent-skill-layer.d.ts +55 -10
- package/dist/coordination/agents/types.d.ts +10 -2
- package/dist/coordination/director-prompts.d.ts +19 -6
- package/dist/coordination/director-tools.d.ts +2 -2
- package/dist/coordination/fleet.d.ts +0 -6
- package/dist/coordination/index.d.ts +1 -1
- package/dist/coordination/index.js +1579 -955
- package/dist/core/agent-types.d.ts +4 -2
- package/dist/core/agent.d.ts +1 -0
- package/dist/core/context.d.ts +15 -0
- package/dist/core/conversation-state.d.ts +14 -0
- package/dist/core/fallback-profile-manager.d.ts +70 -2
- package/dist/core/index.js +308 -108
- package/dist/core/system-prompt-blocks.d.ts +1 -1
- package/dist/core/system-prompt-builder.d.ts +13 -1
- package/dist/core/system-prompt-glossary.d.ts +73 -0
- package/dist/core/system-prompt-memory-skills.d.ts +2 -2
- package/dist/defaults/index.js +910 -693
- package/dist/execution/council-orchestrator.d.ts +3 -13
- package/dist/execution/index.js +211 -75
- package/dist/execution/one-shot-llm.d.ts +5 -0
- package/dist/hq/index.js +17 -7
- package/dist/hq/protocol/kanban.d.ts +21 -0
- package/dist/hq/protocol.js +5 -1
- package/dist/hq/redaction.d.ts +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3482 -2538
- package/dist/infrastructure/index.js +247 -122
- package/dist/plugin/index.js +101 -3
- package/dist/registry/index.js +11 -0
- package/dist/registry/tool-registry.d.ts +8 -0
- package/dist/replay/hash.d.ts +9 -0
- package/dist/replay/index.js +14 -4
- package/dist/replay/replay-provider-runner.d.ts +31 -1
- package/dist/security/index.js +25 -20
- package/dist/security/secret-vault.d.ts +2 -0
- package/dist/session-catalog/index.js +62 -8
- package/dist/session-catalog/project-server.js +73 -13
- package/dist/session-catalog/protocol.d.ts +11 -4
- package/dist/session-catalog/store.d.ts +2 -2
- package/dist/storage/index.js +224 -67
- package/dist/storage/memory-consolidator.d.ts +4 -2
- package/dist/storage/session-resume-validation.d.ts +24 -0
- package/dist/storage/session-store/directory-scan.d.ts +5 -1
- package/dist/storage/session-store/fork-session.d.ts +13 -1
- package/dist/storage/session-store/load-cache.d.ts +11 -0
- package/dist/storage/session-store/prune-helpers.d.ts +5 -0
- package/dist/storage/session-store.d.ts +18 -0
- package/dist/tools/index.js +174 -74
- package/dist/types/config/mcp-features.d.ts +31 -1
- package/dist/types/config/root.d.ts +12 -0
- package/dist/types/config/tools.d.ts +22 -0
- package/dist/types/default-config.d.ts +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/session.d.ts +9 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +214 -76
- package/dist/utils/project-state-guard.d.ts +21 -0
- package/dist/utils/session-scoped-path.d.ts +17 -0
- package/dist/utils/todos-format.d.ts +20 -0
- package/instructions/leader-after-task.md +3 -4
- package/instructions/system-lite.md +10 -13
- package/instructions/system-pro.md +18 -25
- package/instructions/system.md +18 -23
- package/package.json +3 -3
- package/skills/wrongstack-kanban/SKILL.md +95 -124
package/dist/core/index.js
CHANGED
|
@@ -2177,12 +2177,11 @@ function redactHqValueInternal(value, options, preserveRawContentKeys) {
|
|
|
2177
2177
|
});
|
|
2178
2178
|
return { value: result.value, redacted: result.redacted };
|
|
2179
2179
|
}
|
|
2180
|
+
function redactHqEventPayload(type, payload, options = {}) {
|
|
2181
|
+
return redactHqValueInternal(payload, options, HQ_PROJECT_STATE_EVENT_TYPES.has(type));
|
|
2182
|
+
}
|
|
2180
2183
|
function redactHqEvent(event, options = {}) {
|
|
2181
|
-
const payload =
|
|
2182
|
-
event.payload,
|
|
2183
|
-
options,
|
|
2184
|
-
HQ_PROJECT_STATE_EVENT_TYPES.has(event.type)
|
|
2185
|
-
);
|
|
2184
|
+
const payload = redactHqEventPayload(event.type, event.payload, options);
|
|
2186
2185
|
const nextEvent = {
|
|
2187
2186
|
...event,
|
|
2188
2187
|
payload: payload.value
|
|
@@ -2334,7 +2333,9 @@ function queuedFrameCoalesceKey(frame) {
|
|
|
2334
2333
|
if (frame.type !== "client.event" || !frame.event.type.endsWith(".snapshot")) {
|
|
2335
2334
|
return void 0;
|
|
2336
2335
|
}
|
|
2337
|
-
|
|
2336
|
+
const payload = frame.event.payload;
|
|
2337
|
+
const chunk = typeof payload?.chunkIndex === "number" && Number.isFinite(payload.chunkIndex) ? String(payload.chunkIndex) : "";
|
|
2338
|
+
return [frame.event.type, frame.event.sessionId ?? "", frame.event.runId ?? "", chunk].join("|");
|
|
2338
2339
|
}
|
|
2339
2340
|
function defaultSocketFactory(url) {
|
|
2340
2341
|
const WebSocketCtor = globalThis.WebSocket;
|
|
@@ -2667,6 +2668,10 @@ var HqPublisher = class {
|
|
|
2667
2668
|
if (bytes > this.maxQueuedBytes) {
|
|
2668
2669
|
this.droppedFrames += 1;
|
|
2669
2670
|
this.droppedBytes += bytes;
|
|
2671
|
+
process.emitWarning(
|
|
2672
|
+
`HQ telemetry frame of ${bytes} bytes exceeds the ${this.maxQueuedBytes}-byte offline queue cap and was dropped.`,
|
|
2673
|
+
{ code: "WRONGSTACK_HQ_FRAME_TOO_LARGE" }
|
|
2674
|
+
);
|
|
2670
2675
|
return;
|
|
2671
2676
|
}
|
|
2672
2677
|
if (coalesceKey !== void 0) {
|
|
@@ -4338,6 +4343,18 @@ function metadataReferencedByText(metadata, haystack) {
|
|
|
4338
4343
|
}
|
|
4339
4344
|
|
|
4340
4345
|
// src/utils/todos-format.ts
|
|
4346
|
+
function formatTodoForModel(todo) {
|
|
4347
|
+
const binding = todo.kanbanBoardId && todo.kanbanTaskId ? ` <kanban ${todo.kanbanBoardId}/${todo.kanbanTaskId}>` : "";
|
|
4348
|
+
const blocked = todo.blockedBy?.length ? ` [blocked by: ${todo.blockedBy.join("; ")}]` : "";
|
|
4349
|
+
return `- [${todo.status}]${blocked} ${todo.content} (${todo.id})${binding}`;
|
|
4350
|
+
}
|
|
4351
|
+
function formatTodosForModel(todos, emptyLine = "- No active todos remain.") {
|
|
4352
|
+
return todos.length ? todos.map(formatTodoForModel).join("\n") : emptyLine;
|
|
4353
|
+
}
|
|
4354
|
+
function hasKanbanBoundTodos(todos) {
|
|
4355
|
+
if (!Array.isArray(todos)) return false;
|
|
4356
|
+
return todos.some((todo) => Boolean(todo.kanbanBoardId && todo.kanbanTaskId));
|
|
4357
|
+
}
|
|
4341
4358
|
function hasOpenTodos(todos) {
|
|
4342
4359
|
if (!Array.isArray(todos) || todos.length === 0) return false;
|
|
4343
4360
|
return todos.some((t2) => t2.status === "pending" || t2.status === "in_progress");
|
|
@@ -4620,6 +4637,12 @@ function getCalibrationState(calibrationKey = CALIBRATION_GLOBAL_KEY) {
|
|
|
4620
4637
|
import * as path10 from "node:path";
|
|
4621
4638
|
|
|
4622
4639
|
// src/core/conversation-state.ts
|
|
4640
|
+
function hasToolResultBlock(message) {
|
|
4641
|
+
return message !== void 0 && Array.isArray(message.content) && message.content.some((block) => block.type === "tool_result");
|
|
4642
|
+
}
|
|
4643
|
+
function hasToolUseBlock(message) {
|
|
4644
|
+
return message?.role === "assistant" && Array.isArray(message.content) && message.content.some((block) => block.type === "tool_use");
|
|
4645
|
+
}
|
|
4623
4646
|
var ConversationState = class {
|
|
4624
4647
|
ctx;
|
|
4625
4648
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -4687,15 +4710,32 @@ var ConversationState = class {
|
|
|
4687
4710
|
*/
|
|
4688
4711
|
overflowCount(arr) {
|
|
4689
4712
|
let drop = Context.MAX_MESSAGES > 0 ? Math.max(0, arr.length - Context.MAX_MESSAGES) : 0;
|
|
4690
|
-
if (Context.MAX_MESSAGE_TOKENS <= 0) return drop;
|
|
4713
|
+
if (Context.MAX_MESSAGE_TOKENS <= 0) return this.protocolSafeDropCount(arr, drop);
|
|
4691
4714
|
let total = 0;
|
|
4692
4715
|
for (let i = drop; i < arr.length; i++) total += arr[i]?._estTokens ?? 0;
|
|
4693
|
-
if (total <= Context.MAX_MESSAGE_TOKENS) return drop;
|
|
4716
|
+
if (total <= Context.MAX_MESSAGE_TOKENS) return this.protocolSafeDropCount(arr, drop);
|
|
4694
4717
|
while (drop < arr.length - 1 && total > Context.MAX_MESSAGE_TOKENS) {
|
|
4695
4718
|
total -= arr[drop]?._estTokens ?? 0;
|
|
4696
4719
|
drop++;
|
|
4697
4720
|
}
|
|
4698
|
-
return drop;
|
|
4721
|
+
return this.protocolSafeDropCount(arr, drop);
|
|
4722
|
+
}
|
|
4723
|
+
/**
|
|
4724
|
+
* Front eviction must not retain a `tool_result` after evicting the
|
|
4725
|
+
* immediately preceding assistant `tool_use`. Long tool-heavy sessions sit
|
|
4726
|
+
* at the retention cap, so an unsafe boundary would create a fresh orphan on
|
|
4727
|
+
* nearly every append and make the request-time repair discard protocol
|
|
4728
|
+
* history continuously.
|
|
4729
|
+
*
|
|
4730
|
+
* Move the boundary backward to retain the complete exchange for one more
|
|
4731
|
+
* eviction cycle. Moving it forward would also drop non-protocol text/images
|
|
4732
|
+
* that may share either message. The temporary one-message cap overshoot is
|
|
4733
|
+
* the minimum lossless representation; once enough newer messages exist, the
|
|
4734
|
+
* next eviction boundary naturally moves past both halves together.
|
|
4735
|
+
*/
|
|
4736
|
+
protocolSafeDropCount(arr, drop) {
|
|
4737
|
+
if (drop <= 0 || drop >= arr.length) return drop;
|
|
4738
|
+
return hasToolResultBlock(arr[drop]) && hasToolUseBlock(arr[drop - 1]) ? drop - 1 : drop;
|
|
4699
4739
|
}
|
|
4700
4740
|
/**
|
|
4701
4741
|
* Append a content block to the trailing user message's content array.
|
|
@@ -5103,6 +5143,28 @@ var Context = class _Context {
|
|
|
5103
5143
|
return _Context.CONVERSATION_JOURNAL_MAX_BYTES + 1;
|
|
5104
5144
|
}
|
|
5105
5145
|
}
|
|
5146
|
+
_journalDropCount = 0;
|
|
5147
|
+
_journalDropWarnAt = 0;
|
|
5148
|
+
/** Throttled notice that a conversation event never reached the journal. */
|
|
5149
|
+
warnConversationJournalDrop(eventType) {
|
|
5150
|
+
this._journalDropCount++;
|
|
5151
|
+
const now = Date.now();
|
|
5152
|
+
if (now - this._journalDropWarnAt < 5e3) return;
|
|
5153
|
+
this._journalDropWarnAt = now;
|
|
5154
|
+
const dropped = this._journalDropCount;
|
|
5155
|
+
this._journalDropCount = 0;
|
|
5156
|
+
console.warn(
|
|
5157
|
+
JSON.stringify({
|
|
5158
|
+
level: "error",
|
|
5159
|
+
event: "session.conversation_journal_drop",
|
|
5160
|
+
sessionId: this.session?.id,
|
|
5161
|
+
eventType,
|
|
5162
|
+
droppedEvents: dropped,
|
|
5163
|
+
message: "Session writer is not draining; replay of this session will be incomplete.",
|
|
5164
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5165
|
+
})
|
|
5166
|
+
);
|
|
5167
|
+
}
|
|
5106
5168
|
enqueueConversationJournal(event, writer) {
|
|
5107
5169
|
const bytes = this.conversationJournalBytes(event);
|
|
5108
5170
|
const shouldSnapshot = event.type === "messages_replaced" || this._conversationJournalQueue.length >= _Context.CONVERSATION_JOURNAL_MAX_EVENTS || this._conversationJournalBytes + bytes > _Context.CONVERSATION_JOURNAL_MAX_BYTES;
|
|
@@ -5120,18 +5182,21 @@ var Context = class _Context {
|
|
|
5120
5182
|
this._conversationJournalBytes = Math.max(0, this._conversationJournalBytes - queued.bytes);
|
|
5121
5183
|
this._conversationJournalQueue.splice(index, 1);
|
|
5122
5184
|
}
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
this._conversationJournalBytes += snapshotBytes;
|
|
5126
|
-
}
|
|
5185
|
+
this._conversationJournalQueue.push({ event: snapshot, bytes: snapshotBytes, writer });
|
|
5186
|
+
this._conversationJournalBytes += snapshotBytes;
|
|
5127
5187
|
} else {
|
|
5128
5188
|
this._conversationJournalQueue.push({ event, bytes, writer });
|
|
5129
5189
|
this._conversationJournalBytes += bytes;
|
|
5130
5190
|
}
|
|
5131
5191
|
while (this._conversationJournalQueue.length > _Context.CONVERSATION_JOURNAL_MAX_EVENTS || this._conversationJournalBytes > _Context.CONVERSATION_JOURNAL_MAX_BYTES) {
|
|
5132
|
-
const
|
|
5192
|
+
const index = this._conversationJournalQueue.findIndex(
|
|
5193
|
+
(queued) => queued.event.type !== "messages_replaced"
|
|
5194
|
+
);
|
|
5195
|
+
if (index === -1) break;
|
|
5196
|
+
const [dropped] = this._conversationJournalQueue.splice(index, 1);
|
|
5133
5197
|
if (!dropped) break;
|
|
5134
5198
|
this._conversationJournalBytes = Math.max(0, this._conversationJournalBytes - dropped.bytes);
|
|
5199
|
+
this.warnConversationJournalDrop(dropped.event.type);
|
|
5135
5200
|
}
|
|
5136
5201
|
this.startConversationJournalDrain();
|
|
5137
5202
|
}
|
|
@@ -7220,7 +7285,7 @@ ${text}` : text;
|
|
|
7220
7285
|
if (a.ctx.agentId === "leader" && a.tools.get("todo") !== void 0 && hasOpenTodos(a.ctx.todos) && todoReconcileSteers < 2) {
|
|
7221
7286
|
todoReconcileSteers++;
|
|
7222
7287
|
queueLoopSteer(
|
|
7223
|
-
"[todo-reconciliation] The live todo/Kanban list still has open work, but you tried to end the turn without reconciling it. Call the `todo` tool now with the complete current list. Mark work you actually finished as completed, put the one item you are actively working on in_progress, and leave the rest pending. If the current item is genuinely unfinished, continue doing the work before answering; do not merely repeat the previous final response or emit <nextsteps
|
|
7288
|
+
"[todo-reconciliation] The live todo/Kanban list still has open work, but you tried to end the turn without reconciling it. Call the `todo` tool now with the complete current list. Mark work you actually finished as completed, put the one item you are actively working on in_progress, and leave the rest pending. If the current item is genuinely unfinished, continue doing the work before answering; do not merely repeat the previous final response or emit <nextsteps>.\nCanonical live list:\n" + formatTodosForModel(a.ctx.todos) + (hasKanbanBoundTodos(a.ctx.todos) ? "\nEach <kanban board/task> binding must be resent verbatim as `kanbanBoardId`/`kanbanTaskId`; a row without it is not applied to its card." : "")
|
|
7224
7289
|
);
|
|
7225
7290
|
await a.extensions.runAfterIteration(a.ctx, i);
|
|
7226
7291
|
continue;
|
|
@@ -7441,12 +7506,15 @@ function buildLiveNextStepsGateBlock(ctx) {
|
|
|
7441
7506
|
const todoSnapshot = openTodos.slice(0, MAX_TODO_SNAPSHOT_ITEMS).map((todo) => {
|
|
7442
7507
|
const normalized = todo.content.replace(/\s+/g, " ").trim();
|
|
7443
7508
|
const content = normalized.length > MAX_TODO_SNAPSHOT_CONTENT ? `${normalized.slice(0, MAX_TODO_SNAPSHOT_CONTENT - 1)}\u2026` : normalized;
|
|
7444
|
-
return
|
|
7509
|
+
return formatTodoForModel({ ...todo, content });
|
|
7445
7510
|
});
|
|
7446
7511
|
const omitted = openTodos.length - todoSnapshot.length;
|
|
7447
7512
|
if (omitted > 0) todoSnapshot.push(`- \u2026and ${omitted} more open todo(s)`);
|
|
7448
7513
|
const todoReconciliation = ctx.tools?.some((tool) => tool.name === "todo") ? [
|
|
7449
|
-
"Before ending the turn, you MUST call the `todo` tool with the complete current list to reconcile actual progress: finished items completed, exactly one actively worked item in_progress, and untouched items pending. A prose claim that work is done does not update the Todo/Kanban state."
|
|
7514
|
+
"Before ending the turn, you MUST call the `todo` tool with the complete current list to reconcile actual progress: finished items completed, exactly one actively worked item in_progress, and untouched items pending. A prose claim that work is done does not update the Todo/Kanban state.",
|
|
7515
|
+
...hasKanbanBoundTodos(openTodos) ? [
|
|
7516
|
+
"Rows below carry a <kanban board/task> binding. Pass those exact ids back as `kanbanBoardId`/`kanbanTaskId` on every row you resend; a row that arrives without its binding is not applied to its card."
|
|
7517
|
+
] : []
|
|
7450
7518
|
] : [];
|
|
7451
7519
|
return {
|
|
7452
7520
|
type: "text",
|
|
@@ -8162,6 +8230,7 @@ var Agent = class {
|
|
|
8162
8230
|
/** Resolved loop-detector settings (see `tools.loopDetection`). */
|
|
8163
8231
|
loopDetection;
|
|
8164
8232
|
autonomousContinue;
|
|
8233
|
+
refreshSystemPrompt;
|
|
8165
8234
|
tracer;
|
|
8166
8235
|
extensions;
|
|
8167
8236
|
_toolHandler;
|
|
@@ -8191,6 +8260,7 @@ var Agent = class {
|
|
|
8191
8260
|
this.autoExtendLimit = init.autoExtendLimit ?? true;
|
|
8192
8261
|
this.loopDetection = resolveLoopDetection(init.loopDetection);
|
|
8193
8262
|
this.autonomousContinue = init.autonomousContinue ?? false;
|
|
8263
|
+
this.refreshSystemPrompt = init.refreshSystemPrompt ?? false;
|
|
8194
8264
|
this.tracer = init.tracer;
|
|
8195
8265
|
this.extensions = init.extensions ?? new ExtensionRegistry();
|
|
8196
8266
|
this._logger = this.container.resolve(TOKENS.Logger).child({ sessionId: this.ctx.session.id });
|
|
@@ -8268,6 +8338,7 @@ var Agent = class {
|
|
|
8268
8338
|
context: { phase: "concurrency-guard" }
|
|
8269
8339
|
});
|
|
8270
8340
|
}
|
|
8341
|
+
let newInputHash;
|
|
8271
8342
|
const inputText = typeof userInput === "string" ? userInput : userInput?.prompt ?? "";
|
|
8272
8343
|
if (inputText.length > 0) {
|
|
8273
8344
|
const hash2 = createHash7("sha256").update(inputText).digest("hex");
|
|
@@ -8277,7 +8348,7 @@ var Agent = class {
|
|
|
8277
8348
|
iterations: 0
|
|
8278
8349
|
};
|
|
8279
8350
|
}
|
|
8280
|
-
|
|
8351
|
+
newInputHash = hash2;
|
|
8281
8352
|
}
|
|
8282
8353
|
this._runInProgress = true;
|
|
8283
8354
|
const controller = new RunController({ parentSignal: opts.signal });
|
|
@@ -8294,16 +8365,33 @@ var Agent = class {
|
|
|
8294
8365
|
});
|
|
8295
8366
|
this.ctx.tools = this.tools.listForProvider();
|
|
8296
8367
|
this.ctx.catalogTools = this.tools.list();
|
|
8297
|
-
const span = this.tracer?.startSpan("agent.run", {
|
|
8298
|
-
"agent.model": opts.model ?? this.ctx.model,
|
|
8299
|
-
"agent.executionStrategy": opts.executionStrategy ?? this.executionStrategy
|
|
8300
|
-
});
|
|
8301
|
-
const { blocks, text } = normalizeInput(userInput);
|
|
8302
|
-
const inputPayload = { content: blocks, text, ctx: this.ctx };
|
|
8303
|
-
await this.extensions.runBeforeRun(this.ctx, inputPayload);
|
|
8304
8368
|
const runStartedAt = Date.now();
|
|
8305
8369
|
const runStartedIso = new Date(runStartedAt).toISOString();
|
|
8370
|
+
let span;
|
|
8306
8371
|
try {
|
|
8372
|
+
if (this.refreshSystemPrompt) {
|
|
8373
|
+
const builder = this.container.safeResolve(TOKENS.SystemPromptBuilder);
|
|
8374
|
+
if (builder) {
|
|
8375
|
+
const onlineAgents = Array.isArray(this.ctx.meta["promptOnlineAgents"]) ? this.ctx.meta["promptOnlineAgents"] : void 0;
|
|
8376
|
+
this.ctx.systemPrompt = await builder.build({
|
|
8377
|
+
cwd: this.ctx.cwd,
|
|
8378
|
+
projectRoot: this.ctx.projectRoot,
|
|
8379
|
+
tools: this.ctx.tools,
|
|
8380
|
+
catalogTools: this.ctx.catalogTools,
|
|
8381
|
+
provider: this.ctx.provider.id,
|
|
8382
|
+
model: opts.model ?? this.ctx.model,
|
|
8383
|
+
onlineAgents
|
|
8384
|
+
});
|
|
8385
|
+
}
|
|
8386
|
+
}
|
|
8387
|
+
span = this.tracer?.startSpan("agent.run", {
|
|
8388
|
+
"agent.model": opts.model ?? this.ctx.model,
|
|
8389
|
+
"agent.executionStrategy": opts.executionStrategy ?? this.executionStrategy
|
|
8390
|
+
});
|
|
8391
|
+
const { blocks, text } = normalizeInput(userInput);
|
|
8392
|
+
const inputPayload = { content: blocks, text, ctx: this.ctx };
|
|
8393
|
+
await this.extensions.runBeforeRun(this.ctx, inputPayload);
|
|
8394
|
+
this._lastInputHash = newInputHash;
|
|
8307
8395
|
this.events.emit("agent.run.started", {
|
|
8308
8396
|
sessionId,
|
|
8309
8397
|
ctx: this.ctx,
|
|
@@ -8771,12 +8859,97 @@ var FallbackProfileManager = class {
|
|
|
8771
8859
|
return this.resolveRefs([ref], exclude);
|
|
8772
8860
|
}
|
|
8773
8861
|
/**
|
|
8774
|
-
* Resolve every usable configured target as
|
|
8862
|
+
* Resolve every usable configured target as a bounded last-resort chain.
|
|
8775
8863
|
* Normal smart defaults stay bounded; callers append this only after the
|
|
8776
|
-
* preferred chain and only when automatic fallback is enabled.
|
|
8864
|
+
* preferred chain and only when automatic fallback is enabled. The cap
|
|
8865
|
+
* ({@link MAX_LAST_RESORT_CANDIDATES}) prevents a config with many providers
|
|
8866
|
+
* from producing a degenerate chain of doomed requests during a systemic
|
|
8867
|
+
* outage — by this point the smart default, bridge, and default profile
|
|
8868
|
+
* have already failed.
|
|
8777
8869
|
*/
|
|
8778
8870
|
resolveAllConfigured(exclude) {
|
|
8779
|
-
return this.smartDefault(exclude,
|
|
8871
|
+
return this.smartDefault(exclude, this.lastResortCap());
|
|
8872
|
+
}
|
|
8873
|
+
/**
|
|
8874
|
+
* Effective cap for the last-resort append. Reads the user-configurable
|
|
8875
|
+
* {@link Config.fallbackMaxLastResortCandidates} when set and valid;
|
|
8876
|
+
* otherwise falls back to the compiled-in default
|
|
8877
|
+
* {@link MAX_LAST_RESORT_CANDIDATES}.
|
|
8878
|
+
*/
|
|
8879
|
+
lastResortCap() {
|
|
8880
|
+
const configured = this.config.fallbackMaxLastResortCandidates;
|
|
8881
|
+
if (typeof configured === "number" && Number.isFinite(configured) && configured >= 0) {
|
|
8882
|
+
return Math.floor(configured);
|
|
8883
|
+
}
|
|
8884
|
+
return MAX_LAST_RESORT_CANDIDATES;
|
|
8885
|
+
}
|
|
8886
|
+
/**
|
|
8887
|
+
* Build the complete fallback candidate chain shared by the agent-loop
|
|
8888
|
+
* extension and the one-shot orchestrator. Centralizes the bridge → primary →
|
|
8889
|
+
* selected → default-profile → all-configured ladder and the fromExplicitSource
|
|
8890
|
+
* gate so both consumers produce identical ordering and depth semantics.
|
|
8891
|
+
*
|
|
8892
|
+
* Layering (each step deduped against all prior):
|
|
8893
|
+
* 1. Bridge (emergency continuity route).
|
|
8894
|
+
* 2. Configured primary, when the live context drifted from it.
|
|
8895
|
+
* 3. The selected chain (explicit refs → named profile → smart default),
|
|
8896
|
+
* via {@link resolveEffective}.
|
|
8897
|
+
* 4. The "default" profile — extra depth, ONLY when the chain was auto-derived.
|
|
8898
|
+
* 5. Every other configured provider — last resort, ONLY when the chain was
|
|
8899
|
+
* auto-derived AND `effectiveFallbackAuto` is true.
|
|
8900
|
+
*
|
|
8901
|
+
* Returns the empty chain when `closedWorld` is true and no explicit
|
|
8902
|
+
* refs/profile resolved — a model allowlist never leaks to unlisted models.
|
|
8903
|
+
*
|
|
8904
|
+
* @internal caller-aware options (primary, closedWorld) are accepted because
|
|
8905
|
+
* the agent loop has context the manager does not own; the resolution
|
|
8906
|
+
* pipeline itself is identical for both callers.
|
|
8907
|
+
*/
|
|
8908
|
+
resolveCandidates(current, opts = {}) {
|
|
8909
|
+
const configuredPrimary = opts.primary ?? {
|
|
8910
|
+
providerId: this.config.provider,
|
|
8911
|
+
model: this.config.model
|
|
8912
|
+
};
|
|
8913
|
+
const configFallbackAuto = this.config.fallbackAuto;
|
|
8914
|
+
const effectiveFallbackAuto = configFallbackAuto !== void 0 && configFallbackAuto !== null ? configFallbackAuto : !opts.closedWorld;
|
|
8915
|
+
const explicitRefs = opts.fallbackModels ?? this.config.fallbackModels;
|
|
8916
|
+
const explicitUsable = explicitRefs !== void 0 && explicitRefs.length > 0 && this.resolveRefs(explicitRefs, current).length > 0;
|
|
8917
|
+
const profileUsable = opts.fallbackProfile !== void 0 && this.hasProfile(opts.fallbackProfile) && this.resolve(opts.fallbackProfile, { exclude: current }).length > 0;
|
|
8918
|
+
const fromExplicitSource = explicitUsable || profileUsable;
|
|
8919
|
+
const selectedChain = opts.closedWorld ? explicitRefs && explicitRefs.length > 0 ? this.resolveRefs(explicitRefs, current) : opts.fallbackProfile ? this.resolve(opts.fallbackProfile, { exclude: current }) : FREEZER_EMPTY : this.resolveEffective({
|
|
8920
|
+
fallbackModels: explicitRefs,
|
|
8921
|
+
fallbackProfile: opts.fallbackProfile,
|
|
8922
|
+
fallbackAuto: effectiveFallbackAuto,
|
|
8923
|
+
exclude: current
|
|
8924
|
+
});
|
|
8925
|
+
const candidates = [];
|
|
8926
|
+
if (opts.closedWorld) {
|
|
8927
|
+
candidates.push(...selectedChain);
|
|
8928
|
+
} else {
|
|
8929
|
+
candidates.push(...this.resolveBridge(current));
|
|
8930
|
+
if (!(configuredPrimary.providerId === current.providerId && configuredPrimary.model === current.model)) {
|
|
8931
|
+
candidates.push({
|
|
8932
|
+
providerId: configuredPrimary.providerId,
|
|
8933
|
+
model: configuredPrimary.model,
|
|
8934
|
+
providerSwitched: configuredPrimary.providerId !== current.providerId
|
|
8935
|
+
});
|
|
8936
|
+
}
|
|
8937
|
+
candidates.push(...selectedChain);
|
|
8938
|
+
if (!fromExplicitSource && effectiveFallbackAuto && opts.fallbackProfile !== "default") {
|
|
8939
|
+
candidates.push(...this.resolve("default", { exclude: current }));
|
|
8940
|
+
}
|
|
8941
|
+
if (!fromExplicitSource && effectiveFallbackAuto) {
|
|
8942
|
+
const cap = this.lastResortCap();
|
|
8943
|
+
if (cap > 0) {
|
|
8944
|
+
const usedKeys = new Set(
|
|
8945
|
+
candidates.map((c) => `${c.providerId}/${c.model}`)
|
|
8946
|
+
);
|
|
8947
|
+
const lastResort = this.smartDefault(current, Number.POSITIVE_INFINITY).filter((c) => !usedKeys.has(`${c.providerId}/${c.model}`)).slice(0, cap);
|
|
8948
|
+
candidates.push(...lastResort);
|
|
8949
|
+
}
|
|
8950
|
+
}
|
|
8951
|
+
}
|
|
8952
|
+
return dedupeChain(candidates, current);
|
|
8780
8953
|
}
|
|
8781
8954
|
// ── Provider availability (read-only) ──────────────────────────────────
|
|
8782
8955
|
checkProvider(providerId) {
|
|
@@ -8900,7 +9073,20 @@ var FallbackProfileManager = class {
|
|
|
8900
9073
|
);
|
|
8901
9074
|
}
|
|
8902
9075
|
};
|
|
9076
|
+
var MAX_LAST_RESORT_CANDIDATES = 12;
|
|
8903
9077
|
var FREEZER_EMPTY = Object.freeze([]);
|
|
9078
|
+
function dedupeChain(entries, current) {
|
|
9079
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9080
|
+
const currentKey = `${current.providerId}/${current.model}`;
|
|
9081
|
+
return Object.freeze(
|
|
9082
|
+
entries.filter((entry) => {
|
|
9083
|
+
const key = `${entry.providerId}/${entry.model}`;
|
|
9084
|
+
if (key === currentKey || seen.has(key)) return false;
|
|
9085
|
+
seen.add(key);
|
|
9086
|
+
return true;
|
|
9087
|
+
})
|
|
9088
|
+
);
|
|
9089
|
+
}
|
|
8904
9090
|
|
|
8905
9091
|
// src/core/fallback-model.ts
|
|
8906
9092
|
function fallbackProfileChain(config, profileName) {
|
|
@@ -8949,56 +9135,12 @@ function sameTarget(a, b) {
|
|
|
8949
9135
|
}
|
|
8950
9136
|
function fallbackCandidates(config, current, opts = {}) {
|
|
8951
9137
|
const mgr = opts.sharedManager ?? new FallbackProfileManager(config);
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
const effectiveFallbackAuto = configFallbackAuto !== void 0 && configFallbackAuto !== null ? configFallbackAuto : !opts.closedWorld;
|
|
8955
|
-
const explicitRefs = opts.fallbackModels ?? config.fallbackModels;
|
|
8956
|
-
const explicitUsable = explicitRefs !== void 0 && explicitRefs.length > 0 && mgr.resolveRefs(explicitRefs, current).length > 0;
|
|
8957
|
-
const profileUsable = opts.fallbackProfile !== void 0 && mgr.hasProfile(opts.fallbackProfile) && mgr.resolve(opts.fallbackProfile, { exclude: current }).length > 0;
|
|
8958
|
-
const fromExplicitSource = explicitUsable || profileUsable;
|
|
8959
|
-
const selectedChain = opts.closedWorld ? explicitRefs && explicitRefs.length > 0 ? mgr.resolveRefs(explicitRefs, current) : opts.fallbackProfile ? mgr.resolve(opts.fallbackProfile, { exclude: current }) : Object.freeze([]) : mgr.resolveEffective({
|
|
8960
|
-
fallbackModels: explicitRefs,
|
|
9138
|
+
return mgr.resolveCandidates(current, {
|
|
9139
|
+
fallbackModels: opts.fallbackModels,
|
|
8961
9140
|
fallbackProfile: opts.fallbackProfile,
|
|
8962
|
-
|
|
8963
|
-
|
|
9141
|
+
primary: opts.primary ?? primaryTarget(config),
|
|
9142
|
+
closedWorld: opts.closedWorld
|
|
8964
9143
|
});
|
|
8965
|
-
const candidates = [];
|
|
8966
|
-
if (opts.closedWorld) {
|
|
8967
|
-
candidates.push(...selectedChain);
|
|
8968
|
-
const seen2 = /* @__PURE__ */ new Set();
|
|
8969
|
-
return Object.freeze(
|
|
8970
|
-
candidates.filter((entry) => {
|
|
8971
|
-
const key = `${entry.providerId}/${entry.model}`;
|
|
8972
|
-
if (key === `${current.providerId}/${current.model}` || seen2.has(key)) return false;
|
|
8973
|
-
seen2.add(key);
|
|
8974
|
-
return true;
|
|
8975
|
-
})
|
|
8976
|
-
);
|
|
8977
|
-
}
|
|
8978
|
-
candidates.push(...mgr.resolveBridge(current));
|
|
8979
|
-
if (!sameTarget(configuredPrimary, current)) {
|
|
8980
|
-
candidates.push({
|
|
8981
|
-
providerId: configuredPrimary.providerId,
|
|
8982
|
-
model: configuredPrimary.model,
|
|
8983
|
-
providerSwitched: configuredPrimary.providerId !== current.providerId
|
|
8984
|
-
});
|
|
8985
|
-
}
|
|
8986
|
-
candidates.push(...selectedChain);
|
|
8987
|
-
if (!fromExplicitSource && opts.fallbackProfile !== "default") {
|
|
8988
|
-
candidates.push(...mgr.resolve("default", { exclude: current }));
|
|
8989
|
-
}
|
|
8990
|
-
if (!fromExplicitSource && effectiveFallbackAuto) {
|
|
8991
|
-
candidates.push(...mgr.resolveAllConfigured(current));
|
|
8992
|
-
}
|
|
8993
|
-
const seen = /* @__PURE__ */ new Set();
|
|
8994
|
-
return Object.freeze(
|
|
8995
|
-
candidates.filter((entry) => {
|
|
8996
|
-
const key = `${entry.providerId}/${entry.model}`;
|
|
8997
|
-
if (key === `${current.providerId}/${current.model}` || seen.has(key)) return false;
|
|
8998
|
-
seen.add(key);
|
|
8999
|
-
return true;
|
|
9000
|
-
})
|
|
9001
|
-
);
|
|
9002
9144
|
}
|
|
9003
9145
|
var primaryTarget = (cfg) => ({ providerId: cfg.provider, model: cfg.model });
|
|
9004
9146
|
function maxContextOf(provider) {
|
|
@@ -10500,7 +10642,7 @@ async function buildEnvironment(ctx, env) {
|
|
|
10500
10642
|
]);
|
|
10501
10643
|
const tier = env.tier;
|
|
10502
10644
|
const lines = ["## Environment"];
|
|
10503
|
-
if (tier === "minimal") {
|
|
10645
|
+
if (tier === "minimal" || tier === "aggressive") {
|
|
10504
10646
|
lines.push(`- Git: ${git} | Date: ${today}`);
|
|
10505
10647
|
} else {
|
|
10506
10648
|
lines.push(`- Operating system: ${platform2}`);
|
|
@@ -10508,38 +10650,26 @@ async function buildEnvironment(ctx, env) {
|
|
|
10508
10650
|
lines.push(`- Shell: ${shell}`);
|
|
10509
10651
|
lines.push(`- Node.js: ${node}`);
|
|
10510
10652
|
}
|
|
10511
|
-
if (tier === "off" || tier === "medium"
|
|
10653
|
+
if (tier === "off" || tier === "medium") {
|
|
10512
10654
|
lines.push(`- Detected languages: ${langs}`);
|
|
10513
10655
|
}
|
|
10514
10656
|
lines.push(`- Git status: ${git}`);
|
|
10515
10657
|
lines.push(`- Today's date: ${today}`);
|
|
10516
|
-
if (
|
|
10517
|
-
if (ctx.provider || ctx.model) {
|
|
10518
|
-
lines.push(
|
|
10519
|
-
`- Running on: ${ctx.provider ?? "<unknown provider>"}/${ctx.model ?? "<unknown model>"}`
|
|
10520
|
-
);
|
|
10521
|
-
}
|
|
10522
|
-
if (modelCapabilities) {
|
|
10523
|
-
lines.push(
|
|
10524
|
-
`- Context window: ${modelCapabilities.maxContextTokens.toLocaleString()} tokens max`
|
|
10525
|
-
);
|
|
10526
|
-
}
|
|
10527
|
-
}
|
|
10528
|
-
if (tier !== "aggressive" && modelCapabilities) {
|
|
10658
|
+
if (modelCapabilities) {
|
|
10529
10659
|
lines.push(
|
|
10530
10660
|
`- Context window: ${modelCapabilities.maxContextTokens.toLocaleString()} tokens max`
|
|
10531
10661
|
);
|
|
10532
10662
|
}
|
|
10533
|
-
if (
|
|
10663
|
+
if (ctx.provider || ctx.model) {
|
|
10534
10664
|
lines.push(
|
|
10535
10665
|
`- Running on: ${ctx.provider ?? "<unknown provider>"}/${ctx.model ?? "<unknown model>"}`
|
|
10536
10666
|
);
|
|
10537
10667
|
}
|
|
10538
|
-
if (
|
|
10668
|
+
if (env.modeId && env.modeId !== "default") {
|
|
10539
10669
|
lines.push(`- Mode: ${env.modeId}`);
|
|
10540
10670
|
}
|
|
10541
10671
|
}
|
|
10542
|
-
if (ctx.tools.some((tool) => tool.name === "bash") && effShell !== "posix" && tier !== "minimal") {
|
|
10672
|
+
if (ctx.tools.some((tool) => tool.name === "bash") && effShell !== "posix" && tier !== "minimal" && tier !== "aggressive") {
|
|
10543
10673
|
const guide = shellGuidanceBlock(effShell, tier === "light" ? "short" : "full");
|
|
10544
10674
|
if (guide) lines.push("", guide);
|
|
10545
10675
|
}
|
|
@@ -10562,6 +10692,70 @@ async function buildEnvironment(ctx, env) {
|
|
|
10562
10692
|
return text;
|
|
10563
10693
|
}
|
|
10564
10694
|
|
|
10695
|
+
// src/core/system-prompt-glossary.ts
|
|
10696
|
+
function findDomainGlossaryEntries(memory) {
|
|
10697
|
+
return safeList(memory, { limit: 200 }).then((rows) => rows ?? []).then(
|
|
10698
|
+
(rows) => rows.filter(
|
|
10699
|
+
(r) => Array.isArray(r?.tags) && r.tags.includes("domain-term")
|
|
10700
|
+
)
|
|
10701
|
+
);
|
|
10702
|
+
}
|
|
10703
|
+
async function safeList(memory, opts) {
|
|
10704
|
+
try {
|
|
10705
|
+
const rows = await memory.list("project-memory", opts.limit);
|
|
10706
|
+
if (!Array.isArray(rows) || rows.length === 0) return null;
|
|
10707
|
+
return rows;
|
|
10708
|
+
} catch {
|
|
10709
|
+
return null;
|
|
10710
|
+
}
|
|
10711
|
+
}
|
|
10712
|
+
var GLOSSARY_HEADING = "# Project Jargon Dictionary (auto-mined from SAGE; update via SageDomainTermExtractor)";
|
|
10713
|
+
async function renderDomainGlossary(ctx, memory, options = {}) {
|
|
10714
|
+
if (!memory) return null;
|
|
10715
|
+
const maxEntries = options.maxEntries ?? 12;
|
|
10716
|
+
const maxEntryChars = options.maxEntryChars ?? 80;
|
|
10717
|
+
const entries = await findDomainGlossaryEntries(memory);
|
|
10718
|
+
if (entries.length === 0) return "";
|
|
10719
|
+
const sorted = [...entries].sort((a, b) => {
|
|
10720
|
+
const dc = (b.confidence ?? 0) - (a.confidence ?? 0);
|
|
10721
|
+
if (dc !== 0) return dc;
|
|
10722
|
+
return b.ts.localeCompare(a.ts);
|
|
10723
|
+
});
|
|
10724
|
+
const lines = [GLOSSARY_HEADING, ""];
|
|
10725
|
+
let emitted = 0;
|
|
10726
|
+
for (const entry of sorted) {
|
|
10727
|
+
if (emitted >= maxEntries) break;
|
|
10728
|
+
const { term, definition } = parseTermEntry(entry.text);
|
|
10729
|
+
if (!term) continue;
|
|
10730
|
+
const def = (definition || "").slice(0, maxEntryChars).trim();
|
|
10731
|
+
lines.push(def ? `- **${term}** \u2014 ${def}` : `- **${term}**`);
|
|
10732
|
+
emitted += 1;
|
|
10733
|
+
}
|
|
10734
|
+
if (emitted === 0) return "";
|
|
10735
|
+
lines.push("");
|
|
10736
|
+
lines.push(
|
|
10737
|
+
`_Source: <${ctx.projectRoot}>/.wrongstack/domain-terms.md (auto-generated; do not edit by hand)._`
|
|
10738
|
+
);
|
|
10739
|
+
lines.push(
|
|
10740
|
+
'_Lookup tag: `domain-term` (search: `memory_search({ query: "domain-term", scope: "project-memory" })`)._'
|
|
10741
|
+
);
|
|
10742
|
+
return lines.join("\n");
|
|
10743
|
+
}
|
|
10744
|
+
function parseTermEntry(text) {
|
|
10745
|
+
const trimmed = text.trim();
|
|
10746
|
+
const separators = [" \u2014 ", " \u2013 ", " - ", " -- "];
|
|
10747
|
+
for (const sep of separators) {
|
|
10748
|
+
const idx = trimmed.indexOf(sep);
|
|
10749
|
+
if (idx > 0) {
|
|
10750
|
+
return {
|
|
10751
|
+
term: trimmed.slice(0, idx).trim(),
|
|
10752
|
+
definition: trimmed.slice(idx + sep.length).trim()
|
|
10753
|
+
};
|
|
10754
|
+
}
|
|
10755
|
+
}
|
|
10756
|
+
return { term: trimmed, definition: "" };
|
|
10757
|
+
}
|
|
10758
|
+
|
|
10565
10759
|
// src/skills/limits.ts
|
|
10566
10760
|
var SKILL_LIMITS = {
|
|
10567
10761
|
/**
|
|
@@ -10828,7 +11022,7 @@ function renderOnlineAgents(agents, tier, cache) {
|
|
|
10828
11022
|
return { text: cache.text, cache };
|
|
10829
11023
|
}
|
|
10830
11024
|
const totalCount = agents.length;
|
|
10831
|
-
if (tier === "minimal" || tier === "light") {
|
|
11025
|
+
if (tier === "minimal" || tier === "light" || tier === "aggressive") {
|
|
10832
11026
|
const text2 = ` (${totalCount} agent${totalCount !== 1 ? "s" : ""} online)`;
|
|
10833
11027
|
return { text: text2, cache: { hash: hash2, text: text2 } };
|
|
10834
11028
|
}
|
|
@@ -10853,8 +11047,8 @@ ${agentList}`;
|
|
|
10853
11047
|
async function buildMemoryAndSkills(mem) {
|
|
10854
11048
|
const parts = [];
|
|
10855
11049
|
let skillBodyCache = mem.skillBodyCache;
|
|
10856
|
-
const memoryCount = mem.tier === "minimal" || mem.tier === "light" ? 3 : 5;
|
|
10857
|
-
const compactMemory = mem.tier === "minimal";
|
|
11050
|
+
const memoryCount = mem.tier === "minimal" || mem.tier === "light" || mem.tier === "aggressive" ? 3 : 5;
|
|
11051
|
+
const compactMemory = mem.tier === "minimal" || mem.tier === "aggressive";
|
|
10858
11052
|
if (mem.memoryStore && mem.injectMemory !== false) {
|
|
10859
11053
|
try {
|
|
10860
11054
|
if (mem.memoryStore.scoreRelevant) {
|
|
@@ -11035,7 +11229,7 @@ var DefaultSystemPromptBuilder = class {
|
|
|
11035
11229
|
}
|
|
11036
11230
|
/**
|
|
11037
11231
|
* Returns the max tool description length for the current tier.
|
|
11038
|
-
*
|
|
11232
|
+
* The aggressive tier has the shortest descriptions; off keeps the most detail.
|
|
11039
11233
|
*/
|
|
11040
11234
|
toolDescLimit() {
|
|
11041
11235
|
switch (this.tier) {
|
|
@@ -11046,7 +11240,7 @@ var DefaultSystemPromptBuilder = class {
|
|
|
11046
11240
|
case "medium":
|
|
11047
11241
|
return 50;
|
|
11048
11242
|
case "aggressive":
|
|
11049
|
-
return
|
|
11243
|
+
return 20;
|
|
11050
11244
|
default:
|
|
11051
11245
|
return 70;
|
|
11052
11246
|
}
|
|
@@ -11158,6 +11352,12 @@ var DefaultSystemPromptBuilder = class {
|
|
|
11158
11352
|
}
|
|
11159
11353
|
}
|
|
11160
11354
|
}
|
|
11355
|
+
if (this.opts.domainGlossary) {
|
|
11356
|
+
const glossary = await renderDomainGlossary(ctx, this.opts.domainGlossary);
|
|
11357
|
+
if (glossary) {
|
|
11358
|
+
volatile.push(tagBlock({ type: "text", text: glossary }, "glossary"));
|
|
11359
|
+
}
|
|
11360
|
+
}
|
|
11161
11361
|
if (!ctx.subagent) {
|
|
11162
11362
|
session.push(
|
|
11163
11363
|
tagBlock(
|
|
@@ -11315,8 +11515,8 @@ ${hint.trim()}`);
|
|
|
11315
11515
|
return Array.isArray(role) ? role.filter((r) => typeof r === "string") : [];
|
|
11316
11516
|
})();
|
|
11317
11517
|
const roleList = enumValues.length > 0 ? enumValues.join(", ") : "(no roster configured)";
|
|
11318
|
-
if (this.tier === "minimal") {
|
|
11319
|
-
} else if (this.tier === "light" || this.tier === "medium"
|
|
11518
|
+
if (this.tier === "minimal" || this.tier === "aggressive") {
|
|
11519
|
+
} else if (this.tier === "light" || this.tier === "medium") {
|
|
11320
11520
|
const delegation = section("tool.delegation.compact", {
|
|
11321
11521
|
roleList
|
|
11322
11522
|
});
|
|
@@ -11352,7 +11552,7 @@ ${hint.trim()}`);
|
|
|
11352
11552
|
}
|
|
11353
11553
|
}
|
|
11354
11554
|
const hasGitTool = tools.some((t2) => t2.name === "git");
|
|
11355
|
-
if (hasGitTool && this.tier !== "minimal" && this.tier !== "light") {
|
|
11555
|
+
if (hasGitTool && this.tier !== "minimal" && this.tier !== "light" && this.tier !== "aggressive") {
|
|
11356
11556
|
const commitHygiene = section("tool.commit.hygiene");
|
|
11357
11557
|
if (commitHygiene) lines.push(commitHygiene);
|
|
11358
11558
|
}
|
|
@@ -11369,7 +11569,7 @@ ${hint.trim()}`);
|
|
|
11369
11569
|
}
|
|
11370
11570
|
const hasContextManager = tools.some((t2) => t2.name === "context_manager");
|
|
11371
11571
|
if (hasContextManager) {
|
|
11372
|
-
if (this.tier === "minimal" || this.tier === "light") {
|
|
11572
|
+
if (this.tier === "minimal" || this.tier === "light" || this.tier === "aggressive") {
|
|
11373
11573
|
} else if (this.tier === "medium") {
|
|
11374
11574
|
const contextManagement = section("tool.context.management.compact");
|
|
11375
11575
|
if (contextManagement) lines.push(contextManagement);
|
|
@@ -11422,11 +11622,11 @@ ${hint.trim()}`);
|
|
|
11422
11622
|
return result.text;
|
|
11423
11623
|
}
|
|
11424
11624
|
async buildMode() {
|
|
11425
|
-
if (this.opts.
|
|
11426
|
-
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
return
|
|
11625
|
+
if (this.opts.modeStore) {
|
|
11626
|
+
const mode = await this.opts.modeStore.getActiveMode();
|
|
11627
|
+
if (mode?.prompt) return mode.prompt;
|
|
11628
|
+
}
|
|
11629
|
+
return this.opts.modePrompt ?? "";
|
|
11430
11630
|
}
|
|
11431
11631
|
};
|
|
11432
11632
|
export {
|
|
@@ -18,7 +18,7 @@ import { type InstructionTemplateContext } from './instruction-template.js';
|
|
|
18
18
|
* `getContextBreakdown()` to attribute real token counts per category in the
|
|
19
19
|
* `/context` display.
|
|
20
20
|
*/
|
|
21
|
-
export type SystemBlockSource = 'identity' | 'tool-usage' | 'environment' | 'skills' | 'mode' | 'plan' | 'leader-after-task' | 'contributor' | 'ledger' | 'nextsteps';
|
|
21
|
+
export type SystemBlockSource = 'identity' | 'tool-usage' | 'environment' | 'skills' | 'mode' | 'plan' | 'leader-after-task' | 'contributor' | 'ledger' | 'glossary' | 'nextsteps';
|
|
22
22
|
/**
|
|
23
23
|
* Side-table mapping each system-prompt TextBlock to the section it came from.
|
|
24
24
|
* Kept as a WeakMap rather than a field on TextBlock so the label never reaches
|