@defai.digital/automatosx 11.2.9 → 11.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/dist/index.js +2906 -20
- package/dist/mcp/index.js +13 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { Mutex } from 'async-mutex';
|
|
|
19
19
|
import { promisify } from 'util';
|
|
20
20
|
import yargs from 'yargs';
|
|
21
21
|
import { hideBin } from 'yargs/helpers';
|
|
22
|
-
import { randomUUID, createHash } from 'crypto';
|
|
22
|
+
import crypto2, { randomUUID, createHash } from 'crypto';
|
|
23
23
|
import * as yaml4 from 'js-yaml';
|
|
24
24
|
import yaml4__default, { load, dump } from 'js-yaml';
|
|
25
25
|
import Table from 'cli-table3';
|
|
@@ -2943,8 +2943,18 @@ var init_base_provider = __esm({
|
|
|
2943
2943
|
/**
|
|
2944
2944
|
* Check if CLI is available - Template method pattern
|
|
2945
2945
|
* Uses getCLICommand() to determine which CLI to check
|
|
2946
|
+
*
|
|
2947
|
+
* v11.2.9 Fix: Always return true in mock mode (AX_MOCK_PROVIDERS=true)
|
|
2948
|
+
* This allows integration tests in CI to run without installing actual provider CLIs
|
|
2946
2949
|
*/
|
|
2947
2950
|
async checkCLIAvailable() {
|
|
2951
|
+
if (process.env.AX_MOCK_PROVIDERS === "true") {
|
|
2952
|
+
logger.debug(`${this.getCLICommand()} CLI availability check (mock mode)`, {
|
|
2953
|
+
available: true,
|
|
2954
|
+
mockMode: true
|
|
2955
|
+
});
|
|
2956
|
+
return true;
|
|
2957
|
+
}
|
|
2948
2958
|
try {
|
|
2949
2959
|
const cliCommand2 = this.getCLICommand();
|
|
2950
2960
|
const result = findOnPath(cliCommand2);
|
|
@@ -9263,7 +9273,7 @@ var PRECOMPILED_CONFIG = {
|
|
|
9263
9273
|
"enableFreeTierPrioritization": true,
|
|
9264
9274
|
"enableWorkloadAwareRouting": true
|
|
9265
9275
|
},
|
|
9266
|
-
"version": "11.
|
|
9276
|
+
"version": "11.3.0"
|
|
9267
9277
|
};
|
|
9268
9278
|
|
|
9269
9279
|
// src/core/config/schemas.ts
|
|
@@ -22176,8 +22186,8 @@ var ProjectContextLoader = class {
|
|
|
22176
22186
|
const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
|
|
22177
22187
|
if (projectMatch && projectMatch[1]) {
|
|
22178
22188
|
const parts = projectMatch[1].trim().split(/\s+v/);
|
|
22179
|
-
metadata.name = parts[0];
|
|
22180
|
-
if (parts[1]) {
|
|
22189
|
+
metadata.name = parts[0] || "";
|
|
22190
|
+
if (parts.length > 1 && parts[1]) {
|
|
22181
22191
|
metadata.version = parts[1];
|
|
22182
22192
|
}
|
|
22183
22193
|
}
|
|
@@ -36225,10 +36235,10 @@ var runCommand = {
|
|
|
36225
36235
|
}).positional("task", {
|
|
36226
36236
|
describe: "Task to execute",
|
|
36227
36237
|
type: "string"
|
|
36228
|
-
}).option("
|
|
36229
|
-
describe: "
|
|
36238
|
+
}).option("auto-select", {
|
|
36239
|
+
describe: "Enable agent auto-selection when agent not found (v11.1.0+)",
|
|
36230
36240
|
type: "boolean",
|
|
36231
|
-
default:
|
|
36241
|
+
default: true
|
|
36232
36242
|
}).option("provider", {
|
|
36233
36243
|
describe: "Override provider (claude, gemini, openai)",
|
|
36234
36244
|
type: "string"
|
|
@@ -36370,7 +36380,7 @@ var runCommand = {
|
|
|
36370
36380
|
console.log(chalk5.gray(' ax run backend "implement API" # uses specified agent'));
|
|
36371
36381
|
process.exit(1);
|
|
36372
36382
|
}
|
|
36373
|
-
if (!agentProvided && argv.
|
|
36383
|
+
if (!agentProvided && argv.autoSelect === false) {
|
|
36374
36384
|
console.log(chalk5.red.bold("\n\u274C Error: Agent name is required when --no-auto-select is used\n"));
|
|
36375
36385
|
console.log(chalk5.gray("Usage: ax run <agent> <task> --no-auto-select"));
|
|
36376
36386
|
process.exit(1);
|
|
@@ -36505,7 +36515,7 @@ var runCommand = {
|
|
|
36505
36515
|
}
|
|
36506
36516
|
}
|
|
36507
36517
|
} catch (error) {
|
|
36508
|
-
if (argv.
|
|
36518
|
+
if (argv.autoSelect === false) {
|
|
36509
36519
|
console.error(chalk5.red.bold(`
|
|
36510
36520
|
\u274C Agent not found: ${actualAgent}
|
|
36511
36521
|
`));
|
|
@@ -44867,24 +44877,24 @@ async function handleList(config, argv) {
|
|
|
44867
44877
|
});
|
|
44868
44878
|
}
|
|
44869
44879
|
}
|
|
44870
|
-
let
|
|
44880
|
+
let displayProviders2 = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
|
|
44871
44881
|
switch (argv.sort) {
|
|
44872
44882
|
case "cost":
|
|
44873
|
-
|
|
44883
|
+
displayProviders2.sort((a, b) => {
|
|
44874
44884
|
const costA = a.metadata ? (a.metadata.costPerToken.input + a.metadata.costPerToken.output) / 2 : Infinity;
|
|
44875
44885
|
const costB = b.metadata ? (b.metadata.costPerToken.input + b.metadata.costPerToken.output) / 2 : Infinity;
|
|
44876
44886
|
return costA - costB;
|
|
44877
44887
|
});
|
|
44878
44888
|
break;
|
|
44879
44889
|
case "latency":
|
|
44880
|
-
|
|
44890
|
+
displayProviders2.sort((a, b) => {
|
|
44881
44891
|
const latA = a.metadata?.latencyEstimate.p95 || Infinity;
|
|
44882
44892
|
const latB = b.metadata?.latencyEstimate.p95 || Infinity;
|
|
44883
44893
|
return latA - latB;
|
|
44884
44894
|
});
|
|
44885
44895
|
break;
|
|
44886
44896
|
case "reliability":
|
|
44887
|
-
|
|
44897
|
+
displayProviders2.sort((a, b) => {
|
|
44888
44898
|
const relA = a.metadata?.reliability.availability || 0;
|
|
44889
44899
|
const relB = b.metadata?.reliability.availability || 0;
|
|
44890
44900
|
return relB - relA;
|
|
@@ -44892,15 +44902,15 @@ async function handleList(config, argv) {
|
|
|
44892
44902
|
break;
|
|
44893
44903
|
case "priority":
|
|
44894
44904
|
default:
|
|
44895
|
-
|
|
44905
|
+
displayProviders2.sort((a, b) => a.priority - b.priority);
|
|
44896
44906
|
break;
|
|
44897
44907
|
}
|
|
44898
44908
|
if (argv.json) {
|
|
44899
|
-
console.log(JSON.stringify({ providers:
|
|
44909
|
+
console.log(JSON.stringify({ providers: displayProviders2 }, null, 2));
|
|
44900
44910
|
return;
|
|
44901
44911
|
}
|
|
44902
44912
|
console.log(chalk5.gray("Provider Status & Metadata:\n"));
|
|
44903
|
-
for (const provider of
|
|
44913
|
+
for (const provider of displayProviders2) {
|
|
44904
44914
|
const status = provider.enabled ? provider.limitInfo?.isBlocked ? chalk5.red("\u25CF BLOCKED") : chalk5.green("\u25CF ENABLED") : chalk5.gray("\u25CB DISABLED");
|
|
44905
44915
|
console.log(`${status} ${chalk5.bold(provider.name)} ${chalk5.gray(`(priority: ${provider.priority})`)}`);
|
|
44906
44916
|
if (provider.metadata && argv.verbose) {
|
|
@@ -46147,9 +46157,11 @@ async function checkDiskSpace(workingDir, verbose) {
|
|
|
46147
46157
|
timeout: 5e3
|
|
46148
46158
|
});
|
|
46149
46159
|
const parts = dfOutput.trim().split(/\s+/);
|
|
46150
|
-
const
|
|
46151
|
-
const
|
|
46152
|
-
const
|
|
46160
|
+
const rawAvailable = parts.length > 3 ? parts[3] : "0";
|
|
46161
|
+
const availableKB = parseInt(rawAvailable || "0", 10);
|
|
46162
|
+
const safeAvailableKB = isNaN(availableKB) ? 0 : availableKB;
|
|
46163
|
+
const availableMB = Math.round(safeAvailableKB / 1024);
|
|
46164
|
+
const availableGB = (safeAvailableKB / (1024 * 1024)).toFixed(2);
|
|
46153
46165
|
const hasEnoughSpace = availableMB > 100;
|
|
46154
46166
|
results.push({
|
|
46155
46167
|
name: "Available Disk Space",
|
|
@@ -48519,6 +48531,2880 @@ var uninstallCommand = {
|
|
|
48519
48531
|
}
|
|
48520
48532
|
};
|
|
48521
48533
|
|
|
48534
|
+
// src/cli/commands/mode.ts
|
|
48535
|
+
init_esm_shims();
|
|
48536
|
+
init_logger();
|
|
48537
|
+
|
|
48538
|
+
// src/core/workflow/index.ts
|
|
48539
|
+
init_esm_shims();
|
|
48540
|
+
|
|
48541
|
+
// src/core/workflow/workflow-mode.ts
|
|
48542
|
+
init_esm_shims();
|
|
48543
|
+
var WorkflowModeSchema = z.enum(["default", "plan", "iterate", "review"]);
|
|
48544
|
+
z.object({
|
|
48545
|
+
name: WorkflowModeSchema,
|
|
48546
|
+
description: z.string(),
|
|
48547
|
+
displayName: z.string(),
|
|
48548
|
+
allowedTools: z.array(z.string()).optional(),
|
|
48549
|
+
blockedTools: z.array(z.string()).optional(),
|
|
48550
|
+
systemInstructions: z.string(),
|
|
48551
|
+
allowNesting: z.boolean(),
|
|
48552
|
+
maxNestingDepth: z.number().int().positive().optional(),
|
|
48553
|
+
autoExitConditions: z.object({
|
|
48554
|
+
maxTurns: z.number().int().positive().optional(),
|
|
48555
|
+
onToolUse: z.array(z.string()).optional(),
|
|
48556
|
+
onKeywords: z.array(z.string()).optional()
|
|
48557
|
+
}).optional()
|
|
48558
|
+
});
|
|
48559
|
+
var WRITE_TOOLS = [
|
|
48560
|
+
"Write",
|
|
48561
|
+
"Edit",
|
|
48562
|
+
"NotebookEdit",
|
|
48563
|
+
"Bash"
|
|
48564
|
+
];
|
|
48565
|
+
var DEFAULT_MODE_CONFIG = {
|
|
48566
|
+
name: "default",
|
|
48567
|
+
displayName: "Default",
|
|
48568
|
+
description: "Standard operation mode with all tools available",
|
|
48569
|
+
systemInstructions: "",
|
|
48570
|
+
allowNesting: true,
|
|
48571
|
+
maxNestingDepth: 3
|
|
48572
|
+
};
|
|
48573
|
+
var PLAN_MODE_CONFIG = {
|
|
48574
|
+
name: "plan",
|
|
48575
|
+
displayName: "Plan Mode",
|
|
48576
|
+
description: "Planning mode - read-only exploration without code modifications",
|
|
48577
|
+
blockedTools: [...WRITE_TOOLS],
|
|
48578
|
+
systemInstructions: `## Plan Mode Active
|
|
48579
|
+
|
|
48580
|
+
You are in **Plan Mode**. This mode is for exploration and planning only.
|
|
48581
|
+
|
|
48582
|
+
**Restrictions:**
|
|
48583
|
+
- You CANNOT use Write, Edit, or Bash tools that modify files
|
|
48584
|
+
- Focus on reading, searching, and understanding the codebase
|
|
48585
|
+
- Create a comprehensive plan before implementation
|
|
48586
|
+
|
|
48587
|
+
**Your Goals:**
|
|
48588
|
+
1. Explore the codebase to understand existing patterns
|
|
48589
|
+
2. Identify files that need to be modified
|
|
48590
|
+
3. Design an implementation approach
|
|
48591
|
+
4. Document your plan clearly
|
|
48592
|
+
5. Use ExitPlanMode when ready to implement
|
|
48593
|
+
|
|
48594
|
+
**Remember:** No code modifications in this mode. Plan first, implement later.`,
|
|
48595
|
+
allowNesting: false,
|
|
48596
|
+
autoExitConditions: {
|
|
48597
|
+
onToolUse: ["ExitPlanMode"]
|
|
48598
|
+
}
|
|
48599
|
+
};
|
|
48600
|
+
var ITERATE_MODE_CONFIG = {
|
|
48601
|
+
name: "iterate",
|
|
48602
|
+
displayName: "Iterate Mode",
|
|
48603
|
+
description: "Continuous iteration mode for implementation with automatic continuation",
|
|
48604
|
+
systemInstructions: `## Iterate Mode Active
|
|
48605
|
+
|
|
48606
|
+
You are in **Iterate Mode**. This mode enables continuous task execution.
|
|
48607
|
+
|
|
48608
|
+
**Behavior:**
|
|
48609
|
+
- Continue working until the task is complete
|
|
48610
|
+
- After each step, assess progress and continue
|
|
48611
|
+
- Don't stop to ask for confirmation unless critical
|
|
48612
|
+
- Mark todos as completed as you finish them
|
|
48613
|
+
|
|
48614
|
+
**Guidelines:**
|
|
48615
|
+
1. Work through tasks systematically
|
|
48616
|
+
2. Test changes as you go when possible
|
|
48617
|
+
3. Update todo list to track progress
|
|
48618
|
+
4. Only pause for critical decisions or blockers
|
|
48619
|
+
|
|
48620
|
+
**Remember:** Keep iterating until the task is done or you hit a blocker.`,
|
|
48621
|
+
allowNesting: true,
|
|
48622
|
+
maxNestingDepth: 2
|
|
48623
|
+
};
|
|
48624
|
+
var REVIEW_MODE_CONFIG = {
|
|
48625
|
+
name: "review",
|
|
48626
|
+
displayName: "Review Mode",
|
|
48627
|
+
description: "Code review mode - analyze code quality, security, and best practices",
|
|
48628
|
+
blockedTools: [...WRITE_TOOLS],
|
|
48629
|
+
systemInstructions: `## Review Mode Active
|
|
48630
|
+
|
|
48631
|
+
You are in **Review Mode**. This mode is for code review and analysis.
|
|
48632
|
+
|
|
48633
|
+
**Focus Areas:**
|
|
48634
|
+
- Code quality and readability
|
|
48635
|
+
- Security vulnerabilities (OWASP Top 10)
|
|
48636
|
+
- Performance issues
|
|
48637
|
+
- Best practices and patterns
|
|
48638
|
+
- Test coverage gaps
|
|
48639
|
+
|
|
48640
|
+
**Output Format:**
|
|
48641
|
+
Provide structured feedback:
|
|
48642
|
+
1. **Critical Issues** - Must fix before merge
|
|
48643
|
+
2. **Warnings** - Should address
|
|
48644
|
+
3. **Suggestions** - Nice to have improvements
|
|
48645
|
+
4. **Positive Notes** - Good patterns observed
|
|
48646
|
+
|
|
48647
|
+
**Remember:** No code modifications. Provide actionable feedback only.`,
|
|
48648
|
+
allowNesting: false
|
|
48649
|
+
};
|
|
48650
|
+
var WORKFLOW_MODE_CONFIGS = {
|
|
48651
|
+
default: DEFAULT_MODE_CONFIG,
|
|
48652
|
+
plan: PLAN_MODE_CONFIG,
|
|
48653
|
+
iterate: ITERATE_MODE_CONFIG,
|
|
48654
|
+
review: REVIEW_MODE_CONFIG
|
|
48655
|
+
};
|
|
48656
|
+
function getWorkflowModeConfig(mode) {
|
|
48657
|
+
return WORKFLOW_MODE_CONFIGS[mode];
|
|
48658
|
+
}
|
|
48659
|
+
function isToolAllowedInMode(tool, mode) {
|
|
48660
|
+
const config = getWorkflowModeConfig(mode);
|
|
48661
|
+
if (config.allowedTools && config.allowedTools.length > 0) {
|
|
48662
|
+
return config.allowedTools.includes(tool);
|
|
48663
|
+
}
|
|
48664
|
+
if (config.blockedTools && config.blockedTools.length > 0) {
|
|
48665
|
+
return !config.blockedTools.includes(tool);
|
|
48666
|
+
}
|
|
48667
|
+
return true;
|
|
48668
|
+
}
|
|
48669
|
+
function isValidWorkflowMode(mode) {
|
|
48670
|
+
return mode in WORKFLOW_MODE_CONFIGS;
|
|
48671
|
+
}
|
|
48672
|
+
var WORKFLOW_MODES = WORKFLOW_MODE_CONFIGS;
|
|
48673
|
+
|
|
48674
|
+
// src/core/workflow/workflow-mode-manager.ts
|
|
48675
|
+
init_esm_shims();
|
|
48676
|
+
init_logger();
|
|
48677
|
+
var WorkflowModeManager = class {
|
|
48678
|
+
name = "workflow-mode";
|
|
48679
|
+
modeStack = [];
|
|
48680
|
+
transitionListeners = /* @__PURE__ */ new Set();
|
|
48681
|
+
turnCount = 0;
|
|
48682
|
+
constructor(initialMode = "default") {
|
|
48683
|
+
this.modeStack.push({
|
|
48684
|
+
mode: initialMode,
|
|
48685
|
+
enteredAt: Date.now(),
|
|
48686
|
+
enteredAtTurn: 0,
|
|
48687
|
+
reason: "initial"
|
|
48688
|
+
});
|
|
48689
|
+
logger.debug("WorkflowModeManager initialized", {
|
|
48690
|
+
initialMode
|
|
48691
|
+
});
|
|
48692
|
+
}
|
|
48693
|
+
/**
|
|
48694
|
+
* Get the current active mode
|
|
48695
|
+
*/
|
|
48696
|
+
getCurrentMode() {
|
|
48697
|
+
const top = this.modeStack[this.modeStack.length - 1];
|
|
48698
|
+
return top?.mode ?? "default";
|
|
48699
|
+
}
|
|
48700
|
+
/**
|
|
48701
|
+
* Get the current mode configuration
|
|
48702
|
+
*/
|
|
48703
|
+
getCurrentModeConfig() {
|
|
48704
|
+
const mode = this.getCurrentMode();
|
|
48705
|
+
const entry = this.modeStack[this.modeStack.length - 1];
|
|
48706
|
+
const baseConfig = getWorkflowModeConfig(mode);
|
|
48707
|
+
if (entry?.customConfig) {
|
|
48708
|
+
return {
|
|
48709
|
+
...baseConfig,
|
|
48710
|
+
...entry.customConfig,
|
|
48711
|
+
// Deep merge for nested objects
|
|
48712
|
+
autoExitConditions: {
|
|
48713
|
+
...baseConfig.autoExitConditions,
|
|
48714
|
+
...entry.customConfig.autoExitConditions
|
|
48715
|
+
}
|
|
48716
|
+
};
|
|
48717
|
+
}
|
|
48718
|
+
return baseConfig;
|
|
48719
|
+
}
|
|
48720
|
+
/**
|
|
48721
|
+
* Get the full mode stack
|
|
48722
|
+
*/
|
|
48723
|
+
getModeStack() {
|
|
48724
|
+
return [...this.modeStack];
|
|
48725
|
+
}
|
|
48726
|
+
/**
|
|
48727
|
+
* Get the current stack depth
|
|
48728
|
+
*/
|
|
48729
|
+
getStackDepth() {
|
|
48730
|
+
return this.modeStack.length;
|
|
48731
|
+
}
|
|
48732
|
+
/**
|
|
48733
|
+
* Push a new mode onto the stack
|
|
48734
|
+
*/
|
|
48735
|
+
pushMode(mode, options) {
|
|
48736
|
+
const currentConfig = this.getCurrentModeConfig();
|
|
48737
|
+
if (!currentConfig.allowNesting) {
|
|
48738
|
+
logger.warn("Cannot push mode: current mode does not allow nesting", {
|
|
48739
|
+
currentMode: this.getCurrentMode(),
|
|
48740
|
+
attemptedMode: mode
|
|
48741
|
+
});
|
|
48742
|
+
return false;
|
|
48743
|
+
}
|
|
48744
|
+
const maxDepth = currentConfig.maxNestingDepth ?? 3;
|
|
48745
|
+
if (this.modeStack.length >= maxDepth) {
|
|
48746
|
+
logger.warn("Cannot push mode: max nesting depth reached", {
|
|
48747
|
+
currentDepth: this.modeStack.length,
|
|
48748
|
+
maxDepth
|
|
48749
|
+
});
|
|
48750
|
+
return false;
|
|
48751
|
+
}
|
|
48752
|
+
const previousMode = this.getCurrentMode();
|
|
48753
|
+
this.modeStack.push({
|
|
48754
|
+
mode,
|
|
48755
|
+
enteredAt: Date.now(),
|
|
48756
|
+
enteredAtTurn: this.turnCount,
|
|
48757
|
+
customConfig: options?.customConfig,
|
|
48758
|
+
reason: options?.reason
|
|
48759
|
+
});
|
|
48760
|
+
this.emitTransition({
|
|
48761
|
+
from: previousMode,
|
|
48762
|
+
to: mode,
|
|
48763
|
+
type: "push",
|
|
48764
|
+
timestamp: Date.now(),
|
|
48765
|
+
reason: options?.reason
|
|
48766
|
+
});
|
|
48767
|
+
logger.info("Pushed workflow mode", {
|
|
48768
|
+
from: previousMode,
|
|
48769
|
+
to: mode,
|
|
48770
|
+
stackDepth: this.modeStack.length,
|
|
48771
|
+
reason: options?.reason
|
|
48772
|
+
});
|
|
48773
|
+
return true;
|
|
48774
|
+
}
|
|
48775
|
+
/**
|
|
48776
|
+
* Pop the current mode from the stack
|
|
48777
|
+
*/
|
|
48778
|
+
popMode(reason) {
|
|
48779
|
+
if (this.modeStack.length <= 1) {
|
|
48780
|
+
logger.warn("Cannot pop mode: at base level");
|
|
48781
|
+
return null;
|
|
48782
|
+
}
|
|
48783
|
+
const popped = this.modeStack.pop();
|
|
48784
|
+
const newMode = this.getCurrentMode();
|
|
48785
|
+
if (popped) {
|
|
48786
|
+
this.emitTransition({
|
|
48787
|
+
from: popped.mode,
|
|
48788
|
+
to: newMode,
|
|
48789
|
+
type: "pop",
|
|
48790
|
+
timestamp: Date.now(),
|
|
48791
|
+
reason
|
|
48792
|
+
});
|
|
48793
|
+
logger.info("Popped workflow mode", {
|
|
48794
|
+
from: popped.mode,
|
|
48795
|
+
to: newMode,
|
|
48796
|
+
stackDepth: this.modeStack.length,
|
|
48797
|
+
reason
|
|
48798
|
+
});
|
|
48799
|
+
}
|
|
48800
|
+
return popped?.mode ?? null;
|
|
48801
|
+
}
|
|
48802
|
+
/**
|
|
48803
|
+
* Replace the current mode (pop then push)
|
|
48804
|
+
*/
|
|
48805
|
+
replaceMode(mode, options) {
|
|
48806
|
+
const previousMode = this.getCurrentMode();
|
|
48807
|
+
if (this.modeStack.length === 1) {
|
|
48808
|
+
this.modeStack[0] = {
|
|
48809
|
+
mode,
|
|
48810
|
+
enteredAt: Date.now(),
|
|
48811
|
+
enteredAtTurn: this.turnCount,
|
|
48812
|
+
customConfig: options?.customConfig,
|
|
48813
|
+
reason: options?.reason
|
|
48814
|
+
};
|
|
48815
|
+
} else {
|
|
48816
|
+
this.modeStack.pop();
|
|
48817
|
+
this.modeStack.push({
|
|
48818
|
+
mode,
|
|
48819
|
+
enteredAt: Date.now(),
|
|
48820
|
+
enteredAtTurn: this.turnCount,
|
|
48821
|
+
customConfig: options?.customConfig,
|
|
48822
|
+
reason: options?.reason
|
|
48823
|
+
});
|
|
48824
|
+
}
|
|
48825
|
+
this.emitTransition({
|
|
48826
|
+
from: previousMode,
|
|
48827
|
+
to: mode,
|
|
48828
|
+
type: "replace",
|
|
48829
|
+
timestamp: Date.now(),
|
|
48830
|
+
reason: options?.reason
|
|
48831
|
+
});
|
|
48832
|
+
logger.info("Replaced workflow mode", {
|
|
48833
|
+
from: previousMode,
|
|
48834
|
+
to: mode,
|
|
48835
|
+
reason: options?.reason
|
|
48836
|
+
});
|
|
48837
|
+
return true;
|
|
48838
|
+
}
|
|
48839
|
+
/**
|
|
48840
|
+
* Set mode directly (clears stack and sets new base mode)
|
|
48841
|
+
*/
|
|
48842
|
+
setMode(mode, options) {
|
|
48843
|
+
const previousMode = this.getCurrentMode();
|
|
48844
|
+
this.modeStack = [{
|
|
48845
|
+
mode,
|
|
48846
|
+
enteredAt: Date.now(),
|
|
48847
|
+
enteredAtTurn: this.turnCount,
|
|
48848
|
+
customConfig: options?.customConfig,
|
|
48849
|
+
reason: options?.reason
|
|
48850
|
+
}];
|
|
48851
|
+
this.emitTransition({
|
|
48852
|
+
from: previousMode,
|
|
48853
|
+
to: mode,
|
|
48854
|
+
type: "replace",
|
|
48855
|
+
timestamp: Date.now(),
|
|
48856
|
+
reason: options?.reason
|
|
48857
|
+
});
|
|
48858
|
+
logger.info("Set workflow mode", {
|
|
48859
|
+
from: previousMode,
|
|
48860
|
+
to: mode,
|
|
48861
|
+
reason: options?.reason
|
|
48862
|
+
});
|
|
48863
|
+
}
|
|
48864
|
+
/**
|
|
48865
|
+
* Check if a tool is allowed in the current mode
|
|
48866
|
+
*/
|
|
48867
|
+
isToolAllowed(tool) {
|
|
48868
|
+
return isToolAllowedInMode(tool, this.getCurrentMode());
|
|
48869
|
+
}
|
|
48870
|
+
/**
|
|
48871
|
+
* Get list of blocked tools in current mode
|
|
48872
|
+
*/
|
|
48873
|
+
getBlockedTools() {
|
|
48874
|
+
const config = this.getCurrentModeConfig();
|
|
48875
|
+
return config.blockedTools || [];
|
|
48876
|
+
}
|
|
48877
|
+
/**
|
|
48878
|
+
* Filter a list of tools based on current mode
|
|
48879
|
+
*/
|
|
48880
|
+
filterTools(tools) {
|
|
48881
|
+
return tools.filter((tool) => this.isToolAllowed(tool.name));
|
|
48882
|
+
}
|
|
48883
|
+
/**
|
|
48884
|
+
* Update turn count (for auto-exit tracking)
|
|
48885
|
+
*/
|
|
48886
|
+
updateTurnCount(turn) {
|
|
48887
|
+
this.turnCount = turn;
|
|
48888
|
+
this.checkAutoExit();
|
|
48889
|
+
}
|
|
48890
|
+
/**
|
|
48891
|
+
* Check and handle auto-exit conditions
|
|
48892
|
+
*/
|
|
48893
|
+
checkAutoExit() {
|
|
48894
|
+
const config = this.getCurrentModeConfig();
|
|
48895
|
+
const entry = this.modeStack[this.modeStack.length - 1];
|
|
48896
|
+
if (!config.autoExitConditions || !entry) return;
|
|
48897
|
+
if (config.autoExitConditions.maxTurns) {
|
|
48898
|
+
const turnsInMode = this.turnCount - entry.enteredAtTurn;
|
|
48899
|
+
if (turnsInMode >= config.autoExitConditions.maxTurns) {
|
|
48900
|
+
logger.info("Auto-exiting mode due to max turns", {
|
|
48901
|
+
mode: this.getCurrentMode(),
|
|
48902
|
+
turnsInMode,
|
|
48903
|
+
maxTurns: config.autoExitConditions.maxTurns
|
|
48904
|
+
});
|
|
48905
|
+
this.popMode("max_turns_reached");
|
|
48906
|
+
}
|
|
48907
|
+
}
|
|
48908
|
+
}
|
|
48909
|
+
/**
|
|
48910
|
+
* Notify that a tool was used (for auto-exit on tool use)
|
|
48911
|
+
*/
|
|
48912
|
+
notifyToolUsed(tool) {
|
|
48913
|
+
const config = this.getCurrentModeConfig();
|
|
48914
|
+
if (config.autoExitConditions?.onToolUse?.includes(tool)) {
|
|
48915
|
+
logger.info("Auto-exiting mode due to tool use", {
|
|
48916
|
+
mode: this.getCurrentMode(),
|
|
48917
|
+
tool
|
|
48918
|
+
});
|
|
48919
|
+
this.popMode(`tool_used:${tool}`);
|
|
48920
|
+
}
|
|
48921
|
+
}
|
|
48922
|
+
/**
|
|
48923
|
+
* Add a mode transition listener
|
|
48924
|
+
*/
|
|
48925
|
+
onTransition(listener) {
|
|
48926
|
+
this.transitionListeners.add(listener);
|
|
48927
|
+
return () => this.transitionListeners.delete(listener);
|
|
48928
|
+
}
|
|
48929
|
+
/**
|
|
48930
|
+
* Emit a transition event to all listeners
|
|
48931
|
+
*/
|
|
48932
|
+
emitTransition(event) {
|
|
48933
|
+
for (const listener of this.transitionListeners) {
|
|
48934
|
+
try {
|
|
48935
|
+
listener(event);
|
|
48936
|
+
} catch (error) {
|
|
48937
|
+
logger.error("Mode transition listener error", {
|
|
48938
|
+
error: error instanceof Error ? error.message : String(error)
|
|
48939
|
+
});
|
|
48940
|
+
}
|
|
48941
|
+
}
|
|
48942
|
+
}
|
|
48943
|
+
// InstructionProvider implementation
|
|
48944
|
+
/**
|
|
48945
|
+
* Check if mode instructions should be generated
|
|
48946
|
+
*/
|
|
48947
|
+
shouldGenerate(context) {
|
|
48948
|
+
return this.getCurrentMode() !== "default";
|
|
48949
|
+
}
|
|
48950
|
+
/**
|
|
48951
|
+
* Get mode-specific instructions
|
|
48952
|
+
*/
|
|
48953
|
+
async getInstructions(context) {
|
|
48954
|
+
const config = this.getCurrentModeConfig();
|
|
48955
|
+
const instructions = [];
|
|
48956
|
+
if (config.systemInstructions && config.systemInstructions.length > 0) {
|
|
48957
|
+
instructions.push({
|
|
48958
|
+
type: "mode",
|
|
48959
|
+
priority: "high",
|
|
48960
|
+
content: config.systemInstructions,
|
|
48961
|
+
source: "automatosx",
|
|
48962
|
+
createdAt: Date.now(),
|
|
48963
|
+
id: `mode-${config.name}-${Date.now()}`
|
|
48964
|
+
});
|
|
48965
|
+
}
|
|
48966
|
+
if (config.blockedTools && config.blockedTools.length > 0) {
|
|
48967
|
+
instructions.push({
|
|
48968
|
+
type: "mode",
|
|
48969
|
+
priority: "critical",
|
|
48970
|
+
content: `**Tool Restrictions:** The following tools are NOT available in ${config.displayName}: ${config.blockedTools.join(", ")}`,
|
|
48971
|
+
source: "automatosx",
|
|
48972
|
+
createdAt: Date.now(),
|
|
48973
|
+
id: `mode-blocked-tools-${Date.now()}`
|
|
48974
|
+
});
|
|
48975
|
+
}
|
|
48976
|
+
return instructions;
|
|
48977
|
+
}
|
|
48978
|
+
/**
|
|
48979
|
+
* Reset to default state
|
|
48980
|
+
*/
|
|
48981
|
+
reset() {
|
|
48982
|
+
const previousMode = this.getCurrentMode();
|
|
48983
|
+
this.modeStack = [{
|
|
48984
|
+
mode: "default",
|
|
48985
|
+
enteredAt: Date.now(),
|
|
48986
|
+
enteredAtTurn: 0,
|
|
48987
|
+
reason: "reset"
|
|
48988
|
+
}];
|
|
48989
|
+
this.turnCount = 0;
|
|
48990
|
+
if (previousMode !== "default") {
|
|
48991
|
+
this.emitTransition({
|
|
48992
|
+
from: previousMode,
|
|
48993
|
+
to: "default",
|
|
48994
|
+
type: "replace",
|
|
48995
|
+
timestamp: Date.now(),
|
|
48996
|
+
reason: "reset"
|
|
48997
|
+
});
|
|
48998
|
+
}
|
|
48999
|
+
logger.debug("WorkflowModeManager reset");
|
|
49000
|
+
}
|
|
49001
|
+
/**
|
|
49002
|
+
* Get status information for debugging
|
|
49003
|
+
*/
|
|
49004
|
+
getStatus() {
|
|
49005
|
+
return {
|
|
49006
|
+
currentMode: this.getCurrentMode(),
|
|
49007
|
+
stackDepth: this.modeStack.length,
|
|
49008
|
+
stack: this.modeStack.map((entry) => ({
|
|
49009
|
+
mode: entry.mode,
|
|
49010
|
+
enteredAt: entry.enteredAt,
|
|
49011
|
+
reason: entry.reason
|
|
49012
|
+
})),
|
|
49013
|
+
blockedTools: this.getBlockedTools(),
|
|
49014
|
+
turnCount: this.turnCount
|
|
49015
|
+
};
|
|
49016
|
+
}
|
|
49017
|
+
};
|
|
49018
|
+
|
|
49019
|
+
// src/cli/commands/mode.ts
|
|
49020
|
+
var modeCommand = {
|
|
49021
|
+
command: "mode [mode]",
|
|
49022
|
+
describe: "Manage workflow modes for embedded instructions (v11.3.0)",
|
|
49023
|
+
builder: (yargs2) => {
|
|
49024
|
+
return yargs2.positional("mode", {
|
|
49025
|
+
describe: "Workflow mode to set (default, plan, iterate, review)",
|
|
49026
|
+
type: "string"
|
|
49027
|
+
}).option("list", {
|
|
49028
|
+
alias: "l",
|
|
49029
|
+
describe: "List available workflow modes",
|
|
49030
|
+
type: "boolean",
|
|
49031
|
+
default: false
|
|
49032
|
+
}).option("status", {
|
|
49033
|
+
alias: "s",
|
|
49034
|
+
describe: "Show current workflow mode status",
|
|
49035
|
+
type: "boolean",
|
|
49036
|
+
default: false
|
|
49037
|
+
}).example("$0 mode plan", "Enter plan mode (restricts code-modifying tools)").example("$0 mode iterate", "Enter iterate mode (for autonomous execution)").example("$0 mode default", "Return to default mode").example("$0 mode --list", "List all available modes").example("$0 mode --status", "Show current mode status");
|
|
49038
|
+
},
|
|
49039
|
+
handler: async (argv) => {
|
|
49040
|
+
try {
|
|
49041
|
+
if (argv.list) {
|
|
49042
|
+
displayModeList();
|
|
49043
|
+
return;
|
|
49044
|
+
}
|
|
49045
|
+
if (argv.status || !argv.mode) {
|
|
49046
|
+
displayModeStatus();
|
|
49047
|
+
return;
|
|
49048
|
+
}
|
|
49049
|
+
const modeName = argv.mode.toLowerCase();
|
|
49050
|
+
if (!isValidWorkflowMode(modeName)) {
|
|
49051
|
+
console.error(chalk5.red.bold(`
|
|
49052
|
+
\u274C Invalid workflow mode: ${argv.mode}
|
|
49053
|
+
`));
|
|
49054
|
+
console.log(chalk5.gray("Available modes:"));
|
|
49055
|
+
Object.keys(WORKFLOW_MODES).forEach((mode) => {
|
|
49056
|
+
console.log(chalk5.cyan(` \u2022 ${mode}`));
|
|
49057
|
+
});
|
|
49058
|
+
console.log();
|
|
49059
|
+
process.exit(1);
|
|
49060
|
+
}
|
|
49061
|
+
const modeConfig = WORKFLOW_MODES[modeName];
|
|
49062
|
+
console.log(chalk5.green.bold(`
|
|
49063
|
+
\u2705 Workflow mode set to: ${modeName}
|
|
49064
|
+
`));
|
|
49065
|
+
console.log(chalk5.gray(`Description: ${modeConfig.description}`));
|
|
49066
|
+
if (modeConfig.blockedTools && modeConfig.blockedTools.length > 0) {
|
|
49067
|
+
console.log(chalk5.yellow("\nRestricted tools in this mode:"));
|
|
49068
|
+
modeConfig.blockedTools.forEach((tool) => {
|
|
49069
|
+
console.log(chalk5.yellow(` \u2022 ${tool}`));
|
|
49070
|
+
});
|
|
49071
|
+
}
|
|
49072
|
+
if (modeConfig.allowedTools && modeConfig.allowedTools.length > 0) {
|
|
49073
|
+
console.log(chalk5.cyan("\nAllowed tools in this mode:"));
|
|
49074
|
+
modeConfig.allowedTools.forEach((tool) => {
|
|
49075
|
+
console.log(chalk5.cyan(` \u2022 ${tool}`));
|
|
49076
|
+
});
|
|
49077
|
+
}
|
|
49078
|
+
console.log();
|
|
49079
|
+
console.log(chalk5.gray("Note: Mode setting applies to the current session."));
|
|
49080
|
+
console.log(chalk5.gray("Use with --iterate flag in ax run for persistent mode.\n"));
|
|
49081
|
+
logger.info("Workflow mode set", { mode: modeName });
|
|
49082
|
+
} catch (error) {
|
|
49083
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
49084
|
+
console.error(chalk5.red.bold(`
|
|
49085
|
+
\u274C Error: ${err.message}
|
|
49086
|
+
`));
|
|
49087
|
+
logger.error("Mode command failed", { error: err.message });
|
|
49088
|
+
process.exit(1);
|
|
49089
|
+
}
|
|
49090
|
+
}
|
|
49091
|
+
};
|
|
49092
|
+
function displayModeList() {
|
|
49093
|
+
console.log(chalk5.blue.bold("\n\u{1F4CB} Available Workflow Modes\n"));
|
|
49094
|
+
console.log(chalk5.dim("\u2500".repeat(60)));
|
|
49095
|
+
for (const [name, config] of Object.entries(WORKFLOW_MODES)) {
|
|
49096
|
+
console.log();
|
|
49097
|
+
console.log(chalk5.cyan.bold(` ${name}`));
|
|
49098
|
+
console.log(chalk5.gray(` ${config.description}`));
|
|
49099
|
+
if (config.blockedTools && config.blockedTools.length > 0) {
|
|
49100
|
+
console.log(chalk5.yellow(` Blocked: ${config.blockedTools.join(", ")}`));
|
|
49101
|
+
}
|
|
49102
|
+
if (config.maxNestingDepth !== void 0) {
|
|
49103
|
+
console.log(chalk5.gray(` Max nesting depth: ${config.maxNestingDepth}`));
|
|
49104
|
+
}
|
|
49105
|
+
}
|
|
49106
|
+
console.log();
|
|
49107
|
+
console.log(chalk5.dim("\u2500".repeat(60)));
|
|
49108
|
+
console.log(chalk5.gray("\nUsage: ax mode <mode-name>"));
|
|
49109
|
+
console.log(chalk5.gray("Example: ax mode plan\n"));
|
|
49110
|
+
}
|
|
49111
|
+
function displayModeStatus() {
|
|
49112
|
+
const currentMode = "default";
|
|
49113
|
+
const modeConfig = WORKFLOW_MODES[currentMode];
|
|
49114
|
+
console.log(chalk5.blue.bold("\n\u{1F4CA} Workflow Mode Status\n"));
|
|
49115
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
49116
|
+
console.log(` Current mode: ${chalk5.cyan.bold(currentMode)}`);
|
|
49117
|
+
console.log(` Description: ${chalk5.gray(modeConfig.description)}`);
|
|
49118
|
+
if (modeConfig.blockedTools && modeConfig.blockedTools.length > 0) {
|
|
49119
|
+
console.log(` Blocked tools: ${chalk5.yellow(modeConfig.blockedTools.length)}`);
|
|
49120
|
+
} else {
|
|
49121
|
+
console.log(` Blocked tools: ${chalk5.green("none")}`);
|
|
49122
|
+
}
|
|
49123
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
49124
|
+
console.log();
|
|
49125
|
+
console.log(chalk5.gray("To change mode: ax mode <mode-name>"));
|
|
49126
|
+
console.log(chalk5.gray("To list modes: ax mode --list\n"));
|
|
49127
|
+
}
|
|
49128
|
+
|
|
49129
|
+
// src/cli/commands/debug-instructions.ts
|
|
49130
|
+
init_esm_shims();
|
|
49131
|
+
init_logger();
|
|
49132
|
+
|
|
49133
|
+
// src/core/orchestration/orchestration-service.ts
|
|
49134
|
+
init_esm_shims();
|
|
49135
|
+
init_logger();
|
|
49136
|
+
|
|
49137
|
+
// src/core/orchestration/types.ts
|
|
49138
|
+
init_esm_shims();
|
|
49139
|
+
z.object({
|
|
49140
|
+
type: z.enum(["task", "memory", "session", "delegation", "mode"]),
|
|
49141
|
+
priority: z.enum(["critical", "high", "normal", "low"]),
|
|
49142
|
+
content: z.string().min(1).max(5e3),
|
|
49143
|
+
source: z.literal("automatosx"),
|
|
49144
|
+
expiresAfter: z.number().int().positive().optional(),
|
|
49145
|
+
createdAt: z.number(),
|
|
49146
|
+
id: z.string().optional()
|
|
49147
|
+
});
|
|
49148
|
+
var TodoItemSchema = z.object({
|
|
49149
|
+
id: z.string(),
|
|
49150
|
+
content: z.string().min(1).max(1e3),
|
|
49151
|
+
status: z.enum(["pending", "in_progress", "completed"]),
|
|
49152
|
+
activeForm: z.string().min(1).max(1e3),
|
|
49153
|
+
createdAt: z.number(),
|
|
49154
|
+
updatedAt: z.number().optional(),
|
|
49155
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
49156
|
+
});
|
|
49157
|
+
z.object({
|
|
49158
|
+
name: z.enum(["default", "plan", "iterate", "review"]),
|
|
49159
|
+
description: z.string(),
|
|
49160
|
+
allowedTools: z.array(z.string()).optional(),
|
|
49161
|
+
blockedTools: z.array(z.string()).optional(),
|
|
49162
|
+
systemInstructions: z.string(),
|
|
49163
|
+
allowNesting: z.boolean()
|
|
49164
|
+
});
|
|
49165
|
+
z.object({
|
|
49166
|
+
todos: z.array(TodoItemSchema),
|
|
49167
|
+
currentTask: z.string().optional(),
|
|
49168
|
+
agentName: z.string().optional(),
|
|
49169
|
+
turnCount: z.number().int().nonnegative(),
|
|
49170
|
+
workflowMode: z.enum(["default", "plan", "iterate", "review"]),
|
|
49171
|
+
sessionId: z.string().optional(),
|
|
49172
|
+
parentAgent: z.string().optional(),
|
|
49173
|
+
memories: z.array(z.object({
|
|
49174
|
+
content: z.string(),
|
|
49175
|
+
relevance: z.number().min(0).max(1),
|
|
49176
|
+
agent: z.string().optional(),
|
|
49177
|
+
timestamp: z.number()
|
|
49178
|
+
})).optional()
|
|
49179
|
+
});
|
|
49180
|
+
var DEFAULT_TOKEN_BUDGET = {
|
|
49181
|
+
maxTotal: 2e3,
|
|
49182
|
+
perType: {
|
|
49183
|
+
task: 500,
|
|
49184
|
+
memory: 600,
|
|
49185
|
+
session: 300,
|
|
49186
|
+
delegation: 200,
|
|
49187
|
+
mode: 400
|
|
49188
|
+
},
|
|
49189
|
+
criticalReserve: 300
|
|
49190
|
+
};
|
|
49191
|
+
var TokenBudgetConfigSchema = z.object({
|
|
49192
|
+
maxTotal: z.number().int().positive().max(1e4),
|
|
49193
|
+
perType: z.record(
|
|
49194
|
+
z.enum(["task", "memory", "session", "delegation", "mode"]),
|
|
49195
|
+
z.number().int().nonnegative()
|
|
49196
|
+
),
|
|
49197
|
+
criticalReserve: z.number().int().nonnegative()
|
|
49198
|
+
});
|
|
49199
|
+
var DEFAULT_ORCHESTRATION_CONFIG = {
|
|
49200
|
+
enabled: true,
|
|
49201
|
+
tokenBudget: DEFAULT_TOKEN_BUDGET,
|
|
49202
|
+
todoIntegration: {
|
|
49203
|
+
enabled: true,
|
|
49204
|
+
reminderFrequency: 3,
|
|
49205
|
+
compactMode: false
|
|
49206
|
+
},
|
|
49207
|
+
memoryIntegration: {
|
|
49208
|
+
enabled: true,
|
|
49209
|
+
maxEntries: 5,
|
|
49210
|
+
minRelevance: 0.5
|
|
49211
|
+
},
|
|
49212
|
+
sessionIntegration: {
|
|
49213
|
+
enabled: true,
|
|
49214
|
+
showCollaboration: true
|
|
49215
|
+
},
|
|
49216
|
+
agentTemplates: {
|
|
49217
|
+
enabled: true,
|
|
49218
|
+
reminderFrequency: 5
|
|
49219
|
+
}
|
|
49220
|
+
};
|
|
49221
|
+
z.object({
|
|
49222
|
+
enabled: z.boolean(),
|
|
49223
|
+
tokenBudget: TokenBudgetConfigSchema,
|
|
49224
|
+
todoIntegration: z.object({
|
|
49225
|
+
enabled: z.boolean(),
|
|
49226
|
+
reminderFrequency: z.number().int().positive(),
|
|
49227
|
+
compactMode: z.boolean()
|
|
49228
|
+
}),
|
|
49229
|
+
memoryIntegration: z.object({
|
|
49230
|
+
enabled: z.boolean(),
|
|
49231
|
+
maxEntries: z.number().int().nonnegative(),
|
|
49232
|
+
minRelevance: z.number().min(0).max(1)
|
|
49233
|
+
}),
|
|
49234
|
+
sessionIntegration: z.object({
|
|
49235
|
+
enabled: z.boolean(),
|
|
49236
|
+
showCollaboration: z.boolean()
|
|
49237
|
+
}),
|
|
49238
|
+
agentTemplates: z.object({
|
|
49239
|
+
enabled: z.boolean(),
|
|
49240
|
+
reminderFrequency: z.number().int().positive()
|
|
49241
|
+
})
|
|
49242
|
+
});
|
|
49243
|
+
|
|
49244
|
+
// src/core/orchestration/instruction-injector.ts
|
|
49245
|
+
init_esm_shims();
|
|
49246
|
+
init_logger();
|
|
49247
|
+
|
|
49248
|
+
// src/core/orchestration/token-budget.ts
|
|
49249
|
+
init_esm_shims();
|
|
49250
|
+
init_logger();
|
|
49251
|
+
var TokenBudgetManager = class _TokenBudgetManager {
|
|
49252
|
+
config;
|
|
49253
|
+
/** Characters per token estimate (conservative) */
|
|
49254
|
+
static CHARS_PER_TOKEN = 4;
|
|
49255
|
+
constructor(config) {
|
|
49256
|
+
this.config = {
|
|
49257
|
+
...DEFAULT_TOKEN_BUDGET,
|
|
49258
|
+
...config,
|
|
49259
|
+
perType: {
|
|
49260
|
+
...DEFAULT_TOKEN_BUDGET.perType,
|
|
49261
|
+
...config?.perType
|
|
49262
|
+
}
|
|
49263
|
+
};
|
|
49264
|
+
logger.debug("TokenBudgetManager initialized", {
|
|
49265
|
+
maxTotal: this.config.maxTotal,
|
|
49266
|
+
criticalReserve: this.config.criticalReserve
|
|
49267
|
+
});
|
|
49268
|
+
}
|
|
49269
|
+
/**
|
|
49270
|
+
* Estimate tokens for a string
|
|
49271
|
+
*/
|
|
49272
|
+
estimateTokens(content) {
|
|
49273
|
+
const characters = content.length;
|
|
49274
|
+
const tokens = Math.ceil(characters / _TokenBudgetManager.CHARS_PER_TOKEN);
|
|
49275
|
+
return {
|
|
49276
|
+
tokens,
|
|
49277
|
+
characters,
|
|
49278
|
+
isEstimate: true
|
|
49279
|
+
};
|
|
49280
|
+
}
|
|
49281
|
+
/**
|
|
49282
|
+
* Estimate tokens for an instruction (including formatting overhead)
|
|
49283
|
+
*/
|
|
49284
|
+
estimateInstructionTokens(instruction) {
|
|
49285
|
+
const overhead = 50;
|
|
49286
|
+
const contentTokens = this.estimateTokens(instruction.content).tokens;
|
|
49287
|
+
return contentTokens + overhead;
|
|
49288
|
+
}
|
|
49289
|
+
/**
|
|
49290
|
+
* Allocate budget for instructions
|
|
49291
|
+
*
|
|
49292
|
+
* Priority order:
|
|
49293
|
+
* 1. Critical instructions (always included, use reserve)
|
|
49294
|
+
* 2. High priority (included if budget allows)
|
|
49295
|
+
* 3. Normal priority (included if budget allows)
|
|
49296
|
+
* 4. Low priority (only if significant budget remains)
|
|
49297
|
+
*/
|
|
49298
|
+
allocateBudget(instructions) {
|
|
49299
|
+
const included = [];
|
|
49300
|
+
const excluded = [];
|
|
49301
|
+
const perTypeUsage = {
|
|
49302
|
+
task: 0,
|
|
49303
|
+
memory: 0,
|
|
49304
|
+
session: 0,
|
|
49305
|
+
delegation: 0,
|
|
49306
|
+
mode: 0
|
|
49307
|
+
};
|
|
49308
|
+
let tokensUsed = 0;
|
|
49309
|
+
const availableBudget = this.config.maxTotal;
|
|
49310
|
+
const priorityOrder = {
|
|
49311
|
+
critical: 0,
|
|
49312
|
+
high: 1,
|
|
49313
|
+
normal: 2,
|
|
49314
|
+
low: 3
|
|
49315
|
+
};
|
|
49316
|
+
const sorted = [...instructions].sort((a, b) => {
|
|
49317
|
+
const aPriority = priorityOrder[a.priority] ?? 2;
|
|
49318
|
+
const bPriority = priorityOrder[b.priority] ?? 2;
|
|
49319
|
+
const priorityDiff = aPriority - bPriority;
|
|
49320
|
+
if (priorityDiff !== 0) return priorityDiff;
|
|
49321
|
+
return a.createdAt - b.createdAt;
|
|
49322
|
+
});
|
|
49323
|
+
for (const instruction of sorted) {
|
|
49324
|
+
const instructionTokens = this.estimateInstructionTokens(instruction);
|
|
49325
|
+
const typeLimit = this.config.perType[instruction.type] || 0;
|
|
49326
|
+
const currentTypeUsage = perTypeUsage[instruction.type] || 0;
|
|
49327
|
+
const wouldExceedTotal = tokensUsed + instructionTokens > availableBudget;
|
|
49328
|
+
const wouldExceedTypeLimit = currentTypeUsage + instructionTokens > typeLimit;
|
|
49329
|
+
if (instruction.priority === "critical") {
|
|
49330
|
+
const criticalBudget = availableBudget + this.config.criticalReserve;
|
|
49331
|
+
if (tokensUsed + instructionTokens <= criticalBudget) {
|
|
49332
|
+
included.push(instruction);
|
|
49333
|
+
tokensUsed += instructionTokens;
|
|
49334
|
+
perTypeUsage[instruction.type] = currentTypeUsage + instructionTokens;
|
|
49335
|
+
continue;
|
|
49336
|
+
}
|
|
49337
|
+
}
|
|
49338
|
+
if (!wouldExceedTotal && !wouldExceedTypeLimit) {
|
|
49339
|
+
included.push(instruction);
|
|
49340
|
+
tokensUsed += instructionTokens;
|
|
49341
|
+
perTypeUsage[instruction.type] = currentTypeUsage + instructionTokens;
|
|
49342
|
+
} else {
|
|
49343
|
+
excluded.push(instruction);
|
|
49344
|
+
logger.debug("Instruction excluded from budget", {
|
|
49345
|
+
type: instruction.type,
|
|
49346
|
+
priority: instruction.priority,
|
|
49347
|
+
tokens: instructionTokens,
|
|
49348
|
+
reason: wouldExceedTotal ? "total_limit" : "type_limit"
|
|
49349
|
+
});
|
|
49350
|
+
}
|
|
49351
|
+
}
|
|
49352
|
+
const result = {
|
|
49353
|
+
included,
|
|
49354
|
+
excluded,
|
|
49355
|
+
tokensUsed,
|
|
49356
|
+
remaining: availableBudget - tokensUsed,
|
|
49357
|
+
perTypeUsage
|
|
49358
|
+
};
|
|
49359
|
+
logger.debug("Budget allocation complete", {
|
|
49360
|
+
included: included.length,
|
|
49361
|
+
excluded: excluded.length,
|
|
49362
|
+
tokensUsed,
|
|
49363
|
+
remaining: result.remaining
|
|
49364
|
+
});
|
|
49365
|
+
return result;
|
|
49366
|
+
}
|
|
49367
|
+
/**
|
|
49368
|
+
* Check if an instruction fits within budget
|
|
49369
|
+
*/
|
|
49370
|
+
fitsInBudget(instruction, currentUsage, typeUsage) {
|
|
49371
|
+
const instructionTokens = this.estimateInstructionTokens(instruction);
|
|
49372
|
+
const typeLimit = this.config.perType[instruction.type] || 0;
|
|
49373
|
+
const currentTypeUsage = typeUsage[instruction.type] || 0;
|
|
49374
|
+
if (instruction.priority === "critical") {
|
|
49375
|
+
return currentUsage + instructionTokens <= this.config.maxTotal + this.config.criticalReserve;
|
|
49376
|
+
}
|
|
49377
|
+
return currentUsage + instructionTokens <= this.config.maxTotal && currentTypeUsage + instructionTokens <= typeLimit;
|
|
49378
|
+
}
|
|
49379
|
+
/**
|
|
49380
|
+
* Get current configuration
|
|
49381
|
+
*/
|
|
49382
|
+
getConfig() {
|
|
49383
|
+
return { ...this.config };
|
|
49384
|
+
}
|
|
49385
|
+
/**
|
|
49386
|
+
* Update configuration
|
|
49387
|
+
*/
|
|
49388
|
+
updateConfig(updates) {
|
|
49389
|
+
this.config = {
|
|
49390
|
+
...this.config,
|
|
49391
|
+
...updates,
|
|
49392
|
+
perType: {
|
|
49393
|
+
...this.config.perType,
|
|
49394
|
+
...updates.perType
|
|
49395
|
+
}
|
|
49396
|
+
};
|
|
49397
|
+
logger.debug("TokenBudgetManager config updated", {
|
|
49398
|
+
maxTotal: this.config.maxTotal
|
|
49399
|
+
});
|
|
49400
|
+
}
|
|
49401
|
+
/**
|
|
49402
|
+
* Get remaining budget for a specific type
|
|
49403
|
+
*/
|
|
49404
|
+
getRemainingTypeBudget(type, currentTypeUsage) {
|
|
49405
|
+
const limit = this.config.perType[type] || 0;
|
|
49406
|
+
const used = currentTypeUsage[type] || 0;
|
|
49407
|
+
return Math.max(0, limit - used);
|
|
49408
|
+
}
|
|
49409
|
+
/**
|
|
49410
|
+
* Format budget status for debugging
|
|
49411
|
+
*/
|
|
49412
|
+
formatBudgetStatus(allocation) {
|
|
49413
|
+
const lines = [
|
|
49414
|
+
`Token Budget Status:`,
|
|
49415
|
+
` Total: ${allocation.tokensUsed}/${this.config.maxTotal} (${allocation.remaining} remaining)`,
|
|
49416
|
+
` Per-Type Usage:`
|
|
49417
|
+
];
|
|
49418
|
+
for (const [type, used] of Object.entries(allocation.perTypeUsage)) {
|
|
49419
|
+
const limit = this.config.perType[type] || 0;
|
|
49420
|
+
lines.push(` ${type}: ${used}/${limit}`);
|
|
49421
|
+
}
|
|
49422
|
+
if (allocation.excluded.length > 0) {
|
|
49423
|
+
lines.push(` Excluded: ${allocation.excluded.length} instruction(s)`);
|
|
49424
|
+
}
|
|
49425
|
+
return lines.join("\n");
|
|
49426
|
+
}
|
|
49427
|
+
};
|
|
49428
|
+
|
|
49429
|
+
// src/core/orchestration/instruction-injector.ts
|
|
49430
|
+
var OrchestrationInstructionInjector = class {
|
|
49431
|
+
providers = /* @__PURE__ */ new Map();
|
|
49432
|
+
budgetManager;
|
|
49433
|
+
config;
|
|
49434
|
+
lastInjectionTime = 0;
|
|
49435
|
+
instructionCache = /* @__PURE__ */ new Map();
|
|
49436
|
+
constructor(config) {
|
|
49437
|
+
this.config = {
|
|
49438
|
+
...DEFAULT_ORCHESTRATION_CONFIG,
|
|
49439
|
+
...config
|
|
49440
|
+
};
|
|
49441
|
+
this.budgetManager = new TokenBudgetManager(this.config.tokenBudget);
|
|
49442
|
+
logger.debug("OrchestrationInstructionInjector initialized", {
|
|
49443
|
+
enabled: this.config.enabled,
|
|
49444
|
+
providers: this.providers.size
|
|
49445
|
+
});
|
|
49446
|
+
}
|
|
49447
|
+
/**
|
|
49448
|
+
* Register an instruction provider
|
|
49449
|
+
*/
|
|
49450
|
+
registerProvider(provider) {
|
|
49451
|
+
if (this.providers.has(provider.name)) {
|
|
49452
|
+
logger.warn("Provider already registered, replacing", {
|
|
49453
|
+
name: provider.name
|
|
49454
|
+
});
|
|
49455
|
+
}
|
|
49456
|
+
this.providers.set(provider.name, provider);
|
|
49457
|
+
logger.debug("Instruction provider registered", {
|
|
49458
|
+
name: provider.name,
|
|
49459
|
+
totalProviders: this.providers.size
|
|
49460
|
+
});
|
|
49461
|
+
}
|
|
49462
|
+
/**
|
|
49463
|
+
* Unregister an instruction provider
|
|
49464
|
+
*/
|
|
49465
|
+
unregisterProvider(name) {
|
|
49466
|
+
const removed = this.providers.delete(name);
|
|
49467
|
+
if (removed) {
|
|
49468
|
+
logger.debug("Instruction provider unregistered", { name });
|
|
49469
|
+
}
|
|
49470
|
+
return removed;
|
|
49471
|
+
}
|
|
49472
|
+
/**
|
|
49473
|
+
* Get all registered providers
|
|
49474
|
+
*/
|
|
49475
|
+
getProviders() {
|
|
49476
|
+
return Array.from(this.providers.values());
|
|
49477
|
+
}
|
|
49478
|
+
/**
|
|
49479
|
+
* Generate and inject instructions based on context
|
|
49480
|
+
*/
|
|
49481
|
+
async inject(context, options = {}) {
|
|
49482
|
+
if (!this.config.enabled) {
|
|
49483
|
+
return this.emptyResult();
|
|
49484
|
+
}
|
|
49485
|
+
const startTime = Date.now();
|
|
49486
|
+
const allInstructions = [];
|
|
49487
|
+
for (const provider of this.providers.values()) {
|
|
49488
|
+
try {
|
|
49489
|
+
if (!provider.shouldGenerate(context)) {
|
|
49490
|
+
continue;
|
|
49491
|
+
}
|
|
49492
|
+
const instructions = await provider.getInstructions(context);
|
|
49493
|
+
let filtered = instructions;
|
|
49494
|
+
if (options.includeTypes) {
|
|
49495
|
+
filtered = filtered.filter((i) => options.includeTypes.includes(i.type));
|
|
49496
|
+
}
|
|
49497
|
+
if (options.excludeTypes) {
|
|
49498
|
+
filtered = filtered.filter((i) => !options.excludeTypes.includes(i.type));
|
|
49499
|
+
}
|
|
49500
|
+
allInstructions.push(...filtered);
|
|
49501
|
+
} catch (error) {
|
|
49502
|
+
logger.error("Provider failed to generate instructions", {
|
|
49503
|
+
provider: provider.name,
|
|
49504
|
+
error: error instanceof Error ? error.message : String(error)
|
|
49505
|
+
});
|
|
49506
|
+
}
|
|
49507
|
+
}
|
|
49508
|
+
const activeInstructions = this.filterExpiredInstructions(
|
|
49509
|
+
allInstructions,
|
|
49510
|
+
context.turnCount
|
|
49511
|
+
);
|
|
49512
|
+
let allocation;
|
|
49513
|
+
if (options.skipBudget) {
|
|
49514
|
+
allocation = {
|
|
49515
|
+
included: activeInstructions,
|
|
49516
|
+
excluded: [],
|
|
49517
|
+
tokensUsed: activeInstructions.reduce(
|
|
49518
|
+
(sum, i) => sum + this.budgetManager.estimateInstructionTokens(i),
|
|
49519
|
+
0
|
|
49520
|
+
),
|
|
49521
|
+
remaining: 0,
|
|
49522
|
+
perTypeUsage: this.calculateTypeUsage(activeInstructions)
|
|
49523
|
+
};
|
|
49524
|
+
} else {
|
|
49525
|
+
allocation = this.budgetManager.allocateBudget(activeInstructions);
|
|
49526
|
+
}
|
|
49527
|
+
const formattedText = this.formatInstructions(allocation.included);
|
|
49528
|
+
this.lastInjectionTime = Date.now();
|
|
49529
|
+
const duration = Date.now() - startTime;
|
|
49530
|
+
logger.debug("Instruction injection complete", {
|
|
49531
|
+
providers: this.providers.size,
|
|
49532
|
+
instructionsGenerated: allInstructions.length,
|
|
49533
|
+
instructionsIncluded: allocation.included.length,
|
|
49534
|
+
tokensUsed: allocation.tokensUsed,
|
|
49535
|
+
durationMs: duration
|
|
49536
|
+
});
|
|
49537
|
+
return {
|
|
49538
|
+
formattedText,
|
|
49539
|
+
instructions: allocation.included,
|
|
49540
|
+
allocation,
|
|
49541
|
+
hasInstructions: allocation.included.length > 0
|
|
49542
|
+
};
|
|
49543
|
+
}
|
|
49544
|
+
/**
|
|
49545
|
+
* Format instructions as system reminder tags
|
|
49546
|
+
*/
|
|
49547
|
+
formatInstructions(instructions) {
|
|
49548
|
+
if (instructions.length === 0) {
|
|
49549
|
+
return "";
|
|
49550
|
+
}
|
|
49551
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
49552
|
+
for (const instruction of instructions) {
|
|
49553
|
+
const existing = grouped.get(instruction.type) || [];
|
|
49554
|
+
existing.push(instruction);
|
|
49555
|
+
grouped.set(instruction.type, existing);
|
|
49556
|
+
}
|
|
49557
|
+
const parts = [];
|
|
49558
|
+
const typeOrder = ["mode", "task", "memory", "session", "delegation"];
|
|
49559
|
+
for (const type of typeOrder) {
|
|
49560
|
+
const typeInstructions = grouped.get(type);
|
|
49561
|
+
if (!typeInstructions || typeInstructions.length === 0) continue;
|
|
49562
|
+
for (const instruction of typeInstructions) {
|
|
49563
|
+
parts.push(this.formatSingleInstruction(instruction));
|
|
49564
|
+
}
|
|
49565
|
+
}
|
|
49566
|
+
return parts.join("\n");
|
|
49567
|
+
}
|
|
49568
|
+
/**
|
|
49569
|
+
* Format a single instruction as a system reminder
|
|
49570
|
+
*/
|
|
49571
|
+
formatSingleInstruction(instruction) {
|
|
49572
|
+
return `<system-reminder>
|
|
49573
|
+
${instruction.content}
|
|
49574
|
+
</system-reminder>`;
|
|
49575
|
+
}
|
|
49576
|
+
/**
|
|
49577
|
+
* Filter out expired instructions
|
|
49578
|
+
*/
|
|
49579
|
+
filterExpiredInstructions(instructions, currentTurn) {
|
|
49580
|
+
return instructions.filter((instruction) => {
|
|
49581
|
+
if (instruction.expiresAfter === void 0) {
|
|
49582
|
+
return true;
|
|
49583
|
+
}
|
|
49584
|
+
const turnsSinceCreation = currentTurn;
|
|
49585
|
+
return turnsSinceCreation < instruction.expiresAfter;
|
|
49586
|
+
});
|
|
49587
|
+
}
|
|
49588
|
+
/**
|
|
49589
|
+
* Calculate per-type token usage
|
|
49590
|
+
*/
|
|
49591
|
+
calculateTypeUsage(instructions) {
|
|
49592
|
+
const usage = {
|
|
49593
|
+
task: 0,
|
|
49594
|
+
memory: 0,
|
|
49595
|
+
session: 0,
|
|
49596
|
+
delegation: 0,
|
|
49597
|
+
mode: 0
|
|
49598
|
+
};
|
|
49599
|
+
for (const instruction of instructions) {
|
|
49600
|
+
const tokens = this.budgetManager.estimateInstructionTokens(instruction);
|
|
49601
|
+
usage[instruction.type] = (usage[instruction.type] || 0) + tokens;
|
|
49602
|
+
}
|
|
49603
|
+
return usage;
|
|
49604
|
+
}
|
|
49605
|
+
/**
|
|
49606
|
+
* Create an empty result
|
|
49607
|
+
*/
|
|
49608
|
+
emptyResult() {
|
|
49609
|
+
return {
|
|
49610
|
+
formattedText: "",
|
|
49611
|
+
instructions: [],
|
|
49612
|
+
allocation: {
|
|
49613
|
+
included: [],
|
|
49614
|
+
excluded: [],
|
|
49615
|
+
tokensUsed: 0,
|
|
49616
|
+
remaining: this.budgetManager.getConfig().maxTotal,
|
|
49617
|
+
perTypeUsage: {
|
|
49618
|
+
task: 0,
|
|
49619
|
+
memory: 0,
|
|
49620
|
+
session: 0,
|
|
49621
|
+
delegation: 0,
|
|
49622
|
+
mode: 0
|
|
49623
|
+
}
|
|
49624
|
+
},
|
|
49625
|
+
hasInstructions: false
|
|
49626
|
+
};
|
|
49627
|
+
}
|
|
49628
|
+
/**
|
|
49629
|
+
* Clear instruction cache
|
|
49630
|
+
*/
|
|
49631
|
+
clearCache() {
|
|
49632
|
+
this.instructionCache.clear();
|
|
49633
|
+
logger.debug("Instruction cache cleared");
|
|
49634
|
+
}
|
|
49635
|
+
/**
|
|
49636
|
+
* Get current configuration
|
|
49637
|
+
*/
|
|
49638
|
+
getConfig() {
|
|
49639
|
+
return { ...this.config };
|
|
49640
|
+
}
|
|
49641
|
+
/**
|
|
49642
|
+
* Update configuration
|
|
49643
|
+
*/
|
|
49644
|
+
updateConfig(updates) {
|
|
49645
|
+
this.config = {
|
|
49646
|
+
...this.config,
|
|
49647
|
+
...updates
|
|
49648
|
+
};
|
|
49649
|
+
if (updates.tokenBudget) {
|
|
49650
|
+
this.budgetManager.updateConfig(updates.tokenBudget);
|
|
49651
|
+
}
|
|
49652
|
+
logger.debug("OrchestrationInstructionInjector config updated", {
|
|
49653
|
+
enabled: this.config.enabled
|
|
49654
|
+
});
|
|
49655
|
+
}
|
|
49656
|
+
/**
|
|
49657
|
+
* Get budget manager for direct access
|
|
49658
|
+
*/
|
|
49659
|
+
getBudgetManager() {
|
|
49660
|
+
return this.budgetManager;
|
|
49661
|
+
}
|
|
49662
|
+
/**
|
|
49663
|
+
* Check if orchestration is enabled
|
|
49664
|
+
*/
|
|
49665
|
+
isEnabled() {
|
|
49666
|
+
return this.config.enabled;
|
|
49667
|
+
}
|
|
49668
|
+
/**
|
|
49669
|
+
* Enable or disable orchestration
|
|
49670
|
+
*/
|
|
49671
|
+
setEnabled(enabled) {
|
|
49672
|
+
this.config.enabled = enabled;
|
|
49673
|
+
logger.debug("Orchestration enabled state changed", { enabled });
|
|
49674
|
+
}
|
|
49675
|
+
};
|
|
49676
|
+
|
|
49677
|
+
// src/core/orchestration/todo-instruction-provider.ts
|
|
49678
|
+
init_esm_shims();
|
|
49679
|
+
init_logger();
|
|
49680
|
+
var DEFAULT_TODO_CONFIG = {
|
|
49681
|
+
enabled: true,
|
|
49682
|
+
reminderFrequency: 3,
|
|
49683
|
+
compactMode: false,
|
|
49684
|
+
maxCompactItems: 5,
|
|
49685
|
+
showCompleted: false
|
|
49686
|
+
};
|
|
49687
|
+
var TodoInstructionProvider = class {
|
|
49688
|
+
name = "todo";
|
|
49689
|
+
config;
|
|
49690
|
+
lastStateHash = "";
|
|
49691
|
+
lastReminderTurn = 0;
|
|
49692
|
+
constructor(config) {
|
|
49693
|
+
this.config = {
|
|
49694
|
+
...DEFAULT_TODO_CONFIG,
|
|
49695
|
+
...config
|
|
49696
|
+
};
|
|
49697
|
+
logger.debug("TodoInstructionProvider initialized", {
|
|
49698
|
+
enabled: this.config.enabled,
|
|
49699
|
+
reminderFrequency: this.config.reminderFrequency
|
|
49700
|
+
});
|
|
49701
|
+
}
|
|
49702
|
+
/**
|
|
49703
|
+
* Check if provider should generate instructions
|
|
49704
|
+
*/
|
|
49705
|
+
shouldGenerate(context) {
|
|
49706
|
+
if (!this.config.enabled) {
|
|
49707
|
+
return false;
|
|
49708
|
+
}
|
|
49709
|
+
if (!context.todos || context.todos.length === 0) {
|
|
49710
|
+
return false;
|
|
49711
|
+
}
|
|
49712
|
+
const currentHash = this.computeStateHash(context.todos);
|
|
49713
|
+
const stateChanged = currentHash !== this.lastStateHash;
|
|
49714
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
49715
|
+
const reminderDue = turnsSinceReminder >= this.config.reminderFrequency;
|
|
49716
|
+
return stateChanged || reminderDue;
|
|
49717
|
+
}
|
|
49718
|
+
/**
|
|
49719
|
+
* Generate instructions based on todo state
|
|
49720
|
+
*/
|
|
49721
|
+
async getInstructions(context) {
|
|
49722
|
+
const instructions = [];
|
|
49723
|
+
if (!context.todos || context.todos.length === 0) {
|
|
49724
|
+
return instructions;
|
|
49725
|
+
}
|
|
49726
|
+
const currentHash = this.computeStateHash(context.todos);
|
|
49727
|
+
const stateChanged = currentHash !== this.lastStateHash;
|
|
49728
|
+
const activeTodos = context.todos.filter(
|
|
49729
|
+
(todo) => todo.status !== "completed" || this.config.showCompleted
|
|
49730
|
+
);
|
|
49731
|
+
const inProgressTasks = activeTodos.filter((todo) => todo.status === "in_progress");
|
|
49732
|
+
const pendingTasks = activeTodos.filter((todo) => todo.status === "pending");
|
|
49733
|
+
const completedTasks = context.todos.filter((todo) => todo.status === "completed");
|
|
49734
|
+
let content;
|
|
49735
|
+
let priority;
|
|
49736
|
+
if (stateChanged) {
|
|
49737
|
+
content = this.formatFullTodoList(inProgressTasks, pendingTasks, completedTasks);
|
|
49738
|
+
priority = "high";
|
|
49739
|
+
} else if (this.config.compactMode) {
|
|
49740
|
+
content = this.formatCompactReminder(inProgressTasks, pendingTasks);
|
|
49741
|
+
priority = "normal";
|
|
49742
|
+
} else {
|
|
49743
|
+
content = this.formatStandardReminder(inProgressTasks, pendingTasks);
|
|
49744
|
+
priority = "normal";
|
|
49745
|
+
}
|
|
49746
|
+
instructions.push({
|
|
49747
|
+
type: "task",
|
|
49748
|
+
priority,
|
|
49749
|
+
content,
|
|
49750
|
+
source: "automatosx",
|
|
49751
|
+
createdAt: Date.now(),
|
|
49752
|
+
expiresAfter: this.config.reminderFrequency + 1,
|
|
49753
|
+
id: `todo-${currentHash.substring(0, 8)}`
|
|
49754
|
+
});
|
|
49755
|
+
this.lastStateHash = currentHash;
|
|
49756
|
+
this.lastReminderTurn = context.turnCount;
|
|
49757
|
+
logger.debug("Todo instructions generated", {
|
|
49758
|
+
inProgress: inProgressTasks.length,
|
|
49759
|
+
pending: pendingTasks.length,
|
|
49760
|
+
completed: completedTasks.length,
|
|
49761
|
+
stateChanged
|
|
49762
|
+
});
|
|
49763
|
+
return instructions;
|
|
49764
|
+
}
|
|
49765
|
+
/**
|
|
49766
|
+
* Format full todo list (used when state changes)
|
|
49767
|
+
*/
|
|
49768
|
+
formatFullTodoList(inProgress, pending, completed) {
|
|
49769
|
+
const lines = [
|
|
49770
|
+
"## Current Task List"
|
|
49771
|
+
];
|
|
49772
|
+
if (inProgress.length > 0) {
|
|
49773
|
+
lines.push("");
|
|
49774
|
+
lines.push("### Currently Working On:");
|
|
49775
|
+
for (const task of inProgress) {
|
|
49776
|
+
lines.push(`- **${task.activeForm}**`);
|
|
49777
|
+
}
|
|
49778
|
+
}
|
|
49779
|
+
if (pending.length > 0) {
|
|
49780
|
+
lines.push("");
|
|
49781
|
+
lines.push("### Pending Tasks:");
|
|
49782
|
+
for (const task of pending) {
|
|
49783
|
+
lines.push(`- [ ] ${task.content}`);
|
|
49784
|
+
}
|
|
49785
|
+
}
|
|
49786
|
+
if (this.config.showCompleted && completed.length > 0) {
|
|
49787
|
+
lines.push("");
|
|
49788
|
+
lines.push("### Completed:");
|
|
49789
|
+
for (const task of completed.slice(-3)) {
|
|
49790
|
+
lines.push(`- [x] ${task.content}`);
|
|
49791
|
+
}
|
|
49792
|
+
}
|
|
49793
|
+
lines.push("");
|
|
49794
|
+
lines.push("**Remember:** Complete the current in-progress task before starting new ones.");
|
|
49795
|
+
lines.push("Mark tasks as completed as soon as they are done.");
|
|
49796
|
+
return lines.join("\n");
|
|
49797
|
+
}
|
|
49798
|
+
/**
|
|
49799
|
+
* Format standard reminder
|
|
49800
|
+
*/
|
|
49801
|
+
formatStandardReminder(inProgress, pending) {
|
|
49802
|
+
const lines = [];
|
|
49803
|
+
if (inProgress.length > 0) {
|
|
49804
|
+
lines.push(`**Current Task:** ${inProgress[0].activeForm}`);
|
|
49805
|
+
}
|
|
49806
|
+
if (pending.length > 0) {
|
|
49807
|
+
lines.push(`**Next:** ${pending[0].content}`);
|
|
49808
|
+
if (pending.length > 1) {
|
|
49809
|
+
lines.push(`(${pending.length - 1} more tasks pending)`);
|
|
49810
|
+
}
|
|
49811
|
+
}
|
|
49812
|
+
return lines.join("\n");
|
|
49813
|
+
}
|
|
49814
|
+
/**
|
|
49815
|
+
* Format compact reminder (minimal tokens)
|
|
49816
|
+
*/
|
|
49817
|
+
formatCompactReminder(inProgress, pending) {
|
|
49818
|
+
const parts = [];
|
|
49819
|
+
if (inProgress.length > 0) {
|
|
49820
|
+
parts.push(`Doing: ${inProgress[0].activeForm}`);
|
|
49821
|
+
}
|
|
49822
|
+
if (pending.length > 0) {
|
|
49823
|
+
const count = Math.min(pending.length, this.config.maxCompactItems);
|
|
49824
|
+
parts.push(`Next: ${pending.slice(0, count).map((t) => t.content).join(", ")}`);
|
|
49825
|
+
}
|
|
49826
|
+
return parts.join(" | ");
|
|
49827
|
+
}
|
|
49828
|
+
/**
|
|
49829
|
+
* Compute hash of todo state for change detection
|
|
49830
|
+
*/
|
|
49831
|
+
computeStateHash(todos) {
|
|
49832
|
+
const stateString = todos.map((t) => `${t.id}:${t.status}:${t.content}`).sort().join("|");
|
|
49833
|
+
return crypto2.createHash("sha256").update(stateString).digest("hex").substring(0, 16);
|
|
49834
|
+
}
|
|
49835
|
+
/**
|
|
49836
|
+
* Get current configuration
|
|
49837
|
+
*/
|
|
49838
|
+
getConfig() {
|
|
49839
|
+
return { ...this.config };
|
|
49840
|
+
}
|
|
49841
|
+
/**
|
|
49842
|
+
* Update configuration
|
|
49843
|
+
*/
|
|
49844
|
+
updateConfig(updates) {
|
|
49845
|
+
this.config = {
|
|
49846
|
+
...this.config,
|
|
49847
|
+
...updates
|
|
49848
|
+
};
|
|
49849
|
+
logger.debug("TodoInstructionProvider config updated", {
|
|
49850
|
+
enabled: this.config.enabled,
|
|
49851
|
+
compactMode: this.config.compactMode
|
|
49852
|
+
});
|
|
49853
|
+
}
|
|
49854
|
+
/**
|
|
49855
|
+
* Reset state tracking (useful for testing)
|
|
49856
|
+
*/
|
|
49857
|
+
reset() {
|
|
49858
|
+
this.lastStateHash = "";
|
|
49859
|
+
this.lastReminderTurn = 0;
|
|
49860
|
+
logger.debug("TodoInstructionProvider state reset");
|
|
49861
|
+
}
|
|
49862
|
+
};
|
|
49863
|
+
|
|
49864
|
+
// src/core/orchestration/memory-instruction-provider.ts
|
|
49865
|
+
init_esm_shims();
|
|
49866
|
+
init_logger();
|
|
49867
|
+
var DEFAULT_MEMORY_CONFIG = {
|
|
49868
|
+
enabled: true,
|
|
49869
|
+
maxEntries: 5,
|
|
49870
|
+
minRelevance: 0.5,
|
|
49871
|
+
searchFrequency: 3,
|
|
49872
|
+
maxAge: 0,
|
|
49873
|
+
// No limit by default
|
|
49874
|
+
includeMetadata: true,
|
|
49875
|
+
cacheTTL: 6e4
|
|
49876
|
+
// 1 minute
|
|
49877
|
+
};
|
|
49878
|
+
var MemoryInstructionProvider = class {
|
|
49879
|
+
name = "memory";
|
|
49880
|
+
config;
|
|
49881
|
+
searchProvider;
|
|
49882
|
+
cache;
|
|
49883
|
+
lastSearchTurn = 0;
|
|
49884
|
+
constructor(searchProvider, config) {
|
|
49885
|
+
this.config = {
|
|
49886
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
49887
|
+
...config
|
|
49888
|
+
};
|
|
49889
|
+
this.searchProvider = searchProvider;
|
|
49890
|
+
logger.debug("MemoryInstructionProvider initialized", {
|
|
49891
|
+
enabled: this.config.enabled,
|
|
49892
|
+
maxEntries: this.config.maxEntries,
|
|
49893
|
+
hasSearchProvider: !!searchProvider
|
|
49894
|
+
});
|
|
49895
|
+
}
|
|
49896
|
+
/**
|
|
49897
|
+
* Set the memory search provider
|
|
49898
|
+
*/
|
|
49899
|
+
setSearchProvider(provider) {
|
|
49900
|
+
this.searchProvider = provider;
|
|
49901
|
+
this.clearCache();
|
|
49902
|
+
logger.debug("Memory search provider set");
|
|
49903
|
+
}
|
|
49904
|
+
/**
|
|
49905
|
+
* Check if provider should generate instructions
|
|
49906
|
+
*/
|
|
49907
|
+
shouldGenerate(context) {
|
|
49908
|
+
if (!this.config.enabled) {
|
|
49909
|
+
return false;
|
|
49910
|
+
}
|
|
49911
|
+
if (!this.searchProvider) {
|
|
49912
|
+
return false;
|
|
49913
|
+
}
|
|
49914
|
+
if (!context.currentTask && context.todos.length === 0) {
|
|
49915
|
+
return false;
|
|
49916
|
+
}
|
|
49917
|
+
const turnsSinceSearch = context.turnCount - this.lastSearchTurn;
|
|
49918
|
+
const searchDue = turnsSinceSearch >= this.config.searchFrequency;
|
|
49919
|
+
const cacheValid = this.cache && Date.now() - this.cache.timestamp < this.config.cacheTTL;
|
|
49920
|
+
return searchDue || !cacheValid;
|
|
49921
|
+
}
|
|
49922
|
+
/**
|
|
49923
|
+
* Generate instructions based on relevant memories
|
|
49924
|
+
*/
|
|
49925
|
+
async getInstructions(context) {
|
|
49926
|
+
const instructions = [];
|
|
49927
|
+
if (!this.searchProvider) {
|
|
49928
|
+
return instructions;
|
|
49929
|
+
}
|
|
49930
|
+
const searchQuery = this.buildSearchQuery(context);
|
|
49931
|
+
if (!searchQuery) {
|
|
49932
|
+
return instructions;
|
|
49933
|
+
}
|
|
49934
|
+
try {
|
|
49935
|
+
const memories = await this.searchMemories(searchQuery, context);
|
|
49936
|
+
if (memories.length === 0) {
|
|
49937
|
+
return instructions;
|
|
49938
|
+
}
|
|
49939
|
+
this.lastSearchTurn = context.turnCount;
|
|
49940
|
+
const content = this.formatMemories(memories);
|
|
49941
|
+
instructions.push({
|
|
49942
|
+
type: "memory",
|
|
49943
|
+
priority: "normal",
|
|
49944
|
+
content,
|
|
49945
|
+
source: "automatosx",
|
|
49946
|
+
createdAt: Date.now(),
|
|
49947
|
+
expiresAfter: this.config.searchFrequency + 1,
|
|
49948
|
+
id: `memory-${Date.now()}`
|
|
49949
|
+
});
|
|
49950
|
+
logger.debug("Memory instructions generated", {
|
|
49951
|
+
memoriesFound: memories.length,
|
|
49952
|
+
query: searchQuery.substring(0, 50)
|
|
49953
|
+
});
|
|
49954
|
+
} catch (error) {
|
|
49955
|
+
logger.error("Failed to search memories", {
|
|
49956
|
+
error: error instanceof Error ? error.message : String(error)
|
|
49957
|
+
});
|
|
49958
|
+
}
|
|
49959
|
+
return instructions;
|
|
49960
|
+
}
|
|
49961
|
+
/**
|
|
49962
|
+
* Build search query from context
|
|
49963
|
+
*/
|
|
49964
|
+
buildSearchQuery(context) {
|
|
49965
|
+
const parts = [];
|
|
49966
|
+
if (context.currentTask) {
|
|
49967
|
+
parts.push(context.currentTask);
|
|
49968
|
+
}
|
|
49969
|
+
const inProgressTodos = context.todos.filter((t) => t.status === "in_progress");
|
|
49970
|
+
for (const todo of inProgressTodos.slice(0, 2)) {
|
|
49971
|
+
parts.push(todo.content);
|
|
49972
|
+
}
|
|
49973
|
+
if (context.agentName) {
|
|
49974
|
+
parts.push(context.agentName);
|
|
49975
|
+
}
|
|
49976
|
+
if (parts.length === 0) {
|
|
49977
|
+
return null;
|
|
49978
|
+
}
|
|
49979
|
+
return parts.join(" ");
|
|
49980
|
+
}
|
|
49981
|
+
/**
|
|
49982
|
+
* Search for relevant memories
|
|
49983
|
+
*/
|
|
49984
|
+
async searchMemories(query, context) {
|
|
49985
|
+
if (!this.searchProvider) {
|
|
49986
|
+
return [];
|
|
49987
|
+
}
|
|
49988
|
+
if (this.cache && this.cache.query === query) {
|
|
49989
|
+
const age = Date.now() - this.cache.timestamp;
|
|
49990
|
+
if (age < this.config.cacheTTL) {
|
|
49991
|
+
logger.debug("Using cached memory results", {
|
|
49992
|
+
cacheAge: age,
|
|
49993
|
+
resultCount: this.cache.results.length
|
|
49994
|
+
});
|
|
49995
|
+
return this.cache.results;
|
|
49996
|
+
}
|
|
49997
|
+
}
|
|
49998
|
+
const results = await this.searchProvider.search({
|
|
49999
|
+
text: query,
|
|
50000
|
+
limit: this.config.maxEntries * 2,
|
|
50001
|
+
// Get extra in case some are filtered
|
|
50002
|
+
filters: context.agentName ? { agentId: context.agentName } : void 0
|
|
50003
|
+
});
|
|
50004
|
+
const filtered = results.filter((r) => r.score >= this.config.minRelevance).filter((r) => this.isWithinMaxAge(r.createdAt)).slice(0, this.config.maxEntries);
|
|
50005
|
+
const memories = filtered.map((r) => ({
|
|
50006
|
+
content: r.content,
|
|
50007
|
+
relevance: r.score,
|
|
50008
|
+
agent: r.metadata?.agentId,
|
|
50009
|
+
timestamp: r.createdAt.getTime()
|
|
50010
|
+
}));
|
|
50011
|
+
this.cache = {
|
|
50012
|
+
query,
|
|
50013
|
+
results: memories,
|
|
50014
|
+
timestamp: Date.now()
|
|
50015
|
+
};
|
|
50016
|
+
return memories;
|
|
50017
|
+
}
|
|
50018
|
+
/**
|
|
50019
|
+
* Check if memory is within max age limit
|
|
50020
|
+
*/
|
|
50021
|
+
isWithinMaxAge(createdAt) {
|
|
50022
|
+
if (this.config.maxAge === 0) {
|
|
50023
|
+
return true;
|
|
50024
|
+
}
|
|
50025
|
+
const age = Date.now() - createdAt.getTime();
|
|
50026
|
+
return age <= this.config.maxAge;
|
|
50027
|
+
}
|
|
50028
|
+
/**
|
|
50029
|
+
* Format memories into instruction content
|
|
50030
|
+
*/
|
|
50031
|
+
formatMemories(memories) {
|
|
50032
|
+
const lines = [
|
|
50033
|
+
"## Relevant Context from Memory",
|
|
50034
|
+
""
|
|
50035
|
+
];
|
|
50036
|
+
for (let i = 0; i < memories.length; i++) {
|
|
50037
|
+
const memory = memories[i];
|
|
50038
|
+
if (!memory) continue;
|
|
50039
|
+
const relevancePercent = Math.round(memory.relevance * 100);
|
|
50040
|
+
if (this.config.includeMetadata && memory.agent) {
|
|
50041
|
+
lines.push(`### Memory ${i + 1} (${relevancePercent}% relevant, from ${memory.agent})`);
|
|
50042
|
+
} else {
|
|
50043
|
+
lines.push(`### Memory ${i + 1} (${relevancePercent}% relevant)`);
|
|
50044
|
+
}
|
|
50045
|
+
const maxLength = 500;
|
|
50046
|
+
const content = memory.content.length > maxLength ? memory.content.substring(0, maxLength) + "..." : memory.content;
|
|
50047
|
+
lines.push(content);
|
|
50048
|
+
lines.push("");
|
|
50049
|
+
}
|
|
50050
|
+
lines.push("**Note:** Use this context to inform your decisions, but verify current state.");
|
|
50051
|
+
return lines.join("\n");
|
|
50052
|
+
}
|
|
50053
|
+
/**
|
|
50054
|
+
* Clear the memory cache
|
|
50055
|
+
*/
|
|
50056
|
+
clearCache() {
|
|
50057
|
+
this.cache = void 0;
|
|
50058
|
+
logger.debug("Memory cache cleared");
|
|
50059
|
+
}
|
|
50060
|
+
/**
|
|
50061
|
+
* Get current configuration
|
|
50062
|
+
*/
|
|
50063
|
+
getConfig() {
|
|
50064
|
+
return { ...this.config };
|
|
50065
|
+
}
|
|
50066
|
+
/**
|
|
50067
|
+
* Update configuration
|
|
50068
|
+
*/
|
|
50069
|
+
updateConfig(updates) {
|
|
50070
|
+
this.config = {
|
|
50071
|
+
...this.config,
|
|
50072
|
+
...updates
|
|
50073
|
+
};
|
|
50074
|
+
if (updates.minRelevance !== void 0 || updates.maxEntries !== void 0) {
|
|
50075
|
+
this.clearCache();
|
|
50076
|
+
}
|
|
50077
|
+
logger.debug("MemoryInstructionProvider config updated", {
|
|
50078
|
+
enabled: this.config.enabled,
|
|
50079
|
+
maxEntries: this.config.maxEntries
|
|
50080
|
+
});
|
|
50081
|
+
}
|
|
50082
|
+
/**
|
|
50083
|
+
* Reset state
|
|
50084
|
+
*/
|
|
50085
|
+
reset() {
|
|
50086
|
+
this.cache = void 0;
|
|
50087
|
+
this.lastSearchTurn = 0;
|
|
50088
|
+
logger.debug("MemoryInstructionProvider reset");
|
|
50089
|
+
}
|
|
50090
|
+
/**
|
|
50091
|
+
* Check if search provider is configured
|
|
50092
|
+
*/
|
|
50093
|
+
hasSearchProvider() {
|
|
50094
|
+
return !!this.searchProvider;
|
|
50095
|
+
}
|
|
50096
|
+
};
|
|
50097
|
+
|
|
50098
|
+
// src/core/orchestration/session-instruction-provider.ts
|
|
50099
|
+
init_esm_shims();
|
|
50100
|
+
init_logger();
|
|
50101
|
+
var DEFAULT_SESSION_CONFIG = {
|
|
50102
|
+
enabled: true,
|
|
50103
|
+
showCollaboration: true,
|
|
50104
|
+
showProgress: true,
|
|
50105
|
+
reminderFrequency: 5,
|
|
50106
|
+
showHandoffContext: true
|
|
50107
|
+
};
|
|
50108
|
+
var SessionInstructionProvider = class {
|
|
50109
|
+
name = "session";
|
|
50110
|
+
config;
|
|
50111
|
+
stateProvider;
|
|
50112
|
+
lastReminderTurn = 0;
|
|
50113
|
+
cachedState;
|
|
50114
|
+
cacheExpiry = 0;
|
|
50115
|
+
CACHE_TTL = 3e4;
|
|
50116
|
+
// 30 seconds
|
|
50117
|
+
constructor(stateProvider, config) {
|
|
50118
|
+
this.config = {
|
|
50119
|
+
...DEFAULT_SESSION_CONFIG,
|
|
50120
|
+
...config
|
|
50121
|
+
};
|
|
50122
|
+
this.stateProvider = stateProvider;
|
|
50123
|
+
logger.debug("SessionInstructionProvider initialized", {
|
|
50124
|
+
enabled: this.config.enabled,
|
|
50125
|
+
hasStateProvider: !!stateProvider
|
|
50126
|
+
});
|
|
50127
|
+
}
|
|
50128
|
+
/**
|
|
50129
|
+
* Set the session state provider
|
|
50130
|
+
*/
|
|
50131
|
+
setStateProvider(provider) {
|
|
50132
|
+
this.stateProvider = provider;
|
|
50133
|
+
this.clearCache();
|
|
50134
|
+
logger.debug("Session state provider set");
|
|
50135
|
+
}
|
|
50136
|
+
/**
|
|
50137
|
+
* Check if provider should generate instructions
|
|
50138
|
+
*/
|
|
50139
|
+
shouldGenerate(context) {
|
|
50140
|
+
if (!this.config.enabled) {
|
|
50141
|
+
return false;
|
|
50142
|
+
}
|
|
50143
|
+
if (!context.sessionId && !this.stateProvider) {
|
|
50144
|
+
return false;
|
|
50145
|
+
}
|
|
50146
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
50147
|
+
return turnsSinceReminder >= this.config.reminderFrequency;
|
|
50148
|
+
}
|
|
50149
|
+
/**
|
|
50150
|
+
* Generate instructions based on session state
|
|
50151
|
+
*/
|
|
50152
|
+
async getInstructions(context) {
|
|
50153
|
+
const instructions = [];
|
|
50154
|
+
const state = await this.getSessionState(context);
|
|
50155
|
+
if (!state && !context.sessionId) {
|
|
50156
|
+
return instructions;
|
|
50157
|
+
}
|
|
50158
|
+
const content = this.formatSessionContext(context, state);
|
|
50159
|
+
if (content) {
|
|
50160
|
+
instructions.push({
|
|
50161
|
+
type: "session",
|
|
50162
|
+
priority: "normal",
|
|
50163
|
+
content,
|
|
50164
|
+
source: "automatosx",
|
|
50165
|
+
createdAt: Date.now(),
|
|
50166
|
+
expiresAfter: this.config.reminderFrequency,
|
|
50167
|
+
id: `session-${context.sessionId || "default"}-${Date.now()}`
|
|
50168
|
+
});
|
|
50169
|
+
}
|
|
50170
|
+
this.lastReminderTurn = context.turnCount;
|
|
50171
|
+
logger.debug("Session instructions generated", {
|
|
50172
|
+
sessionId: context.sessionId,
|
|
50173
|
+
hasState: !!state
|
|
50174
|
+
});
|
|
50175
|
+
return instructions;
|
|
50176
|
+
}
|
|
50177
|
+
/**
|
|
50178
|
+
* Get session state from provider or cache
|
|
50179
|
+
*/
|
|
50180
|
+
async getSessionState(context) {
|
|
50181
|
+
if (!context.sessionId) {
|
|
50182
|
+
return null;
|
|
50183
|
+
}
|
|
50184
|
+
if (this.cachedState && this.cachedState.id === context.sessionId && Date.now() < this.cacheExpiry) {
|
|
50185
|
+
return this.cachedState;
|
|
50186
|
+
}
|
|
50187
|
+
if (!this.stateProvider) {
|
|
50188
|
+
return null;
|
|
50189
|
+
}
|
|
50190
|
+
try {
|
|
50191
|
+
const state = await this.stateProvider.getSessionState(context.sessionId);
|
|
50192
|
+
if (state) {
|
|
50193
|
+
this.cachedState = state;
|
|
50194
|
+
this.cacheExpiry = Date.now() + this.CACHE_TTL;
|
|
50195
|
+
}
|
|
50196
|
+
return state;
|
|
50197
|
+
} catch (error) {
|
|
50198
|
+
logger.error("Failed to get session state", {
|
|
50199
|
+
sessionId: context.sessionId,
|
|
50200
|
+
error: error instanceof Error ? error.message : String(error)
|
|
50201
|
+
});
|
|
50202
|
+
return null;
|
|
50203
|
+
}
|
|
50204
|
+
}
|
|
50205
|
+
/**
|
|
50206
|
+
* Format session context into instruction content
|
|
50207
|
+
*/
|
|
50208
|
+
formatSessionContext(context, state) {
|
|
50209
|
+
const lines = [];
|
|
50210
|
+
if (context.sessionId) {
|
|
50211
|
+
lines.push("## Session Context");
|
|
50212
|
+
lines.push("");
|
|
50213
|
+
}
|
|
50214
|
+
if (this.config.showCollaboration && state && state.participants.length > 1) {
|
|
50215
|
+
lines.push("### Multi-Agent Collaboration");
|
|
50216
|
+
lines.push(`- **Session:** ${state.id.substring(0, 8)}...`);
|
|
50217
|
+
lines.push(`- **Participants:** ${state.participants.join(", ")}`);
|
|
50218
|
+
if (state.activeAgent) {
|
|
50219
|
+
lines.push(`- **Currently Active:** ${state.activeAgent}`);
|
|
50220
|
+
}
|
|
50221
|
+
lines.push("");
|
|
50222
|
+
}
|
|
50223
|
+
if (this.config.showProgress && state) {
|
|
50224
|
+
const totalTasks = state.completedTasks + state.remainingTasks;
|
|
50225
|
+
if (totalTasks > 0) {
|
|
50226
|
+
const progress = Math.round(state.completedTasks / totalTasks * 100);
|
|
50227
|
+
lines.push("### Session Progress");
|
|
50228
|
+
lines.push(`- Completed: ${state.completedTasks}/${totalTasks} (${progress}%)`);
|
|
50229
|
+
if (state.remainingTasks > 0) {
|
|
50230
|
+
lines.push(`- Remaining: ${state.remainingTasks} task(s)`);
|
|
50231
|
+
}
|
|
50232
|
+
lines.push("");
|
|
50233
|
+
}
|
|
50234
|
+
}
|
|
50235
|
+
if (this.config.showHandoffContext && context.parentAgent) {
|
|
50236
|
+
lines.push("### Delegation Context");
|
|
50237
|
+
lines.push(`- **Delegated from:** ${context.parentAgent}`);
|
|
50238
|
+
if (context.currentTask) {
|
|
50239
|
+
lines.push(`- **Task:** ${context.currentTask}`);
|
|
50240
|
+
}
|
|
50241
|
+
lines.push("");
|
|
50242
|
+
lines.push("**Note:** Complete this task and return control to the parent agent.");
|
|
50243
|
+
lines.push("");
|
|
50244
|
+
}
|
|
50245
|
+
if (context.agentName && !context.parentAgent) {
|
|
50246
|
+
lines.push(`**Current Agent:** ${context.agentName}`);
|
|
50247
|
+
lines.push("");
|
|
50248
|
+
}
|
|
50249
|
+
if (lines.length <= 2) {
|
|
50250
|
+
return null;
|
|
50251
|
+
}
|
|
50252
|
+
return lines.join("\n");
|
|
50253
|
+
}
|
|
50254
|
+
/**
|
|
50255
|
+
* Clear cached state
|
|
50256
|
+
*/
|
|
50257
|
+
clearCache() {
|
|
50258
|
+
this.cachedState = void 0;
|
|
50259
|
+
this.cacheExpiry = 0;
|
|
50260
|
+
logger.debug("Session cache cleared");
|
|
50261
|
+
}
|
|
50262
|
+
/**
|
|
50263
|
+
* Get current configuration
|
|
50264
|
+
*/
|
|
50265
|
+
getConfig() {
|
|
50266
|
+
return { ...this.config };
|
|
50267
|
+
}
|
|
50268
|
+
/**
|
|
50269
|
+
* Update configuration
|
|
50270
|
+
*/
|
|
50271
|
+
updateConfig(updates) {
|
|
50272
|
+
this.config = {
|
|
50273
|
+
...this.config,
|
|
50274
|
+
...updates
|
|
50275
|
+
};
|
|
50276
|
+
logger.debug("SessionInstructionProvider config updated", {
|
|
50277
|
+
enabled: this.config.enabled
|
|
50278
|
+
});
|
|
50279
|
+
}
|
|
50280
|
+
/**
|
|
50281
|
+
* Reset state
|
|
50282
|
+
*/
|
|
50283
|
+
reset() {
|
|
50284
|
+
this.lastReminderTurn = 0;
|
|
50285
|
+
this.clearCache();
|
|
50286
|
+
logger.debug("SessionInstructionProvider reset");
|
|
50287
|
+
}
|
|
50288
|
+
/**
|
|
50289
|
+
* Check if state provider is configured
|
|
50290
|
+
*/
|
|
50291
|
+
hasStateProvider() {
|
|
50292
|
+
return !!this.stateProvider;
|
|
50293
|
+
}
|
|
50294
|
+
};
|
|
50295
|
+
|
|
50296
|
+
// src/agents/agent-instruction-injector.ts
|
|
50297
|
+
init_esm_shims();
|
|
50298
|
+
init_logger();
|
|
50299
|
+
|
|
50300
|
+
// src/agents/instruction-templates.ts
|
|
50301
|
+
init_esm_shims();
|
|
50302
|
+
var BACKEND_TEMPLATE = {
|
|
50303
|
+
domain: "backend",
|
|
50304
|
+
displayName: "Backend Engineer",
|
|
50305
|
+
domainReminders: [
|
|
50306
|
+
"Follow RESTful API design principles",
|
|
50307
|
+
"Use proper HTTP status codes",
|
|
50308
|
+
"Implement input validation at API boundaries",
|
|
50309
|
+
"Consider database query performance",
|
|
50310
|
+
"Handle errors gracefully with meaningful messages"
|
|
50311
|
+
],
|
|
50312
|
+
qualityChecklist: [
|
|
50313
|
+
"API endpoints follow REST conventions",
|
|
50314
|
+
"Database queries are optimized (no N+1)",
|
|
50315
|
+
"Input is validated before processing",
|
|
50316
|
+
"Errors are logged with context",
|
|
50317
|
+
"Sensitive data is not exposed in responses"
|
|
50318
|
+
],
|
|
50319
|
+
delegationTriggers: [
|
|
50320
|
+
{
|
|
50321
|
+
keywords: ["security", "authentication", "authorization", "OWASP", "vulnerability"],
|
|
50322
|
+
suggestedAgent: "security",
|
|
50323
|
+
reason: "Security-related tasks benefit from specialized security review"
|
|
50324
|
+
},
|
|
50325
|
+
{
|
|
50326
|
+
keywords: ["frontend", "UI", "React", "CSS", "component"],
|
|
50327
|
+
suggestedAgent: "frontend",
|
|
50328
|
+
reason: "Frontend implementation should be handled by frontend specialist"
|
|
50329
|
+
},
|
|
50330
|
+
{
|
|
50331
|
+
keywords: ["test", "testing", "unit test", "integration test"],
|
|
50332
|
+
suggestedAgent: "quality",
|
|
50333
|
+
reason: "Testing strategy benefits from QA expertise"
|
|
50334
|
+
}
|
|
50335
|
+
],
|
|
50336
|
+
antiPatterns: [
|
|
50337
|
+
"Avoid SQL injection by using parameterized queries",
|
|
50338
|
+
"Don't expose internal error details to clients",
|
|
50339
|
+
"Avoid synchronous blocking operations",
|
|
50340
|
+
"Don't hardcode configuration values"
|
|
50341
|
+
],
|
|
50342
|
+
bestPractices: [
|
|
50343
|
+
"Use prepared statements for database queries",
|
|
50344
|
+
"Implement proper logging with correlation IDs",
|
|
50345
|
+
"Use dependency injection for testability",
|
|
50346
|
+
"Follow the principle of least privilege"
|
|
50347
|
+
]
|
|
50348
|
+
};
|
|
50349
|
+
var FRONTEND_TEMPLATE = {
|
|
50350
|
+
domain: "frontend",
|
|
50351
|
+
displayName: "Frontend Engineer",
|
|
50352
|
+
domainReminders: [
|
|
50353
|
+
"Ensure accessibility (WCAG compliance)",
|
|
50354
|
+
"Optimize for performance (Core Web Vitals)",
|
|
50355
|
+
"Handle loading and error states",
|
|
50356
|
+
"Implement responsive design",
|
|
50357
|
+
"Consider keyboard navigation"
|
|
50358
|
+
],
|
|
50359
|
+
qualityChecklist: [
|
|
50360
|
+
"Components are accessible (ARIA labels, roles)",
|
|
50361
|
+
"Loading states are handled",
|
|
50362
|
+
"Error boundaries catch failures gracefully",
|
|
50363
|
+
"Forms have proper validation feedback",
|
|
50364
|
+
"Images have alt text"
|
|
50365
|
+
],
|
|
50366
|
+
delegationTriggers: [
|
|
50367
|
+
{
|
|
50368
|
+
keywords: ["API", "endpoint", "database", "backend", "server"],
|
|
50369
|
+
suggestedAgent: "backend",
|
|
50370
|
+
reason: "Backend changes should be handled by backend specialist"
|
|
50371
|
+
},
|
|
50372
|
+
{
|
|
50373
|
+
keywords: ["security", "XSS", "CSRF", "sanitize"],
|
|
50374
|
+
suggestedAgent: "security",
|
|
50375
|
+
reason: "Security concerns require specialized review"
|
|
50376
|
+
}
|
|
50377
|
+
],
|
|
50378
|
+
antiPatterns: [
|
|
50379
|
+
"Avoid inline styles for reusable components",
|
|
50380
|
+
"Don't mutate state directly",
|
|
50381
|
+
"Avoid excessive re-renders",
|
|
50382
|
+
"Don't ignore accessibility requirements"
|
|
50383
|
+
],
|
|
50384
|
+
bestPractices: [
|
|
50385
|
+
"Use semantic HTML elements",
|
|
50386
|
+
"Implement proper form validation",
|
|
50387
|
+
"Optimize bundle size",
|
|
50388
|
+
"Use React.memo for expensive components"
|
|
50389
|
+
]
|
|
50390
|
+
};
|
|
50391
|
+
var SECURITY_TEMPLATE = {
|
|
50392
|
+
domain: "security",
|
|
50393
|
+
displayName: "Security Engineer",
|
|
50394
|
+
domainReminders: [
|
|
50395
|
+
"Apply OWASP Top 10 security guidelines",
|
|
50396
|
+
"Validate and sanitize ALL user input",
|
|
50397
|
+
"Use parameterized queries to prevent SQL injection",
|
|
50398
|
+
"Implement proper authentication and authorization",
|
|
50399
|
+
"Never expose sensitive data in logs or responses"
|
|
50400
|
+
],
|
|
50401
|
+
qualityChecklist: [
|
|
50402
|
+
"Input validation is present at all entry points",
|
|
50403
|
+
"Authentication tokens are handled securely",
|
|
50404
|
+
"Sensitive data is encrypted at rest and in transit",
|
|
50405
|
+
"Error messages don't leak implementation details",
|
|
50406
|
+
"Dependencies are checked for known vulnerabilities"
|
|
50407
|
+
],
|
|
50408
|
+
delegationTriggers: [
|
|
50409
|
+
{
|
|
50410
|
+
keywords: ["performance", "optimization", "speed", "latency"],
|
|
50411
|
+
suggestedAgent: "backend",
|
|
50412
|
+
reason: "Performance optimization is a backend concern"
|
|
50413
|
+
}
|
|
50414
|
+
],
|
|
50415
|
+
antiPatterns: [
|
|
50416
|
+
"Never trust user input without validation",
|
|
50417
|
+
"Don't store passwords in plain text",
|
|
50418
|
+
"Avoid security through obscurity",
|
|
50419
|
+
"Don't disable security features for convenience"
|
|
50420
|
+
],
|
|
50421
|
+
bestPractices: [
|
|
50422
|
+
"Follow the principle of least privilege",
|
|
50423
|
+
"Implement defense in depth",
|
|
50424
|
+
"Use secure defaults",
|
|
50425
|
+
"Fail securely (deny by default)"
|
|
50426
|
+
]
|
|
50427
|
+
};
|
|
50428
|
+
var QUALITY_TEMPLATE = {
|
|
50429
|
+
domain: "quality",
|
|
50430
|
+
displayName: "Quality Assurance Engineer",
|
|
50431
|
+
domainReminders: [
|
|
50432
|
+
"Write tests that verify behavior, not implementation",
|
|
50433
|
+
"Cover edge cases and error scenarios",
|
|
50434
|
+
"Ensure test isolation (no shared state)",
|
|
50435
|
+
"Use meaningful test descriptions",
|
|
50436
|
+
"Follow the Arrange-Act-Assert pattern"
|
|
50437
|
+
],
|
|
50438
|
+
qualityChecklist: [
|
|
50439
|
+
"Unit tests cover critical paths",
|
|
50440
|
+
"Integration tests verify component interactions",
|
|
50441
|
+
"Edge cases are tested",
|
|
50442
|
+
"Error handling is verified",
|
|
50443
|
+
"Tests are maintainable and readable"
|
|
50444
|
+
],
|
|
50445
|
+
delegationTriggers: [
|
|
50446
|
+
{
|
|
50447
|
+
keywords: ["implement", "build", "create", "develop"],
|
|
50448
|
+
suggestedAgent: "backend",
|
|
50449
|
+
reason: "Implementation tasks should go to domain specialists"
|
|
50450
|
+
},
|
|
50451
|
+
{
|
|
50452
|
+
keywords: ["security", "vulnerability", "penetration"],
|
|
50453
|
+
suggestedAgent: "security",
|
|
50454
|
+
reason: "Security testing requires specialized expertise"
|
|
50455
|
+
}
|
|
50456
|
+
],
|
|
50457
|
+
antiPatterns: [
|
|
50458
|
+
"Avoid testing implementation details",
|
|
50459
|
+
"Don't use flaky tests",
|
|
50460
|
+
"Avoid excessive mocking",
|
|
50461
|
+
"Don't ignore failing tests"
|
|
50462
|
+
],
|
|
50463
|
+
bestPractices: [
|
|
50464
|
+
"Test behavior, not implementation",
|
|
50465
|
+
"Use descriptive test names",
|
|
50466
|
+
"Keep tests independent",
|
|
50467
|
+
"Follow the testing pyramid"
|
|
50468
|
+
]
|
|
50469
|
+
};
|
|
50470
|
+
var ARCHITECTURE_TEMPLATE = {
|
|
50471
|
+
domain: "architecture",
|
|
50472
|
+
displayName: "Software Architect",
|
|
50473
|
+
domainReminders: [
|
|
50474
|
+
"Consider scalability implications",
|
|
50475
|
+
"Document architectural decisions (ADRs)",
|
|
50476
|
+
"Evaluate trade-offs explicitly",
|
|
50477
|
+
"Design for maintainability",
|
|
50478
|
+
"Consider operational concerns"
|
|
50479
|
+
],
|
|
50480
|
+
qualityChecklist: [
|
|
50481
|
+
"Architecture supports future scaling",
|
|
50482
|
+
"Components have clear boundaries",
|
|
50483
|
+
"Dependencies are managed properly",
|
|
50484
|
+
"System is observable (logging, metrics)",
|
|
50485
|
+
"Failure modes are handled"
|
|
50486
|
+
],
|
|
50487
|
+
delegationTriggers: [
|
|
50488
|
+
{
|
|
50489
|
+
keywords: ["implement", "code", "fix", "bug"],
|
|
50490
|
+
suggestedAgent: "backend",
|
|
50491
|
+
reason: "Implementation details should be handled by domain specialists"
|
|
50492
|
+
},
|
|
50493
|
+
{
|
|
50494
|
+
keywords: ["security", "compliance", "audit"],
|
|
50495
|
+
suggestedAgent: "security",
|
|
50496
|
+
reason: "Security architecture needs specialized review"
|
|
50497
|
+
}
|
|
50498
|
+
],
|
|
50499
|
+
antiPatterns: [
|
|
50500
|
+
"Avoid premature optimization",
|
|
50501
|
+
"Don't over-engineer solutions",
|
|
50502
|
+
"Avoid tight coupling between components",
|
|
50503
|
+
"Don't ignore non-functional requirements"
|
|
50504
|
+
],
|
|
50505
|
+
bestPractices: [
|
|
50506
|
+
"Design for change",
|
|
50507
|
+
"Use well-known patterns",
|
|
50508
|
+
"Document decisions and rationale",
|
|
50509
|
+
"Consider operational requirements"
|
|
50510
|
+
]
|
|
50511
|
+
};
|
|
50512
|
+
var DEVOPS_TEMPLATE = {
|
|
50513
|
+
domain: "devops",
|
|
50514
|
+
displayName: "DevOps Engineer",
|
|
50515
|
+
domainReminders: [
|
|
50516
|
+
"Automate repetitive tasks",
|
|
50517
|
+
"Implement proper monitoring and alerting",
|
|
50518
|
+
"Follow infrastructure as code principles",
|
|
50519
|
+
"Consider disaster recovery",
|
|
50520
|
+
"Optimize for reliability and cost"
|
|
50521
|
+
],
|
|
50522
|
+
qualityChecklist: [
|
|
50523
|
+
"Deployments are automated and repeatable",
|
|
50524
|
+
"Monitoring covers key metrics",
|
|
50525
|
+
"Alerts are actionable",
|
|
50526
|
+
"Backups are tested",
|
|
50527
|
+
"Security is integrated into CI/CD"
|
|
50528
|
+
],
|
|
50529
|
+
delegationTriggers: [
|
|
50530
|
+
{
|
|
50531
|
+
keywords: ["code", "feature", "bug", "implement"],
|
|
50532
|
+
suggestedAgent: "backend",
|
|
50533
|
+
reason: "Application code changes should go to developers"
|
|
50534
|
+
},
|
|
50535
|
+
{
|
|
50536
|
+
keywords: ["security", "credentials", "secrets"],
|
|
50537
|
+
suggestedAgent: "security",
|
|
50538
|
+
reason: "Security-sensitive changes need security review"
|
|
50539
|
+
}
|
|
50540
|
+
],
|
|
50541
|
+
antiPatterns: [
|
|
50542
|
+
"Avoid manual deployments",
|
|
50543
|
+
"Don't store secrets in code",
|
|
50544
|
+
"Avoid single points of failure",
|
|
50545
|
+
"Don't ignore monitoring gaps"
|
|
50546
|
+
],
|
|
50547
|
+
bestPractices: [
|
|
50548
|
+
"Use infrastructure as code",
|
|
50549
|
+
"Implement CI/CD pipelines",
|
|
50550
|
+
"Follow GitOps practices",
|
|
50551
|
+
"Use immutable infrastructure"
|
|
50552
|
+
]
|
|
50553
|
+
};
|
|
50554
|
+
var WRITER_TEMPLATE = {
|
|
50555
|
+
domain: "writer",
|
|
50556
|
+
displayName: "Technical Writer",
|
|
50557
|
+
domainReminders: [
|
|
50558
|
+
"Write for the target audience",
|
|
50559
|
+
"Use clear, concise language",
|
|
50560
|
+
"Include practical examples",
|
|
50561
|
+
"Structure content logically",
|
|
50562
|
+
"Keep documentation up to date"
|
|
50563
|
+
],
|
|
50564
|
+
qualityChecklist: [
|
|
50565
|
+
"Documentation matches current code",
|
|
50566
|
+
"Examples are working and tested",
|
|
50567
|
+
"Content is well-organized",
|
|
50568
|
+
"Technical terms are explained",
|
|
50569
|
+
"Links and references are valid"
|
|
50570
|
+
],
|
|
50571
|
+
delegationTriggers: [
|
|
50572
|
+
{
|
|
50573
|
+
keywords: ["implement", "code", "fix", "develop"],
|
|
50574
|
+
suggestedAgent: "backend",
|
|
50575
|
+
reason: "Code changes should be handled by developers"
|
|
50576
|
+
}
|
|
50577
|
+
],
|
|
50578
|
+
antiPatterns: [
|
|
50579
|
+
"Avoid jargon without explanation",
|
|
50580
|
+
"Don't assume reader knowledge",
|
|
50581
|
+
"Avoid outdated examples",
|
|
50582
|
+
"Don't ignore code comments"
|
|
50583
|
+
],
|
|
50584
|
+
bestPractices: [
|
|
50585
|
+
"Use consistent terminology",
|
|
50586
|
+
"Include code examples",
|
|
50587
|
+
"Keep documentation near code",
|
|
50588
|
+
"Update docs with code changes"
|
|
50589
|
+
]
|
|
50590
|
+
};
|
|
50591
|
+
var STANDARD_TEMPLATE = {
|
|
50592
|
+
domain: "standard",
|
|
50593
|
+
displayName: "General Assistant",
|
|
50594
|
+
domainReminders: [
|
|
50595
|
+
"Understand the task before starting",
|
|
50596
|
+
"Ask clarifying questions when needed",
|
|
50597
|
+
"Break complex tasks into smaller steps",
|
|
50598
|
+
"Verify your work before completing",
|
|
50599
|
+
"Document your changes"
|
|
50600
|
+
],
|
|
50601
|
+
qualityChecklist: [
|
|
50602
|
+
"Task requirements are understood",
|
|
50603
|
+
"Changes are tested",
|
|
50604
|
+
"Code follows project conventions",
|
|
50605
|
+
"Documentation is updated",
|
|
50606
|
+
"No regressions introduced"
|
|
50607
|
+
],
|
|
50608
|
+
delegationTriggers: [
|
|
50609
|
+
{
|
|
50610
|
+
keywords: ["security", "vulnerability", "authentication"],
|
|
50611
|
+
suggestedAgent: "security",
|
|
50612
|
+
reason: "Security tasks need specialized attention"
|
|
50613
|
+
},
|
|
50614
|
+
{
|
|
50615
|
+
keywords: ["test", "testing", "QA", "quality"],
|
|
50616
|
+
suggestedAgent: "quality",
|
|
50617
|
+
reason: "Testing benefits from QA expertise"
|
|
50618
|
+
},
|
|
50619
|
+
{
|
|
50620
|
+
keywords: ["architecture", "design", "scalability"],
|
|
50621
|
+
suggestedAgent: "architecture",
|
|
50622
|
+
reason: "Architectural decisions need careful consideration"
|
|
50623
|
+
}
|
|
50624
|
+
],
|
|
50625
|
+
antiPatterns: [
|
|
50626
|
+
"Avoid making changes without understanding context",
|
|
50627
|
+
"Don't skip testing",
|
|
50628
|
+
"Avoid large, monolithic changes",
|
|
50629
|
+
"Don't ignore existing patterns"
|
|
50630
|
+
],
|
|
50631
|
+
bestPractices: [
|
|
50632
|
+
"Follow existing code conventions",
|
|
50633
|
+
"Write self-documenting code",
|
|
50634
|
+
"Test your changes",
|
|
50635
|
+
"Keep changes focused"
|
|
50636
|
+
]
|
|
50637
|
+
};
|
|
50638
|
+
var AGENT_TEMPLATES = {
|
|
50639
|
+
backend: BACKEND_TEMPLATE,
|
|
50640
|
+
frontend: FRONTEND_TEMPLATE,
|
|
50641
|
+
fullstack: { ...BACKEND_TEMPLATE, domain: "fullstack", displayName: "Fullstack Engineer" },
|
|
50642
|
+
security: SECURITY_TEMPLATE,
|
|
50643
|
+
quality: QUALITY_TEMPLATE,
|
|
50644
|
+
architecture: ARCHITECTURE_TEMPLATE,
|
|
50645
|
+
devops: DEVOPS_TEMPLATE,
|
|
50646
|
+
data: { ...BACKEND_TEMPLATE, domain: "data", displayName: "Data Engineer" },
|
|
50647
|
+
mobile: { ...FRONTEND_TEMPLATE, domain: "mobile", displayName: "Mobile Engineer" },
|
|
50648
|
+
writer: WRITER_TEMPLATE,
|
|
50649
|
+
researcher: { ...STANDARD_TEMPLATE, domain: "researcher", displayName: "Researcher" },
|
|
50650
|
+
standard: STANDARD_TEMPLATE
|
|
50651
|
+
};
|
|
50652
|
+
function getAgentTemplate(domain) {
|
|
50653
|
+
return AGENT_TEMPLATES[domain] || STANDARD_TEMPLATE;
|
|
50654
|
+
}
|
|
50655
|
+
function isValidAgentDomain(domain) {
|
|
50656
|
+
return domain in AGENT_TEMPLATES;
|
|
50657
|
+
}
|
|
50658
|
+
function getDelegationSuggestions(text, currentDomain) {
|
|
50659
|
+
const template = getAgentTemplate(currentDomain);
|
|
50660
|
+
const suggestions = [];
|
|
50661
|
+
const textLower = text.toLowerCase();
|
|
50662
|
+
for (const trigger of template.delegationTriggers) {
|
|
50663
|
+
const matchedKeywords = trigger.keywords.filter(
|
|
50664
|
+
(kw) => textLower.includes(kw.toLowerCase())
|
|
50665
|
+
);
|
|
50666
|
+
if (matchedKeywords.length > 0) {
|
|
50667
|
+
suggestions.push({
|
|
50668
|
+
agent: trigger.suggestedAgent,
|
|
50669
|
+
reason: trigger.reason,
|
|
50670
|
+
keywords: matchedKeywords
|
|
50671
|
+
});
|
|
50672
|
+
}
|
|
50673
|
+
}
|
|
50674
|
+
return suggestions;
|
|
50675
|
+
}
|
|
50676
|
+
|
|
50677
|
+
// src/agents/agent-instruction-injector.ts
|
|
50678
|
+
var DEFAULT_AGENT_CONFIG = {
|
|
50679
|
+
enabled: true,
|
|
50680
|
+
reminderFrequency: 5,
|
|
50681
|
+
delegationDetection: true,
|
|
50682
|
+
minDelegationKeywords: 1,
|
|
50683
|
+
includeQualityChecklist: true,
|
|
50684
|
+
qualityChecklistFrequency: 10,
|
|
50685
|
+
includeAntiPatterns: true
|
|
50686
|
+
};
|
|
50687
|
+
var AgentInstructionInjector = class {
|
|
50688
|
+
name = "agent-template";
|
|
50689
|
+
config;
|
|
50690
|
+
lastReminderTurn = 0;
|
|
50691
|
+
lastQualityCheckTurn = 0;
|
|
50692
|
+
currentDomain;
|
|
50693
|
+
recentTaskText = "";
|
|
50694
|
+
constructor(config) {
|
|
50695
|
+
this.config = {
|
|
50696
|
+
...DEFAULT_AGENT_CONFIG,
|
|
50697
|
+
...config
|
|
50698
|
+
};
|
|
50699
|
+
logger.debug("AgentInstructionInjector initialized", {
|
|
50700
|
+
enabled: this.config.enabled,
|
|
50701
|
+
reminderFrequency: this.config.reminderFrequency
|
|
50702
|
+
});
|
|
50703
|
+
}
|
|
50704
|
+
/**
|
|
50705
|
+
* Set the current agent domain
|
|
50706
|
+
*/
|
|
50707
|
+
setDomain(domain) {
|
|
50708
|
+
if (isValidAgentDomain(domain)) {
|
|
50709
|
+
this.currentDomain = domain;
|
|
50710
|
+
logger.debug("Agent domain set", { domain });
|
|
50711
|
+
} else {
|
|
50712
|
+
this.currentDomain = "standard";
|
|
50713
|
+
logger.debug("Unknown domain, using standard", { domain });
|
|
50714
|
+
}
|
|
50715
|
+
}
|
|
50716
|
+
/**
|
|
50717
|
+
* Get the current domain
|
|
50718
|
+
*/
|
|
50719
|
+
getDomain() {
|
|
50720
|
+
return this.currentDomain;
|
|
50721
|
+
}
|
|
50722
|
+
/**
|
|
50723
|
+
* Check if provider should generate instructions
|
|
50724
|
+
*/
|
|
50725
|
+
shouldGenerate(context) {
|
|
50726
|
+
if (!this.config.enabled) {
|
|
50727
|
+
return false;
|
|
50728
|
+
}
|
|
50729
|
+
const domain = this.resolveDomain(context);
|
|
50730
|
+
if (!domain) {
|
|
50731
|
+
return false;
|
|
50732
|
+
}
|
|
50733
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
50734
|
+
const reminderDue = turnsSinceReminder >= this.config.reminderFrequency;
|
|
50735
|
+
const turnsSinceQuality = context.turnCount - this.lastQualityCheckTurn;
|
|
50736
|
+
const qualityDue = this.config.includeQualityChecklist && turnsSinceQuality >= this.config.qualityChecklistFrequency;
|
|
50737
|
+
const hasDelegationTriggers = this.config.delegationDetection && this.checkDelegationTriggers(context);
|
|
50738
|
+
return reminderDue || qualityDue || hasDelegationTriggers;
|
|
50739
|
+
}
|
|
50740
|
+
/**
|
|
50741
|
+
* Generate instructions based on agent domain
|
|
50742
|
+
*/
|
|
50743
|
+
async getInstructions(context) {
|
|
50744
|
+
const instructions = [];
|
|
50745
|
+
const domain = this.resolveDomain(context);
|
|
50746
|
+
if (!domain) {
|
|
50747
|
+
return instructions;
|
|
50748
|
+
}
|
|
50749
|
+
const template = getAgentTemplate(domain);
|
|
50750
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
50751
|
+
const turnsSinceQuality = context.turnCount - this.lastQualityCheckTurn;
|
|
50752
|
+
if (turnsSinceReminder >= this.config.reminderFrequency) {
|
|
50753
|
+
const reminderContent = this.formatDomainReminders(template);
|
|
50754
|
+
instructions.push({
|
|
50755
|
+
type: "delegation",
|
|
50756
|
+
priority: "normal",
|
|
50757
|
+
content: reminderContent,
|
|
50758
|
+
source: "automatosx",
|
|
50759
|
+
createdAt: Date.now(),
|
|
50760
|
+
expiresAfter: this.config.reminderFrequency,
|
|
50761
|
+
id: `agent-reminder-${domain}-${Date.now()}`
|
|
50762
|
+
});
|
|
50763
|
+
this.lastReminderTurn = context.turnCount;
|
|
50764
|
+
}
|
|
50765
|
+
if (this.config.includeQualityChecklist && turnsSinceQuality >= this.config.qualityChecklistFrequency) {
|
|
50766
|
+
const checklistContent = this.formatQualityChecklist(template);
|
|
50767
|
+
instructions.push({
|
|
50768
|
+
type: "delegation",
|
|
50769
|
+
priority: "normal",
|
|
50770
|
+
content: checklistContent,
|
|
50771
|
+
source: "automatosx",
|
|
50772
|
+
createdAt: Date.now(),
|
|
50773
|
+
expiresAfter: this.config.qualityChecklistFrequency,
|
|
50774
|
+
id: `agent-quality-${domain}-${Date.now()}`
|
|
50775
|
+
});
|
|
50776
|
+
this.lastQualityCheckTurn = context.turnCount;
|
|
50777
|
+
}
|
|
50778
|
+
if (this.config.delegationDetection) {
|
|
50779
|
+
const taskText = this.extractTaskText(context);
|
|
50780
|
+
if (taskText !== this.recentTaskText) {
|
|
50781
|
+
this.recentTaskText = taskText;
|
|
50782
|
+
const delegationContent = this.checkAndFormatDelegation(template, taskText);
|
|
50783
|
+
if (delegationContent) {
|
|
50784
|
+
instructions.push({
|
|
50785
|
+
type: "delegation",
|
|
50786
|
+
priority: "high",
|
|
50787
|
+
content: delegationContent,
|
|
50788
|
+
source: "automatosx",
|
|
50789
|
+
createdAt: Date.now(),
|
|
50790
|
+
expiresAfter: 3,
|
|
50791
|
+
id: `agent-delegation-${Date.now()}`
|
|
50792
|
+
});
|
|
50793
|
+
}
|
|
50794
|
+
}
|
|
50795
|
+
}
|
|
50796
|
+
logger.debug("Agent instructions generated", {
|
|
50797
|
+
domain,
|
|
50798
|
+
instructionCount: instructions.length
|
|
50799
|
+
});
|
|
50800
|
+
return instructions;
|
|
50801
|
+
}
|
|
50802
|
+
/**
|
|
50803
|
+
* Resolve domain from context or current setting
|
|
50804
|
+
*/
|
|
50805
|
+
resolveDomain(context) {
|
|
50806
|
+
if (context.agentName && isValidAgentDomain(context.agentName)) {
|
|
50807
|
+
return context.agentName;
|
|
50808
|
+
}
|
|
50809
|
+
return this.currentDomain;
|
|
50810
|
+
}
|
|
50811
|
+
/**
|
|
50812
|
+
* Extract task text from context for delegation detection
|
|
50813
|
+
*/
|
|
50814
|
+
extractTaskText(context) {
|
|
50815
|
+
const parts = [];
|
|
50816
|
+
if (context.currentTask) {
|
|
50817
|
+
parts.push(context.currentTask);
|
|
50818
|
+
}
|
|
50819
|
+
for (const todo of context.todos.filter((t) => t.status === "in_progress")) {
|
|
50820
|
+
parts.push(todo.content);
|
|
50821
|
+
}
|
|
50822
|
+
return parts.join(" ");
|
|
50823
|
+
}
|
|
50824
|
+
/**
|
|
50825
|
+
* Check if delegation triggers are present
|
|
50826
|
+
*/
|
|
50827
|
+
checkDelegationTriggers(context) {
|
|
50828
|
+
const domain = this.resolveDomain(context);
|
|
50829
|
+
if (!domain) return false;
|
|
50830
|
+
const taskText = this.extractTaskText(context);
|
|
50831
|
+
if (!taskText) return false;
|
|
50832
|
+
const suggestions = getDelegationSuggestions(taskText, domain);
|
|
50833
|
+
return suggestions.some((s) => s.keywords.length >= this.config.minDelegationKeywords);
|
|
50834
|
+
}
|
|
50835
|
+
/**
|
|
50836
|
+
* Format domain reminders
|
|
50837
|
+
*/
|
|
50838
|
+
formatDomainReminders(template) {
|
|
50839
|
+
const lines = [
|
|
50840
|
+
`## ${template.displayName} Reminders`,
|
|
50841
|
+
""
|
|
50842
|
+
];
|
|
50843
|
+
for (const reminder of template.domainReminders) {
|
|
50844
|
+
lines.push(`- ${reminder}`);
|
|
50845
|
+
}
|
|
50846
|
+
if (this.config.includeAntiPatterns && template.antiPatterns.length > 0) {
|
|
50847
|
+
lines.push("");
|
|
50848
|
+
lines.push("**Avoid:**");
|
|
50849
|
+
for (const antiPattern of template.antiPatterns.slice(0, 3)) {
|
|
50850
|
+
lines.push(`- ${antiPattern}`);
|
|
50851
|
+
}
|
|
50852
|
+
}
|
|
50853
|
+
return lines.join("\n");
|
|
50854
|
+
}
|
|
50855
|
+
/**
|
|
50856
|
+
* Format quality checklist
|
|
50857
|
+
*/
|
|
50858
|
+
formatQualityChecklist(template) {
|
|
50859
|
+
const lines = [
|
|
50860
|
+
`## Quality Checklist (${template.displayName})`,
|
|
50861
|
+
"",
|
|
50862
|
+
"Before completing, verify:"
|
|
50863
|
+
];
|
|
50864
|
+
for (const item of template.qualityChecklist) {
|
|
50865
|
+
lines.push(`- [ ] ${item}`);
|
|
50866
|
+
}
|
|
50867
|
+
return lines.join("\n");
|
|
50868
|
+
}
|
|
50869
|
+
/**
|
|
50870
|
+
* Check for delegation triggers and format suggestion
|
|
50871
|
+
*/
|
|
50872
|
+
checkAndFormatDelegation(template, taskText) {
|
|
50873
|
+
const suggestions = getDelegationSuggestions(taskText, template.domain);
|
|
50874
|
+
const relevantSuggestions = suggestions.filter(
|
|
50875
|
+
(s) => s.keywords.length >= this.config.minDelegationKeywords
|
|
50876
|
+
);
|
|
50877
|
+
if (relevantSuggestions.length === 0) {
|
|
50878
|
+
return null;
|
|
50879
|
+
}
|
|
50880
|
+
const lines = [
|
|
50881
|
+
"## Delegation Suggestion",
|
|
50882
|
+
""
|
|
50883
|
+
];
|
|
50884
|
+
for (const suggestion of relevantSuggestions) {
|
|
50885
|
+
lines.push(`**Consider delegating to @${suggestion.agent}**`);
|
|
50886
|
+
lines.push(`- Reason: ${suggestion.reason}`);
|
|
50887
|
+
lines.push(`- Triggered by: ${suggestion.keywords.join(", ")}`);
|
|
50888
|
+
lines.push("");
|
|
50889
|
+
}
|
|
50890
|
+
lines.push("Use `DELEGATE TO @agent: task` or `@agent task` syntax to delegate.");
|
|
50891
|
+
return lines.join("\n");
|
|
50892
|
+
}
|
|
50893
|
+
/**
|
|
50894
|
+
* Get current configuration
|
|
50895
|
+
*/
|
|
50896
|
+
getConfig() {
|
|
50897
|
+
return { ...this.config };
|
|
50898
|
+
}
|
|
50899
|
+
/**
|
|
50900
|
+
* Update configuration
|
|
50901
|
+
*/
|
|
50902
|
+
updateConfig(updates) {
|
|
50903
|
+
this.config = {
|
|
50904
|
+
...this.config,
|
|
50905
|
+
...updates
|
|
50906
|
+
};
|
|
50907
|
+
logger.debug("AgentInstructionInjector config updated", {
|
|
50908
|
+
enabled: this.config.enabled
|
|
50909
|
+
});
|
|
50910
|
+
}
|
|
50911
|
+
/**
|
|
50912
|
+
* Reset state
|
|
50913
|
+
*/
|
|
50914
|
+
reset() {
|
|
50915
|
+
this.lastReminderTurn = 0;
|
|
50916
|
+
this.lastQualityCheckTurn = 0;
|
|
50917
|
+
this.recentTaskText = "";
|
|
50918
|
+
logger.debug("AgentInstructionInjector reset");
|
|
50919
|
+
}
|
|
50920
|
+
};
|
|
50921
|
+
|
|
50922
|
+
// src/core/orchestration/orchestration-service.ts
|
|
50923
|
+
var OrchestrationService = class {
|
|
50924
|
+
config;
|
|
50925
|
+
injector;
|
|
50926
|
+
tokenBudgetManager;
|
|
50927
|
+
workflowModeManager;
|
|
50928
|
+
agentInjector;
|
|
50929
|
+
todoProvider;
|
|
50930
|
+
memoryProvider;
|
|
50931
|
+
sessionProvider;
|
|
50932
|
+
turnCount = 0;
|
|
50933
|
+
currentTodos = [];
|
|
50934
|
+
constructor(serviceConfig = {}) {
|
|
50935
|
+
this.config = {
|
|
50936
|
+
...DEFAULT_ORCHESTRATION_CONFIG,
|
|
50937
|
+
...serviceConfig
|
|
50938
|
+
};
|
|
50939
|
+
this.injector = new OrchestrationInstructionInjector(this.config);
|
|
50940
|
+
this.tokenBudgetManager = new TokenBudgetManager(this.config.tokenBudget);
|
|
50941
|
+
this.workflowModeManager = new WorkflowModeManager();
|
|
50942
|
+
this.agentInjector = new AgentInstructionInjector({
|
|
50943
|
+
enabled: this.config.agentTemplates?.enabled ?? true,
|
|
50944
|
+
reminderFrequency: this.config.agentTemplates?.reminderFrequency ?? 5
|
|
50945
|
+
});
|
|
50946
|
+
this.initializeProviders(serviceConfig);
|
|
50947
|
+
logger.debug("OrchestrationService initialized", {
|
|
50948
|
+
todoEnabled: this.config.todoIntegration?.enabled,
|
|
50949
|
+
memoryEnabled: this.config.memoryIntegration?.enabled,
|
|
50950
|
+
sessionEnabled: this.config.sessionIntegration?.enabled,
|
|
50951
|
+
agentTemplatesEnabled: this.config.agentTemplates?.enabled
|
|
50952
|
+
});
|
|
50953
|
+
}
|
|
50954
|
+
/**
|
|
50955
|
+
* Initialize instruction providers
|
|
50956
|
+
*/
|
|
50957
|
+
initializeProviders(serviceConfig) {
|
|
50958
|
+
if (this.config.todoIntegration?.enabled !== false) {
|
|
50959
|
+
this.todoProvider = new TodoInstructionProvider({
|
|
50960
|
+
enabled: true,
|
|
50961
|
+
reminderFrequency: this.config.todoIntegration?.reminderFrequency ?? 3,
|
|
50962
|
+
compactMode: this.config.todoIntegration?.compactMode ?? false
|
|
50963
|
+
});
|
|
50964
|
+
this.injector.registerProvider(this.todoProvider);
|
|
50965
|
+
}
|
|
50966
|
+
if (this.config.memoryIntegration?.enabled !== false && serviceConfig.memorySearchProvider) {
|
|
50967
|
+
this.memoryProvider = new MemoryInstructionProvider(
|
|
50968
|
+
serviceConfig.memorySearchProvider,
|
|
50969
|
+
{
|
|
50970
|
+
enabled: true,
|
|
50971
|
+
maxEntries: this.config.memoryIntegration?.maxEntries ?? 5,
|
|
50972
|
+
minRelevance: this.config.memoryIntegration?.minRelevance ?? 0.5
|
|
50973
|
+
}
|
|
50974
|
+
);
|
|
50975
|
+
this.injector.registerProvider(this.memoryProvider);
|
|
50976
|
+
}
|
|
50977
|
+
if (this.config.sessionIntegration?.enabled !== false) {
|
|
50978
|
+
this.sessionProvider = new SessionInstructionProvider(
|
|
50979
|
+
serviceConfig.sessionStateProvider,
|
|
50980
|
+
{
|
|
50981
|
+
enabled: true,
|
|
50982
|
+
showCollaboration: this.config.sessionIntegration?.showCollaboration ?? true,
|
|
50983
|
+
showProgress: true,
|
|
50984
|
+
reminderFrequency: 5,
|
|
50985
|
+
showHandoffContext: true
|
|
50986
|
+
}
|
|
50987
|
+
);
|
|
50988
|
+
this.injector.registerProvider(this.sessionProvider);
|
|
50989
|
+
}
|
|
50990
|
+
if (this.config.agentTemplates?.enabled !== false) {
|
|
50991
|
+
if (serviceConfig.agentDomain) {
|
|
50992
|
+
this.agentInjector.setDomain(serviceConfig.agentDomain);
|
|
50993
|
+
}
|
|
50994
|
+
this.injector.registerProvider(this.agentInjector);
|
|
50995
|
+
}
|
|
50996
|
+
}
|
|
50997
|
+
/**
|
|
50998
|
+
* Set the current agent domain for agent-specific instructions
|
|
50999
|
+
*/
|
|
51000
|
+
setAgentDomain(domain) {
|
|
51001
|
+
this.agentInjector.setDomain(domain);
|
|
51002
|
+
logger.debug("Agent domain set", { domain });
|
|
51003
|
+
}
|
|
51004
|
+
/**
|
|
51005
|
+
* Set the memory search provider
|
|
51006
|
+
*/
|
|
51007
|
+
setMemoryProvider(provider) {
|
|
51008
|
+
if (this.memoryProvider) {
|
|
51009
|
+
this.memoryProvider.setSearchProvider(provider);
|
|
51010
|
+
} else if (this.config.memoryIntegration?.enabled !== false) {
|
|
51011
|
+
this.memoryProvider = new MemoryInstructionProvider(provider, {
|
|
51012
|
+
enabled: true,
|
|
51013
|
+
maxEntries: this.config.memoryIntegration?.maxEntries ?? 5,
|
|
51014
|
+
minRelevance: this.config.memoryIntegration?.minRelevance ?? 0.5
|
|
51015
|
+
});
|
|
51016
|
+
this.injector.registerProvider(this.memoryProvider);
|
|
51017
|
+
}
|
|
51018
|
+
}
|
|
51019
|
+
/**
|
|
51020
|
+
* Set the session state provider
|
|
51021
|
+
*/
|
|
51022
|
+
setSessionProvider(provider) {
|
|
51023
|
+
if (this.sessionProvider) {
|
|
51024
|
+
this.sessionProvider.setStateProvider(provider);
|
|
51025
|
+
}
|
|
51026
|
+
}
|
|
51027
|
+
/**
|
|
51028
|
+
* Update the current todo list
|
|
51029
|
+
*/
|
|
51030
|
+
updateTodos(todos) {
|
|
51031
|
+
this.currentTodos = todos;
|
|
51032
|
+
}
|
|
51033
|
+
/**
|
|
51034
|
+
* Set the workflow mode
|
|
51035
|
+
*/
|
|
51036
|
+
setWorkflowMode(mode) {
|
|
51037
|
+
this.workflowModeManager.setMode(mode);
|
|
51038
|
+
logger.debug("Workflow mode set", { mode });
|
|
51039
|
+
}
|
|
51040
|
+
/**
|
|
51041
|
+
* Get current workflow mode
|
|
51042
|
+
*/
|
|
51043
|
+
getWorkflowMode() {
|
|
51044
|
+
return this.workflowModeManager.getCurrentMode();
|
|
51045
|
+
}
|
|
51046
|
+
/**
|
|
51047
|
+
* Check if a tool is allowed in current workflow mode
|
|
51048
|
+
*/
|
|
51049
|
+
isToolAllowed(toolName) {
|
|
51050
|
+
return this.workflowModeManager.isToolAllowed(toolName);
|
|
51051
|
+
}
|
|
51052
|
+
/**
|
|
51053
|
+
* Filter tools based on current workflow mode
|
|
51054
|
+
*/
|
|
51055
|
+
filterTools(tools) {
|
|
51056
|
+
return this.workflowModeManager.filterTools(tools);
|
|
51057
|
+
}
|
|
51058
|
+
/**
|
|
51059
|
+
* Increment turn count (called after each agent response)
|
|
51060
|
+
*/
|
|
51061
|
+
incrementTurn() {
|
|
51062
|
+
this.turnCount++;
|
|
51063
|
+
}
|
|
51064
|
+
/**
|
|
51065
|
+
* Get current turn count
|
|
51066
|
+
*/
|
|
51067
|
+
getTurnCount() {
|
|
51068
|
+
return this.turnCount;
|
|
51069
|
+
}
|
|
51070
|
+
/**
|
|
51071
|
+
* Generate and inject instructions for the current context
|
|
51072
|
+
*/
|
|
51073
|
+
async injectInstructions(options = {}) {
|
|
51074
|
+
const context = {
|
|
51075
|
+
todos: this.currentTodos,
|
|
51076
|
+
turnCount: this.turnCount,
|
|
51077
|
+
workflowMode: this.workflowModeManager.getCurrentMode(),
|
|
51078
|
+
currentTask: options.task,
|
|
51079
|
+
agentName: options.agentName,
|
|
51080
|
+
sessionId: options.sessionId,
|
|
51081
|
+
parentAgent: options.parentAgent
|
|
51082
|
+
};
|
|
51083
|
+
const result = await this.injector.inject(context);
|
|
51084
|
+
logger.debug("Instructions injected", {
|
|
51085
|
+
instructionCount: result.instructions.length,
|
|
51086
|
+
tokensUsed: result.allocation.tokensUsed,
|
|
51087
|
+
hasInstructions: result.hasInstructions
|
|
51088
|
+
});
|
|
51089
|
+
return {
|
|
51090
|
+
content: result.formattedText,
|
|
51091
|
+
instructions: result.instructions,
|
|
51092
|
+
tokenCount: result.allocation.tokensUsed,
|
|
51093
|
+
applied: result.hasInstructions
|
|
51094
|
+
};
|
|
51095
|
+
}
|
|
51096
|
+
/**
|
|
51097
|
+
* Format instructions as system reminder tags
|
|
51098
|
+
*/
|
|
51099
|
+
formatAsSystemReminder(content) {
|
|
51100
|
+
if (!content || content.trim().length === 0) {
|
|
51101
|
+
return "";
|
|
51102
|
+
}
|
|
51103
|
+
return `<system-reminder>
|
|
51104
|
+
${content}
|
|
51105
|
+
</system-reminder>`;
|
|
51106
|
+
}
|
|
51107
|
+
/**
|
|
51108
|
+
* Get debug information about current orchestration state
|
|
51109
|
+
*/
|
|
51110
|
+
getDebugInfo() {
|
|
51111
|
+
const budgetConfig = this.tokenBudgetManager.getConfig();
|
|
51112
|
+
const providers = this.injector.getProviders().map((p) => p.name);
|
|
51113
|
+
return {
|
|
51114
|
+
turnCount: this.turnCount,
|
|
51115
|
+
workflowMode: this.workflowModeManager.getCurrentMode(),
|
|
51116
|
+
todoCount: this.currentTodos.length,
|
|
51117
|
+
providers,
|
|
51118
|
+
tokenBudget: {
|
|
51119
|
+
used: 0,
|
|
51120
|
+
// Would need to track this
|
|
51121
|
+
total: budgetConfig.maxTotal,
|
|
51122
|
+
remaining: budgetConfig.maxTotal
|
|
51123
|
+
}
|
|
51124
|
+
};
|
|
51125
|
+
}
|
|
51126
|
+
/**
|
|
51127
|
+
* Reset all state (for new conversations)
|
|
51128
|
+
*/
|
|
51129
|
+
reset() {
|
|
51130
|
+
this.turnCount = 0;
|
|
51131
|
+
this.currentTodos = [];
|
|
51132
|
+
this.workflowModeManager.reset();
|
|
51133
|
+
this.agentInjector.reset();
|
|
51134
|
+
this.injector.clearCache();
|
|
51135
|
+
if (this.todoProvider) {
|
|
51136
|
+
this.todoProvider.reset();
|
|
51137
|
+
}
|
|
51138
|
+
if (this.memoryProvider) {
|
|
51139
|
+
this.memoryProvider.clearCache();
|
|
51140
|
+
}
|
|
51141
|
+
if (this.sessionProvider) {
|
|
51142
|
+
this.sessionProvider.reset();
|
|
51143
|
+
}
|
|
51144
|
+
logger.debug("OrchestrationService reset");
|
|
51145
|
+
}
|
|
51146
|
+
/**
|
|
51147
|
+
* Update configuration
|
|
51148
|
+
*/
|
|
51149
|
+
updateConfig(updates) {
|
|
51150
|
+
this.config = {
|
|
51151
|
+
...this.config,
|
|
51152
|
+
...updates
|
|
51153
|
+
};
|
|
51154
|
+
if (updates.tokenBudget) {
|
|
51155
|
+
this.tokenBudgetManager = new TokenBudgetManager(updates.tokenBudget);
|
|
51156
|
+
}
|
|
51157
|
+
logger.debug("OrchestrationService config updated", { updates });
|
|
51158
|
+
}
|
|
51159
|
+
/**
|
|
51160
|
+
* Get current configuration
|
|
51161
|
+
*/
|
|
51162
|
+
getConfig() {
|
|
51163
|
+
return { ...this.config };
|
|
51164
|
+
}
|
|
51165
|
+
};
|
|
51166
|
+
|
|
51167
|
+
// src/cli/commands/debug-instructions.ts
|
|
51168
|
+
var debugInstructionsCommand = {
|
|
51169
|
+
command: "debug:instructions",
|
|
51170
|
+
describe: "Show current embedded instructions state (v11.3.0)",
|
|
51171
|
+
builder: (yargs2) => {
|
|
51172
|
+
return yargs2.option("tokens", {
|
|
51173
|
+
alias: "t",
|
|
51174
|
+
describe: "Show token budget details",
|
|
51175
|
+
type: "boolean",
|
|
51176
|
+
default: false
|
|
51177
|
+
}).option("providers", {
|
|
51178
|
+
alias: "p",
|
|
51179
|
+
describe: "Show registered instruction providers",
|
|
51180
|
+
type: "boolean",
|
|
51181
|
+
default: false
|
|
51182
|
+
}).option("templates", {
|
|
51183
|
+
describe: "Show available agent templates",
|
|
51184
|
+
type: "boolean",
|
|
51185
|
+
default: false
|
|
51186
|
+
}).option("agent", {
|
|
51187
|
+
alias: "a",
|
|
51188
|
+
describe: "Show template for specific agent domain",
|
|
51189
|
+
type: "string"
|
|
51190
|
+
}).option("verbose", {
|
|
51191
|
+
alias: "v",
|
|
51192
|
+
describe: "Show verbose output",
|
|
51193
|
+
type: "boolean",
|
|
51194
|
+
default: false
|
|
51195
|
+
}).example("$0 debug:instructions", "Show overall instruction state").example("$0 debug:instructions --tokens", "Show token budget details").example("$0 debug:instructions --providers", "List instruction providers").example("$0 debug:instructions --templates", "List agent templates").example("$0 debug:instructions --agent backend", "Show backend agent template");
|
|
51196
|
+
},
|
|
51197
|
+
handler: async (argv) => {
|
|
51198
|
+
try {
|
|
51199
|
+
if (argv.tokens) {
|
|
51200
|
+
displayTokenBudget(argv.verbose);
|
|
51201
|
+
return;
|
|
51202
|
+
}
|
|
51203
|
+
if (argv.providers) {
|
|
51204
|
+
displayProviders(argv.verbose);
|
|
51205
|
+
return;
|
|
51206
|
+
}
|
|
51207
|
+
if (argv.templates) {
|
|
51208
|
+
displayAgentTemplates(argv.verbose);
|
|
51209
|
+
return;
|
|
51210
|
+
}
|
|
51211
|
+
if (argv.agent) {
|
|
51212
|
+
displayAgentTemplate(argv.agent, argv.verbose);
|
|
51213
|
+
return;
|
|
51214
|
+
}
|
|
51215
|
+
displayOverallState(argv.verbose);
|
|
51216
|
+
} catch (error) {
|
|
51217
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
51218
|
+
console.error(chalk5.red.bold(`
|
|
51219
|
+
\u274C Error: ${err.message}
|
|
51220
|
+
`));
|
|
51221
|
+
logger.error("Debug instructions command failed", { error: err.message });
|
|
51222
|
+
process.exit(1);
|
|
51223
|
+
}
|
|
51224
|
+
}
|
|
51225
|
+
};
|
|
51226
|
+
function displayOverallState(verbose) {
|
|
51227
|
+
console.log(chalk5.blue.bold("\n\u{1F50D} Embedded Instructions Debug Info\n"));
|
|
51228
|
+
console.log(chalk5.dim("\u2550".repeat(60)));
|
|
51229
|
+
const service = new OrchestrationService();
|
|
51230
|
+
const debugInfo = service.getDebugInfo();
|
|
51231
|
+
console.log(chalk5.cyan("\n\u{1F4CA} Current State"));
|
|
51232
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51233
|
+
console.log(` Turn count: ${chalk5.yellow(debugInfo.turnCount)}`);
|
|
51234
|
+
console.log(` Workflow mode: ${chalk5.cyan(debugInfo.workflowMode)}`);
|
|
51235
|
+
console.log(` Active todos: ${chalk5.yellow(debugInfo.todoCount)}`);
|
|
51236
|
+
console.log(` Registered providers: ${chalk5.green(debugInfo.providers.length)}`);
|
|
51237
|
+
console.log(chalk5.cyan("\n\u{1F4B0} Token Budget"));
|
|
51238
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51239
|
+
console.log(` Used: ${chalk5.yellow(debugInfo.tokenBudget.used)} / ${debugInfo.tokenBudget.total}`);
|
|
51240
|
+
const usagePercent = Math.round(debugInfo.tokenBudget.used / debugInfo.tokenBudget.total * 100);
|
|
51241
|
+
const barLength = 30;
|
|
51242
|
+
const filledLength = Math.round(usagePercent / 100 * barLength);
|
|
51243
|
+
const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
|
|
51244
|
+
const barColor = usagePercent > 80 ? chalk5.red : usagePercent > 50 ? chalk5.yellow : chalk5.green;
|
|
51245
|
+
console.log(` ${barColor(bar)} ${usagePercent}%`);
|
|
51246
|
+
if (debugInfo.providers.length > 0) {
|
|
51247
|
+
console.log(chalk5.cyan("\n\u{1F50C} Active Providers"));
|
|
51248
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51249
|
+
debugInfo.providers.forEach((provider, index) => {
|
|
51250
|
+
console.log(` ${index + 1}. ${chalk5.green(provider)}`);
|
|
51251
|
+
});
|
|
51252
|
+
}
|
|
51253
|
+
console.log(chalk5.cyan("\n\u{1F504} Workflow Modes"));
|
|
51254
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51255
|
+
Object.keys(WORKFLOW_MODES).forEach((mode) => {
|
|
51256
|
+
const isCurrent = mode === debugInfo.workflowMode;
|
|
51257
|
+
const prefix = isCurrent ? chalk5.green("\u25BA") : " ";
|
|
51258
|
+
const modeText = isCurrent ? chalk5.green.bold(mode) : chalk5.gray(mode);
|
|
51259
|
+
console.log(` ${prefix} ${modeText}`);
|
|
51260
|
+
});
|
|
51261
|
+
console.log(chalk5.dim("\n" + "\u2550".repeat(60)));
|
|
51262
|
+
console.log(chalk5.gray("\nUse --tokens, --providers, or --templates for detailed info.\n"));
|
|
51263
|
+
}
|
|
51264
|
+
function displayTokenBudget(verbose) {
|
|
51265
|
+
console.log(chalk5.blue.bold("\n\u{1F4B0} Token Budget Details\n"));
|
|
51266
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
51267
|
+
const budgetManager = new TokenBudgetManager();
|
|
51268
|
+
const config = budgetManager.getConfig();
|
|
51269
|
+
console.log(`
|
|
51270
|
+
Total budget: ${chalk5.cyan(config.maxTotal)} tokens`);
|
|
51271
|
+
console.log(` Critical reserve: ${chalk5.yellow(config.criticalReserve)} tokens`);
|
|
51272
|
+
console.log(` Available: ${chalk5.green(config.maxTotal - config.criticalReserve)} tokens`);
|
|
51273
|
+
console.log(chalk5.cyan("\n Per-Type Allocations:"));
|
|
51274
|
+
const typeAllocations = [
|
|
51275
|
+
{ type: "task", budget: 500, description: "Todo/task reminders" },
|
|
51276
|
+
{ type: "memory", budget: 400, description: "Memory context" },
|
|
51277
|
+
{ type: "session", budget: 300, description: "Session state" },
|
|
51278
|
+
{ type: "delegation", budget: 300, description: "Agent delegation hints" },
|
|
51279
|
+
{ type: "mode", budget: 200, description: "Workflow mode instructions" }
|
|
51280
|
+
];
|
|
51281
|
+
typeAllocations.forEach(({ type, budget, description }) => {
|
|
51282
|
+
console.log(` \u2022 ${chalk5.cyan(type)}: ${budget} tokens`);
|
|
51283
|
+
if (verbose) {
|
|
51284
|
+
console.log(chalk5.gray(` ${description}`));
|
|
51285
|
+
}
|
|
51286
|
+
});
|
|
51287
|
+
console.log(chalk5.cyan("\n Token Estimation:"));
|
|
51288
|
+
console.log(chalk5.gray(" ~4 characters = 1 token (approximation)"));
|
|
51289
|
+
console.log(chalk5.gray(" Actual usage may vary by content"));
|
|
51290
|
+
console.log(chalk5.dim("\n\u2500".repeat(50)));
|
|
51291
|
+
console.log();
|
|
51292
|
+
}
|
|
51293
|
+
function displayProviders(verbose) {
|
|
51294
|
+
console.log(chalk5.blue.bold("\n\u{1F50C} Instruction Providers\n"));
|
|
51295
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
51296
|
+
const providers = [
|
|
51297
|
+
{
|
|
51298
|
+
name: "TodoInstructionProvider",
|
|
51299
|
+
description: "Generates task reminders from todo list",
|
|
51300
|
+
triggers: "Todo state changes, periodic reminders",
|
|
51301
|
+
priority: "high"
|
|
51302
|
+
},
|
|
51303
|
+
{
|
|
51304
|
+
name: "MemoryInstructionProvider",
|
|
51305
|
+
description: "Injects relevant context from memory",
|
|
51306
|
+
triggers: "Task keywords, memory relevance",
|
|
51307
|
+
priority: "normal"
|
|
51308
|
+
},
|
|
51309
|
+
{
|
|
51310
|
+
name: "SessionInstructionProvider",
|
|
51311
|
+
description: "Shows multi-agent collaboration state",
|
|
51312
|
+
triggers: "Session changes, periodic reminders",
|
|
51313
|
+
priority: "normal"
|
|
51314
|
+
},
|
|
51315
|
+
{
|
|
51316
|
+
name: "AgentInstructionInjector",
|
|
51317
|
+
description: "Domain-specific reminders and delegation hints",
|
|
51318
|
+
triggers: "Agent domain, task keywords",
|
|
51319
|
+
priority: "normal"
|
|
51320
|
+
},
|
|
51321
|
+
{
|
|
51322
|
+
name: "WorkflowModeManager",
|
|
51323
|
+
description: "Mode-specific instructions and tool filtering",
|
|
51324
|
+
triggers: "Mode changes",
|
|
51325
|
+
priority: "high"
|
|
51326
|
+
}
|
|
51327
|
+
];
|
|
51328
|
+
providers.forEach((provider, index) => {
|
|
51329
|
+
console.log(`
|
|
51330
|
+
${index + 1}. ${chalk5.cyan.bold(provider.name)}`);
|
|
51331
|
+
console.log(chalk5.gray(` ${provider.description}`));
|
|
51332
|
+
if (verbose) {
|
|
51333
|
+
console.log(` Triggers: ${chalk5.yellow(provider.triggers)}`);
|
|
51334
|
+
console.log(` Priority: ${chalk5.green(provider.priority)}`);
|
|
51335
|
+
}
|
|
51336
|
+
});
|
|
51337
|
+
console.log(chalk5.dim("\n\u2500".repeat(50)));
|
|
51338
|
+
console.log();
|
|
51339
|
+
}
|
|
51340
|
+
function displayAgentTemplates(verbose) {
|
|
51341
|
+
console.log(chalk5.blue.bold("\n\u{1F4CB} Agent Instruction Templates\n"));
|
|
51342
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
51343
|
+
for (const [domain, template] of Object.entries(AGENT_TEMPLATES)) {
|
|
51344
|
+
console.log(`
|
|
51345
|
+
${chalk5.cyan.bold(template.displayName)} (${domain})`);
|
|
51346
|
+
if (verbose) {
|
|
51347
|
+
console.log(chalk5.gray(` Reminders: ${template.domainReminders.length}`));
|
|
51348
|
+
console.log(chalk5.gray(` Checklist items: ${template.qualityChecklist.length}`));
|
|
51349
|
+
console.log(chalk5.gray(` Delegation triggers: ${template.delegationTriggers.length}`));
|
|
51350
|
+
console.log(chalk5.gray(` Anti-patterns: ${template.antiPatterns.length}`));
|
|
51351
|
+
console.log(chalk5.gray(` Best practices: ${template.bestPractices.length}`));
|
|
51352
|
+
}
|
|
51353
|
+
}
|
|
51354
|
+
console.log(chalk5.dim("\n\u2500".repeat(50)));
|
|
51355
|
+
console.log(chalk5.gray("\nUse --agent <domain> to see template details.\n"));
|
|
51356
|
+
}
|
|
51357
|
+
function displayAgentTemplate(domain, verbose) {
|
|
51358
|
+
const template = AGENT_TEMPLATES[domain];
|
|
51359
|
+
if (!template) {
|
|
51360
|
+
console.error(chalk5.red.bold(`
|
|
51361
|
+
\u274C Unknown agent domain: ${domain}
|
|
51362
|
+
`));
|
|
51363
|
+
console.log(chalk5.gray("Available domains:"));
|
|
51364
|
+
Object.keys(AGENT_TEMPLATES).forEach((d) => {
|
|
51365
|
+
console.log(chalk5.cyan(` \u2022 ${d}`));
|
|
51366
|
+
});
|
|
51367
|
+
console.log();
|
|
51368
|
+
process.exit(1);
|
|
51369
|
+
}
|
|
51370
|
+
console.log(chalk5.blue.bold(`
|
|
51371
|
+
\u{1F4CB} ${template.displayName} Agent Template
|
|
51372
|
+
`));
|
|
51373
|
+
console.log(chalk5.dim("\u2550".repeat(60)));
|
|
51374
|
+
console.log(chalk5.cyan("\n\u{1F514} Domain Reminders:"));
|
|
51375
|
+
template.domainReminders.forEach((reminder, i) => {
|
|
51376
|
+
console.log(` ${i + 1}. ${reminder}`);
|
|
51377
|
+
});
|
|
51378
|
+
console.log(chalk5.cyan("\n\u2705 Quality Checklist:"));
|
|
51379
|
+
template.qualityChecklist.forEach((item, i) => {
|
|
51380
|
+
console.log(` ${i + 1}. ${item}`);
|
|
51381
|
+
});
|
|
51382
|
+
if (template.delegationTriggers.length > 0) {
|
|
51383
|
+
console.log(chalk5.cyan("\n\u{1F500} Delegation Triggers:"));
|
|
51384
|
+
template.delegationTriggers.forEach((trigger, i) => {
|
|
51385
|
+
console.log(` ${i + 1}. \u2192 ${chalk5.yellow(trigger.suggestedAgent)}`);
|
|
51386
|
+
console.log(chalk5.gray(` Keywords: ${trigger.keywords.join(", ")}`));
|
|
51387
|
+
if (verbose) {
|
|
51388
|
+
console.log(chalk5.gray(` Reason: ${trigger.reason}`));
|
|
51389
|
+
}
|
|
51390
|
+
});
|
|
51391
|
+
}
|
|
51392
|
+
if (verbose && template.antiPatterns.length > 0) {
|
|
51393
|
+
console.log(chalk5.red("\n\u26A0\uFE0F Anti-Patterns to Avoid:"));
|
|
51394
|
+
template.antiPatterns.forEach((pattern, i) => {
|
|
51395
|
+
console.log(` ${i + 1}. ${pattern}`);
|
|
51396
|
+
});
|
|
51397
|
+
}
|
|
51398
|
+
if (verbose && template.bestPractices.length > 0) {
|
|
51399
|
+
console.log(chalk5.green("\n\u2728 Best Practices:"));
|
|
51400
|
+
template.bestPractices.forEach((practice, i) => {
|
|
51401
|
+
console.log(` ${i + 1}. ${practice}`);
|
|
51402
|
+
});
|
|
51403
|
+
}
|
|
51404
|
+
console.log(chalk5.dim("\n\u2550".repeat(60)));
|
|
51405
|
+
console.log();
|
|
51406
|
+
}
|
|
51407
|
+
|
|
48522
51408
|
// src/cli/index.ts
|
|
48523
51409
|
installExitHandlers();
|
|
48524
51410
|
var VERSION2 = getVersion();
|
|
@@ -48541,7 +51427,7 @@ globalTracker.mark("cli_start");
|
|
|
48541
51427
|
type: "string",
|
|
48542
51428
|
description: "Path to custom config file",
|
|
48543
51429
|
global: true
|
|
48544
|
-
}).command(setupCommand).command(initCommand).command(configureCommand).command(cliCommand).command(agentCommand).command(listCommand).command(runCommand).command(resumeCommand).command(runsCommand).command(sessionCommand).command(workspaceCommand).command(cacheCommand).command(configCommand).command(statusCommand4).command(doctorCommand2).command(cleanupCommand2).command(analyticsCommand).command(memoryCommand).command(mcpCommand).command(geminiCommand).command(providerLimitsCommand).command(providersCommand).command(flagsCommand).command(specCommand).command(genCommand).command(updateCommand).command(uninstallCommand).demandCommand(1, "You must provide a command. Run --help for usage.").help().version(VERSION2).alias("h", "help").alias("v", "version").strict().wrap(Math.min(120, yargs().terminalWidth())).parse();
|
|
51430
|
+
}).command(setupCommand).command(initCommand).command(configureCommand).command(cliCommand).command(agentCommand).command(listCommand).command(runCommand).command(resumeCommand).command(runsCommand).command(sessionCommand).command(workspaceCommand).command(cacheCommand).command(configCommand).command(statusCommand4).command(doctorCommand2).command(cleanupCommand2).command(analyticsCommand).command(memoryCommand).command(mcpCommand).command(geminiCommand).command(providerLimitsCommand).command(providersCommand).command(flagsCommand).command(specCommand).command(genCommand).command(updateCommand).command(uninstallCommand).command(modeCommand).command(debugInstructionsCommand).demandCommand(1, "You must provide a command. Run --help for usage.").help().version(VERSION2).alias("h", "help").alias("v", "version").strict().wrap(Math.min(120, yargs().terminalWidth())).parse();
|
|
48545
51431
|
globalTracker.mark("yargs_parse_end");
|
|
48546
51432
|
globalTracker.measure("yargs_parsing", "yargs_parse_start", "yargs_parse_end");
|
|
48547
51433
|
globalTracker.mark("options_setup_start");
|