@defai.digital/automatosx 11.2.9 → 11.3.1
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 +3650 -229
- package/dist/mcp/index.js +42 -10
- 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);
|
|
@@ -3003,8 +3013,12 @@ ${fullPrompt}
|
|
|
3003
3013
|
logger.debug(`Full prompt saved to ${debugPath}`);
|
|
3004
3014
|
}
|
|
3005
3015
|
const result = await this.executeCLI(fullPrompt);
|
|
3016
|
+
const latencyMs = Date.now() - startTime;
|
|
3006
3017
|
this.health.consecutiveFailures = 0;
|
|
3007
3018
|
this.health.available = true;
|
|
3019
|
+
this.health.errorRate = 0;
|
|
3020
|
+
this.health.latencyMs = latencyMs;
|
|
3021
|
+
this.health.lastCheck = Date.now();
|
|
3008
3022
|
const response = {
|
|
3009
3023
|
content: result,
|
|
3010
3024
|
model: "default",
|
|
@@ -3015,7 +3029,7 @@ ${fullPrompt}
|
|
|
3015
3029
|
completion: 0,
|
|
3016
3030
|
total: 0
|
|
3017
3031
|
},
|
|
3018
|
-
latencyMs
|
|
3032
|
+
latencyMs,
|
|
3019
3033
|
finishReason: "stop",
|
|
3020
3034
|
cached: false
|
|
3021
3035
|
};
|
|
@@ -3035,6 +3049,8 @@ ${fullPrompt}
|
|
|
3035
3049
|
this.health.consecutiveFailures++;
|
|
3036
3050
|
this.health.available = false;
|
|
3037
3051
|
this.health.errorRate = 1;
|
|
3052
|
+
this.health.latencyMs = Date.now() - startTime;
|
|
3053
|
+
this.health.lastCheck = Date.now();
|
|
3038
3054
|
throw this.handleError(error);
|
|
3039
3055
|
}
|
|
3040
3056
|
}
|
|
@@ -3055,6 +3071,8 @@ ${fullPrompt}
|
|
|
3055
3071
|
} catch (error) {
|
|
3056
3072
|
this.health.available = false;
|
|
3057
3073
|
this.health.errorRate = 1;
|
|
3074
|
+
this.health.lastCheck = Date.now();
|
|
3075
|
+
this.health.consecutiveFailures = this.health.consecutiveFailures + 1;
|
|
3058
3076
|
return false;
|
|
3059
3077
|
}
|
|
3060
3078
|
}
|
|
@@ -3062,13 +3080,13 @@ ${fullPrompt}
|
|
|
3062
3080
|
* Get health status
|
|
3063
3081
|
*/
|
|
3064
3082
|
async healthCheck() {
|
|
3065
|
-
|
|
3083
|
+
await this.isAvailable();
|
|
3066
3084
|
return {
|
|
3067
|
-
available:
|
|
3085
|
+
available: this.health.available,
|
|
3068
3086
|
latencyMs: this.health.latencyMs,
|
|
3069
|
-
errorRate:
|
|
3070
|
-
consecutiveFailures:
|
|
3071
|
-
lastCheckTime:
|
|
3087
|
+
errorRate: this.health.errorRate,
|
|
3088
|
+
consecutiveFailures: this.health.consecutiveFailures,
|
|
3089
|
+
lastCheckTime: this.health.lastCheck
|
|
3072
3090
|
};
|
|
3073
3091
|
}
|
|
3074
3092
|
/**
|
|
@@ -3786,8 +3804,9 @@ var init_cli_wrapper = __esm({
|
|
|
3786
3804
|
child.stdin.write(prompt);
|
|
3787
3805
|
child.stdin.end();
|
|
3788
3806
|
}
|
|
3807
|
+
let rl = null;
|
|
3789
3808
|
if (child.stdout && renderer) {
|
|
3790
|
-
|
|
3809
|
+
rl = readline2__default.createInterface({
|
|
3791
3810
|
input: child.stdout,
|
|
3792
3811
|
crlfDelay: Infinity
|
|
3793
3812
|
});
|
|
@@ -3795,6 +3814,11 @@ var init_cli_wrapper = __esm({
|
|
|
3795
3814
|
stdout += line + "\n";
|
|
3796
3815
|
renderer.processLine(line);
|
|
3797
3816
|
});
|
|
3817
|
+
rl.on("error", (error) => {
|
|
3818
|
+
logger.warn("Readline error during streaming", {
|
|
3819
|
+
error: error.message
|
|
3820
|
+
});
|
|
3821
|
+
});
|
|
3798
3822
|
} else if (child.stdout) {
|
|
3799
3823
|
child.stdout.on("data", (data) => {
|
|
3800
3824
|
stdout += data.toString();
|
|
@@ -3810,6 +3834,10 @@ var init_cli_wrapper = __esm({
|
|
|
3810
3834
|
clearTimeout(timeoutHandle);
|
|
3811
3835
|
timeoutHandle = null;
|
|
3812
3836
|
}
|
|
3837
|
+
if (rl) {
|
|
3838
|
+
rl.close();
|
|
3839
|
+
rl = null;
|
|
3840
|
+
}
|
|
3813
3841
|
this.activeProcesses.delete(child);
|
|
3814
3842
|
if (hasTimedOut) {
|
|
3815
3843
|
return;
|
|
@@ -3837,6 +3865,10 @@ var init_cli_wrapper = __esm({
|
|
|
3837
3865
|
clearTimeout(timeoutHandle);
|
|
3838
3866
|
timeoutHandle = null;
|
|
3839
3867
|
}
|
|
3868
|
+
if (rl) {
|
|
3869
|
+
rl.close();
|
|
3870
|
+
rl = null;
|
|
3871
|
+
}
|
|
3840
3872
|
this.activeProcesses.delete(child);
|
|
3841
3873
|
if (!hasTimedOut) {
|
|
3842
3874
|
if (renderer) {
|
|
@@ -5529,11 +5561,17 @@ ${result.content.substring(0, 1e3)}
|
|
|
5529
5561
|
setupAutoSave() {
|
|
5530
5562
|
this.autoSaveTimer = setInterval(async () => {
|
|
5531
5563
|
if (this.pendingCheckpoint) {
|
|
5532
|
-
|
|
5533
|
-
this.
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5564
|
+
try {
|
|
5565
|
+
await this.save(
|
|
5566
|
+
this.pendingCheckpoint.workflowId,
|
|
5567
|
+
this.pendingCheckpoint
|
|
5568
|
+
);
|
|
5569
|
+
this.pendingCheckpoint = null;
|
|
5570
|
+
} catch (error) {
|
|
5571
|
+
logger.warn("Auto-save failed", {
|
|
5572
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5573
|
+
});
|
|
5574
|
+
}
|
|
5537
5575
|
}
|
|
5538
5576
|
}, this.options.autoSaveInterval);
|
|
5539
5577
|
}
|
|
@@ -5545,13 +5583,29 @@ ${result.content.substring(0, 1e3)}
|
|
|
5545
5583
|
}
|
|
5546
5584
|
/**
|
|
5547
5585
|
* Cleanup resources
|
|
5586
|
+
* BUG FIX: Flush pending checkpoint before destroying to prevent data loss
|
|
5548
5587
|
*/
|
|
5549
|
-
destroy() {
|
|
5588
|
+
async destroy() {
|
|
5550
5589
|
if (this.autoSaveTimer) {
|
|
5551
5590
|
clearInterval(this.autoSaveTimer);
|
|
5552
5591
|
this.autoSaveTimer = null;
|
|
5553
5592
|
}
|
|
5554
|
-
this.pendingCheckpoint
|
|
5593
|
+
if (this.pendingCheckpoint) {
|
|
5594
|
+
try {
|
|
5595
|
+
await this.save(
|
|
5596
|
+
this.pendingCheckpoint.workflowId,
|
|
5597
|
+
this.pendingCheckpoint
|
|
5598
|
+
);
|
|
5599
|
+
logger.debug("Pending checkpoint flushed on destroy", {
|
|
5600
|
+
workflowId: this.pendingCheckpoint.workflowId
|
|
5601
|
+
});
|
|
5602
|
+
} catch (error) {
|
|
5603
|
+
logger.warn("Failed to flush pending checkpoint on destroy", {
|
|
5604
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5605
|
+
});
|
|
5606
|
+
}
|
|
5607
|
+
this.pendingCheckpoint = null;
|
|
5608
|
+
}
|
|
5555
5609
|
this.sdkCheckpointManager = null;
|
|
5556
5610
|
logger.debug("CheckpointAdapter destroyed");
|
|
5557
5611
|
}
|
|
@@ -7032,7 +7086,10 @@ var init_adapter2 = __esm({
|
|
|
7032
7086
|
}
|
|
7033
7087
|
if (this.checkpointAdapter) {
|
|
7034
7088
|
try {
|
|
7035
|
-
this.checkpointAdapter.destroy();
|
|
7089
|
+
const result = this.checkpointAdapter.destroy();
|
|
7090
|
+
if (result instanceof Promise) {
|
|
7091
|
+
await result;
|
|
7092
|
+
}
|
|
7036
7093
|
this.checkpointAdapter = null;
|
|
7037
7094
|
logger.debug("CheckpointAdapter destroyed");
|
|
7038
7095
|
} catch (error) {
|
|
@@ -9263,7 +9320,7 @@ var PRECOMPILED_CONFIG = {
|
|
|
9263
9320
|
"enableFreeTierPrioritization": true,
|
|
9264
9321
|
"enableWorkloadAwareRouting": true
|
|
9265
9322
|
},
|
|
9266
|
-
"version": "11.
|
|
9323
|
+
"version": "11.3.1"
|
|
9267
9324
|
};
|
|
9268
9325
|
|
|
9269
9326
|
// src/core/config/schemas.ts
|
|
@@ -10117,6 +10174,7 @@ async function saveConfigFile(path7, config) {
|
|
|
10117
10174
|
content = JSON.stringify(config, null, 2);
|
|
10118
10175
|
}
|
|
10119
10176
|
await writeFile(path7, content, "utf-8");
|
|
10177
|
+
configCache.clear();
|
|
10120
10178
|
logger.info("Config saved successfully", { path: normalizePath(path7), format: ext });
|
|
10121
10179
|
} catch (error) {
|
|
10122
10180
|
if (error instanceof ConfigError) {
|
|
@@ -13191,12 +13249,6 @@ var setupCommand = {
|
|
|
13191
13249
|
describe: "Force setup even if .automatosx already exists",
|
|
13192
13250
|
type: "boolean",
|
|
13193
13251
|
default: false
|
|
13194
|
-
}).option("spec-kit", {
|
|
13195
|
-
describe: "Automatically initialize GitHub Spec-Kit for spec-driven development",
|
|
13196
|
-
type: "boolean"
|
|
13197
|
-
}).option("skip-spec-kit", {
|
|
13198
|
-
describe: "Skip Spec-Kit initialization (useful for CI/CD)",
|
|
13199
|
-
type: "boolean"
|
|
13200
13252
|
}).option("claude-code", {
|
|
13201
13253
|
describe: "Setup Claude Code integration (generates manifests and registers MCP server)",
|
|
13202
13254
|
type: "boolean",
|
|
@@ -13386,7 +13438,6 @@ var setupCommand = {
|
|
|
13386
13438
|
console.log(chalk5.cyan("\u{1F4DD} Updating .gitignore..."));
|
|
13387
13439
|
await updateGitignore(projectDir);
|
|
13388
13440
|
console.log(chalk5.green(" \u2713 .gitignore updated"));
|
|
13389
|
-
const specKitInitialized = await maybeInitializeSpecKit(projectDir, argv);
|
|
13390
13441
|
let claudeCodeSetupSucceeded = false;
|
|
13391
13442
|
if (argv.claudeCode) {
|
|
13392
13443
|
console.log(chalk5.blue("\n\u{1F527} Setting up Claude Code integration...\n"));
|
|
@@ -13440,13 +13491,6 @@ var setupCommand = {
|
|
|
13440
13491
|
console.log(chalk5.gray(' ax run backend "implement auth" --workflow auth-flow'));
|
|
13441
13492
|
console.log(chalk5.gray(' ax run backend "create API" --workflow api-flow'));
|
|
13442
13493
|
console.log(chalk5.gray(" \u2022 Available: auth-flow, feature-flow, api-flow, refactor-flow\n"));
|
|
13443
|
-
if (specKitInitialized) {
|
|
13444
|
-
console.log(chalk5.cyan("Spec Files (.specify/):"));
|
|
13445
|
-
console.log(chalk5.gray(" \u2022 Spec files created for documentation"));
|
|
13446
|
-
console.log(chalk5.gray(" \u2022 Use agents to work with specs:"));
|
|
13447
|
-
console.log(chalk5.gray(' ax run product "Write spec for feature X"'));
|
|
13448
|
-
console.log(chalk5.gray(" \u2022 Note: ax spec run removed in v11.0.0, use --workflow instead\n"));
|
|
13449
|
-
}
|
|
13450
13494
|
console.log(chalk5.cyan("Iterate Mode (Autonomous Multi-Iteration):"));
|
|
13451
13495
|
console.log(chalk5.gray(" \u2022 Enable with --iterate flag for autonomous task loops"));
|
|
13452
13496
|
console.log(chalk5.gray(' \u2022 Example: ax run quality "find bugs" --iterate --iterate-max-iterations 5'));
|
|
@@ -13881,9 +13925,9 @@ async function initializeGitRepository(projectDir) {
|
|
|
13881
13925
|
logger.info("Git repository already exists, skipping initialization");
|
|
13882
13926
|
return true;
|
|
13883
13927
|
}
|
|
13884
|
-
const { spawn:
|
|
13928
|
+
const { spawn: spawn10 } = await import('child_process');
|
|
13885
13929
|
await new Promise((resolve13, reject) => {
|
|
13886
|
-
const child =
|
|
13930
|
+
const child = spawn10("git", ["init"], {
|
|
13887
13931
|
cwd: projectDir,
|
|
13888
13932
|
stdio: "pipe",
|
|
13889
13933
|
shell: false
|
|
@@ -13964,155 +14008,6 @@ async function updateGitignore(projectDir) {
|
|
|
13964
14008
|
logger.warn("Failed to update .gitignore", { error: error.message });
|
|
13965
14009
|
}
|
|
13966
14010
|
}
|
|
13967
|
-
async function maybeInitializeSpecKit(projectDir, argv) {
|
|
13968
|
-
const specifyDir = join(projectDir, ".specify");
|
|
13969
|
-
const specifyExists = await checkExists2(specifyDir);
|
|
13970
|
-
if (specifyExists) {
|
|
13971
|
-
logger.info("Spec-Kit directory already exists, skipping initialization", {
|
|
13972
|
-
path: specifyDir
|
|
13973
|
-
});
|
|
13974
|
-
return true;
|
|
13975
|
-
}
|
|
13976
|
-
if (argv.skipSpecKit) {
|
|
13977
|
-
logger.info("Skipping Spec-Kit initialization (--skip-spec-kit flag)");
|
|
13978
|
-
return false;
|
|
13979
|
-
}
|
|
13980
|
-
if (argv.specKit) {
|
|
13981
|
-
console.log(chalk5.cyan("\n\u{1F4CB} Initializing GitHub Spec-Kit..."));
|
|
13982
|
-
return await initializeSpecKit(projectDir);
|
|
13983
|
-
}
|
|
13984
|
-
if (process.stdout.isTTY && process.stdin.isTTY) {
|
|
13985
|
-
console.log(chalk5.cyan("\n\u{1F4CB} GitHub Spec-Kit Integration"));
|
|
13986
|
-
console.log(chalk5.gray(" Spec-Kit enables spec-driven development workflows."));
|
|
13987
|
-
console.log(chalk5.gray(" It creates .specify/ directory with spec.md, plan.md, and tasks.md"));
|
|
13988
|
-
console.log(chalk5.gray(" for structured planning and task management.\n"));
|
|
13989
|
-
try {
|
|
13990
|
-
const prompt = new PromptHelper();
|
|
13991
|
-
try {
|
|
13992
|
-
const answer = await prompt.question(
|
|
13993
|
-
chalk5.cyan(" Initialize Spec-Kit now? (y/N): ")
|
|
13994
|
-
);
|
|
13995
|
-
const shouldInit = answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
13996
|
-
if (shouldInit) {
|
|
13997
|
-
console.log(chalk5.cyan("\n Initializing Spec-Kit..."));
|
|
13998
|
-
return await initializeSpecKit(projectDir);
|
|
13999
|
-
} else {
|
|
14000
|
-
logger.info("User declined Spec-Kit initialization");
|
|
14001
|
-
return false;
|
|
14002
|
-
}
|
|
14003
|
-
} finally {
|
|
14004
|
-
prompt.close();
|
|
14005
|
-
}
|
|
14006
|
-
} catch (error) {
|
|
14007
|
-
logger.warn("Failed to prompt for Spec-Kit initialization", {
|
|
14008
|
-
error: error.message
|
|
14009
|
-
});
|
|
14010
|
-
return false;
|
|
14011
|
-
}
|
|
14012
|
-
}
|
|
14013
|
-
logger.info("Non-interactive mode, skipping Spec-Kit initialization");
|
|
14014
|
-
return false;
|
|
14015
|
-
}
|
|
14016
|
-
async function initializeSpecKit(projectDir) {
|
|
14017
|
-
try {
|
|
14018
|
-
const specifyDir = join(projectDir, ".specify");
|
|
14019
|
-
await mkdir(specifyDir, { recursive: true });
|
|
14020
|
-
const specTemplate = `# Project Specification
|
|
14021
|
-
|
|
14022
|
-
## Overview
|
|
14023
|
-
<!-- Brief description of what this project does -->
|
|
14024
|
-
|
|
14025
|
-
## Goals
|
|
14026
|
-
<!-- List the main goals and objectives -->
|
|
14027
|
-
|
|
14028
|
-
## Requirements
|
|
14029
|
-
<!-- Detailed requirements -->
|
|
14030
|
-
|
|
14031
|
-
### Functional Requirements
|
|
14032
|
-
<!-- What the system should do -->
|
|
14033
|
-
|
|
14034
|
-
### Non-Functional Requirements
|
|
14035
|
-
<!-- Performance, security, scalability, etc. -->
|
|
14036
|
-
|
|
14037
|
-
## Success Criteria
|
|
14038
|
-
<!-- How do we measure success? -->
|
|
14039
|
-
|
|
14040
|
-
## Out of Scope
|
|
14041
|
-
<!-- What this project explicitly does NOT include -->
|
|
14042
|
-
`;
|
|
14043
|
-
const planTemplate = `# Technical Plan
|
|
14044
|
-
|
|
14045
|
-
## Architecture
|
|
14046
|
-
<!-- High-level architecture diagram or description -->
|
|
14047
|
-
|
|
14048
|
-
## Technology Stack
|
|
14049
|
-
<!-- Languages, frameworks, libraries, tools -->
|
|
14050
|
-
|
|
14051
|
-
## Implementation Approach
|
|
14052
|
-
<!-- Step-by-step approach to implementation -->
|
|
14053
|
-
|
|
14054
|
-
## Data Model
|
|
14055
|
-
<!-- Database schema, data structures -->
|
|
14056
|
-
|
|
14057
|
-
## API Design
|
|
14058
|
-
<!-- API endpoints, interfaces -->
|
|
14059
|
-
|
|
14060
|
-
## Security Considerations
|
|
14061
|
-
<!-- Authentication, authorization, data protection -->
|
|
14062
|
-
|
|
14063
|
-
## Testing Strategy
|
|
14064
|
-
<!-- Unit tests, integration tests, E2E tests -->
|
|
14065
|
-
|
|
14066
|
-
## Deployment Plan
|
|
14067
|
-
<!-- How will this be deployed? -->
|
|
14068
|
-
|
|
14069
|
-
## Risks and Mitigations
|
|
14070
|
-
<!-- Potential risks and how to handle them -->
|
|
14071
|
-
`;
|
|
14072
|
-
const tasksTemplate = `# Tasks
|
|
14073
|
-
|
|
14074
|
-
<!-- Task format: - [ ] id:task-id ops:"command" dep:dependency-id -->
|
|
14075
|
-
<!-- Example: -->
|
|
14076
|
-
<!-- - [ ] id:setup:env ops:"ax run devops 'Setup development environment'" -->
|
|
14077
|
-
<!-- - [ ] id:impl:api ops:"ax run backend 'Implement REST API'" dep:setup:env -->
|
|
14078
|
-
<!-- - [ ] id:test:api ops:"ax run quality 'Write API tests'" dep:impl:api -->
|
|
14079
|
-
|
|
14080
|
-
## Phase 1: Setup
|
|
14081
|
-
- [ ] id:setup:env ops:"ax run devops 'Setup development environment'"
|
|
14082
|
-
- [ ] id:setup:db ops:"ax run backend 'Setup database schema'" dep:setup:env
|
|
14083
|
-
|
|
14084
|
-
## Phase 2: Implementation
|
|
14085
|
-
- [ ] id:impl:core ops:"ax run backend 'Implement core functionality'" dep:setup:db
|
|
14086
|
-
|
|
14087
|
-
## Phase 3: Testing
|
|
14088
|
-
- [ ] id:test:unit ops:"ax run quality 'Write unit tests'" dep:impl:core
|
|
14089
|
-
- [ ] id:test:integration ops:"ax run quality 'Write integration tests'" dep:impl:core
|
|
14090
|
-
|
|
14091
|
-
## Phase 4: Documentation
|
|
14092
|
-
- [ ] id:docs:api ops:"ax run writer 'Write API documentation'" dep:impl:core
|
|
14093
|
-
`;
|
|
14094
|
-
await writeFile(join(specifyDir, "spec.md"), specTemplate, "utf8");
|
|
14095
|
-
await writeFile(join(specifyDir, "plan.md"), planTemplate, "utf8");
|
|
14096
|
-
await writeFile(join(specifyDir, "tasks.md"), tasksTemplate, "utf8");
|
|
14097
|
-
console.log(chalk5.green(" \u2713 Spec-Kit set up successfully"));
|
|
14098
|
-
console.log(chalk5.gray(" Files created: .specify/spec.md, plan.md, tasks.md"));
|
|
14099
|
-
logger.info("Spec-Kit set up successfully", {
|
|
14100
|
-
projectDir,
|
|
14101
|
-
specifyDir
|
|
14102
|
-
});
|
|
14103
|
-
return true;
|
|
14104
|
-
} catch (error) {
|
|
14105
|
-
const errorMessage = error.message;
|
|
14106
|
-
console.log(chalk5.yellow(" \u26A0\uFE0F Failed to initialize Spec-Kit"));
|
|
14107
|
-
console.log(chalk5.gray(` ${errorMessage}
|
|
14108
|
-
`));
|
|
14109
|
-
logger.warn("Spec-Kit initialization failed (non-critical)", {
|
|
14110
|
-
error: errorMessage,
|
|
14111
|
-
projectDir
|
|
14112
|
-
});
|
|
14113
|
-
return false;
|
|
14114
|
-
}
|
|
14115
|
-
}
|
|
14116
14011
|
async function setupGeminiIntegration(projectDir, packageRoot) {
|
|
14117
14012
|
const geminiDir = join(projectDir, ".gemini");
|
|
14118
14013
|
await mkdir(geminiDir, { recursive: true });
|
|
@@ -16146,12 +16041,12 @@ var listCommand = {
|
|
|
16146
16041
|
};
|
|
16147
16042
|
async function listAgents(pathResolver, format) {
|
|
16148
16043
|
const agentsDir = pathResolver.getAgentsDirectory();
|
|
16149
|
-
const { existsSync:
|
|
16044
|
+
const { existsSync: existsSync26 } = await import('fs');
|
|
16150
16045
|
const projectDir = await detectProjectRoot();
|
|
16151
16046
|
const examplesDir = join(projectDir, "examples", "agents");
|
|
16152
16047
|
try {
|
|
16153
16048
|
const agentFiles = [];
|
|
16154
|
-
if (
|
|
16049
|
+
if (existsSync26(agentsDir)) {
|
|
16155
16050
|
const files = await readdir(agentsDir);
|
|
16156
16051
|
for (const file of files) {
|
|
16157
16052
|
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
@@ -16163,7 +16058,7 @@ async function listAgents(pathResolver, format) {
|
|
|
16163
16058
|
}
|
|
16164
16059
|
}
|
|
16165
16060
|
}
|
|
16166
|
-
if (
|
|
16061
|
+
if (existsSync26(examplesDir)) {
|
|
16167
16062
|
const files = await readdir(examplesDir);
|
|
16168
16063
|
for (const file of files) {
|
|
16169
16064
|
if (file.endsWith(".yaml") || file.endsWith(".yml")) {
|
|
@@ -22176,8 +22071,8 @@ var ProjectContextLoader = class {
|
|
|
22176
22071
|
const projectMatch = markdown.match(/>\s*Project:\s*(.+?)$/im);
|
|
22177
22072
|
if (projectMatch && projectMatch[1]) {
|
|
22178
22073
|
const parts = projectMatch[1].trim().split(/\s+v/);
|
|
22179
|
-
metadata.name = parts[0];
|
|
22180
|
-
if (parts[1]) {
|
|
22074
|
+
metadata.name = parts[0] || "";
|
|
22075
|
+
if (parts.length > 1 && parts[1]) {
|
|
22181
22076
|
metadata.version = parts[1];
|
|
22182
22077
|
}
|
|
22183
22078
|
}
|
|
@@ -36202,6 +36097,707 @@ function formatForSave(result, format, metadata) {
|
|
|
36202
36097
|
}
|
|
36203
36098
|
return formatOutput(result, format, true);
|
|
36204
36099
|
}
|
|
36100
|
+
|
|
36101
|
+
// src/core/workflow/index.ts
|
|
36102
|
+
init_esm_shims();
|
|
36103
|
+
|
|
36104
|
+
// src/core/workflow/workflow-mode.ts
|
|
36105
|
+
init_esm_shims();
|
|
36106
|
+
var WorkflowModeSchema = z.enum(["default", "plan", "iterate", "review"]);
|
|
36107
|
+
z.object({
|
|
36108
|
+
name: WorkflowModeSchema,
|
|
36109
|
+
description: z.string(),
|
|
36110
|
+
displayName: z.string(),
|
|
36111
|
+
allowedTools: z.array(z.string()).optional(),
|
|
36112
|
+
blockedTools: z.array(z.string()).optional(),
|
|
36113
|
+
systemInstructions: z.string(),
|
|
36114
|
+
allowNesting: z.boolean(),
|
|
36115
|
+
maxNestingDepth: z.number().int().positive().optional(),
|
|
36116
|
+
autoExitConditions: z.object({
|
|
36117
|
+
maxTurns: z.number().int().positive().optional(),
|
|
36118
|
+
onToolUse: z.array(z.string()).optional(),
|
|
36119
|
+
onKeywords: z.array(z.string()).optional()
|
|
36120
|
+
}).optional()
|
|
36121
|
+
});
|
|
36122
|
+
var WRITE_TOOLS = [
|
|
36123
|
+
"Write",
|
|
36124
|
+
"Edit",
|
|
36125
|
+
"NotebookEdit",
|
|
36126
|
+
"Bash"
|
|
36127
|
+
];
|
|
36128
|
+
var DEFAULT_MODE_CONFIG = {
|
|
36129
|
+
name: "default",
|
|
36130
|
+
displayName: "Default",
|
|
36131
|
+
description: "Standard operation mode with all tools available",
|
|
36132
|
+
systemInstructions: "",
|
|
36133
|
+
allowNesting: true,
|
|
36134
|
+
maxNestingDepth: 3
|
|
36135
|
+
};
|
|
36136
|
+
var PLAN_MODE_CONFIG = {
|
|
36137
|
+
name: "plan",
|
|
36138
|
+
displayName: "Plan Mode",
|
|
36139
|
+
description: "Planning mode - read-only exploration without code modifications",
|
|
36140
|
+
blockedTools: [...WRITE_TOOLS],
|
|
36141
|
+
systemInstructions: `## Plan Mode Active
|
|
36142
|
+
|
|
36143
|
+
You are in **Plan Mode**. This mode is for exploration and planning only.
|
|
36144
|
+
|
|
36145
|
+
**Restrictions:**
|
|
36146
|
+
- You CANNOT use Write, Edit, or Bash tools that modify files
|
|
36147
|
+
- Focus on reading, searching, and understanding the codebase
|
|
36148
|
+
- Create a comprehensive plan before implementation
|
|
36149
|
+
|
|
36150
|
+
**Your Goals:**
|
|
36151
|
+
1. Explore the codebase to understand existing patterns
|
|
36152
|
+
2. Identify files that need to be modified
|
|
36153
|
+
3. Design an implementation approach
|
|
36154
|
+
4. Document your plan clearly
|
|
36155
|
+
5. Use ExitPlanMode when ready to implement
|
|
36156
|
+
|
|
36157
|
+
**Remember:** No code modifications in this mode. Plan first, implement later.`,
|
|
36158
|
+
allowNesting: false,
|
|
36159
|
+
autoExitConditions: {
|
|
36160
|
+
onToolUse: ["ExitPlanMode"]
|
|
36161
|
+
}
|
|
36162
|
+
};
|
|
36163
|
+
var ITERATE_MODE_CONFIG = {
|
|
36164
|
+
name: "iterate",
|
|
36165
|
+
displayName: "Iterate Mode",
|
|
36166
|
+
description: "Continuous iteration mode for implementation with automatic continuation",
|
|
36167
|
+
systemInstructions: `## Iterate Mode Active
|
|
36168
|
+
|
|
36169
|
+
You are in **Iterate Mode**. This mode enables continuous task execution.
|
|
36170
|
+
|
|
36171
|
+
**Behavior:**
|
|
36172
|
+
- Continue working until the task is complete
|
|
36173
|
+
- After each step, assess progress and continue
|
|
36174
|
+
- Don't stop to ask for confirmation unless critical
|
|
36175
|
+
- Mark todos as completed as you finish them
|
|
36176
|
+
|
|
36177
|
+
**Guidelines:**
|
|
36178
|
+
1. Work through tasks systematically
|
|
36179
|
+
2. Test changes as you go when possible
|
|
36180
|
+
3. Update todo list to track progress
|
|
36181
|
+
4. Only pause for critical decisions or blockers
|
|
36182
|
+
|
|
36183
|
+
**Remember:** Keep iterating until the task is done or you hit a blocker.`,
|
|
36184
|
+
allowNesting: true,
|
|
36185
|
+
maxNestingDepth: 2
|
|
36186
|
+
};
|
|
36187
|
+
var REVIEW_MODE_CONFIG = {
|
|
36188
|
+
name: "review",
|
|
36189
|
+
displayName: "Review Mode",
|
|
36190
|
+
description: "Code review mode - analyze code quality, security, and best practices",
|
|
36191
|
+
blockedTools: [...WRITE_TOOLS],
|
|
36192
|
+
systemInstructions: `## Review Mode Active
|
|
36193
|
+
|
|
36194
|
+
You are in **Review Mode**. This mode is for code review and analysis.
|
|
36195
|
+
|
|
36196
|
+
**Focus Areas:**
|
|
36197
|
+
- Code quality and readability
|
|
36198
|
+
- Security vulnerabilities (OWASP Top 10)
|
|
36199
|
+
- Performance issues
|
|
36200
|
+
- Best practices and patterns
|
|
36201
|
+
- Test coverage gaps
|
|
36202
|
+
|
|
36203
|
+
**Output Format:**
|
|
36204
|
+
Provide structured feedback:
|
|
36205
|
+
1. **Critical Issues** - Must fix before merge
|
|
36206
|
+
2. **Warnings** - Should address
|
|
36207
|
+
3. **Suggestions** - Nice to have improvements
|
|
36208
|
+
4. **Positive Notes** - Good patterns observed
|
|
36209
|
+
|
|
36210
|
+
**Remember:** No code modifications. Provide actionable feedback only.`,
|
|
36211
|
+
allowNesting: false
|
|
36212
|
+
};
|
|
36213
|
+
var WORKFLOW_MODE_CONFIGS = {
|
|
36214
|
+
default: DEFAULT_MODE_CONFIG,
|
|
36215
|
+
plan: PLAN_MODE_CONFIG,
|
|
36216
|
+
iterate: ITERATE_MODE_CONFIG,
|
|
36217
|
+
review: REVIEW_MODE_CONFIG
|
|
36218
|
+
};
|
|
36219
|
+
function getWorkflowModeConfig(mode) {
|
|
36220
|
+
return WORKFLOW_MODE_CONFIGS[mode];
|
|
36221
|
+
}
|
|
36222
|
+
function isToolAllowedInMode(tool, mode) {
|
|
36223
|
+
const config = getWorkflowModeConfig(mode);
|
|
36224
|
+
if (config.allowedTools && config.allowedTools.length > 0) {
|
|
36225
|
+
return config.allowedTools.includes(tool);
|
|
36226
|
+
}
|
|
36227
|
+
if (config.blockedTools && config.blockedTools.length > 0) {
|
|
36228
|
+
return !config.blockedTools.includes(tool);
|
|
36229
|
+
}
|
|
36230
|
+
return true;
|
|
36231
|
+
}
|
|
36232
|
+
function isValidWorkflowMode(mode) {
|
|
36233
|
+
return Object.prototype.hasOwnProperty.call(WORKFLOW_MODE_CONFIGS, mode);
|
|
36234
|
+
}
|
|
36235
|
+
var WORKFLOW_MODES = WORKFLOW_MODE_CONFIGS;
|
|
36236
|
+
|
|
36237
|
+
// src/core/workflow/workflow-mode-manager.ts
|
|
36238
|
+
init_esm_shims();
|
|
36239
|
+
init_logger();
|
|
36240
|
+
|
|
36241
|
+
// src/core/orchestration/types.ts
|
|
36242
|
+
init_esm_shims();
|
|
36243
|
+
var INSTRUCTION_SOURCE = "automatosx";
|
|
36244
|
+
z.object({
|
|
36245
|
+
type: z.enum(["task", "memory", "session", "delegation", "mode", "context"]),
|
|
36246
|
+
priority: z.enum(["critical", "high", "normal", "low"]),
|
|
36247
|
+
content: z.string().min(1).max(5e3),
|
|
36248
|
+
source: z.literal(INSTRUCTION_SOURCE),
|
|
36249
|
+
expiresAfter: z.number().int().positive().optional(),
|
|
36250
|
+
createdAt: z.number(),
|
|
36251
|
+
createdAtTurn: z.number().int().nonnegative().optional(),
|
|
36252
|
+
id: z.string().optional()
|
|
36253
|
+
});
|
|
36254
|
+
var TodoItemSchema = z.object({
|
|
36255
|
+
id: z.string(),
|
|
36256
|
+
content: z.string().min(1).max(1e3),
|
|
36257
|
+
status: z.enum(["pending", "in_progress", "completed"]),
|
|
36258
|
+
activeForm: z.string().min(1).max(1e3),
|
|
36259
|
+
createdAt: z.number(),
|
|
36260
|
+
updatedAt: z.number().optional(),
|
|
36261
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
36262
|
+
});
|
|
36263
|
+
z.object({
|
|
36264
|
+
name: z.enum(["default", "plan", "iterate", "review"]),
|
|
36265
|
+
description: z.string(),
|
|
36266
|
+
displayName: z.string(),
|
|
36267
|
+
allowedTools: z.array(z.string()).optional(),
|
|
36268
|
+
blockedTools: z.array(z.string()).optional(),
|
|
36269
|
+
systemInstructions: z.string(),
|
|
36270
|
+
allowNesting: z.boolean(),
|
|
36271
|
+
maxNestingDepth: z.number().int().positive().optional(),
|
|
36272
|
+
autoExitConditions: z.object({
|
|
36273
|
+
maxTurns: z.number().int().positive().optional(),
|
|
36274
|
+
onToolUse: z.array(z.string()).optional(),
|
|
36275
|
+
onKeywords: z.array(z.string()).optional()
|
|
36276
|
+
}).optional()
|
|
36277
|
+
});
|
|
36278
|
+
z.object({
|
|
36279
|
+
todos: z.array(TodoItemSchema),
|
|
36280
|
+
currentTask: z.string().optional(),
|
|
36281
|
+
agentName: z.string().optional(),
|
|
36282
|
+
turnCount: z.number().int().nonnegative(),
|
|
36283
|
+
workflowMode: z.enum(["default", "plan", "iterate", "review"]),
|
|
36284
|
+
sessionId: z.string().optional(),
|
|
36285
|
+
parentAgent: z.string().optional(),
|
|
36286
|
+
memories: z.array(z.object({
|
|
36287
|
+
content: z.string(),
|
|
36288
|
+
relevance: z.number().min(0).max(1),
|
|
36289
|
+
agent: z.string().optional(),
|
|
36290
|
+
timestamp: z.number()
|
|
36291
|
+
})).optional()
|
|
36292
|
+
});
|
|
36293
|
+
var DEFAULT_TOKEN_BUDGET = {
|
|
36294
|
+
maxTotal: 2e3,
|
|
36295
|
+
perType: {
|
|
36296
|
+
task: 500,
|
|
36297
|
+
memory: 600,
|
|
36298
|
+
session: 300,
|
|
36299
|
+
delegation: 200,
|
|
36300
|
+
mode: 400,
|
|
36301
|
+
context: 300
|
|
36302
|
+
},
|
|
36303
|
+
criticalReserve: 300
|
|
36304
|
+
};
|
|
36305
|
+
var TokenBudgetConfigSchema = z.object({
|
|
36306
|
+
maxTotal: z.number().int().positive().max(1e4),
|
|
36307
|
+
perType: z.record(
|
|
36308
|
+
z.enum(["task", "memory", "session", "delegation", "mode", "context"]),
|
|
36309
|
+
z.number().int().nonnegative()
|
|
36310
|
+
),
|
|
36311
|
+
criticalReserve: z.number().int().nonnegative()
|
|
36312
|
+
});
|
|
36313
|
+
var DEFAULT_ORCHESTRATION_CONFIG = {
|
|
36314
|
+
enabled: true,
|
|
36315
|
+
tokenBudget: DEFAULT_TOKEN_BUDGET,
|
|
36316
|
+
todoIntegration: {
|
|
36317
|
+
enabled: true,
|
|
36318
|
+
reminderFrequency: 3,
|
|
36319
|
+
compactMode: false
|
|
36320
|
+
},
|
|
36321
|
+
memoryIntegration: {
|
|
36322
|
+
enabled: true,
|
|
36323
|
+
maxEntries: 5,
|
|
36324
|
+
minRelevance: 0.5
|
|
36325
|
+
},
|
|
36326
|
+
sessionIntegration: {
|
|
36327
|
+
enabled: true,
|
|
36328
|
+
showCollaboration: true
|
|
36329
|
+
},
|
|
36330
|
+
agentTemplates: {
|
|
36331
|
+
enabled: true,
|
|
36332
|
+
reminderFrequency: 5
|
|
36333
|
+
}
|
|
36334
|
+
};
|
|
36335
|
+
z.object({
|
|
36336
|
+
enabled: z.boolean(),
|
|
36337
|
+
tokenBudget: TokenBudgetConfigSchema,
|
|
36338
|
+
todoIntegration: z.object({
|
|
36339
|
+
enabled: z.boolean(),
|
|
36340
|
+
reminderFrequency: z.number().int().positive(),
|
|
36341
|
+
compactMode: z.boolean()
|
|
36342
|
+
}),
|
|
36343
|
+
memoryIntegration: z.object({
|
|
36344
|
+
enabled: z.boolean(),
|
|
36345
|
+
maxEntries: z.number().int().nonnegative(),
|
|
36346
|
+
minRelevance: z.number().min(0).max(1)
|
|
36347
|
+
}),
|
|
36348
|
+
sessionIntegration: z.object({
|
|
36349
|
+
enabled: z.boolean(),
|
|
36350
|
+
showCollaboration: z.boolean()
|
|
36351
|
+
}),
|
|
36352
|
+
agentTemplates: z.object({
|
|
36353
|
+
enabled: z.boolean(),
|
|
36354
|
+
reminderFrequency: z.number().int().positive()
|
|
36355
|
+
})
|
|
36356
|
+
});
|
|
36357
|
+
|
|
36358
|
+
// src/core/workflow/workflow-mode-manager.ts
|
|
36359
|
+
var WorkflowModeManager = class {
|
|
36360
|
+
name = "workflow-mode";
|
|
36361
|
+
modeStack = [];
|
|
36362
|
+
transitionListeners = /* @__PURE__ */ new Set();
|
|
36363
|
+
turnCount = 0;
|
|
36364
|
+
constructor(initialMode = "default") {
|
|
36365
|
+
this.modeStack.push({
|
|
36366
|
+
mode: initialMode,
|
|
36367
|
+
enteredAt: Date.now(),
|
|
36368
|
+
enteredAtTurn: 0,
|
|
36369
|
+
reason: "initial"
|
|
36370
|
+
});
|
|
36371
|
+
logger.debug("WorkflowModeManager initialized", {
|
|
36372
|
+
initialMode
|
|
36373
|
+
});
|
|
36374
|
+
}
|
|
36375
|
+
/**
|
|
36376
|
+
* Get the top entry from the mode stack (private helper to reduce repetition)
|
|
36377
|
+
*/
|
|
36378
|
+
getTopEntry() {
|
|
36379
|
+
return this.modeStack[this.modeStack.length - 1];
|
|
36380
|
+
}
|
|
36381
|
+
/**
|
|
36382
|
+
* Get the current active mode
|
|
36383
|
+
*/
|
|
36384
|
+
getCurrentMode() {
|
|
36385
|
+
return this.getTopEntry()?.mode ?? "default";
|
|
36386
|
+
}
|
|
36387
|
+
/**
|
|
36388
|
+
* Get the current mode configuration
|
|
36389
|
+
*/
|
|
36390
|
+
getCurrentModeConfig() {
|
|
36391
|
+
const mode = this.getCurrentMode();
|
|
36392
|
+
const entry = this.getTopEntry();
|
|
36393
|
+
const baseConfig = getWorkflowModeConfig(mode);
|
|
36394
|
+
if (entry?.customConfig) {
|
|
36395
|
+
const mergedAutoExit = entry.customConfig.autoExitConditions || baseConfig.autoExitConditions ? {
|
|
36396
|
+
...baseConfig.autoExitConditions ?? {},
|
|
36397
|
+
...entry.customConfig.autoExitConditions ?? {}
|
|
36398
|
+
} : void 0;
|
|
36399
|
+
return {
|
|
36400
|
+
...baseConfig,
|
|
36401
|
+
...entry.customConfig,
|
|
36402
|
+
// Deep merge for nested objects
|
|
36403
|
+
autoExitConditions: mergedAutoExit
|
|
36404
|
+
};
|
|
36405
|
+
}
|
|
36406
|
+
return baseConfig;
|
|
36407
|
+
}
|
|
36408
|
+
/**
|
|
36409
|
+
* Get the full mode stack
|
|
36410
|
+
*/
|
|
36411
|
+
getModeStack() {
|
|
36412
|
+
return [...this.modeStack];
|
|
36413
|
+
}
|
|
36414
|
+
/**
|
|
36415
|
+
* Get the current stack depth
|
|
36416
|
+
*/
|
|
36417
|
+
getStackDepth() {
|
|
36418
|
+
return this.modeStack.length;
|
|
36419
|
+
}
|
|
36420
|
+
/**
|
|
36421
|
+
* Push a new mode onto the stack
|
|
36422
|
+
*/
|
|
36423
|
+
pushMode(mode, options) {
|
|
36424
|
+
const currentConfig = this.getCurrentModeConfig();
|
|
36425
|
+
if (!currentConfig.allowNesting) {
|
|
36426
|
+
logger.warn("Cannot push mode: current mode does not allow nesting", {
|
|
36427
|
+
currentMode: this.getCurrentMode(),
|
|
36428
|
+
attemptedMode: mode
|
|
36429
|
+
});
|
|
36430
|
+
return false;
|
|
36431
|
+
}
|
|
36432
|
+
const maxDepth = currentConfig.maxNestingDepth ?? 3;
|
|
36433
|
+
if (this.modeStack.length >= maxDepth) {
|
|
36434
|
+
logger.warn("Cannot push mode: max nesting depth reached", {
|
|
36435
|
+
currentDepth: this.modeStack.length,
|
|
36436
|
+
maxDepth
|
|
36437
|
+
});
|
|
36438
|
+
return false;
|
|
36439
|
+
}
|
|
36440
|
+
const previousMode = this.getCurrentMode();
|
|
36441
|
+
this.modeStack.push({
|
|
36442
|
+
mode,
|
|
36443
|
+
enteredAt: Date.now(),
|
|
36444
|
+
enteredAtTurn: this.turnCount,
|
|
36445
|
+
customConfig: options?.customConfig,
|
|
36446
|
+
reason: options?.reason
|
|
36447
|
+
});
|
|
36448
|
+
this.emitTransition({
|
|
36449
|
+
from: previousMode,
|
|
36450
|
+
to: mode,
|
|
36451
|
+
type: "push",
|
|
36452
|
+
timestamp: Date.now(),
|
|
36453
|
+
reason: options?.reason
|
|
36454
|
+
});
|
|
36455
|
+
logger.info("Pushed workflow mode", {
|
|
36456
|
+
from: previousMode,
|
|
36457
|
+
to: mode,
|
|
36458
|
+
stackDepth: this.modeStack.length,
|
|
36459
|
+
reason: options?.reason
|
|
36460
|
+
});
|
|
36461
|
+
return true;
|
|
36462
|
+
}
|
|
36463
|
+
/**
|
|
36464
|
+
* Pop the current mode from the stack
|
|
36465
|
+
*/
|
|
36466
|
+
popMode(reason) {
|
|
36467
|
+
if (this.modeStack.length <= 1) {
|
|
36468
|
+
logger.warn("Cannot pop mode: at base level");
|
|
36469
|
+
return null;
|
|
36470
|
+
}
|
|
36471
|
+
const popped = this.modeStack.pop();
|
|
36472
|
+
const newMode = this.getCurrentMode();
|
|
36473
|
+
if (popped) {
|
|
36474
|
+
this.emitTransition({
|
|
36475
|
+
from: popped.mode,
|
|
36476
|
+
to: newMode,
|
|
36477
|
+
type: "pop",
|
|
36478
|
+
timestamp: Date.now(),
|
|
36479
|
+
reason
|
|
36480
|
+
});
|
|
36481
|
+
logger.info("Popped workflow mode", {
|
|
36482
|
+
from: popped.mode,
|
|
36483
|
+
to: newMode,
|
|
36484
|
+
stackDepth: this.modeStack.length,
|
|
36485
|
+
reason
|
|
36486
|
+
});
|
|
36487
|
+
}
|
|
36488
|
+
return popped?.mode ?? null;
|
|
36489
|
+
}
|
|
36490
|
+
/**
|
|
36491
|
+
* Replace the current mode (pop then push)
|
|
36492
|
+
*/
|
|
36493
|
+
replaceMode(mode, options) {
|
|
36494
|
+
const previousMode = this.getCurrentMode();
|
|
36495
|
+
if (this.modeStack.length === 1) {
|
|
36496
|
+
this.modeStack[0] = {
|
|
36497
|
+
mode,
|
|
36498
|
+
enteredAt: Date.now(),
|
|
36499
|
+
enteredAtTurn: this.turnCount,
|
|
36500
|
+
customConfig: options?.customConfig,
|
|
36501
|
+
reason: options?.reason
|
|
36502
|
+
};
|
|
36503
|
+
} else {
|
|
36504
|
+
this.modeStack.pop();
|
|
36505
|
+
this.modeStack.push({
|
|
36506
|
+
mode,
|
|
36507
|
+
enteredAt: Date.now(),
|
|
36508
|
+
enteredAtTurn: this.turnCount,
|
|
36509
|
+
customConfig: options?.customConfig,
|
|
36510
|
+
reason: options?.reason
|
|
36511
|
+
});
|
|
36512
|
+
}
|
|
36513
|
+
this.emitTransition({
|
|
36514
|
+
from: previousMode,
|
|
36515
|
+
to: mode,
|
|
36516
|
+
type: "replace",
|
|
36517
|
+
timestamp: Date.now(),
|
|
36518
|
+
reason: options?.reason
|
|
36519
|
+
});
|
|
36520
|
+
logger.info("Replaced workflow mode", {
|
|
36521
|
+
from: previousMode,
|
|
36522
|
+
to: mode,
|
|
36523
|
+
reason: options?.reason
|
|
36524
|
+
});
|
|
36525
|
+
return true;
|
|
36526
|
+
}
|
|
36527
|
+
/**
|
|
36528
|
+
* Set mode directly (clears stack and sets new base mode)
|
|
36529
|
+
*/
|
|
36530
|
+
setMode(mode, options) {
|
|
36531
|
+
const previousMode = this.getCurrentMode();
|
|
36532
|
+
this.modeStack = [{
|
|
36533
|
+
mode,
|
|
36534
|
+
enteredAt: Date.now(),
|
|
36535
|
+
enteredAtTurn: this.turnCount,
|
|
36536
|
+
customConfig: options?.customConfig,
|
|
36537
|
+
reason: options?.reason
|
|
36538
|
+
}];
|
|
36539
|
+
this.emitTransition({
|
|
36540
|
+
from: previousMode,
|
|
36541
|
+
to: mode,
|
|
36542
|
+
type: "replace",
|
|
36543
|
+
timestamp: Date.now(),
|
|
36544
|
+
reason: options?.reason
|
|
36545
|
+
});
|
|
36546
|
+
logger.info("Set workflow mode", {
|
|
36547
|
+
from: previousMode,
|
|
36548
|
+
to: mode,
|
|
36549
|
+
reason: options?.reason
|
|
36550
|
+
});
|
|
36551
|
+
}
|
|
36552
|
+
/**
|
|
36553
|
+
* Check if a tool is allowed in the current mode
|
|
36554
|
+
*/
|
|
36555
|
+
isToolAllowed(tool) {
|
|
36556
|
+
return isToolAllowedInMode(tool, this.getCurrentMode());
|
|
36557
|
+
}
|
|
36558
|
+
/**
|
|
36559
|
+
* Get list of blocked tools in current mode
|
|
36560
|
+
*/
|
|
36561
|
+
getBlockedTools() {
|
|
36562
|
+
const config = this.getCurrentModeConfig();
|
|
36563
|
+
return config.blockedTools || [];
|
|
36564
|
+
}
|
|
36565
|
+
/**
|
|
36566
|
+
* Filter a list of tools based on current mode
|
|
36567
|
+
*/
|
|
36568
|
+
filterTools(tools) {
|
|
36569
|
+
return tools.filter((tool) => this.isToolAllowed(tool.name));
|
|
36570
|
+
}
|
|
36571
|
+
/**
|
|
36572
|
+
* Update turn count (for auto-exit tracking)
|
|
36573
|
+
*/
|
|
36574
|
+
updateTurnCount(turn) {
|
|
36575
|
+
this.turnCount = turn;
|
|
36576
|
+
this.checkAutoExit();
|
|
36577
|
+
}
|
|
36578
|
+
/**
|
|
36579
|
+
* Check and handle auto-exit conditions
|
|
36580
|
+
*/
|
|
36581
|
+
checkAutoExit() {
|
|
36582
|
+
const config = this.getCurrentModeConfig();
|
|
36583
|
+
const entry = this.getTopEntry();
|
|
36584
|
+
if (!config.autoExitConditions || !entry) return;
|
|
36585
|
+
if (config.autoExitConditions.maxTurns) {
|
|
36586
|
+
const turnsInMode = this.turnCount - entry.enteredAtTurn;
|
|
36587
|
+
if (turnsInMode >= config.autoExitConditions.maxTurns) {
|
|
36588
|
+
logger.info("Auto-exiting mode due to max turns", {
|
|
36589
|
+
mode: this.getCurrentMode(),
|
|
36590
|
+
turnsInMode,
|
|
36591
|
+
maxTurns: config.autoExitConditions.maxTurns
|
|
36592
|
+
});
|
|
36593
|
+
this.popMode("max_turns_reached");
|
|
36594
|
+
}
|
|
36595
|
+
}
|
|
36596
|
+
}
|
|
36597
|
+
/**
|
|
36598
|
+
* Notify that a tool was used (for auto-exit on tool use)
|
|
36599
|
+
*/
|
|
36600
|
+
notifyToolUsed(tool) {
|
|
36601
|
+
const config = this.getCurrentModeConfig();
|
|
36602
|
+
if (config.autoExitConditions?.onToolUse?.includes(tool)) {
|
|
36603
|
+
logger.info("Auto-exiting mode due to tool use", {
|
|
36604
|
+
mode: this.getCurrentMode(),
|
|
36605
|
+
tool
|
|
36606
|
+
});
|
|
36607
|
+
this.popMode(`tool_used:${tool}`);
|
|
36608
|
+
}
|
|
36609
|
+
}
|
|
36610
|
+
/**
|
|
36611
|
+
* Add a mode transition listener
|
|
36612
|
+
*/
|
|
36613
|
+
onTransition(listener) {
|
|
36614
|
+
this.transitionListeners.add(listener);
|
|
36615
|
+
return () => this.transitionListeners.delete(listener);
|
|
36616
|
+
}
|
|
36617
|
+
/**
|
|
36618
|
+
* Emit a transition event to all listeners
|
|
36619
|
+
*/
|
|
36620
|
+
emitTransition(event) {
|
|
36621
|
+
for (const listener of this.transitionListeners) {
|
|
36622
|
+
try {
|
|
36623
|
+
listener(event);
|
|
36624
|
+
} catch (error) {
|
|
36625
|
+
logger.error("Mode transition listener error", {
|
|
36626
|
+
error: error instanceof Error ? error.message : String(error)
|
|
36627
|
+
});
|
|
36628
|
+
}
|
|
36629
|
+
}
|
|
36630
|
+
}
|
|
36631
|
+
// InstructionProvider implementation
|
|
36632
|
+
/**
|
|
36633
|
+
* Check if mode instructions should be generated
|
|
36634
|
+
*/
|
|
36635
|
+
shouldGenerate(context) {
|
|
36636
|
+
return this.getCurrentMode() !== "default";
|
|
36637
|
+
}
|
|
36638
|
+
/**
|
|
36639
|
+
* Get mode-specific instructions
|
|
36640
|
+
*/
|
|
36641
|
+
async getInstructions(context) {
|
|
36642
|
+
const config = this.getCurrentModeConfig();
|
|
36643
|
+
const instructions = [];
|
|
36644
|
+
if (config.systemInstructions && config.systemInstructions.length > 0) {
|
|
36645
|
+
instructions.push({
|
|
36646
|
+
type: "mode",
|
|
36647
|
+
priority: "high",
|
|
36648
|
+
content: config.systemInstructions,
|
|
36649
|
+
source: INSTRUCTION_SOURCE,
|
|
36650
|
+
createdAt: Date.now(),
|
|
36651
|
+
id: `mode-${config.name}-${Date.now()}`
|
|
36652
|
+
});
|
|
36653
|
+
}
|
|
36654
|
+
if (config.blockedTools && config.blockedTools.length > 0) {
|
|
36655
|
+
instructions.push({
|
|
36656
|
+
type: "mode",
|
|
36657
|
+
priority: "critical",
|
|
36658
|
+
content: `**Tool Restrictions:** The following tools are NOT available in ${config.displayName}: ${config.blockedTools.join(", ")}`,
|
|
36659
|
+
source: INSTRUCTION_SOURCE,
|
|
36660
|
+
createdAt: Date.now(),
|
|
36661
|
+
id: `mode-blocked-tools-${Date.now()}`
|
|
36662
|
+
});
|
|
36663
|
+
}
|
|
36664
|
+
return instructions;
|
|
36665
|
+
}
|
|
36666
|
+
/**
|
|
36667
|
+
* Reset to default state
|
|
36668
|
+
*/
|
|
36669
|
+
reset() {
|
|
36670
|
+
const previousMode = this.getCurrentMode();
|
|
36671
|
+
this.modeStack = [{
|
|
36672
|
+
mode: "default",
|
|
36673
|
+
enteredAt: Date.now(),
|
|
36674
|
+
enteredAtTurn: 0,
|
|
36675
|
+
reason: "reset"
|
|
36676
|
+
}];
|
|
36677
|
+
this.turnCount = 0;
|
|
36678
|
+
if (previousMode !== "default") {
|
|
36679
|
+
this.emitTransition({
|
|
36680
|
+
from: previousMode,
|
|
36681
|
+
to: "default",
|
|
36682
|
+
type: "replace",
|
|
36683
|
+
timestamp: Date.now(),
|
|
36684
|
+
reason: "reset"
|
|
36685
|
+
});
|
|
36686
|
+
}
|
|
36687
|
+
logger.debug("WorkflowModeManager reset");
|
|
36688
|
+
}
|
|
36689
|
+
/**
|
|
36690
|
+
* Get status information for debugging
|
|
36691
|
+
*/
|
|
36692
|
+
getStatus() {
|
|
36693
|
+
return {
|
|
36694
|
+
currentMode: this.getCurrentMode(),
|
|
36695
|
+
stackDepth: this.modeStack.length,
|
|
36696
|
+
stack: this.modeStack.map((entry) => ({
|
|
36697
|
+
mode: entry.mode,
|
|
36698
|
+
enteredAt: entry.enteredAt,
|
|
36699
|
+
reason: entry.reason
|
|
36700
|
+
})),
|
|
36701
|
+
blockedTools: this.getBlockedTools(),
|
|
36702
|
+
turnCount: this.turnCount
|
|
36703
|
+
};
|
|
36704
|
+
}
|
|
36705
|
+
};
|
|
36706
|
+
|
|
36707
|
+
// src/core/workflow/mode-state-manager.ts
|
|
36708
|
+
init_esm_shims();
|
|
36709
|
+
init_logger();
|
|
36710
|
+
init_path_resolver();
|
|
36711
|
+
var ModeStateSchema = z.object({
|
|
36712
|
+
mode: z.enum(["default", "plan", "iterate", "review"]),
|
|
36713
|
+
setAt: z.number(),
|
|
36714
|
+
setBy: z.string().optional(),
|
|
36715
|
+
reason: z.string().optional(),
|
|
36716
|
+
expiresAt: z.number().optional()
|
|
36717
|
+
});
|
|
36718
|
+
var STATE_FILE_PATH = ".automatosx/state/mode.json";
|
|
36719
|
+
var DEFAULT_EXPIRATION_MS = 4 * 60 * 60 * 1e3;
|
|
36720
|
+
async function getStateFilePath() {
|
|
36721
|
+
const projectRoot = await detectProjectRoot(process.cwd());
|
|
36722
|
+
return join(projectRoot, STATE_FILE_PATH);
|
|
36723
|
+
}
|
|
36724
|
+
async function loadModeState() {
|
|
36725
|
+
try {
|
|
36726
|
+
const statePath = await getStateFilePath();
|
|
36727
|
+
if (!existsSync(statePath)) {
|
|
36728
|
+
logger.debug("No mode state file found", { path: statePath });
|
|
36729
|
+
return null;
|
|
36730
|
+
}
|
|
36731
|
+
const content = readFileSync(statePath, "utf-8");
|
|
36732
|
+
const parsed = JSON.parse(content);
|
|
36733
|
+
const result = ModeStateSchema.safeParse(parsed);
|
|
36734
|
+
if (!result.success) {
|
|
36735
|
+
logger.warn("Invalid mode state file", {
|
|
36736
|
+
path: statePath,
|
|
36737
|
+
error: result.error.message
|
|
36738
|
+
});
|
|
36739
|
+
return null;
|
|
36740
|
+
}
|
|
36741
|
+
const state = result.data;
|
|
36742
|
+
if (state.expiresAt && Date.now() > state.expiresAt) {
|
|
36743
|
+
logger.debug("Mode state expired", {
|
|
36744
|
+
mode: state.mode,
|
|
36745
|
+
expiredAt: new Date(state.expiresAt).toISOString()
|
|
36746
|
+
});
|
|
36747
|
+
return null;
|
|
36748
|
+
}
|
|
36749
|
+
logger.debug("Loaded mode state", {
|
|
36750
|
+
mode: state.mode,
|
|
36751
|
+
setAt: new Date(state.setAt).toISOString()
|
|
36752
|
+
});
|
|
36753
|
+
return state;
|
|
36754
|
+
} catch (error) {
|
|
36755
|
+
logger.error("Failed to load mode state", {
|
|
36756
|
+
error: error instanceof Error ? error.message : String(error)
|
|
36757
|
+
});
|
|
36758
|
+
return null;
|
|
36759
|
+
}
|
|
36760
|
+
}
|
|
36761
|
+
async function saveModeState(mode, options) {
|
|
36762
|
+
try {
|
|
36763
|
+
const statePath = await getStateFilePath();
|
|
36764
|
+
const stateDir = dirname(statePath);
|
|
36765
|
+
if (!existsSync(stateDir)) {
|
|
36766
|
+
mkdirSync(stateDir, { recursive: true });
|
|
36767
|
+
}
|
|
36768
|
+
const state = {
|
|
36769
|
+
mode,
|
|
36770
|
+
setAt: Date.now(),
|
|
36771
|
+
setBy: options?.setBy ?? "cli",
|
|
36772
|
+
reason: options?.reason,
|
|
36773
|
+
expiresAt: Date.now() + (options?.expiresIn ?? DEFAULT_EXPIRATION_MS)
|
|
36774
|
+
};
|
|
36775
|
+
writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
36776
|
+
logger.debug("Saved mode state", {
|
|
36777
|
+
mode,
|
|
36778
|
+
expiresAt: new Date(state.expiresAt).toISOString()
|
|
36779
|
+
});
|
|
36780
|
+
return true;
|
|
36781
|
+
} catch (error) {
|
|
36782
|
+
logger.error("Failed to save mode state", {
|
|
36783
|
+
error: error instanceof Error ? error.message : String(error)
|
|
36784
|
+
});
|
|
36785
|
+
return false;
|
|
36786
|
+
}
|
|
36787
|
+
}
|
|
36788
|
+
async function getCurrentPersistedMode() {
|
|
36789
|
+
const state = await loadModeState();
|
|
36790
|
+
return state?.mode ?? "default";
|
|
36791
|
+
}
|
|
36792
|
+
function isModePersistenceEnabled() {
|
|
36793
|
+
return process.env.AX_DISABLE_MODE_PERSISTENCE !== "true";
|
|
36794
|
+
}
|
|
36795
|
+
|
|
36796
|
+
// src/core/workflow/workflow-progress-provider.ts
|
|
36797
|
+
init_esm_shims();
|
|
36798
|
+
init_logger();
|
|
36799
|
+
|
|
36800
|
+
// src/cli/commands/run.ts
|
|
36205
36801
|
function displayAutoSelectionResult(selection, verbosity, showBanner = true) {
|
|
36206
36802
|
if (!showBanner || !verbosity.shouldShow("showBanner")) return;
|
|
36207
36803
|
const confidenceEmoji = selection.confidence === "high" ? "\u2705" : selection.confidence === "medium" ? "\u26A1" : "\u{1F4A1}";
|
|
@@ -36225,10 +36821,10 @@ var runCommand = {
|
|
|
36225
36821
|
}).positional("task", {
|
|
36226
36822
|
describe: "Task to execute",
|
|
36227
36823
|
type: "string"
|
|
36228
|
-
}).option("
|
|
36229
|
-
describe: "
|
|
36824
|
+
}).option("auto-select", {
|
|
36825
|
+
describe: "Enable agent auto-selection when agent not found (v11.1.0+)",
|
|
36230
36826
|
type: "boolean",
|
|
36231
|
-
default:
|
|
36827
|
+
default: true
|
|
36232
36828
|
}).option("provider", {
|
|
36233
36829
|
describe: "Override provider (claude, gemini, openai)",
|
|
36234
36830
|
type: "string"
|
|
@@ -36301,10 +36897,6 @@ var runCommand = {
|
|
|
36301
36897
|
describe: "Show execution timeline after completion (requires --parallel)",
|
|
36302
36898
|
type: "boolean",
|
|
36303
36899
|
default: true
|
|
36304
|
-
}).option("no-spec", {
|
|
36305
|
-
describe: "Bypass spec-kit suggestion for complex tasks (v5.8.3+)",
|
|
36306
|
-
type: "boolean",
|
|
36307
|
-
default: false
|
|
36308
36900
|
}).option("sandbox", {
|
|
36309
36901
|
describe: "Sandbox mode for code execution (v6.0.7 Phase 3)",
|
|
36310
36902
|
type: "string",
|
|
@@ -36370,7 +36962,7 @@ var runCommand = {
|
|
|
36370
36962
|
console.log(chalk5.gray(' ax run backend "implement API" # uses specified agent'));
|
|
36371
36963
|
process.exit(1);
|
|
36372
36964
|
}
|
|
36373
|
-
if (!agentProvided && argv.
|
|
36965
|
+
if (!agentProvided && argv.autoSelect === false) {
|
|
36374
36966
|
console.log(chalk5.red.bold("\n\u274C Error: Agent name is required when --no-auto-select is used\n"));
|
|
36375
36967
|
console.log(chalk5.gray("Usage: ax run <agent> <task> --no-auto-select"));
|
|
36376
36968
|
process.exit(1);
|
|
@@ -36436,6 +37028,32 @@ var runCommand = {
|
|
|
36436
37028
|
process.exit(1);
|
|
36437
37029
|
}
|
|
36438
37030
|
}
|
|
37031
|
+
if (!argv.workflow && !argv.iterate && isModePersistenceEnabled()) {
|
|
37032
|
+
const persistedMode = await getCurrentPersistedMode();
|
|
37033
|
+
if (persistedMode === "iterate") {
|
|
37034
|
+
argv.iterate = true;
|
|
37035
|
+
if (verbosity.shouldShow("showBanner")) {
|
|
37036
|
+
console.log(chalk5.cyan(`\u{1F4CB} Using persisted mode: iterate`));
|
|
37037
|
+
console.log(chalk5.gray(` (set via \`ax mode iterate\`, use \`ax mode default\` to clear)
|
|
37038
|
+
`));
|
|
37039
|
+
}
|
|
37040
|
+
logger.info("Applied persisted iterate mode");
|
|
37041
|
+
} else if (persistedMode === "plan") {
|
|
37042
|
+
if (verbosity.shouldShow("showBanner")) {
|
|
37043
|
+
console.log(chalk5.cyan(`\u{1F4CB} Using persisted mode: plan`));
|
|
37044
|
+
console.log(chalk5.gray(` (read-only exploration mode)
|
|
37045
|
+
`));
|
|
37046
|
+
}
|
|
37047
|
+
logger.info("Applied persisted plan mode");
|
|
37048
|
+
} else if (persistedMode === "review") {
|
|
37049
|
+
if (verbosity.shouldShow("showBanner")) {
|
|
37050
|
+
console.log(chalk5.cyan(`\u{1F4CB} Using persisted mode: review`));
|
|
37051
|
+
console.log(chalk5.gray(` (code review mode)
|
|
37052
|
+
`));
|
|
37053
|
+
}
|
|
37054
|
+
logger.info("Applied persisted review mode");
|
|
37055
|
+
}
|
|
37056
|
+
}
|
|
36439
37057
|
if (verbosity.isQuiet()) {
|
|
36440
37058
|
argv.showDependencyGraph = false;
|
|
36441
37059
|
argv.showTimeline = false;
|
|
@@ -36505,7 +37123,7 @@ var runCommand = {
|
|
|
36505
37123
|
}
|
|
36506
37124
|
}
|
|
36507
37125
|
} catch (error) {
|
|
36508
|
-
if (argv.
|
|
37126
|
+
if (argv.autoSelect === false) {
|
|
36509
37127
|
console.error(chalk5.red.bold(`
|
|
36510
37128
|
\u274C Agent not found: ${actualAgent}
|
|
36511
37129
|
`));
|
|
@@ -38052,11 +38670,11 @@ async function getCurrentVersion() {
|
|
|
38052
38670
|
return result.dependencies["@defai.digital/automatosx"]?.version || "unknown";
|
|
38053
38671
|
} catch (error) {
|
|
38054
38672
|
const { readFile: readFile24 } = await import('fs/promises');
|
|
38055
|
-
const { dirname:
|
|
38673
|
+
const { dirname: dirname15, join: join50 } = await import('path');
|
|
38056
38674
|
const { fileURLToPath: fileURLToPath5 } = await import('url');
|
|
38057
38675
|
const __filename3 = fileURLToPath5(import.meta.url);
|
|
38058
|
-
const __dirname4 =
|
|
38059
|
-
const pkgPath =
|
|
38676
|
+
const __dirname4 = dirname15(__filename3);
|
|
38677
|
+
const pkgPath = join50(__dirname4, "../../../package.json");
|
|
38060
38678
|
const content = await readFile24(pkgPath, "utf-8");
|
|
38061
38679
|
const pkg = JSON.parse(content);
|
|
38062
38680
|
return pkg.version;
|
|
@@ -44867,24 +45485,24 @@ async function handleList(config, argv) {
|
|
|
44867
45485
|
});
|
|
44868
45486
|
}
|
|
44869
45487
|
}
|
|
44870
|
-
let
|
|
45488
|
+
let displayProviders2 = argv.available ? providers.filter((p) => p.enabled && !p.limitInfo?.isBlocked) : providers;
|
|
44871
45489
|
switch (argv.sort) {
|
|
44872
45490
|
case "cost":
|
|
44873
|
-
|
|
45491
|
+
displayProviders2.sort((a, b) => {
|
|
44874
45492
|
const costA = a.metadata ? (a.metadata.costPerToken.input + a.metadata.costPerToken.output) / 2 : Infinity;
|
|
44875
45493
|
const costB = b.metadata ? (b.metadata.costPerToken.input + b.metadata.costPerToken.output) / 2 : Infinity;
|
|
44876
45494
|
return costA - costB;
|
|
44877
45495
|
});
|
|
44878
45496
|
break;
|
|
44879
45497
|
case "latency":
|
|
44880
|
-
|
|
45498
|
+
displayProviders2.sort((a, b) => {
|
|
44881
45499
|
const latA = a.metadata?.latencyEstimate.p95 || Infinity;
|
|
44882
45500
|
const latB = b.metadata?.latencyEstimate.p95 || Infinity;
|
|
44883
45501
|
return latA - latB;
|
|
44884
45502
|
});
|
|
44885
45503
|
break;
|
|
44886
45504
|
case "reliability":
|
|
44887
|
-
|
|
45505
|
+
displayProviders2.sort((a, b) => {
|
|
44888
45506
|
const relA = a.metadata?.reliability.availability || 0;
|
|
44889
45507
|
const relB = b.metadata?.reliability.availability || 0;
|
|
44890
45508
|
return relB - relA;
|
|
@@ -44892,15 +45510,15 @@ async function handleList(config, argv) {
|
|
|
44892
45510
|
break;
|
|
44893
45511
|
case "priority":
|
|
44894
45512
|
default:
|
|
44895
|
-
|
|
45513
|
+
displayProviders2.sort((a, b) => a.priority - b.priority);
|
|
44896
45514
|
break;
|
|
44897
45515
|
}
|
|
44898
45516
|
if (argv.json) {
|
|
44899
|
-
console.log(JSON.stringify({ providers:
|
|
45517
|
+
console.log(JSON.stringify({ providers: displayProviders2 }, null, 2));
|
|
44900
45518
|
return;
|
|
44901
45519
|
}
|
|
44902
45520
|
console.log(chalk5.gray("Provider Status & Metadata:\n"));
|
|
44903
|
-
for (const provider of
|
|
45521
|
+
for (const provider of displayProviders2) {
|
|
44904
45522
|
const status = provider.enabled ? provider.limitInfo?.isBlocked ? chalk5.red("\u25CF BLOCKED") : chalk5.green("\u25CF ENABLED") : chalk5.gray("\u25CB DISABLED");
|
|
44905
45523
|
console.log(`${status} ${chalk5.bold(provider.name)} ${chalk5.gray(`(priority: ${provider.priority})`)}`);
|
|
44906
45524
|
if (provider.metadata && argv.verbose) {
|
|
@@ -45088,10 +45706,10 @@ async function handleReset() {
|
|
|
45088
45706
|
`));
|
|
45089
45707
|
}
|
|
45090
45708
|
async function handleTrace(workspacePath, argv) {
|
|
45091
|
-
const { existsSync:
|
|
45092
|
-
const { join:
|
|
45093
|
-
const traceFile =
|
|
45094
|
-
if (!
|
|
45709
|
+
const { existsSync: existsSync26, readFileSync: readFileSync9, watchFile } = await import('fs');
|
|
45710
|
+
const { join: join50 } = await import('path');
|
|
45711
|
+
const traceFile = join50(workspacePath, ".automatosx/logs/router.trace.jsonl");
|
|
45712
|
+
if (!existsSync26(traceFile)) {
|
|
45095
45713
|
console.log(chalk5.yellow("\n\u26A0\uFE0F No trace log found\n"));
|
|
45096
45714
|
console.log(chalk5.gray(`Expected location: ${traceFile}
|
|
45097
45715
|
`));
|
|
@@ -45108,7 +45726,7 @@ async function handleTrace(workspacePath, argv) {
|
|
|
45108
45726
|
`));
|
|
45109
45727
|
if (argv.follow) {
|
|
45110
45728
|
console.log(chalk5.gray("Following trace log (Ctrl+C to exit)...\n"));
|
|
45111
|
-
const content =
|
|
45729
|
+
const content = readFileSync9(traceFile, "utf-8");
|
|
45112
45730
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
45113
45731
|
const recentLines = lines.slice(-(argv.lines || 20));
|
|
45114
45732
|
for (const line of recentLines) {
|
|
@@ -45118,7 +45736,7 @@ async function handleTrace(workspacePath, argv) {
|
|
|
45118
45736
|
const { unwatchFile } = await import('fs');
|
|
45119
45737
|
watchFile(traceFile, { interval: 500 }, (curr, prev) => {
|
|
45120
45738
|
if (curr.size > lastSize) {
|
|
45121
|
-
const newContent =
|
|
45739
|
+
const newContent = readFileSync9(traceFile, "utf-8");
|
|
45122
45740
|
const newLines = newContent.slice(lastSize).split("\n").filter((l) => l.trim());
|
|
45123
45741
|
for (const line of newLines) {
|
|
45124
45742
|
displayTraceEvent(line);
|
|
@@ -45136,7 +45754,7 @@ async function handleTrace(workspacePath, argv) {
|
|
|
45136
45754
|
await new Promise(() => {
|
|
45137
45755
|
});
|
|
45138
45756
|
} else {
|
|
45139
|
-
const content =
|
|
45757
|
+
const content = readFileSync9(traceFile, "utf-8");
|
|
45140
45758
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
45141
45759
|
const recentLines = lines.slice(-(argv.lines || 20));
|
|
45142
45760
|
if (recentLines.length === 0) {
|
|
@@ -46147,9 +46765,11 @@ async function checkDiskSpace(workingDir, verbose) {
|
|
|
46147
46765
|
timeout: 5e3
|
|
46148
46766
|
});
|
|
46149
46767
|
const parts = dfOutput.trim().split(/\s+/);
|
|
46150
|
-
const
|
|
46151
|
-
const
|
|
46152
|
-
const
|
|
46768
|
+
const rawAvailable = parts.length > 3 ? parts[3] : "0";
|
|
46769
|
+
const availableKB = parseInt(rawAvailable || "0", 10);
|
|
46770
|
+
const safeAvailableKB = isNaN(availableKB) ? 0 : availableKB;
|
|
46771
|
+
const availableMB = Math.round(safeAvailableKB / 1024);
|
|
46772
|
+
const availableGB = (safeAvailableKB / (1024 * 1024)).toFixed(2);
|
|
46153
46773
|
const hasEnoughSpace = availableMB > 100;
|
|
46154
46774
|
results.push({
|
|
46155
46775
|
name: "Available Disk Space",
|
|
@@ -47294,10 +47914,14 @@ var OptimizationAnalyzer = class {
|
|
|
47294
47914
|
* Analyze usage and generate recommendations
|
|
47295
47915
|
*/
|
|
47296
47916
|
async analyze(timeRange) {
|
|
47297
|
-
logger.debug("Analyzing for optimization opportunities", {
|
|
47917
|
+
logger.debug("Analyzing for optimization opportunities", {
|
|
47918
|
+
timeRange,
|
|
47919
|
+
provider: timeRange.provider
|
|
47920
|
+
});
|
|
47298
47921
|
const summary = await this.analytics.generateSummary({
|
|
47299
47922
|
startDate: timeRange.start,
|
|
47300
|
-
endDate: timeRange.end
|
|
47923
|
+
endDate: timeRange.end,
|
|
47924
|
+
provider: timeRange.provider
|
|
47301
47925
|
});
|
|
47302
47926
|
const recommendations = [];
|
|
47303
47927
|
recommendations.push(...this.findModelDowngradeOpportunities(summary));
|
|
@@ -47384,6 +48008,7 @@ var OptimizationAnalyzer = class {
|
|
|
47384
48008
|
type: "cache_hit",
|
|
47385
48009
|
startDate: timeRange.start,
|
|
47386
48010
|
endDate: timeRange.end,
|
|
48011
|
+
provider: timeRange.provider,
|
|
47387
48012
|
limit: 1e4
|
|
47388
48013
|
});
|
|
47389
48014
|
const totalExecutions = summary.executions.total;
|
|
@@ -47526,10 +48151,11 @@ var analyticsCommand = {
|
|
|
47526
48151
|
}
|
|
47527
48152
|
};
|
|
47528
48153
|
async function summaryHandler(argv) {
|
|
48154
|
+
let telemetry;
|
|
47529
48155
|
try {
|
|
47530
48156
|
const config = await loadConfig(process.cwd());
|
|
47531
48157
|
const telemetryConfig = config.telemetry || { enabled: false };
|
|
47532
|
-
|
|
48158
|
+
telemetry = getTelemetryCollector({
|
|
47533
48159
|
...telemetryConfig,
|
|
47534
48160
|
enabled: true
|
|
47535
48161
|
});
|
|
@@ -47537,15 +48163,19 @@ async function summaryHandler(argv) {
|
|
|
47537
48163
|
const timeRange = parseTimePeriod(argv.period || "7d");
|
|
47538
48164
|
const summary = await analytics.generateSummary({
|
|
47539
48165
|
startDate: timeRange.startDate,
|
|
47540
|
-
endDate: timeRange.endDate
|
|
48166
|
+
endDate: timeRange.endDate,
|
|
48167
|
+
provider: argv.provider
|
|
47541
48168
|
});
|
|
47542
48169
|
if (argv.format === "json") {
|
|
47543
48170
|
console.log(JSON.stringify(summary, null, 2));
|
|
47544
48171
|
return;
|
|
47545
48172
|
}
|
|
47546
48173
|
console.log(chalk5.bold.cyan("\n\u{1F4CA} AutomatosX Analytics Summary\n"));
|
|
47547
|
-
console.log(chalk5.dim(`Period: ${formatPeriod(argv.period || "7d")}
|
|
47548
|
-
|
|
48174
|
+
console.log(chalk5.dim(`Period: ${formatPeriod(argv.period || "7d")}`));
|
|
48175
|
+
if (argv.provider) {
|
|
48176
|
+
console.log(chalk5.dim(`Provider filter: ${argv.provider}`));
|
|
48177
|
+
}
|
|
48178
|
+
console.log();
|
|
47549
48179
|
console.log(chalk5.bold("Executions"));
|
|
47550
48180
|
console.log(` Total: ${summary.executions.total}`);
|
|
47551
48181
|
console.log(` Successful: ${chalk5.green(summary.executions.successful)}`);
|
|
@@ -47589,13 +48219,16 @@ async function summaryHandler(argv) {
|
|
|
47589
48219
|
});
|
|
47590
48220
|
logger.error("Analytics summary failed", { error: error.message });
|
|
47591
48221
|
process.exit(1);
|
|
48222
|
+
} finally {
|
|
48223
|
+
await telemetry?.close();
|
|
47592
48224
|
}
|
|
47593
48225
|
}
|
|
47594
48226
|
async function optimizeHandler(argv) {
|
|
48227
|
+
let telemetry;
|
|
47595
48228
|
try {
|
|
47596
48229
|
const config = await loadConfig(process.cwd());
|
|
47597
48230
|
const telemetryConfig = config.telemetry || { enabled: false };
|
|
47598
|
-
|
|
48231
|
+
telemetry = getTelemetryCollector({
|
|
47599
48232
|
...telemetryConfig,
|
|
47600
48233
|
enabled: true
|
|
47601
48234
|
});
|
|
@@ -47604,15 +48237,19 @@ async function optimizeHandler(argv) {
|
|
|
47604
48237
|
const timeRange = parseTimePeriod(argv.period || "7d");
|
|
47605
48238
|
const recommendations = await optimizer.analyze({
|
|
47606
48239
|
start: timeRange.startDate,
|
|
47607
|
-
end: timeRange.endDate
|
|
48240
|
+
end: timeRange.endDate,
|
|
48241
|
+
provider: argv.provider
|
|
47608
48242
|
});
|
|
47609
48243
|
if (argv.format === "json") {
|
|
47610
48244
|
console.log(JSON.stringify(recommendations, null, 2));
|
|
47611
48245
|
return;
|
|
47612
48246
|
}
|
|
47613
48247
|
console.log(chalk5.bold.cyan("\n\u{1F4A1} Optimization Recommendations\n"));
|
|
47614
|
-
console.log(chalk5.dim(`Period: ${formatPeriod(argv.period || "7d")}
|
|
47615
|
-
|
|
48248
|
+
console.log(chalk5.dim(`Period: ${formatPeriod(argv.period || "7d")}`));
|
|
48249
|
+
if (argv.provider) {
|
|
48250
|
+
console.log(chalk5.dim(`Provider filter: ${argv.provider}`));
|
|
48251
|
+
}
|
|
48252
|
+
console.log();
|
|
47616
48253
|
if (recommendations.length === 0) {
|
|
47617
48254
|
console.log(chalk5.green("\u2705 No optimization opportunities found. You're doing great!\n"));
|
|
47618
48255
|
return;
|
|
@@ -47645,13 +48282,16 @@ async function optimizeHandler(argv) {
|
|
|
47645
48282
|
});
|
|
47646
48283
|
logger.error("Optimization analysis failed", { error: error.message });
|
|
47647
48284
|
process.exit(1);
|
|
48285
|
+
} finally {
|
|
48286
|
+
await telemetry?.close();
|
|
47648
48287
|
}
|
|
47649
48288
|
}
|
|
47650
48289
|
async function clearHandler(argv) {
|
|
48290
|
+
let telemetry;
|
|
47651
48291
|
try {
|
|
47652
48292
|
const config = await loadConfig(process.cwd());
|
|
47653
48293
|
const telemetryConfig = config.telemetry || { enabled: false };
|
|
47654
|
-
|
|
48294
|
+
telemetry = getTelemetryCollector({
|
|
47655
48295
|
...telemetryConfig,
|
|
47656
48296
|
enabled: true
|
|
47657
48297
|
});
|
|
@@ -47678,13 +48318,16 @@ async function clearHandler(argv) {
|
|
|
47678
48318
|
});
|
|
47679
48319
|
logger.error("Clear telemetry failed", { error: error.message });
|
|
47680
48320
|
process.exit(1);
|
|
48321
|
+
} finally {
|
|
48322
|
+
await telemetry?.close();
|
|
47681
48323
|
}
|
|
47682
48324
|
}
|
|
47683
48325
|
async function statusHandler(argv) {
|
|
48326
|
+
let telemetry;
|
|
47684
48327
|
try {
|
|
47685
48328
|
const config = await loadConfig(process.cwd());
|
|
47686
48329
|
const telemetryConfig = config.telemetry || { enabled: false };
|
|
47687
|
-
|
|
48330
|
+
telemetry = getTelemetryCollector({
|
|
47688
48331
|
...telemetryConfig,
|
|
47689
48332
|
enabled: true
|
|
47690
48333
|
});
|
|
@@ -47711,6 +48354,8 @@ async function statusHandler(argv) {
|
|
|
47711
48354
|
});
|
|
47712
48355
|
logger.error("Telemetry status failed", { error: error.message });
|
|
47713
48356
|
process.exit(1);
|
|
48357
|
+
} finally {
|
|
48358
|
+
await telemetry?.close();
|
|
47714
48359
|
}
|
|
47715
48360
|
}
|
|
47716
48361
|
function parseTimePeriod(period) {
|
|
@@ -48519,6 +49164,2782 @@ var uninstallCommand = {
|
|
|
48519
49164
|
}
|
|
48520
49165
|
};
|
|
48521
49166
|
|
|
49167
|
+
// src/cli/commands/mode.ts
|
|
49168
|
+
init_esm_shims();
|
|
49169
|
+
init_logger();
|
|
49170
|
+
var modeCommand = {
|
|
49171
|
+
command: "mode [mode]",
|
|
49172
|
+
describe: "Manage workflow modes for embedded instructions (v11.3.0)",
|
|
49173
|
+
builder: (yargs2) => {
|
|
49174
|
+
return yargs2.positional("mode", {
|
|
49175
|
+
describe: "Workflow mode to set (default, plan, iterate, review)",
|
|
49176
|
+
type: "string"
|
|
49177
|
+
}).option("list", {
|
|
49178
|
+
alias: "l",
|
|
49179
|
+
describe: "List available workflow modes",
|
|
49180
|
+
type: "boolean",
|
|
49181
|
+
default: false
|
|
49182
|
+
}).option("status", {
|
|
49183
|
+
alias: "s",
|
|
49184
|
+
describe: "Show current workflow mode status",
|
|
49185
|
+
type: "boolean",
|
|
49186
|
+
default: false
|
|
49187
|
+
}).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");
|
|
49188
|
+
},
|
|
49189
|
+
handler: async (argv) => {
|
|
49190
|
+
try {
|
|
49191
|
+
if (argv.list) {
|
|
49192
|
+
displayModeList();
|
|
49193
|
+
return;
|
|
49194
|
+
}
|
|
49195
|
+
if (argv.status || !argv.mode) {
|
|
49196
|
+
await displayModeStatus();
|
|
49197
|
+
return;
|
|
49198
|
+
}
|
|
49199
|
+
const modeName = argv.mode.toLowerCase();
|
|
49200
|
+
if (!isValidWorkflowMode(modeName)) {
|
|
49201
|
+
console.error(chalk5.red.bold(`
|
|
49202
|
+
\u274C Invalid workflow mode: ${argv.mode}
|
|
49203
|
+
`));
|
|
49204
|
+
console.log(chalk5.gray("Available modes:"));
|
|
49205
|
+
Object.keys(WORKFLOW_MODES).forEach((mode) => {
|
|
49206
|
+
console.log(chalk5.cyan(` \u2022 ${mode}`));
|
|
49207
|
+
});
|
|
49208
|
+
console.log();
|
|
49209
|
+
process.exit(1);
|
|
49210
|
+
}
|
|
49211
|
+
const modeConfig = WORKFLOW_MODES[modeName];
|
|
49212
|
+
if (isModePersistenceEnabled()) {
|
|
49213
|
+
const saved = await saveModeState(modeName, {
|
|
49214
|
+
setBy: "cli",
|
|
49215
|
+
reason: `ax mode ${modeName}`
|
|
49216
|
+
});
|
|
49217
|
+
if (saved) {
|
|
49218
|
+
console.log(chalk5.green.bold(`
|
|
49219
|
+
\u2705 Workflow mode set to: ${modeName}
|
|
49220
|
+
`));
|
|
49221
|
+
console.log(chalk5.gray(`Description: ${modeConfig.description}`));
|
|
49222
|
+
} else {
|
|
49223
|
+
console.log(chalk5.yellow.bold(`
|
|
49224
|
+
\u26A0\uFE0F Mode set to: ${modeName} (not persisted)
|
|
49225
|
+
`));
|
|
49226
|
+
console.log(chalk5.gray(`Description: ${modeConfig.description}`));
|
|
49227
|
+
}
|
|
49228
|
+
} else {
|
|
49229
|
+
console.log(chalk5.green.bold(`
|
|
49230
|
+
\u2705 Workflow mode set to: ${modeName}
|
|
49231
|
+
`));
|
|
49232
|
+
console.log(chalk5.gray(`Description: ${modeConfig.description}`));
|
|
49233
|
+
console.log(chalk5.gray("(Mode persistence disabled via AX_DISABLE_MODE_PERSISTENCE)"));
|
|
49234
|
+
}
|
|
49235
|
+
if (modeConfig.blockedTools && modeConfig.blockedTools.length > 0) {
|
|
49236
|
+
console.log(chalk5.yellow("\nRestricted tools in this mode:"));
|
|
49237
|
+
modeConfig.blockedTools.forEach((tool) => {
|
|
49238
|
+
console.log(chalk5.yellow(` \u2022 ${tool}`));
|
|
49239
|
+
});
|
|
49240
|
+
}
|
|
49241
|
+
if (modeConfig.allowedTools && modeConfig.allowedTools.length > 0) {
|
|
49242
|
+
console.log(chalk5.cyan("\nAllowed tools in this mode:"));
|
|
49243
|
+
modeConfig.allowedTools.forEach((tool) => {
|
|
49244
|
+
console.log(chalk5.cyan(` \u2022 ${tool}`));
|
|
49245
|
+
});
|
|
49246
|
+
}
|
|
49247
|
+
console.log();
|
|
49248
|
+
if (modeName === "iterate") {
|
|
49249
|
+
console.log(chalk5.cyan('\u{1F4A1} Tip: Use `ax run <agent> "task"` and it will auto-use iterate mode'));
|
|
49250
|
+
} else if (modeName === "plan") {
|
|
49251
|
+
console.log(chalk5.cyan('\u{1F4A1} Tip: Use `ax run <agent> "task"` and it will auto-use plan mode'));
|
|
49252
|
+
console.log(chalk5.gray(" The mode will persist until you run `ax mode default`"));
|
|
49253
|
+
}
|
|
49254
|
+
console.log();
|
|
49255
|
+
logger.info("Workflow mode set", { mode: modeName, persisted: isModePersistenceEnabled() });
|
|
49256
|
+
} catch (error) {
|
|
49257
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
49258
|
+
console.error(chalk5.red.bold(`
|
|
49259
|
+
\u274C Error: ${err.message}
|
|
49260
|
+
`));
|
|
49261
|
+
logger.error("Mode command failed", { error: err.message });
|
|
49262
|
+
process.exit(1);
|
|
49263
|
+
}
|
|
49264
|
+
}
|
|
49265
|
+
};
|
|
49266
|
+
function displayModeList() {
|
|
49267
|
+
console.log(chalk5.blue.bold("\n\u{1F4CB} Available Workflow Modes\n"));
|
|
49268
|
+
console.log(chalk5.dim("\u2500".repeat(60)));
|
|
49269
|
+
for (const [name, config] of Object.entries(WORKFLOW_MODES)) {
|
|
49270
|
+
console.log();
|
|
49271
|
+
console.log(chalk5.cyan.bold(` ${name}`));
|
|
49272
|
+
console.log(chalk5.gray(` ${config.description}`));
|
|
49273
|
+
if (config.blockedTools && config.blockedTools.length > 0) {
|
|
49274
|
+
console.log(chalk5.yellow(` Blocked: ${config.blockedTools.join(", ")}`));
|
|
49275
|
+
}
|
|
49276
|
+
if (config.maxNestingDepth !== void 0) {
|
|
49277
|
+
console.log(chalk5.gray(` Max nesting depth: ${config.maxNestingDepth}`));
|
|
49278
|
+
}
|
|
49279
|
+
}
|
|
49280
|
+
console.log();
|
|
49281
|
+
console.log(chalk5.dim("\u2500".repeat(60)));
|
|
49282
|
+
console.log(chalk5.gray("\nUsage: ax mode <mode-name>"));
|
|
49283
|
+
console.log(chalk5.gray("Example: ax mode plan\n"));
|
|
49284
|
+
}
|
|
49285
|
+
async function displayModeStatus() {
|
|
49286
|
+
const modeState = await loadModeState();
|
|
49287
|
+
const currentMode = modeState?.mode ?? "default";
|
|
49288
|
+
const modeConfig = WORKFLOW_MODES[currentMode];
|
|
49289
|
+
console.log(chalk5.blue.bold("\n\u{1F4CA} Workflow Mode Status\n"));
|
|
49290
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
49291
|
+
console.log(` Current mode: ${chalk5.cyan.bold(currentMode)}`);
|
|
49292
|
+
console.log(` Description: ${chalk5.gray(modeConfig.description)}`);
|
|
49293
|
+
if (modeState) {
|
|
49294
|
+
const setAt = new Date(modeState.setAt);
|
|
49295
|
+
const expiresAt = modeState.expiresAt ? new Date(modeState.expiresAt) : null;
|
|
49296
|
+
console.log(` Set at: ${chalk5.gray(setAt.toLocaleString())}`);
|
|
49297
|
+
if (expiresAt) {
|
|
49298
|
+
const remainingMs = expiresAt.getTime() - Date.now();
|
|
49299
|
+
const remainingMins = Math.round(remainingMs / 6e4);
|
|
49300
|
+
if (remainingMs > 0) {
|
|
49301
|
+
console.log(` Expires in: ${chalk5.gray(`${remainingMins} minutes`)}`);
|
|
49302
|
+
} else {
|
|
49303
|
+
console.log(` Status: ${chalk5.yellow("expired (will use default)")}`);
|
|
49304
|
+
}
|
|
49305
|
+
}
|
|
49306
|
+
}
|
|
49307
|
+
if (modeConfig.blockedTools && modeConfig.blockedTools.length > 0) {
|
|
49308
|
+
console.log(` Blocked tools: ${chalk5.yellow(modeConfig.blockedTools.join(", "))}`);
|
|
49309
|
+
} else {
|
|
49310
|
+
console.log(` Blocked tools: ${chalk5.green("none")}`);
|
|
49311
|
+
}
|
|
49312
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
49313
|
+
console.log();
|
|
49314
|
+
console.log(chalk5.gray("To change mode: ax mode <mode-name>"));
|
|
49315
|
+
console.log(chalk5.gray("To list modes: ax mode --list\n"));
|
|
49316
|
+
}
|
|
49317
|
+
|
|
49318
|
+
// src/cli/commands/debug-instructions.ts
|
|
49319
|
+
init_esm_shims();
|
|
49320
|
+
init_logger();
|
|
49321
|
+
|
|
49322
|
+
// src/core/orchestration/orchestration-service.ts
|
|
49323
|
+
init_esm_shims();
|
|
49324
|
+
init_logger();
|
|
49325
|
+
|
|
49326
|
+
// src/core/orchestration/instruction-injector.ts
|
|
49327
|
+
init_esm_shims();
|
|
49328
|
+
init_logger();
|
|
49329
|
+
|
|
49330
|
+
// src/core/orchestration/token-budget.ts
|
|
49331
|
+
init_esm_shims();
|
|
49332
|
+
init_logger();
|
|
49333
|
+
var PRIORITY_ORDER = {
|
|
49334
|
+
critical: 0,
|
|
49335
|
+
high: 1,
|
|
49336
|
+
normal: 2,
|
|
49337
|
+
low: 3
|
|
49338
|
+
};
|
|
49339
|
+
function createEmptyTypeUsage() {
|
|
49340
|
+
return {
|
|
49341
|
+
task: 0,
|
|
49342
|
+
memory: 0,
|
|
49343
|
+
session: 0,
|
|
49344
|
+
delegation: 0,
|
|
49345
|
+
mode: 0,
|
|
49346
|
+
context: 0
|
|
49347
|
+
};
|
|
49348
|
+
}
|
|
49349
|
+
var TokenBudgetManager = class _TokenBudgetManager {
|
|
49350
|
+
config;
|
|
49351
|
+
/** Characters per token estimate (conservative) */
|
|
49352
|
+
static CHARS_PER_TOKEN = 4;
|
|
49353
|
+
/** Overhead tokens for system-reminder XML tags and formatting */
|
|
49354
|
+
static FORMATTING_OVERHEAD_TOKENS = 50;
|
|
49355
|
+
constructor(config) {
|
|
49356
|
+
this.config = {
|
|
49357
|
+
...DEFAULT_TOKEN_BUDGET,
|
|
49358
|
+
...config,
|
|
49359
|
+
perType: {
|
|
49360
|
+
...DEFAULT_TOKEN_BUDGET.perType,
|
|
49361
|
+
...config?.perType
|
|
49362
|
+
}
|
|
49363
|
+
};
|
|
49364
|
+
logger.debug("TokenBudgetManager initialized", {
|
|
49365
|
+
maxTotal: this.config.maxTotal,
|
|
49366
|
+
criticalReserve: this.config.criticalReserve
|
|
49367
|
+
});
|
|
49368
|
+
}
|
|
49369
|
+
/**
|
|
49370
|
+
* Estimate tokens for a string
|
|
49371
|
+
*/
|
|
49372
|
+
estimateTokens(content) {
|
|
49373
|
+
const characters = content.length;
|
|
49374
|
+
const tokens = Math.ceil(characters / _TokenBudgetManager.CHARS_PER_TOKEN);
|
|
49375
|
+
return {
|
|
49376
|
+
tokens,
|
|
49377
|
+
characters,
|
|
49378
|
+
isEstimate: true
|
|
49379
|
+
};
|
|
49380
|
+
}
|
|
49381
|
+
/**
|
|
49382
|
+
* Estimate tokens for an instruction (including formatting overhead)
|
|
49383
|
+
*/
|
|
49384
|
+
estimateInstructionTokens(instruction) {
|
|
49385
|
+
const contentTokens = this.estimateTokens(instruction.content).tokens;
|
|
49386
|
+
return contentTokens + _TokenBudgetManager.FORMATTING_OVERHEAD_TOKENS;
|
|
49387
|
+
}
|
|
49388
|
+
/**
|
|
49389
|
+
* Allocate budget for instructions
|
|
49390
|
+
*
|
|
49391
|
+
* Priority order:
|
|
49392
|
+
* 1. Critical instructions (always included, use reserve)
|
|
49393
|
+
* 2. High priority (included if budget allows)
|
|
49394
|
+
* 3. Normal priority (included if budget allows)
|
|
49395
|
+
* 4. Low priority (only if significant budget remains)
|
|
49396
|
+
*/
|
|
49397
|
+
allocateBudget(instructions) {
|
|
49398
|
+
const included = [];
|
|
49399
|
+
const excluded = [];
|
|
49400
|
+
const perTypeUsage = createEmptyTypeUsage();
|
|
49401
|
+
let tokensUsed = 0;
|
|
49402
|
+
const availableBudget = this.config.maxTotal;
|
|
49403
|
+
const sorted = [...instructions].sort((a, b) => {
|
|
49404
|
+
const aPriority = PRIORITY_ORDER[a.priority];
|
|
49405
|
+
const bPriority = PRIORITY_ORDER[b.priority];
|
|
49406
|
+
const priorityDiff = aPriority - bPriority;
|
|
49407
|
+
if (priorityDiff !== 0) return priorityDiff;
|
|
49408
|
+
return a.createdAt - b.createdAt;
|
|
49409
|
+
});
|
|
49410
|
+
for (const instruction of sorted) {
|
|
49411
|
+
const instructionTokens = this.estimateInstructionTokens(instruction);
|
|
49412
|
+
const typeLimit = this.config.perType[instruction.type] || 0;
|
|
49413
|
+
const currentTypeUsage = perTypeUsage[instruction.type] || 0;
|
|
49414
|
+
const wouldExceedTotal = tokensUsed + instructionTokens > availableBudget;
|
|
49415
|
+
const wouldExceedTypeLimit = currentTypeUsage + instructionTokens > typeLimit;
|
|
49416
|
+
if (instruction.priority === "critical") {
|
|
49417
|
+
const criticalBudget = availableBudget + this.config.criticalReserve;
|
|
49418
|
+
if (tokensUsed + instructionTokens <= criticalBudget) {
|
|
49419
|
+
included.push(instruction);
|
|
49420
|
+
tokensUsed += instructionTokens;
|
|
49421
|
+
perTypeUsage[instruction.type] = currentTypeUsage + instructionTokens;
|
|
49422
|
+
continue;
|
|
49423
|
+
}
|
|
49424
|
+
}
|
|
49425
|
+
if (!wouldExceedTotal && !wouldExceedTypeLimit) {
|
|
49426
|
+
included.push(instruction);
|
|
49427
|
+
tokensUsed += instructionTokens;
|
|
49428
|
+
perTypeUsage[instruction.type] = currentTypeUsage + instructionTokens;
|
|
49429
|
+
} else {
|
|
49430
|
+
excluded.push(instruction);
|
|
49431
|
+
logger.debug("Instruction excluded from budget", {
|
|
49432
|
+
type: instruction.type,
|
|
49433
|
+
priority: instruction.priority,
|
|
49434
|
+
tokens: instructionTokens,
|
|
49435
|
+
reason: wouldExceedTotal ? "total_limit" : "type_limit"
|
|
49436
|
+
});
|
|
49437
|
+
}
|
|
49438
|
+
}
|
|
49439
|
+
const result = {
|
|
49440
|
+
included,
|
|
49441
|
+
excluded,
|
|
49442
|
+
tokensUsed,
|
|
49443
|
+
remaining: availableBudget - tokensUsed,
|
|
49444
|
+
perTypeUsage
|
|
49445
|
+
};
|
|
49446
|
+
logger.debug("Budget allocation complete", {
|
|
49447
|
+
included: included.length,
|
|
49448
|
+
excluded: excluded.length,
|
|
49449
|
+
tokensUsed,
|
|
49450
|
+
remaining: result.remaining
|
|
49451
|
+
});
|
|
49452
|
+
return result;
|
|
49453
|
+
}
|
|
49454
|
+
/**
|
|
49455
|
+
* Check if an instruction fits within budget
|
|
49456
|
+
*/
|
|
49457
|
+
fitsInBudget(instruction, currentUsage, typeUsage) {
|
|
49458
|
+
const instructionTokens = this.estimateInstructionTokens(instruction);
|
|
49459
|
+
const typeLimit = this.config.perType[instruction.type] || 0;
|
|
49460
|
+
const currentTypeUsage = typeUsage[instruction.type] || 0;
|
|
49461
|
+
if (instruction.priority === "critical") {
|
|
49462
|
+
return currentUsage + instructionTokens <= this.config.maxTotal + this.config.criticalReserve;
|
|
49463
|
+
}
|
|
49464
|
+
return currentUsage + instructionTokens <= this.config.maxTotal && currentTypeUsage + instructionTokens <= typeLimit;
|
|
49465
|
+
}
|
|
49466
|
+
/**
|
|
49467
|
+
* Get current configuration
|
|
49468
|
+
*/
|
|
49469
|
+
getConfig() {
|
|
49470
|
+
return { ...this.config };
|
|
49471
|
+
}
|
|
49472
|
+
/**
|
|
49473
|
+
* Update configuration
|
|
49474
|
+
*/
|
|
49475
|
+
updateConfig(updates) {
|
|
49476
|
+
this.config = {
|
|
49477
|
+
...this.config,
|
|
49478
|
+
...updates,
|
|
49479
|
+
perType: {
|
|
49480
|
+
...this.config.perType,
|
|
49481
|
+
...updates.perType
|
|
49482
|
+
}
|
|
49483
|
+
};
|
|
49484
|
+
logger.debug("TokenBudgetManager config updated", {
|
|
49485
|
+
maxTotal: this.config.maxTotal
|
|
49486
|
+
});
|
|
49487
|
+
}
|
|
49488
|
+
/**
|
|
49489
|
+
* Get remaining budget for a specific type
|
|
49490
|
+
*/
|
|
49491
|
+
getRemainingTypeBudget(type, currentTypeUsage) {
|
|
49492
|
+
const limit = this.config.perType[type] || 0;
|
|
49493
|
+
const used = currentTypeUsage[type] || 0;
|
|
49494
|
+
return Math.max(0, limit - used);
|
|
49495
|
+
}
|
|
49496
|
+
/**
|
|
49497
|
+
* Format budget status for debugging
|
|
49498
|
+
*/
|
|
49499
|
+
formatBudgetStatus(allocation) {
|
|
49500
|
+
const lines = [
|
|
49501
|
+
`Token Budget Status:`,
|
|
49502
|
+
` Total: ${allocation.tokensUsed}/${this.config.maxTotal} (${allocation.remaining} remaining)`,
|
|
49503
|
+
` Per-Type Usage:`
|
|
49504
|
+
];
|
|
49505
|
+
for (const [type, used] of Object.entries(allocation.perTypeUsage)) {
|
|
49506
|
+
const limit = this.config.perType[type] || 0;
|
|
49507
|
+
lines.push(` ${type}: ${used}/${limit}`);
|
|
49508
|
+
}
|
|
49509
|
+
if (allocation.excluded.length > 0) {
|
|
49510
|
+
lines.push(` Excluded: ${allocation.excluded.length} instruction(s)`);
|
|
49511
|
+
}
|
|
49512
|
+
return lines.join("\n");
|
|
49513
|
+
}
|
|
49514
|
+
};
|
|
49515
|
+
|
|
49516
|
+
// src/core/orchestration/instruction-injector.ts
|
|
49517
|
+
var INSTRUCTION_TYPE_ORDER = ["mode", "task", "context", "memory", "session", "delegation"];
|
|
49518
|
+
var OrchestrationInstructionInjector = class {
|
|
49519
|
+
providers = /* @__PURE__ */ new Map();
|
|
49520
|
+
budgetManager;
|
|
49521
|
+
config;
|
|
49522
|
+
lastInjectionTime = 0;
|
|
49523
|
+
constructor(config) {
|
|
49524
|
+
this.config = {
|
|
49525
|
+
...DEFAULT_ORCHESTRATION_CONFIG,
|
|
49526
|
+
...config
|
|
49527
|
+
};
|
|
49528
|
+
this.budgetManager = new TokenBudgetManager(this.config.tokenBudget);
|
|
49529
|
+
logger.debug("OrchestrationInstructionInjector initialized", {
|
|
49530
|
+
enabled: this.config.enabled,
|
|
49531
|
+
providers: this.providers.size
|
|
49532
|
+
});
|
|
49533
|
+
}
|
|
49534
|
+
/**
|
|
49535
|
+
* Register an instruction provider
|
|
49536
|
+
*/
|
|
49537
|
+
registerProvider(provider) {
|
|
49538
|
+
if (this.providers.has(provider.name)) {
|
|
49539
|
+
logger.warn("Provider already registered, replacing", {
|
|
49540
|
+
name: provider.name
|
|
49541
|
+
});
|
|
49542
|
+
}
|
|
49543
|
+
this.providers.set(provider.name, provider);
|
|
49544
|
+
logger.debug("Instruction provider registered", {
|
|
49545
|
+
name: provider.name,
|
|
49546
|
+
totalProviders: this.providers.size
|
|
49547
|
+
});
|
|
49548
|
+
}
|
|
49549
|
+
/**
|
|
49550
|
+
* Unregister an instruction provider
|
|
49551
|
+
*/
|
|
49552
|
+
unregisterProvider(name) {
|
|
49553
|
+
const removed = this.providers.delete(name);
|
|
49554
|
+
if (removed) {
|
|
49555
|
+
logger.debug("Instruction provider unregistered", { name });
|
|
49556
|
+
}
|
|
49557
|
+
return removed;
|
|
49558
|
+
}
|
|
49559
|
+
/**
|
|
49560
|
+
* Get all registered providers
|
|
49561
|
+
*/
|
|
49562
|
+
getProviders() {
|
|
49563
|
+
return Array.from(this.providers.values());
|
|
49564
|
+
}
|
|
49565
|
+
/**
|
|
49566
|
+
* Generate and inject instructions based on context
|
|
49567
|
+
*/
|
|
49568
|
+
async inject(context, options = {}) {
|
|
49569
|
+
if (!this.config.enabled) {
|
|
49570
|
+
return this.emptyResult();
|
|
49571
|
+
}
|
|
49572
|
+
const startTime = Date.now();
|
|
49573
|
+
const allInstructions = [];
|
|
49574
|
+
for (const provider of this.providers.values()) {
|
|
49575
|
+
try {
|
|
49576
|
+
if (!provider.shouldGenerate(context)) {
|
|
49577
|
+
continue;
|
|
49578
|
+
}
|
|
49579
|
+
const instructions = await provider.getInstructions(context);
|
|
49580
|
+
let filtered = instructions;
|
|
49581
|
+
if (options.includeTypes) {
|
|
49582
|
+
filtered = filtered.filter((i) => options.includeTypes.includes(i.type));
|
|
49583
|
+
}
|
|
49584
|
+
if (options.excludeTypes) {
|
|
49585
|
+
filtered = filtered.filter((i) => !options.excludeTypes.includes(i.type));
|
|
49586
|
+
}
|
|
49587
|
+
allInstructions.push(...filtered);
|
|
49588
|
+
} catch (error) {
|
|
49589
|
+
logger.error("Provider failed to generate instructions", {
|
|
49590
|
+
provider: provider.name,
|
|
49591
|
+
error: error instanceof Error ? error.message : String(error)
|
|
49592
|
+
});
|
|
49593
|
+
}
|
|
49594
|
+
}
|
|
49595
|
+
const activeInstructions = this.filterExpiredInstructions(
|
|
49596
|
+
allInstructions,
|
|
49597
|
+
context.turnCount
|
|
49598
|
+
);
|
|
49599
|
+
let allocation;
|
|
49600
|
+
if (options.skipBudget) {
|
|
49601
|
+
allocation = {
|
|
49602
|
+
included: activeInstructions,
|
|
49603
|
+
excluded: [],
|
|
49604
|
+
tokensUsed: activeInstructions.reduce(
|
|
49605
|
+
(sum, i) => sum + this.budgetManager.estimateInstructionTokens(i),
|
|
49606
|
+
0
|
|
49607
|
+
),
|
|
49608
|
+
remaining: 0,
|
|
49609
|
+
perTypeUsage: this.calculateTypeUsage(activeInstructions)
|
|
49610
|
+
};
|
|
49611
|
+
} else {
|
|
49612
|
+
allocation = this.budgetManager.allocateBudget(activeInstructions);
|
|
49613
|
+
}
|
|
49614
|
+
const formattedText = this.formatInstructions(allocation.included);
|
|
49615
|
+
this.lastInjectionTime = Date.now();
|
|
49616
|
+
const duration = Date.now() - startTime;
|
|
49617
|
+
logger.debug("Instruction injection complete", {
|
|
49618
|
+
providers: this.providers.size,
|
|
49619
|
+
instructionsGenerated: allInstructions.length,
|
|
49620
|
+
instructionsIncluded: allocation.included.length,
|
|
49621
|
+
tokensUsed: allocation.tokensUsed,
|
|
49622
|
+
durationMs: duration
|
|
49623
|
+
});
|
|
49624
|
+
return {
|
|
49625
|
+
formattedText,
|
|
49626
|
+
instructions: allocation.included,
|
|
49627
|
+
allocation,
|
|
49628
|
+
hasInstructions: allocation.included.length > 0
|
|
49629
|
+
};
|
|
49630
|
+
}
|
|
49631
|
+
/**
|
|
49632
|
+
* Format instructions as system reminder tags
|
|
49633
|
+
*/
|
|
49634
|
+
formatInstructions(instructions) {
|
|
49635
|
+
if (instructions.length === 0) {
|
|
49636
|
+
return "";
|
|
49637
|
+
}
|
|
49638
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
49639
|
+
for (const instruction of instructions) {
|
|
49640
|
+
const existing = grouped.get(instruction.type) || [];
|
|
49641
|
+
existing.push(instruction);
|
|
49642
|
+
grouped.set(instruction.type, existing);
|
|
49643
|
+
}
|
|
49644
|
+
const parts = [];
|
|
49645
|
+
for (const type of INSTRUCTION_TYPE_ORDER) {
|
|
49646
|
+
const typeInstructions = grouped.get(type);
|
|
49647
|
+
if (!typeInstructions || typeInstructions.length === 0) continue;
|
|
49648
|
+
for (const instruction of typeInstructions) {
|
|
49649
|
+
parts.push(this.formatSingleInstruction(instruction));
|
|
49650
|
+
}
|
|
49651
|
+
}
|
|
49652
|
+
return parts.join("\n");
|
|
49653
|
+
}
|
|
49654
|
+
/**
|
|
49655
|
+
* Format a single instruction as a system reminder
|
|
49656
|
+
*/
|
|
49657
|
+
formatSingleInstruction(instruction) {
|
|
49658
|
+
return `<system-reminder>
|
|
49659
|
+
${instruction.content}
|
|
49660
|
+
</system-reminder>`;
|
|
49661
|
+
}
|
|
49662
|
+
/**
|
|
49663
|
+
* Filter out expired instructions
|
|
49664
|
+
*/
|
|
49665
|
+
filterExpiredInstructions(instructions, currentTurn) {
|
|
49666
|
+
return instructions.filter((instruction) => {
|
|
49667
|
+
if (instruction.expiresAfter === void 0) {
|
|
49668
|
+
return true;
|
|
49669
|
+
}
|
|
49670
|
+
const createdAtTurn = instruction.createdAtTurn ?? currentTurn;
|
|
49671
|
+
const turnsSinceCreation = currentTurn - createdAtTurn;
|
|
49672
|
+
return turnsSinceCreation < instruction.expiresAfter;
|
|
49673
|
+
});
|
|
49674
|
+
}
|
|
49675
|
+
/**
|
|
49676
|
+
* Calculate per-type token usage
|
|
49677
|
+
*/
|
|
49678
|
+
calculateTypeUsage(instructions) {
|
|
49679
|
+
const usage = createEmptyTypeUsage();
|
|
49680
|
+
for (const instruction of instructions) {
|
|
49681
|
+
const tokens = this.budgetManager.estimateInstructionTokens(instruction);
|
|
49682
|
+
usage[instruction.type] += tokens;
|
|
49683
|
+
}
|
|
49684
|
+
return usage;
|
|
49685
|
+
}
|
|
49686
|
+
/**
|
|
49687
|
+
* Create an empty result
|
|
49688
|
+
*/
|
|
49689
|
+
emptyResult() {
|
|
49690
|
+
return {
|
|
49691
|
+
formattedText: "",
|
|
49692
|
+
instructions: [],
|
|
49693
|
+
allocation: {
|
|
49694
|
+
included: [],
|
|
49695
|
+
excluded: [],
|
|
49696
|
+
tokensUsed: 0,
|
|
49697
|
+
remaining: this.budgetManager.getConfig().maxTotal,
|
|
49698
|
+
perTypeUsage: createEmptyTypeUsage()
|
|
49699
|
+
},
|
|
49700
|
+
hasInstructions: false
|
|
49701
|
+
};
|
|
49702
|
+
}
|
|
49703
|
+
/**
|
|
49704
|
+
* Clear instruction cache (placeholder for future caching implementation)
|
|
49705
|
+
*/
|
|
49706
|
+
clearCache() {
|
|
49707
|
+
logger.debug("Instruction cache cleared");
|
|
49708
|
+
}
|
|
49709
|
+
/**
|
|
49710
|
+
* Get current configuration
|
|
49711
|
+
*/
|
|
49712
|
+
getConfig() {
|
|
49713
|
+
return { ...this.config };
|
|
49714
|
+
}
|
|
49715
|
+
/**
|
|
49716
|
+
* Update configuration
|
|
49717
|
+
*/
|
|
49718
|
+
updateConfig(updates) {
|
|
49719
|
+
this.config = {
|
|
49720
|
+
...this.config,
|
|
49721
|
+
...updates
|
|
49722
|
+
};
|
|
49723
|
+
if (updates.tokenBudget) {
|
|
49724
|
+
this.budgetManager.updateConfig(updates.tokenBudget);
|
|
49725
|
+
}
|
|
49726
|
+
logger.debug("OrchestrationInstructionInjector config updated", {
|
|
49727
|
+
enabled: this.config.enabled
|
|
49728
|
+
});
|
|
49729
|
+
}
|
|
49730
|
+
/**
|
|
49731
|
+
* Get budget manager for direct access
|
|
49732
|
+
*/
|
|
49733
|
+
getBudgetManager() {
|
|
49734
|
+
return this.budgetManager;
|
|
49735
|
+
}
|
|
49736
|
+
/**
|
|
49737
|
+
* Check if orchestration is enabled
|
|
49738
|
+
*/
|
|
49739
|
+
isEnabled() {
|
|
49740
|
+
return this.config.enabled;
|
|
49741
|
+
}
|
|
49742
|
+
/**
|
|
49743
|
+
* Enable or disable orchestration
|
|
49744
|
+
*/
|
|
49745
|
+
setEnabled(enabled) {
|
|
49746
|
+
this.config.enabled = enabled;
|
|
49747
|
+
logger.debug("Orchestration enabled state changed", { enabled });
|
|
49748
|
+
}
|
|
49749
|
+
};
|
|
49750
|
+
|
|
49751
|
+
// src/core/orchestration/todo-instruction-provider.ts
|
|
49752
|
+
init_esm_shims();
|
|
49753
|
+
init_logger();
|
|
49754
|
+
var DEFAULT_TODO_CONFIG = {
|
|
49755
|
+
enabled: true,
|
|
49756
|
+
reminderFrequency: 3,
|
|
49757
|
+
compactMode: false,
|
|
49758
|
+
maxCompactItems: 5,
|
|
49759
|
+
showCompleted: false
|
|
49760
|
+
};
|
|
49761
|
+
var TodoInstructionProvider = class {
|
|
49762
|
+
name = "todo";
|
|
49763
|
+
config;
|
|
49764
|
+
lastStateHash = "";
|
|
49765
|
+
lastReminderTurn = 0;
|
|
49766
|
+
constructor(config) {
|
|
49767
|
+
this.config = {
|
|
49768
|
+
...DEFAULT_TODO_CONFIG,
|
|
49769
|
+
...config
|
|
49770
|
+
};
|
|
49771
|
+
logger.debug("TodoInstructionProvider initialized", {
|
|
49772
|
+
enabled: this.config.enabled,
|
|
49773
|
+
reminderFrequency: this.config.reminderFrequency
|
|
49774
|
+
});
|
|
49775
|
+
}
|
|
49776
|
+
/**
|
|
49777
|
+
* Check if provider should generate instructions
|
|
49778
|
+
*/
|
|
49779
|
+
shouldGenerate(context) {
|
|
49780
|
+
if (!this.config.enabled) {
|
|
49781
|
+
return false;
|
|
49782
|
+
}
|
|
49783
|
+
if (!context.todos || context.todos.length === 0) {
|
|
49784
|
+
return false;
|
|
49785
|
+
}
|
|
49786
|
+
const currentHash = computeTodoHash(context.todos);
|
|
49787
|
+
const stateChanged = currentHash !== this.lastStateHash;
|
|
49788
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
49789
|
+
const reminderDue = turnsSinceReminder >= this.config.reminderFrequency;
|
|
49790
|
+
return stateChanged || reminderDue;
|
|
49791
|
+
}
|
|
49792
|
+
/**
|
|
49793
|
+
* Generate instructions based on todo state
|
|
49794
|
+
*/
|
|
49795
|
+
async getInstructions(context) {
|
|
49796
|
+
const instructions = [];
|
|
49797
|
+
if (!context.todos || context.todos.length === 0) {
|
|
49798
|
+
return instructions;
|
|
49799
|
+
}
|
|
49800
|
+
const currentHash = computeTodoHash(context.todos);
|
|
49801
|
+
const stateChanged = currentHash !== this.lastStateHash;
|
|
49802
|
+
const inProgressTasks = [];
|
|
49803
|
+
const pendingTasks = [];
|
|
49804
|
+
const completedTasks = [];
|
|
49805
|
+
for (const todo of context.todos) {
|
|
49806
|
+
switch (todo.status) {
|
|
49807
|
+
case "in_progress":
|
|
49808
|
+
inProgressTasks.push(todo);
|
|
49809
|
+
break;
|
|
49810
|
+
case "pending":
|
|
49811
|
+
pendingTasks.push(todo);
|
|
49812
|
+
break;
|
|
49813
|
+
case "completed":
|
|
49814
|
+
completedTasks.push(todo);
|
|
49815
|
+
break;
|
|
49816
|
+
}
|
|
49817
|
+
}
|
|
49818
|
+
let content;
|
|
49819
|
+
let priority;
|
|
49820
|
+
if (stateChanged) {
|
|
49821
|
+
content = this.formatFullTodoList(inProgressTasks, pendingTasks, completedTasks);
|
|
49822
|
+
priority = "high";
|
|
49823
|
+
} else if (this.config.compactMode) {
|
|
49824
|
+
content = this.formatCompactReminder(inProgressTasks, pendingTasks);
|
|
49825
|
+
priority = "normal";
|
|
49826
|
+
} else {
|
|
49827
|
+
content = this.formatStandardReminder(inProgressTasks, pendingTasks);
|
|
49828
|
+
priority = "normal";
|
|
49829
|
+
}
|
|
49830
|
+
instructions.push({
|
|
49831
|
+
type: "task",
|
|
49832
|
+
priority,
|
|
49833
|
+
content,
|
|
49834
|
+
source: INSTRUCTION_SOURCE,
|
|
49835
|
+
createdAt: Date.now(),
|
|
49836
|
+
createdAtTurn: context.turnCount,
|
|
49837
|
+
expiresAfter: this.config.reminderFrequency + 1,
|
|
49838
|
+
id: `todo-${currentHash.substring(0, 8)}`
|
|
49839
|
+
});
|
|
49840
|
+
this.lastStateHash = currentHash;
|
|
49841
|
+
this.lastReminderTurn = context.turnCount;
|
|
49842
|
+
logger.debug("Todo instructions generated", {
|
|
49843
|
+
inProgress: inProgressTasks.length,
|
|
49844
|
+
pending: pendingTasks.length,
|
|
49845
|
+
completed: completedTasks.length,
|
|
49846
|
+
stateChanged
|
|
49847
|
+
});
|
|
49848
|
+
return instructions;
|
|
49849
|
+
}
|
|
49850
|
+
/**
|
|
49851
|
+
* Format full todo list (used when state changes)
|
|
49852
|
+
*/
|
|
49853
|
+
formatFullTodoList(inProgress, pending, completed) {
|
|
49854
|
+
const lines = [
|
|
49855
|
+
"## Current Task List"
|
|
49856
|
+
];
|
|
49857
|
+
if (inProgress.length > 0) {
|
|
49858
|
+
lines.push("");
|
|
49859
|
+
lines.push("### Currently Working On:");
|
|
49860
|
+
for (const task of inProgress) {
|
|
49861
|
+
lines.push(`- **${task.activeForm}**`);
|
|
49862
|
+
}
|
|
49863
|
+
}
|
|
49864
|
+
if (pending.length > 0) {
|
|
49865
|
+
lines.push("");
|
|
49866
|
+
lines.push("### Pending Tasks:");
|
|
49867
|
+
for (const task of pending) {
|
|
49868
|
+
lines.push(`- [ ] ${task.content}`);
|
|
49869
|
+
}
|
|
49870
|
+
}
|
|
49871
|
+
if (this.config.showCompleted && completed.length > 0) {
|
|
49872
|
+
lines.push("");
|
|
49873
|
+
lines.push("### Completed:");
|
|
49874
|
+
for (const task of completed.slice(-3)) {
|
|
49875
|
+
lines.push(`- [x] ${task.content}`);
|
|
49876
|
+
}
|
|
49877
|
+
}
|
|
49878
|
+
lines.push("");
|
|
49879
|
+
lines.push("**Remember:** Complete the current in-progress task before starting new ones.");
|
|
49880
|
+
lines.push("Mark tasks as completed as soon as they are done.");
|
|
49881
|
+
return lines.join("\n");
|
|
49882
|
+
}
|
|
49883
|
+
/**
|
|
49884
|
+
* Format standard reminder
|
|
49885
|
+
*/
|
|
49886
|
+
formatStandardReminder(inProgress, pending) {
|
|
49887
|
+
const lines = [];
|
|
49888
|
+
if (inProgress.length > 0) {
|
|
49889
|
+
lines.push(`**Current Task:** ${inProgress[0].activeForm}`);
|
|
49890
|
+
}
|
|
49891
|
+
if (pending.length > 0) {
|
|
49892
|
+
lines.push(`**Next:** ${pending[0].content}`);
|
|
49893
|
+
if (pending.length > 1) {
|
|
49894
|
+
lines.push(`(${pending.length - 1} more tasks pending)`);
|
|
49895
|
+
}
|
|
49896
|
+
}
|
|
49897
|
+
return lines.join("\n");
|
|
49898
|
+
}
|
|
49899
|
+
/**
|
|
49900
|
+
* Format compact reminder (minimal tokens)
|
|
49901
|
+
*/
|
|
49902
|
+
formatCompactReminder(inProgress, pending) {
|
|
49903
|
+
const parts = [];
|
|
49904
|
+
if (inProgress.length > 0) {
|
|
49905
|
+
parts.push(`Doing: ${inProgress[0].activeForm}`);
|
|
49906
|
+
}
|
|
49907
|
+
if (pending.length > 0) {
|
|
49908
|
+
const count = Math.min(pending.length, this.config.maxCompactItems);
|
|
49909
|
+
parts.push(`Next: ${pending.slice(0, count).map((t) => t.content).join(", ")}`);
|
|
49910
|
+
}
|
|
49911
|
+
return parts.join(" | ");
|
|
49912
|
+
}
|
|
49913
|
+
/**
|
|
49914
|
+
* Get current configuration
|
|
49915
|
+
*/
|
|
49916
|
+
getConfig() {
|
|
49917
|
+
return { ...this.config };
|
|
49918
|
+
}
|
|
49919
|
+
/**
|
|
49920
|
+
* Update configuration
|
|
49921
|
+
*/
|
|
49922
|
+
updateConfig(updates) {
|
|
49923
|
+
this.config = {
|
|
49924
|
+
...this.config,
|
|
49925
|
+
...updates
|
|
49926
|
+
};
|
|
49927
|
+
logger.debug("TodoInstructionProvider config updated", {
|
|
49928
|
+
enabled: this.config.enabled,
|
|
49929
|
+
compactMode: this.config.compactMode
|
|
49930
|
+
});
|
|
49931
|
+
}
|
|
49932
|
+
/**
|
|
49933
|
+
* Reset state tracking (useful for testing)
|
|
49934
|
+
*/
|
|
49935
|
+
reset() {
|
|
49936
|
+
this.lastStateHash = "";
|
|
49937
|
+
this.lastReminderTurn = 0;
|
|
49938
|
+
logger.debug("TodoInstructionProvider state reset");
|
|
49939
|
+
}
|
|
49940
|
+
};
|
|
49941
|
+
function computeTodoHash(todos) {
|
|
49942
|
+
const stateString = todos.map((t) => `${t.id}:${t.status}:${t.content}`).sort().join("|");
|
|
49943
|
+
return crypto2.createHash("sha256").update(stateString).digest("hex").substring(0, 16);
|
|
49944
|
+
}
|
|
49945
|
+
|
|
49946
|
+
// src/core/orchestration/memory-instruction-provider.ts
|
|
49947
|
+
init_esm_shims();
|
|
49948
|
+
init_logger();
|
|
49949
|
+
var DEFAULT_CONTENT_MAX_LENGTH = 500;
|
|
49950
|
+
var DEFAULT_MEMORY_CONFIG = {
|
|
49951
|
+
enabled: true,
|
|
49952
|
+
maxEntries: 5,
|
|
49953
|
+
minRelevance: 0.5,
|
|
49954
|
+
searchFrequency: 3,
|
|
49955
|
+
maxAge: 0,
|
|
49956
|
+
// No limit by default
|
|
49957
|
+
includeMetadata: true,
|
|
49958
|
+
cacheTTL: 6e4,
|
|
49959
|
+
// 1 minute
|
|
49960
|
+
contentMaxLength: DEFAULT_CONTENT_MAX_LENGTH
|
|
49961
|
+
};
|
|
49962
|
+
var MemoryInstructionProvider = class {
|
|
49963
|
+
name = "memory";
|
|
49964
|
+
config;
|
|
49965
|
+
searchProvider;
|
|
49966
|
+
cache;
|
|
49967
|
+
lastSearchTurn = 0;
|
|
49968
|
+
constructor(searchProvider, config) {
|
|
49969
|
+
this.config = {
|
|
49970
|
+
...DEFAULT_MEMORY_CONFIG,
|
|
49971
|
+
...config
|
|
49972
|
+
};
|
|
49973
|
+
this.searchProvider = searchProvider;
|
|
49974
|
+
logger.debug("MemoryInstructionProvider initialized", {
|
|
49975
|
+
enabled: this.config.enabled,
|
|
49976
|
+
maxEntries: this.config.maxEntries,
|
|
49977
|
+
hasSearchProvider: !!searchProvider
|
|
49978
|
+
});
|
|
49979
|
+
}
|
|
49980
|
+
/**
|
|
49981
|
+
* Set the memory search provider
|
|
49982
|
+
*/
|
|
49983
|
+
setSearchProvider(provider) {
|
|
49984
|
+
this.searchProvider = provider;
|
|
49985
|
+
this.clearCache();
|
|
49986
|
+
logger.debug("Memory search provider set");
|
|
49987
|
+
}
|
|
49988
|
+
/**
|
|
49989
|
+
* Check if provider should generate instructions
|
|
49990
|
+
*/
|
|
49991
|
+
shouldGenerate(context) {
|
|
49992
|
+
if (!this.config.enabled) {
|
|
49993
|
+
return false;
|
|
49994
|
+
}
|
|
49995
|
+
if (!this.searchProvider) {
|
|
49996
|
+
return false;
|
|
49997
|
+
}
|
|
49998
|
+
if (!context.currentTask && context.todos.length === 0) {
|
|
49999
|
+
return false;
|
|
50000
|
+
}
|
|
50001
|
+
const turnsSinceSearch = context.turnCount - this.lastSearchTurn;
|
|
50002
|
+
const searchDue = turnsSinceSearch >= this.config.searchFrequency;
|
|
50003
|
+
const cacheValid = this.cache && Date.now() - this.cache.timestamp < this.config.cacheTTL;
|
|
50004
|
+
return searchDue || !cacheValid;
|
|
50005
|
+
}
|
|
50006
|
+
/**
|
|
50007
|
+
* Generate instructions based on relevant memories
|
|
50008
|
+
*/
|
|
50009
|
+
async getInstructions(context) {
|
|
50010
|
+
const instructions = [];
|
|
50011
|
+
if (!this.searchProvider) {
|
|
50012
|
+
return instructions;
|
|
50013
|
+
}
|
|
50014
|
+
const searchQuery = this.buildSearchQuery(context);
|
|
50015
|
+
if (!searchQuery) {
|
|
50016
|
+
return instructions;
|
|
50017
|
+
}
|
|
50018
|
+
try {
|
|
50019
|
+
const memories = await this.searchMemories(searchQuery, context);
|
|
50020
|
+
if (memories.length === 0) {
|
|
50021
|
+
return instructions;
|
|
50022
|
+
}
|
|
50023
|
+
this.lastSearchTurn = context.turnCount;
|
|
50024
|
+
const content = this.formatMemories(memories);
|
|
50025
|
+
instructions.push({
|
|
50026
|
+
type: "memory",
|
|
50027
|
+
priority: "normal",
|
|
50028
|
+
content,
|
|
50029
|
+
source: INSTRUCTION_SOURCE,
|
|
50030
|
+
createdAt: Date.now(),
|
|
50031
|
+
createdAtTurn: context.turnCount,
|
|
50032
|
+
expiresAfter: this.config.searchFrequency + 1,
|
|
50033
|
+
id: `memory-${Date.now()}`
|
|
50034
|
+
});
|
|
50035
|
+
logger.debug("Memory instructions generated", {
|
|
50036
|
+
memoriesFound: memories.length,
|
|
50037
|
+
query: searchQuery.substring(0, 50)
|
|
50038
|
+
});
|
|
50039
|
+
} catch (error) {
|
|
50040
|
+
logger.error("Failed to search memories", {
|
|
50041
|
+
error: error instanceof Error ? error.message : String(error)
|
|
50042
|
+
});
|
|
50043
|
+
}
|
|
50044
|
+
return instructions;
|
|
50045
|
+
}
|
|
50046
|
+
/**
|
|
50047
|
+
* Build search query from context
|
|
50048
|
+
*/
|
|
50049
|
+
buildSearchQuery(context) {
|
|
50050
|
+
const parts = [];
|
|
50051
|
+
if (context.currentTask) {
|
|
50052
|
+
parts.push(context.currentTask);
|
|
50053
|
+
}
|
|
50054
|
+
let inProgressCount = 0;
|
|
50055
|
+
for (const todo of context.todos) {
|
|
50056
|
+
if (todo.status === "in_progress") {
|
|
50057
|
+
parts.push(todo.content);
|
|
50058
|
+
if (++inProgressCount >= 2) break;
|
|
50059
|
+
}
|
|
50060
|
+
}
|
|
50061
|
+
if (context.agentName) {
|
|
50062
|
+
parts.push(context.agentName);
|
|
50063
|
+
}
|
|
50064
|
+
if (parts.length === 0) {
|
|
50065
|
+
return null;
|
|
50066
|
+
}
|
|
50067
|
+
return parts.join(" ");
|
|
50068
|
+
}
|
|
50069
|
+
/**
|
|
50070
|
+
* Search for relevant memories
|
|
50071
|
+
*/
|
|
50072
|
+
async searchMemories(query, context) {
|
|
50073
|
+
if (!this.searchProvider) {
|
|
50074
|
+
return [];
|
|
50075
|
+
}
|
|
50076
|
+
if (this.cache && this.cache.query === query) {
|
|
50077
|
+
const age = Date.now() - this.cache.timestamp;
|
|
50078
|
+
if (age < this.config.cacheTTL) {
|
|
50079
|
+
logger.debug("Using cached memory results", {
|
|
50080
|
+
cacheAge: age,
|
|
50081
|
+
resultCount: this.cache.results.length
|
|
50082
|
+
});
|
|
50083
|
+
return this.cache.results;
|
|
50084
|
+
}
|
|
50085
|
+
}
|
|
50086
|
+
const results = await this.searchProvider.search({
|
|
50087
|
+
text: query,
|
|
50088
|
+
limit: this.config.maxEntries * 2,
|
|
50089
|
+
// Get extra in case some are filtered
|
|
50090
|
+
filters: context.agentName ? { agentId: context.agentName } : void 0
|
|
50091
|
+
});
|
|
50092
|
+
const filtered = results.filter((r) => r.score >= this.config.minRelevance).filter((r) => this.isWithinMaxAge(r.createdAt)).slice(0, this.config.maxEntries);
|
|
50093
|
+
const memories = filtered.map((r) => ({
|
|
50094
|
+
content: r.content,
|
|
50095
|
+
relevance: r.score,
|
|
50096
|
+
agent: r.metadata?.agentId,
|
|
50097
|
+
timestamp: r.createdAt.getTime()
|
|
50098
|
+
}));
|
|
50099
|
+
this.cache = {
|
|
50100
|
+
query,
|
|
50101
|
+
results: memories,
|
|
50102
|
+
timestamp: Date.now()
|
|
50103
|
+
};
|
|
50104
|
+
return memories;
|
|
50105
|
+
}
|
|
50106
|
+
/**
|
|
50107
|
+
* Check if memory is within max age limit
|
|
50108
|
+
*/
|
|
50109
|
+
isWithinMaxAge(createdAt) {
|
|
50110
|
+
if (this.config.maxAge === 0) {
|
|
50111
|
+
return true;
|
|
50112
|
+
}
|
|
50113
|
+
const age = Date.now() - createdAt.getTime();
|
|
50114
|
+
return age <= this.config.maxAge;
|
|
50115
|
+
}
|
|
50116
|
+
/**
|
|
50117
|
+
* Format memories into instruction content
|
|
50118
|
+
*/
|
|
50119
|
+
formatMemories(memories) {
|
|
50120
|
+
const lines = [
|
|
50121
|
+
"## Relevant Context from Memory",
|
|
50122
|
+
""
|
|
50123
|
+
];
|
|
50124
|
+
for (let i = 0; i < memories.length; i++) {
|
|
50125
|
+
const memory = memories[i];
|
|
50126
|
+
if (!memory) continue;
|
|
50127
|
+
const relevancePercent = Math.round(memory.relevance * 100);
|
|
50128
|
+
if (this.config.includeMetadata && memory.agent) {
|
|
50129
|
+
lines.push(`### Memory ${i + 1} (${relevancePercent}% relevant, from ${memory.agent})`);
|
|
50130
|
+
} else {
|
|
50131
|
+
lines.push(`### Memory ${i + 1} (${relevancePercent}% relevant)`);
|
|
50132
|
+
}
|
|
50133
|
+
const content = memory.content.length > this.config.contentMaxLength ? memory.content.substring(0, this.config.contentMaxLength) + "..." : memory.content;
|
|
50134
|
+
lines.push(content);
|
|
50135
|
+
lines.push("");
|
|
50136
|
+
}
|
|
50137
|
+
lines.push("**Note:** Use this context to inform your decisions, but verify current state.");
|
|
50138
|
+
return lines.join("\n");
|
|
50139
|
+
}
|
|
50140
|
+
/**
|
|
50141
|
+
* Clear the memory cache
|
|
50142
|
+
*/
|
|
50143
|
+
clearCache() {
|
|
50144
|
+
this.cache = void 0;
|
|
50145
|
+
logger.debug("Memory cache cleared");
|
|
50146
|
+
}
|
|
50147
|
+
/**
|
|
50148
|
+
* Get current configuration
|
|
50149
|
+
*/
|
|
50150
|
+
getConfig() {
|
|
50151
|
+
return { ...this.config };
|
|
50152
|
+
}
|
|
50153
|
+
/**
|
|
50154
|
+
* Update configuration
|
|
50155
|
+
*/
|
|
50156
|
+
updateConfig(updates) {
|
|
50157
|
+
this.config = {
|
|
50158
|
+
...this.config,
|
|
50159
|
+
...updates
|
|
50160
|
+
};
|
|
50161
|
+
if (updates.minRelevance !== void 0 || updates.maxEntries !== void 0) {
|
|
50162
|
+
this.clearCache();
|
|
50163
|
+
}
|
|
50164
|
+
logger.debug("MemoryInstructionProvider config updated", {
|
|
50165
|
+
enabled: this.config.enabled,
|
|
50166
|
+
maxEntries: this.config.maxEntries
|
|
50167
|
+
});
|
|
50168
|
+
}
|
|
50169
|
+
/**
|
|
50170
|
+
* Reset state
|
|
50171
|
+
*/
|
|
50172
|
+
reset() {
|
|
50173
|
+
this.cache = void 0;
|
|
50174
|
+
this.lastSearchTurn = 0;
|
|
50175
|
+
logger.debug("MemoryInstructionProvider reset");
|
|
50176
|
+
}
|
|
50177
|
+
/**
|
|
50178
|
+
* Check if search provider is configured
|
|
50179
|
+
*/
|
|
50180
|
+
hasSearchProvider() {
|
|
50181
|
+
return !!this.searchProvider;
|
|
50182
|
+
}
|
|
50183
|
+
};
|
|
50184
|
+
|
|
50185
|
+
// src/core/orchestration/session-instruction-provider.ts
|
|
50186
|
+
init_esm_shims();
|
|
50187
|
+
init_logger();
|
|
50188
|
+
var DEFAULT_SESSION_CONFIG = {
|
|
50189
|
+
enabled: true,
|
|
50190
|
+
showCollaboration: true,
|
|
50191
|
+
showProgress: true,
|
|
50192
|
+
reminderFrequency: 5,
|
|
50193
|
+
showHandoffContext: true
|
|
50194
|
+
};
|
|
50195
|
+
var SESSION_CACHE_TTL_MS = 3e4;
|
|
50196
|
+
var SessionInstructionProvider = class {
|
|
50197
|
+
name = "session";
|
|
50198
|
+
config;
|
|
50199
|
+
stateProvider;
|
|
50200
|
+
lastReminderTurn = 0;
|
|
50201
|
+
cachedState;
|
|
50202
|
+
cacheExpiry = 0;
|
|
50203
|
+
constructor(stateProvider, config) {
|
|
50204
|
+
this.config = {
|
|
50205
|
+
...DEFAULT_SESSION_CONFIG,
|
|
50206
|
+
...config
|
|
50207
|
+
};
|
|
50208
|
+
this.stateProvider = stateProvider;
|
|
50209
|
+
logger.debug("SessionInstructionProvider initialized", {
|
|
50210
|
+
enabled: this.config.enabled,
|
|
50211
|
+
hasStateProvider: !!stateProvider
|
|
50212
|
+
});
|
|
50213
|
+
}
|
|
50214
|
+
/**
|
|
50215
|
+
* Set the session state provider
|
|
50216
|
+
*/
|
|
50217
|
+
setStateProvider(provider) {
|
|
50218
|
+
this.stateProvider = provider;
|
|
50219
|
+
this.clearCache();
|
|
50220
|
+
logger.debug("Session state provider set");
|
|
50221
|
+
}
|
|
50222
|
+
/**
|
|
50223
|
+
* Check if provider should generate instructions
|
|
50224
|
+
*/
|
|
50225
|
+
shouldGenerate(context) {
|
|
50226
|
+
if (!this.config.enabled) {
|
|
50227
|
+
return false;
|
|
50228
|
+
}
|
|
50229
|
+
if (!context.sessionId && !this.stateProvider) {
|
|
50230
|
+
return false;
|
|
50231
|
+
}
|
|
50232
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
50233
|
+
return turnsSinceReminder >= this.config.reminderFrequency;
|
|
50234
|
+
}
|
|
50235
|
+
/**
|
|
50236
|
+
* Generate instructions based on session state
|
|
50237
|
+
*/
|
|
50238
|
+
async getInstructions(context) {
|
|
50239
|
+
const instructions = [];
|
|
50240
|
+
const state = await this.getSessionState(context);
|
|
50241
|
+
if (!state && !context.sessionId) {
|
|
50242
|
+
return instructions;
|
|
50243
|
+
}
|
|
50244
|
+
const content = this.formatSessionContext(context, state);
|
|
50245
|
+
if (content) {
|
|
50246
|
+
instructions.push({
|
|
50247
|
+
type: "session",
|
|
50248
|
+
priority: "normal",
|
|
50249
|
+
content,
|
|
50250
|
+
source: INSTRUCTION_SOURCE,
|
|
50251
|
+
createdAt: Date.now(),
|
|
50252
|
+
createdAtTurn: context.turnCount,
|
|
50253
|
+
expiresAfter: this.config.reminderFrequency,
|
|
50254
|
+
id: `session-${context.sessionId ?? "default"}-${Date.now()}`
|
|
50255
|
+
});
|
|
50256
|
+
}
|
|
50257
|
+
this.lastReminderTurn = context.turnCount;
|
|
50258
|
+
logger.debug("Session instructions generated", {
|
|
50259
|
+
sessionId: context.sessionId,
|
|
50260
|
+
hasState: !!state
|
|
50261
|
+
});
|
|
50262
|
+
return instructions;
|
|
50263
|
+
}
|
|
50264
|
+
/**
|
|
50265
|
+
* Get session state from provider or cache
|
|
50266
|
+
*/
|
|
50267
|
+
async getSessionState(context) {
|
|
50268
|
+
if (!context.sessionId) {
|
|
50269
|
+
return null;
|
|
50270
|
+
}
|
|
50271
|
+
if (this.cachedState && this.cachedState.id === context.sessionId && Date.now() < this.cacheExpiry) {
|
|
50272
|
+
return this.cachedState;
|
|
50273
|
+
}
|
|
50274
|
+
if (!this.stateProvider) {
|
|
50275
|
+
return null;
|
|
50276
|
+
}
|
|
50277
|
+
try {
|
|
50278
|
+
const state = await this.stateProvider.getSessionState(context.sessionId);
|
|
50279
|
+
if (state) {
|
|
50280
|
+
this.cachedState = state;
|
|
50281
|
+
this.cacheExpiry = Date.now() + SESSION_CACHE_TTL_MS;
|
|
50282
|
+
}
|
|
50283
|
+
return state;
|
|
50284
|
+
} catch (error) {
|
|
50285
|
+
logger.error("Failed to get session state", {
|
|
50286
|
+
sessionId: context.sessionId,
|
|
50287
|
+
error: error instanceof Error ? error.message : String(error)
|
|
50288
|
+
});
|
|
50289
|
+
return null;
|
|
50290
|
+
}
|
|
50291
|
+
}
|
|
50292
|
+
/**
|
|
50293
|
+
* Format session context into instruction content
|
|
50294
|
+
*/
|
|
50295
|
+
formatSessionContext(context, state) {
|
|
50296
|
+
const lines = [];
|
|
50297
|
+
if (context.sessionId) {
|
|
50298
|
+
lines.push("## Session Context");
|
|
50299
|
+
lines.push("");
|
|
50300
|
+
}
|
|
50301
|
+
if (this.config.showCollaboration && state && state.participants.length > 1) {
|
|
50302
|
+
lines.push("### Multi-Agent Collaboration");
|
|
50303
|
+
lines.push(`- **Session:** ${state.id.substring(0, 8)}...`);
|
|
50304
|
+
lines.push(`- **Participants:** ${state.participants.join(", ")}`);
|
|
50305
|
+
if (state.activeAgent) {
|
|
50306
|
+
lines.push(`- **Currently Active:** ${state.activeAgent}`);
|
|
50307
|
+
}
|
|
50308
|
+
lines.push("");
|
|
50309
|
+
}
|
|
50310
|
+
if (this.config.showProgress && state) {
|
|
50311
|
+
const totalTasks = state.completedTasks + state.remainingTasks;
|
|
50312
|
+
if (totalTasks > 0) {
|
|
50313
|
+
const progress = Math.round(state.completedTasks / totalTasks * 100);
|
|
50314
|
+
lines.push("### Session Progress");
|
|
50315
|
+
lines.push(`- Completed: ${state.completedTasks}/${totalTasks} (${progress}%)`);
|
|
50316
|
+
if (state.remainingTasks > 0) {
|
|
50317
|
+
lines.push(`- Remaining: ${state.remainingTasks} task(s)`);
|
|
50318
|
+
}
|
|
50319
|
+
lines.push("");
|
|
50320
|
+
}
|
|
50321
|
+
}
|
|
50322
|
+
if (this.config.showHandoffContext && context.parentAgent) {
|
|
50323
|
+
lines.push("### Delegation Context");
|
|
50324
|
+
lines.push(`- **Delegated from:** ${context.parentAgent}`);
|
|
50325
|
+
if (context.currentTask) {
|
|
50326
|
+
lines.push(`- **Task:** ${context.currentTask}`);
|
|
50327
|
+
}
|
|
50328
|
+
lines.push("");
|
|
50329
|
+
lines.push("**Note:** Complete this task and return control to the parent agent.");
|
|
50330
|
+
lines.push("");
|
|
50331
|
+
}
|
|
50332
|
+
if (context.agentName && !context.parentAgent) {
|
|
50333
|
+
lines.push(`**Current Agent:** ${context.agentName}`);
|
|
50334
|
+
lines.push("");
|
|
50335
|
+
}
|
|
50336
|
+
if (lines.length <= 2) {
|
|
50337
|
+
return null;
|
|
50338
|
+
}
|
|
50339
|
+
return lines.join("\n");
|
|
50340
|
+
}
|
|
50341
|
+
/**
|
|
50342
|
+
* Clear cached state
|
|
50343
|
+
*/
|
|
50344
|
+
clearCache() {
|
|
50345
|
+
this.cachedState = void 0;
|
|
50346
|
+
this.cacheExpiry = 0;
|
|
50347
|
+
logger.debug("Session cache cleared");
|
|
50348
|
+
}
|
|
50349
|
+
/**
|
|
50350
|
+
* Get current configuration
|
|
50351
|
+
*/
|
|
50352
|
+
getConfig() {
|
|
50353
|
+
return { ...this.config };
|
|
50354
|
+
}
|
|
50355
|
+
/**
|
|
50356
|
+
* Update configuration
|
|
50357
|
+
*/
|
|
50358
|
+
updateConfig(updates) {
|
|
50359
|
+
this.config = {
|
|
50360
|
+
...this.config,
|
|
50361
|
+
...updates
|
|
50362
|
+
};
|
|
50363
|
+
logger.debug("SessionInstructionProvider config updated", {
|
|
50364
|
+
enabled: this.config.enabled
|
|
50365
|
+
});
|
|
50366
|
+
}
|
|
50367
|
+
/**
|
|
50368
|
+
* Reset state
|
|
50369
|
+
*/
|
|
50370
|
+
reset() {
|
|
50371
|
+
this.lastReminderTurn = 0;
|
|
50372
|
+
this.clearCache();
|
|
50373
|
+
logger.debug("SessionInstructionProvider reset");
|
|
50374
|
+
}
|
|
50375
|
+
/**
|
|
50376
|
+
* Check if state provider is configured
|
|
50377
|
+
*/
|
|
50378
|
+
hasStateProvider() {
|
|
50379
|
+
return !!this.stateProvider;
|
|
50380
|
+
}
|
|
50381
|
+
};
|
|
50382
|
+
|
|
50383
|
+
// src/agents/agent-instruction-injector.ts
|
|
50384
|
+
init_esm_shims();
|
|
50385
|
+
init_logger();
|
|
50386
|
+
|
|
50387
|
+
// src/agents/instruction-templates.ts
|
|
50388
|
+
init_esm_shims();
|
|
50389
|
+
var BACKEND_TEMPLATE = {
|
|
50390
|
+
domain: "backend",
|
|
50391
|
+
displayName: "Backend Engineer",
|
|
50392
|
+
domainReminders: [
|
|
50393
|
+
"Follow RESTful API design principles",
|
|
50394
|
+
"Use proper HTTP status codes",
|
|
50395
|
+
"Implement input validation at API boundaries",
|
|
50396
|
+
"Consider database query performance",
|
|
50397
|
+
"Handle errors gracefully with meaningful messages"
|
|
50398
|
+
],
|
|
50399
|
+
qualityChecklist: [
|
|
50400
|
+
"API endpoints follow REST conventions",
|
|
50401
|
+
"Database queries are optimized (no N+1)",
|
|
50402
|
+
"Input is validated before processing",
|
|
50403
|
+
"Errors are logged with context",
|
|
50404
|
+
"Sensitive data is not exposed in responses"
|
|
50405
|
+
],
|
|
50406
|
+
delegationTriggers: [
|
|
50407
|
+
{
|
|
50408
|
+
keywords: ["security", "authentication", "authorization", "OWASP", "vulnerability"],
|
|
50409
|
+
suggestedAgent: "security",
|
|
50410
|
+
reason: "Security-related tasks benefit from specialized security review"
|
|
50411
|
+
},
|
|
50412
|
+
{
|
|
50413
|
+
keywords: ["frontend", "UI", "React", "CSS", "component"],
|
|
50414
|
+
suggestedAgent: "frontend",
|
|
50415
|
+
reason: "Frontend implementation should be handled by frontend specialist"
|
|
50416
|
+
},
|
|
50417
|
+
{
|
|
50418
|
+
keywords: ["test", "testing", "unit test", "integration test"],
|
|
50419
|
+
suggestedAgent: "quality",
|
|
50420
|
+
reason: "Testing strategy benefits from QA expertise"
|
|
50421
|
+
}
|
|
50422
|
+
],
|
|
50423
|
+
antiPatterns: [
|
|
50424
|
+
"Avoid SQL injection by using parameterized queries",
|
|
50425
|
+
"Don't expose internal error details to clients",
|
|
50426
|
+
"Avoid synchronous blocking operations",
|
|
50427
|
+
"Don't hardcode configuration values"
|
|
50428
|
+
],
|
|
50429
|
+
bestPractices: [
|
|
50430
|
+
"Use prepared statements for database queries",
|
|
50431
|
+
"Implement proper logging with correlation IDs",
|
|
50432
|
+
"Use dependency injection for testability",
|
|
50433
|
+
"Follow the principle of least privilege"
|
|
50434
|
+
]
|
|
50435
|
+
};
|
|
50436
|
+
var FRONTEND_TEMPLATE = {
|
|
50437
|
+
domain: "frontend",
|
|
50438
|
+
displayName: "Frontend Engineer",
|
|
50439
|
+
domainReminders: [
|
|
50440
|
+
"Ensure accessibility (WCAG compliance)",
|
|
50441
|
+
"Optimize for performance (Core Web Vitals)",
|
|
50442
|
+
"Handle loading and error states",
|
|
50443
|
+
"Implement responsive design",
|
|
50444
|
+
"Consider keyboard navigation"
|
|
50445
|
+
],
|
|
50446
|
+
qualityChecklist: [
|
|
50447
|
+
"Components are accessible (ARIA labels, roles)",
|
|
50448
|
+
"Loading states are handled",
|
|
50449
|
+
"Error boundaries catch failures gracefully",
|
|
50450
|
+
"Forms have proper validation feedback",
|
|
50451
|
+
"Images have alt text"
|
|
50452
|
+
],
|
|
50453
|
+
delegationTriggers: [
|
|
50454
|
+
{
|
|
50455
|
+
keywords: ["API", "endpoint", "database", "backend", "server"],
|
|
50456
|
+
suggestedAgent: "backend",
|
|
50457
|
+
reason: "Backend changes should be handled by backend specialist"
|
|
50458
|
+
},
|
|
50459
|
+
{
|
|
50460
|
+
keywords: ["security", "XSS", "CSRF", "sanitize"],
|
|
50461
|
+
suggestedAgent: "security",
|
|
50462
|
+
reason: "Security concerns require specialized review"
|
|
50463
|
+
}
|
|
50464
|
+
],
|
|
50465
|
+
antiPatterns: [
|
|
50466
|
+
"Avoid inline styles for reusable components",
|
|
50467
|
+
"Don't mutate state directly",
|
|
50468
|
+
"Avoid excessive re-renders",
|
|
50469
|
+
"Don't ignore accessibility requirements"
|
|
50470
|
+
],
|
|
50471
|
+
bestPractices: [
|
|
50472
|
+
"Use semantic HTML elements",
|
|
50473
|
+
"Implement proper form validation",
|
|
50474
|
+
"Optimize bundle size",
|
|
50475
|
+
"Use React.memo for expensive components"
|
|
50476
|
+
]
|
|
50477
|
+
};
|
|
50478
|
+
var SECURITY_TEMPLATE = {
|
|
50479
|
+
domain: "security",
|
|
50480
|
+
displayName: "Security Engineer",
|
|
50481
|
+
domainReminders: [
|
|
50482
|
+
"Apply OWASP Top 10 security guidelines",
|
|
50483
|
+
"Validate and sanitize ALL user input",
|
|
50484
|
+
"Use parameterized queries to prevent SQL injection",
|
|
50485
|
+
"Implement proper authentication and authorization",
|
|
50486
|
+
"Never expose sensitive data in logs or responses"
|
|
50487
|
+
],
|
|
50488
|
+
qualityChecklist: [
|
|
50489
|
+
"Input validation is present at all entry points",
|
|
50490
|
+
"Authentication tokens are handled securely",
|
|
50491
|
+
"Sensitive data is encrypted at rest and in transit",
|
|
50492
|
+
"Error messages don't leak implementation details",
|
|
50493
|
+
"Dependencies are checked for known vulnerabilities"
|
|
50494
|
+
],
|
|
50495
|
+
delegationTriggers: [
|
|
50496
|
+
{
|
|
50497
|
+
keywords: ["performance", "optimization", "speed", "latency"],
|
|
50498
|
+
suggestedAgent: "backend",
|
|
50499
|
+
reason: "Performance optimization is a backend concern"
|
|
50500
|
+
}
|
|
50501
|
+
],
|
|
50502
|
+
antiPatterns: [
|
|
50503
|
+
"Never trust user input without validation",
|
|
50504
|
+
"Don't store passwords in plain text",
|
|
50505
|
+
"Avoid security through obscurity",
|
|
50506
|
+
"Don't disable security features for convenience"
|
|
50507
|
+
],
|
|
50508
|
+
bestPractices: [
|
|
50509
|
+
"Follow the principle of least privilege",
|
|
50510
|
+
"Implement defense in depth",
|
|
50511
|
+
"Use secure defaults",
|
|
50512
|
+
"Fail securely (deny by default)"
|
|
50513
|
+
]
|
|
50514
|
+
};
|
|
50515
|
+
var QUALITY_TEMPLATE = {
|
|
50516
|
+
domain: "quality",
|
|
50517
|
+
displayName: "Quality Assurance Engineer",
|
|
50518
|
+
domainReminders: [
|
|
50519
|
+
"Write tests that verify behavior, not implementation",
|
|
50520
|
+
"Cover edge cases and error scenarios",
|
|
50521
|
+
"Ensure test isolation (no shared state)",
|
|
50522
|
+
"Use meaningful test descriptions",
|
|
50523
|
+
"Follow the Arrange-Act-Assert pattern"
|
|
50524
|
+
],
|
|
50525
|
+
qualityChecklist: [
|
|
50526
|
+
"Unit tests cover critical paths",
|
|
50527
|
+
"Integration tests verify component interactions",
|
|
50528
|
+
"Edge cases are tested",
|
|
50529
|
+
"Error handling is verified",
|
|
50530
|
+
"Tests are maintainable and readable"
|
|
50531
|
+
],
|
|
50532
|
+
delegationTriggers: [
|
|
50533
|
+
{
|
|
50534
|
+
keywords: ["implement", "build", "create", "develop"],
|
|
50535
|
+
suggestedAgent: "backend",
|
|
50536
|
+
reason: "Implementation tasks should go to domain specialists"
|
|
50537
|
+
},
|
|
50538
|
+
{
|
|
50539
|
+
keywords: ["security", "vulnerability", "penetration"],
|
|
50540
|
+
suggestedAgent: "security",
|
|
50541
|
+
reason: "Security testing requires specialized expertise"
|
|
50542
|
+
}
|
|
50543
|
+
],
|
|
50544
|
+
antiPatterns: [
|
|
50545
|
+
"Avoid testing implementation details",
|
|
50546
|
+
"Don't use flaky tests",
|
|
50547
|
+
"Avoid excessive mocking",
|
|
50548
|
+
"Don't ignore failing tests"
|
|
50549
|
+
],
|
|
50550
|
+
bestPractices: [
|
|
50551
|
+
"Test behavior, not implementation",
|
|
50552
|
+
"Use descriptive test names",
|
|
50553
|
+
"Keep tests independent",
|
|
50554
|
+
"Follow the testing pyramid"
|
|
50555
|
+
]
|
|
50556
|
+
};
|
|
50557
|
+
var ARCHITECTURE_TEMPLATE = {
|
|
50558
|
+
domain: "architecture",
|
|
50559
|
+
displayName: "Software Architect",
|
|
50560
|
+
domainReminders: [
|
|
50561
|
+
"Consider scalability implications",
|
|
50562
|
+
"Document architectural decisions (ADRs)",
|
|
50563
|
+
"Evaluate trade-offs explicitly",
|
|
50564
|
+
"Design for maintainability",
|
|
50565
|
+
"Consider operational concerns"
|
|
50566
|
+
],
|
|
50567
|
+
qualityChecklist: [
|
|
50568
|
+
"Architecture supports future scaling",
|
|
50569
|
+
"Components have clear boundaries",
|
|
50570
|
+
"Dependencies are managed properly",
|
|
50571
|
+
"System is observable (logging, metrics)",
|
|
50572
|
+
"Failure modes are handled"
|
|
50573
|
+
],
|
|
50574
|
+
delegationTriggers: [
|
|
50575
|
+
{
|
|
50576
|
+
keywords: ["implement", "code", "fix", "bug"],
|
|
50577
|
+
suggestedAgent: "backend",
|
|
50578
|
+
reason: "Implementation details should be handled by domain specialists"
|
|
50579
|
+
},
|
|
50580
|
+
{
|
|
50581
|
+
keywords: ["security", "compliance", "audit"],
|
|
50582
|
+
suggestedAgent: "security",
|
|
50583
|
+
reason: "Security architecture needs specialized review"
|
|
50584
|
+
}
|
|
50585
|
+
],
|
|
50586
|
+
antiPatterns: [
|
|
50587
|
+
"Avoid premature optimization",
|
|
50588
|
+
"Don't over-engineer solutions",
|
|
50589
|
+
"Avoid tight coupling between components",
|
|
50590
|
+
"Don't ignore non-functional requirements"
|
|
50591
|
+
],
|
|
50592
|
+
bestPractices: [
|
|
50593
|
+
"Design for change",
|
|
50594
|
+
"Use well-known patterns",
|
|
50595
|
+
"Document decisions and rationale",
|
|
50596
|
+
"Consider operational requirements"
|
|
50597
|
+
]
|
|
50598
|
+
};
|
|
50599
|
+
var DEVOPS_TEMPLATE = {
|
|
50600
|
+
domain: "devops",
|
|
50601
|
+
displayName: "DevOps Engineer",
|
|
50602
|
+
domainReminders: [
|
|
50603
|
+
"Automate repetitive tasks",
|
|
50604
|
+
"Implement proper monitoring and alerting",
|
|
50605
|
+
"Follow infrastructure as code principles",
|
|
50606
|
+
"Consider disaster recovery",
|
|
50607
|
+
"Optimize for reliability and cost"
|
|
50608
|
+
],
|
|
50609
|
+
qualityChecklist: [
|
|
50610
|
+
"Deployments are automated and repeatable",
|
|
50611
|
+
"Monitoring covers key metrics",
|
|
50612
|
+
"Alerts are actionable",
|
|
50613
|
+
"Backups are tested",
|
|
50614
|
+
"Security is integrated into CI/CD"
|
|
50615
|
+
],
|
|
50616
|
+
delegationTriggers: [
|
|
50617
|
+
{
|
|
50618
|
+
keywords: ["code", "feature", "bug", "implement"],
|
|
50619
|
+
suggestedAgent: "backend",
|
|
50620
|
+
reason: "Application code changes should go to developers"
|
|
50621
|
+
},
|
|
50622
|
+
{
|
|
50623
|
+
keywords: ["security", "credentials", "secrets"],
|
|
50624
|
+
suggestedAgent: "security",
|
|
50625
|
+
reason: "Security-sensitive changes need security review"
|
|
50626
|
+
}
|
|
50627
|
+
],
|
|
50628
|
+
antiPatterns: [
|
|
50629
|
+
"Avoid manual deployments",
|
|
50630
|
+
"Don't store secrets in code",
|
|
50631
|
+
"Avoid single points of failure",
|
|
50632
|
+
"Don't ignore monitoring gaps"
|
|
50633
|
+
],
|
|
50634
|
+
bestPractices: [
|
|
50635
|
+
"Use infrastructure as code",
|
|
50636
|
+
"Implement CI/CD pipelines",
|
|
50637
|
+
"Follow GitOps practices",
|
|
50638
|
+
"Use immutable infrastructure"
|
|
50639
|
+
]
|
|
50640
|
+
};
|
|
50641
|
+
var WRITER_TEMPLATE = {
|
|
50642
|
+
domain: "writer",
|
|
50643
|
+
displayName: "Technical Writer",
|
|
50644
|
+
domainReminders: [
|
|
50645
|
+
"Write for the target audience",
|
|
50646
|
+
"Use clear, concise language",
|
|
50647
|
+
"Include practical examples",
|
|
50648
|
+
"Structure content logically",
|
|
50649
|
+
"Keep documentation up to date"
|
|
50650
|
+
],
|
|
50651
|
+
qualityChecklist: [
|
|
50652
|
+
"Documentation matches current code",
|
|
50653
|
+
"Examples are working and tested",
|
|
50654
|
+
"Content is well-organized",
|
|
50655
|
+
"Technical terms are explained",
|
|
50656
|
+
"Links and references are valid"
|
|
50657
|
+
],
|
|
50658
|
+
delegationTriggers: [
|
|
50659
|
+
{
|
|
50660
|
+
keywords: ["implement", "code", "fix", "develop"],
|
|
50661
|
+
suggestedAgent: "backend",
|
|
50662
|
+
reason: "Code changes should be handled by developers"
|
|
50663
|
+
}
|
|
50664
|
+
],
|
|
50665
|
+
antiPatterns: [
|
|
50666
|
+
"Avoid jargon without explanation",
|
|
50667
|
+
"Don't assume reader knowledge",
|
|
50668
|
+
"Avoid outdated examples",
|
|
50669
|
+
"Don't ignore code comments"
|
|
50670
|
+
],
|
|
50671
|
+
bestPractices: [
|
|
50672
|
+
"Use consistent terminology",
|
|
50673
|
+
"Include code examples",
|
|
50674
|
+
"Keep documentation near code",
|
|
50675
|
+
"Update docs with code changes"
|
|
50676
|
+
]
|
|
50677
|
+
};
|
|
50678
|
+
var STANDARD_TEMPLATE = {
|
|
50679
|
+
domain: "standard",
|
|
50680
|
+
displayName: "General Assistant",
|
|
50681
|
+
domainReminders: [
|
|
50682
|
+
"Understand the task before starting",
|
|
50683
|
+
"Ask clarifying questions when needed",
|
|
50684
|
+
"Break complex tasks into smaller steps",
|
|
50685
|
+
"Verify your work before completing",
|
|
50686
|
+
"Document your changes"
|
|
50687
|
+
],
|
|
50688
|
+
qualityChecklist: [
|
|
50689
|
+
"Task requirements are understood",
|
|
50690
|
+
"Changes are tested",
|
|
50691
|
+
"Code follows project conventions",
|
|
50692
|
+
"Documentation is updated",
|
|
50693
|
+
"No regressions introduced"
|
|
50694
|
+
],
|
|
50695
|
+
delegationTriggers: [
|
|
50696
|
+
{
|
|
50697
|
+
keywords: ["security", "vulnerability", "authentication"],
|
|
50698
|
+
suggestedAgent: "security",
|
|
50699
|
+
reason: "Security tasks need specialized attention"
|
|
50700
|
+
},
|
|
50701
|
+
{
|
|
50702
|
+
keywords: ["test", "testing", "QA", "quality"],
|
|
50703
|
+
suggestedAgent: "quality",
|
|
50704
|
+
reason: "Testing benefits from QA expertise"
|
|
50705
|
+
},
|
|
50706
|
+
{
|
|
50707
|
+
keywords: ["architecture", "design", "scalability"],
|
|
50708
|
+
suggestedAgent: "architecture",
|
|
50709
|
+
reason: "Architectural decisions need careful consideration"
|
|
50710
|
+
}
|
|
50711
|
+
],
|
|
50712
|
+
antiPatterns: [
|
|
50713
|
+
"Avoid making changes without understanding context",
|
|
50714
|
+
"Don't skip testing",
|
|
50715
|
+
"Avoid large, monolithic changes",
|
|
50716
|
+
"Don't ignore existing patterns"
|
|
50717
|
+
],
|
|
50718
|
+
bestPractices: [
|
|
50719
|
+
"Follow existing code conventions",
|
|
50720
|
+
"Write self-documenting code",
|
|
50721
|
+
"Test your changes",
|
|
50722
|
+
"Keep changes focused"
|
|
50723
|
+
]
|
|
50724
|
+
};
|
|
50725
|
+
var FULLSTACK_TEMPLATE = {
|
|
50726
|
+
...BACKEND_TEMPLATE,
|
|
50727
|
+
domain: "fullstack",
|
|
50728
|
+
displayName: "Fullstack Engineer"
|
|
50729
|
+
};
|
|
50730
|
+
var DATA_TEMPLATE = {
|
|
50731
|
+
...BACKEND_TEMPLATE,
|
|
50732
|
+
domain: "data",
|
|
50733
|
+
displayName: "Data Engineer"
|
|
50734
|
+
};
|
|
50735
|
+
var MOBILE_TEMPLATE = {
|
|
50736
|
+
...FRONTEND_TEMPLATE,
|
|
50737
|
+
domain: "mobile",
|
|
50738
|
+
displayName: "Mobile Engineer"
|
|
50739
|
+
};
|
|
50740
|
+
var RESEARCHER_TEMPLATE = {
|
|
50741
|
+
...STANDARD_TEMPLATE,
|
|
50742
|
+
domain: "researcher",
|
|
50743
|
+
displayName: "Researcher"
|
|
50744
|
+
};
|
|
50745
|
+
var AGENT_TEMPLATES = {
|
|
50746
|
+
backend: BACKEND_TEMPLATE,
|
|
50747
|
+
frontend: FRONTEND_TEMPLATE,
|
|
50748
|
+
fullstack: FULLSTACK_TEMPLATE,
|
|
50749
|
+
security: SECURITY_TEMPLATE,
|
|
50750
|
+
quality: QUALITY_TEMPLATE,
|
|
50751
|
+
architecture: ARCHITECTURE_TEMPLATE,
|
|
50752
|
+
devops: DEVOPS_TEMPLATE,
|
|
50753
|
+
data: DATA_TEMPLATE,
|
|
50754
|
+
mobile: MOBILE_TEMPLATE,
|
|
50755
|
+
writer: WRITER_TEMPLATE,
|
|
50756
|
+
researcher: RESEARCHER_TEMPLATE,
|
|
50757
|
+
standard: STANDARD_TEMPLATE
|
|
50758
|
+
};
|
|
50759
|
+
function getAgentTemplate(domain) {
|
|
50760
|
+
return AGENT_TEMPLATES[domain] ?? STANDARD_TEMPLATE;
|
|
50761
|
+
}
|
|
50762
|
+
function isValidAgentDomain(domain) {
|
|
50763
|
+
return domain in AGENT_TEMPLATES;
|
|
50764
|
+
}
|
|
50765
|
+
function getDelegationSuggestions(text, currentDomain) {
|
|
50766
|
+
const template = getAgentTemplate(currentDomain);
|
|
50767
|
+
const suggestions = [];
|
|
50768
|
+
const textLower = text.toLowerCase();
|
|
50769
|
+
for (const trigger of template.delegationTriggers) {
|
|
50770
|
+
const matchedKeywords = trigger.keywords.filter(
|
|
50771
|
+
(kw) => textLower.includes(kw.toLowerCase())
|
|
50772
|
+
);
|
|
50773
|
+
if (matchedKeywords.length > 0) {
|
|
50774
|
+
suggestions.push({
|
|
50775
|
+
agent: trigger.suggestedAgent,
|
|
50776
|
+
reason: trigger.reason,
|
|
50777
|
+
keywords: matchedKeywords
|
|
50778
|
+
});
|
|
50779
|
+
}
|
|
50780
|
+
}
|
|
50781
|
+
return suggestions;
|
|
50782
|
+
}
|
|
50783
|
+
|
|
50784
|
+
// src/agents/agent-instruction-injector.ts
|
|
50785
|
+
var DEFAULT_AGENT_CONFIG = {
|
|
50786
|
+
enabled: true,
|
|
50787
|
+
reminderFrequency: 5,
|
|
50788
|
+
delegationDetection: true,
|
|
50789
|
+
minDelegationKeywords: 1,
|
|
50790
|
+
includeQualityChecklist: true,
|
|
50791
|
+
qualityChecklistFrequency: 10,
|
|
50792
|
+
includeAntiPatterns: true,
|
|
50793
|
+
contextAwareBoosting: true
|
|
50794
|
+
};
|
|
50795
|
+
var CONTEXT_KEYWORD_CATEGORIES = [
|
|
50796
|
+
{
|
|
50797
|
+
name: "security",
|
|
50798
|
+
keywords: ["auth", "authentication", "authorization", "login", "password", "token", "jwt", "oauth", "session", "credential", "encrypt", "decrypt", "hash", "secret", "permission", "role", "access control", "csrf", "xss", "injection", "sanitize", "validate input"],
|
|
50799
|
+
boostDomains: ["security"],
|
|
50800
|
+
additionalChecklist: [
|
|
50801
|
+
"Validate all user input before processing",
|
|
50802
|
+
"Use parameterized queries to prevent injection",
|
|
50803
|
+
"Ensure sensitive data is not logged or exposed",
|
|
50804
|
+
"Implement proper session management",
|
|
50805
|
+
"Follow OWASP Top 10 guidelines"
|
|
50806
|
+
]
|
|
50807
|
+
},
|
|
50808
|
+
{
|
|
50809
|
+
name: "database",
|
|
50810
|
+
keywords: ["database", "db", "sql", "query", "migration", "schema", "table", "index", "transaction", "orm", "prisma", "mongoose", "postgresql", "mysql", "sqlite", "redis", "cache"],
|
|
50811
|
+
boostDomains: ["backend"],
|
|
50812
|
+
additionalChecklist: [
|
|
50813
|
+
"Use transactions for multi-step operations",
|
|
50814
|
+
"Add appropriate indexes for query performance",
|
|
50815
|
+
"Handle connection pooling properly",
|
|
50816
|
+
"Avoid N+1 query patterns",
|
|
50817
|
+
"Use prepared statements for security"
|
|
50818
|
+
]
|
|
50819
|
+
},
|
|
50820
|
+
{
|
|
50821
|
+
name: "api",
|
|
50822
|
+
keywords: ["api", "endpoint", "rest", "graphql", "request", "response", "http", "status code", "route", "middleware", "cors", "rate limit"],
|
|
50823
|
+
boostDomains: ["backend"],
|
|
50824
|
+
additionalChecklist: [
|
|
50825
|
+
"Use appropriate HTTP status codes",
|
|
50826
|
+
"Validate request body and parameters",
|
|
50827
|
+
"Document API with clear examples",
|
|
50828
|
+
"Implement proper error responses",
|
|
50829
|
+
"Consider rate limiting for public endpoints"
|
|
50830
|
+
]
|
|
50831
|
+
},
|
|
50832
|
+
{
|
|
50833
|
+
name: "testing",
|
|
50834
|
+
keywords: ["test", "testing", "unit test", "integration test", "e2e", "mock", "stub", "fixture", "coverage", "assert", "expect", "vitest", "jest", "cypress"],
|
|
50835
|
+
boostDomains: ["quality"],
|
|
50836
|
+
additionalChecklist: [
|
|
50837
|
+
"Test behavior, not implementation details",
|
|
50838
|
+
"Include edge cases and error scenarios",
|
|
50839
|
+
"Keep tests isolated and independent",
|
|
50840
|
+
"Use meaningful test descriptions",
|
|
50841
|
+
"Aim for high coverage on critical paths"
|
|
50842
|
+
]
|
|
50843
|
+
},
|
|
50844
|
+
{
|
|
50845
|
+
name: "performance",
|
|
50846
|
+
keywords: ["performance", "optimize", "slow", "fast", "latency", "memory", "cpu", "bottleneck", "profiling", "benchmark", "cache", "lazy load", "debounce", "throttle"],
|
|
50847
|
+
boostDomains: ["backend", "devops"],
|
|
50848
|
+
additionalChecklist: [
|
|
50849
|
+
"Profile before optimizing",
|
|
50850
|
+
"Consider caching for expensive operations",
|
|
50851
|
+
"Avoid premature optimization",
|
|
50852
|
+
"Measure impact of changes",
|
|
50853
|
+
"Watch for memory leaks"
|
|
50854
|
+
]
|
|
50855
|
+
},
|
|
50856
|
+
{
|
|
50857
|
+
name: "deployment",
|
|
50858
|
+
keywords: ["deploy", "deployment", "ci", "cd", "pipeline", "docker", "kubernetes", "container", "production", "staging", "environment", "config", "secret", "infrastructure"],
|
|
50859
|
+
boostDomains: ["devops"],
|
|
50860
|
+
additionalChecklist: [
|
|
50861
|
+
"Never hardcode secrets or credentials",
|
|
50862
|
+
"Use environment variables for configuration",
|
|
50863
|
+
"Ensure rollback strategy exists",
|
|
50864
|
+
"Test in staging before production",
|
|
50865
|
+
"Monitor deployment health"
|
|
50866
|
+
]
|
|
50867
|
+
},
|
|
50868
|
+
{
|
|
50869
|
+
name: "frontend",
|
|
50870
|
+
keywords: ["ui", "ux", "component", "react", "vue", "angular", "css", "style", "responsive", "accessibility", "a11y", "wcag", "form", "validation", "state", "render"],
|
|
50871
|
+
boostDomains: ["frontend"],
|
|
50872
|
+
additionalChecklist: [
|
|
50873
|
+
"Ensure accessibility (ARIA labels, keyboard nav)",
|
|
50874
|
+
"Handle loading and error states",
|
|
50875
|
+
"Optimize for performance (memo, lazy loading)",
|
|
50876
|
+
"Test across different screen sizes",
|
|
50877
|
+
"Validate forms with clear error messages"
|
|
50878
|
+
]
|
|
50879
|
+
}
|
|
50880
|
+
];
|
|
50881
|
+
var AgentInstructionInjector = class {
|
|
50882
|
+
name = "agent-template";
|
|
50883
|
+
config;
|
|
50884
|
+
lastReminderTurn = 0;
|
|
50885
|
+
lastQualityCheckTurn = 0;
|
|
50886
|
+
currentDomain;
|
|
50887
|
+
recentTaskText = "";
|
|
50888
|
+
constructor(config) {
|
|
50889
|
+
this.config = {
|
|
50890
|
+
...DEFAULT_AGENT_CONFIG,
|
|
50891
|
+
...config
|
|
50892
|
+
};
|
|
50893
|
+
logger.debug("AgentInstructionInjector initialized", {
|
|
50894
|
+
enabled: this.config.enabled,
|
|
50895
|
+
reminderFrequency: this.config.reminderFrequency
|
|
50896
|
+
});
|
|
50897
|
+
}
|
|
50898
|
+
/**
|
|
50899
|
+
* Set the current agent domain
|
|
50900
|
+
*/
|
|
50901
|
+
setDomain(domain) {
|
|
50902
|
+
if (isValidAgentDomain(domain)) {
|
|
50903
|
+
this.currentDomain = domain;
|
|
50904
|
+
logger.debug("Agent domain set", { domain });
|
|
50905
|
+
} else {
|
|
50906
|
+
this.currentDomain = "standard";
|
|
50907
|
+
logger.debug("Unknown domain, using standard", { domain });
|
|
50908
|
+
}
|
|
50909
|
+
}
|
|
50910
|
+
/**
|
|
50911
|
+
* Get the current domain
|
|
50912
|
+
*/
|
|
50913
|
+
getDomain() {
|
|
50914
|
+
return this.currentDomain;
|
|
50915
|
+
}
|
|
50916
|
+
/**
|
|
50917
|
+
* Check if provider should generate instructions
|
|
50918
|
+
*/
|
|
50919
|
+
shouldGenerate(context) {
|
|
50920
|
+
if (!this.config.enabled) {
|
|
50921
|
+
return false;
|
|
50922
|
+
}
|
|
50923
|
+
const domain = this.resolveDomain(context);
|
|
50924
|
+
if (!domain) {
|
|
50925
|
+
return false;
|
|
50926
|
+
}
|
|
50927
|
+
const taskText = this.extractTaskText(context);
|
|
50928
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
50929
|
+
const reminderDue = turnsSinceReminder >= this.config.reminderFrequency;
|
|
50930
|
+
const turnsSinceQuality = context.turnCount - this.lastQualityCheckTurn;
|
|
50931
|
+
const qualityDue = this.config.includeQualityChecklist && turnsSinceQuality >= this.config.qualityChecklistFrequency;
|
|
50932
|
+
const hasDelegationTriggers = this.config.delegationDetection && taskText !== this.recentTaskText && this.checkDelegationTriggers(context, domain, taskText);
|
|
50933
|
+
return reminderDue || qualityDue || hasDelegationTriggers;
|
|
50934
|
+
}
|
|
50935
|
+
/**
|
|
50936
|
+
* Generate instructions based on agent domain
|
|
50937
|
+
*/
|
|
50938
|
+
async getInstructions(context) {
|
|
50939
|
+
const instructions = [];
|
|
50940
|
+
const domain = this.resolveDomain(context);
|
|
50941
|
+
if (!domain) {
|
|
50942
|
+
return instructions;
|
|
50943
|
+
}
|
|
50944
|
+
const template = getAgentTemplate(domain);
|
|
50945
|
+
const turnsSinceReminder = context.turnCount - this.lastReminderTurn;
|
|
50946
|
+
const turnsSinceQuality = context.turnCount - this.lastQualityCheckTurn;
|
|
50947
|
+
if (turnsSinceReminder >= this.config.reminderFrequency) {
|
|
50948
|
+
const reminderContent = this.formatDomainReminders(template);
|
|
50949
|
+
instructions.push({
|
|
50950
|
+
type: "delegation",
|
|
50951
|
+
priority: "normal",
|
|
50952
|
+
content: reminderContent,
|
|
50953
|
+
source: INSTRUCTION_SOURCE,
|
|
50954
|
+
createdAt: Date.now(),
|
|
50955
|
+
createdAtTurn: context.turnCount,
|
|
50956
|
+
expiresAfter: this.config.reminderFrequency,
|
|
50957
|
+
id: `agent-reminder-${domain}-${Date.now()}`
|
|
50958
|
+
});
|
|
50959
|
+
this.lastReminderTurn = context.turnCount;
|
|
50960
|
+
}
|
|
50961
|
+
if (this.config.includeQualityChecklist && turnsSinceQuality >= this.config.qualityChecklistFrequency) {
|
|
50962
|
+
const checklistContent = this.formatQualityChecklist(template);
|
|
50963
|
+
instructions.push({
|
|
50964
|
+
type: "delegation",
|
|
50965
|
+
priority: "normal",
|
|
50966
|
+
content: checklistContent,
|
|
50967
|
+
source: INSTRUCTION_SOURCE,
|
|
50968
|
+
createdAt: Date.now(),
|
|
50969
|
+
createdAtTurn: context.turnCount,
|
|
50970
|
+
expiresAfter: this.config.qualityChecklistFrequency,
|
|
50971
|
+
id: `agent-quality-${domain}-${Date.now()}`
|
|
50972
|
+
});
|
|
50973
|
+
this.lastQualityCheckTurn = context.turnCount;
|
|
50974
|
+
}
|
|
50975
|
+
const taskText = this.extractTaskText(context);
|
|
50976
|
+
if (this.config.delegationDetection) {
|
|
50977
|
+
if (taskText !== this.recentTaskText) {
|
|
50978
|
+
this.recentTaskText = taskText;
|
|
50979
|
+
const delegationContent = this.checkAndFormatDelegation(template, taskText);
|
|
50980
|
+
if (delegationContent) {
|
|
50981
|
+
instructions.push({
|
|
50982
|
+
type: "delegation",
|
|
50983
|
+
priority: "high",
|
|
50984
|
+
content: delegationContent,
|
|
50985
|
+
source: INSTRUCTION_SOURCE,
|
|
50986
|
+
createdAt: Date.now(),
|
|
50987
|
+
createdAtTurn: context.turnCount,
|
|
50988
|
+
expiresAfter: 3,
|
|
50989
|
+
id: `agent-delegation-${Date.now()}`
|
|
50990
|
+
});
|
|
50991
|
+
}
|
|
50992
|
+
}
|
|
50993
|
+
}
|
|
50994
|
+
if (this.config.contextAwareBoosting && taskText) {
|
|
50995
|
+
const detectedCategories = this.detectContextCategories(taskText);
|
|
50996
|
+
const contextBoostContent = this.formatContextBoost(detectedCategories);
|
|
50997
|
+
if (contextBoostContent) {
|
|
50998
|
+
instructions.push({
|
|
50999
|
+
type: "context",
|
|
51000
|
+
priority: "normal",
|
|
51001
|
+
content: contextBoostContent,
|
|
51002
|
+
source: INSTRUCTION_SOURCE,
|
|
51003
|
+
createdAt: Date.now(),
|
|
51004
|
+
createdAtTurn: context.turnCount,
|
|
51005
|
+
expiresAfter: 5,
|
|
51006
|
+
id: `agent-context-boost-${Date.now()}`
|
|
51007
|
+
});
|
|
51008
|
+
logger.debug("Context-aware boost applied", {
|
|
51009
|
+
categories: detectedCategories.map((c) => c.name)
|
|
51010
|
+
});
|
|
51011
|
+
}
|
|
51012
|
+
}
|
|
51013
|
+
logger.debug("Agent instructions generated", {
|
|
51014
|
+
domain,
|
|
51015
|
+
instructionCount: instructions.length
|
|
51016
|
+
});
|
|
51017
|
+
return instructions;
|
|
51018
|
+
}
|
|
51019
|
+
/**
|
|
51020
|
+
* Resolve domain from context or current setting
|
|
51021
|
+
*/
|
|
51022
|
+
resolveDomain(context) {
|
|
51023
|
+
if (context.agentName && isValidAgentDomain(context.agentName)) {
|
|
51024
|
+
return context.agentName;
|
|
51025
|
+
}
|
|
51026
|
+
return this.currentDomain;
|
|
51027
|
+
}
|
|
51028
|
+
/**
|
|
51029
|
+
* Extract task text from context for delegation detection
|
|
51030
|
+
*/
|
|
51031
|
+
extractTaskText(context) {
|
|
51032
|
+
const parts = [];
|
|
51033
|
+
if (context.currentTask) {
|
|
51034
|
+
parts.push(context.currentTask);
|
|
51035
|
+
}
|
|
51036
|
+
for (const todo of context.todos) {
|
|
51037
|
+
if (todo.status === "in_progress") {
|
|
51038
|
+
parts.push(todo.content);
|
|
51039
|
+
}
|
|
51040
|
+
}
|
|
51041
|
+
return parts.join(" ");
|
|
51042
|
+
}
|
|
51043
|
+
/**
|
|
51044
|
+
* Check if delegation triggers are present
|
|
51045
|
+
*/
|
|
51046
|
+
checkDelegationTriggers(context, domain, taskText) {
|
|
51047
|
+
const resolvedDomain = domain ?? this.resolveDomain(context);
|
|
51048
|
+
if (!resolvedDomain) return false;
|
|
51049
|
+
const text = taskText ?? this.extractTaskText(context);
|
|
51050
|
+
if (!text) return false;
|
|
51051
|
+
const suggestions = getDelegationSuggestions(text, resolvedDomain);
|
|
51052
|
+
return suggestions.some((s) => s.keywords.length >= this.config.minDelegationKeywords);
|
|
51053
|
+
}
|
|
51054
|
+
/**
|
|
51055
|
+
* Format domain reminders
|
|
51056
|
+
*/
|
|
51057
|
+
formatDomainReminders(template) {
|
|
51058
|
+
const lines = [
|
|
51059
|
+
`## ${template.displayName} Reminders`,
|
|
51060
|
+
""
|
|
51061
|
+
];
|
|
51062
|
+
for (const reminder of template.domainReminders) {
|
|
51063
|
+
lines.push(`- ${reminder}`);
|
|
51064
|
+
}
|
|
51065
|
+
if (this.config.includeAntiPatterns && template.antiPatterns.length > 0) {
|
|
51066
|
+
lines.push("");
|
|
51067
|
+
lines.push("**Avoid:**");
|
|
51068
|
+
for (const antiPattern of template.antiPatterns.slice(0, 3)) {
|
|
51069
|
+
lines.push(`- ${antiPattern}`);
|
|
51070
|
+
}
|
|
51071
|
+
}
|
|
51072
|
+
return lines.join("\n");
|
|
51073
|
+
}
|
|
51074
|
+
/**
|
|
51075
|
+
* Format quality checklist
|
|
51076
|
+
*/
|
|
51077
|
+
formatQualityChecklist(template) {
|
|
51078
|
+
const lines = [
|
|
51079
|
+
`## Quality Checklist (${template.displayName})`,
|
|
51080
|
+
"",
|
|
51081
|
+
"Before completing, verify:"
|
|
51082
|
+
];
|
|
51083
|
+
for (const item of template.qualityChecklist) {
|
|
51084
|
+
lines.push(`- [ ] ${item}`);
|
|
51085
|
+
}
|
|
51086
|
+
return lines.join("\n");
|
|
51087
|
+
}
|
|
51088
|
+
/**
|
|
51089
|
+
* Check for delegation triggers and format suggestion
|
|
51090
|
+
*/
|
|
51091
|
+
checkAndFormatDelegation(template, taskText) {
|
|
51092
|
+
const suggestions = getDelegationSuggestions(taskText, template.domain);
|
|
51093
|
+
const relevantSuggestions = suggestions.filter(
|
|
51094
|
+
(s) => s.keywords.length >= this.config.minDelegationKeywords
|
|
51095
|
+
);
|
|
51096
|
+
if (relevantSuggestions.length === 0) {
|
|
51097
|
+
return null;
|
|
51098
|
+
}
|
|
51099
|
+
const lines = [
|
|
51100
|
+
"## Delegation Suggestion",
|
|
51101
|
+
""
|
|
51102
|
+
];
|
|
51103
|
+
for (const suggestion of relevantSuggestions) {
|
|
51104
|
+
lines.push(`**Consider delegating to @${suggestion.agent}**`);
|
|
51105
|
+
lines.push(`- Reason: ${suggestion.reason}`);
|
|
51106
|
+
lines.push(`- Triggered by: ${suggestion.keywords.join(", ")}`);
|
|
51107
|
+
lines.push("");
|
|
51108
|
+
}
|
|
51109
|
+
lines.push("Use `DELEGATE TO @agent: task` or `@agent task` syntax to delegate.");
|
|
51110
|
+
return lines.join("\n");
|
|
51111
|
+
}
|
|
51112
|
+
/**
|
|
51113
|
+
* Detect context categories from task text
|
|
51114
|
+
* @since v11.3.1
|
|
51115
|
+
*/
|
|
51116
|
+
detectContextCategories(taskText) {
|
|
51117
|
+
if (!taskText || !this.config.contextAwareBoosting) {
|
|
51118
|
+
return [];
|
|
51119
|
+
}
|
|
51120
|
+
const textLower = taskText.toLowerCase();
|
|
51121
|
+
const matchedCategories = [];
|
|
51122
|
+
for (const category of CONTEXT_KEYWORD_CATEGORIES) {
|
|
51123
|
+
const matchCount = category.keywords.filter(
|
|
51124
|
+
(kw) => textLower.includes(kw.toLowerCase())
|
|
51125
|
+
).length;
|
|
51126
|
+
if (matchCount > 0) {
|
|
51127
|
+
matchedCategories.push(category);
|
|
51128
|
+
}
|
|
51129
|
+
}
|
|
51130
|
+
return matchedCategories;
|
|
51131
|
+
}
|
|
51132
|
+
/**
|
|
51133
|
+
* Format context-aware boosted instructions
|
|
51134
|
+
* @since v11.3.1
|
|
51135
|
+
*/
|
|
51136
|
+
formatContextBoost(categories) {
|
|
51137
|
+
if (categories.length === 0) {
|
|
51138
|
+
return null;
|
|
51139
|
+
}
|
|
51140
|
+
const lines = [];
|
|
51141
|
+
const allChecklistItems = /* @__PURE__ */ new Set();
|
|
51142
|
+
const categoryNames = [];
|
|
51143
|
+
for (const category of categories) {
|
|
51144
|
+
categoryNames.push(category.name);
|
|
51145
|
+
for (const item of category.additionalChecklist.slice(0, 3)) {
|
|
51146
|
+
allChecklistItems.add(item);
|
|
51147
|
+
}
|
|
51148
|
+
}
|
|
51149
|
+
if (allChecklistItems.size === 0) {
|
|
51150
|
+
return null;
|
|
51151
|
+
}
|
|
51152
|
+
lines.push(`## Context-Aware Reminders (${categoryNames.join(", ")})`);
|
|
51153
|
+
lines.push("");
|
|
51154
|
+
lines.push("Based on task keywords, ensure you:");
|
|
51155
|
+
for (const item of Array.from(allChecklistItems).slice(0, 5)) {
|
|
51156
|
+
lines.push(`- ${item}`);
|
|
51157
|
+
}
|
|
51158
|
+
return lines.join("\n");
|
|
51159
|
+
}
|
|
51160
|
+
/**
|
|
51161
|
+
* Get current configuration
|
|
51162
|
+
*/
|
|
51163
|
+
getConfig() {
|
|
51164
|
+
return { ...this.config };
|
|
51165
|
+
}
|
|
51166
|
+
/**
|
|
51167
|
+
* Update configuration
|
|
51168
|
+
*/
|
|
51169
|
+
updateConfig(updates) {
|
|
51170
|
+
this.config = {
|
|
51171
|
+
...this.config,
|
|
51172
|
+
...updates
|
|
51173
|
+
};
|
|
51174
|
+
logger.debug("AgentInstructionInjector config updated", {
|
|
51175
|
+
enabled: this.config.enabled
|
|
51176
|
+
});
|
|
51177
|
+
}
|
|
51178
|
+
/**
|
|
51179
|
+
* Reset state
|
|
51180
|
+
*/
|
|
51181
|
+
reset() {
|
|
51182
|
+
this.lastReminderTurn = 0;
|
|
51183
|
+
this.lastQualityCheckTurn = 0;
|
|
51184
|
+
this.recentTaskText = "";
|
|
51185
|
+
logger.debug("AgentInstructionInjector reset");
|
|
51186
|
+
}
|
|
51187
|
+
};
|
|
51188
|
+
|
|
51189
|
+
// src/core/orchestration/orchestration-service.ts
|
|
51190
|
+
var OrchestrationService = class {
|
|
51191
|
+
config;
|
|
51192
|
+
injector;
|
|
51193
|
+
tokenBudgetManager;
|
|
51194
|
+
workflowModeManager;
|
|
51195
|
+
agentInjector;
|
|
51196
|
+
todoProvider;
|
|
51197
|
+
memoryProvider;
|
|
51198
|
+
sessionProvider;
|
|
51199
|
+
turnCount = 0;
|
|
51200
|
+
currentTodos = [];
|
|
51201
|
+
constructor(serviceConfig = {}) {
|
|
51202
|
+
this.config = {
|
|
51203
|
+
...DEFAULT_ORCHESTRATION_CONFIG,
|
|
51204
|
+
...serviceConfig
|
|
51205
|
+
};
|
|
51206
|
+
this.injector = new OrchestrationInstructionInjector(this.config);
|
|
51207
|
+
this.tokenBudgetManager = new TokenBudgetManager(this.config.tokenBudget);
|
|
51208
|
+
this.workflowModeManager = new WorkflowModeManager();
|
|
51209
|
+
this.agentInjector = new AgentInstructionInjector({
|
|
51210
|
+
enabled: this.config.agentTemplates?.enabled ?? true,
|
|
51211
|
+
reminderFrequency: this.config.agentTemplates?.reminderFrequency ?? 5
|
|
51212
|
+
});
|
|
51213
|
+
this.initializeProviders(serviceConfig);
|
|
51214
|
+
logger.debug("OrchestrationService initialized", {
|
|
51215
|
+
todoEnabled: this.config.todoIntegration?.enabled,
|
|
51216
|
+
memoryEnabled: this.config.memoryIntegration?.enabled,
|
|
51217
|
+
sessionEnabled: this.config.sessionIntegration?.enabled,
|
|
51218
|
+
agentTemplatesEnabled: this.config.agentTemplates?.enabled
|
|
51219
|
+
});
|
|
51220
|
+
}
|
|
51221
|
+
/**
|
|
51222
|
+
* Initialize instruction providers
|
|
51223
|
+
*/
|
|
51224
|
+
initializeProviders(serviceConfig) {
|
|
51225
|
+
if (this.config.todoIntegration?.enabled !== false) {
|
|
51226
|
+
this.todoProvider = new TodoInstructionProvider({
|
|
51227
|
+
enabled: true,
|
|
51228
|
+
reminderFrequency: this.config.todoIntegration?.reminderFrequency ?? 3,
|
|
51229
|
+
compactMode: this.config.todoIntegration?.compactMode ?? false
|
|
51230
|
+
});
|
|
51231
|
+
this.injector.registerProvider(this.todoProvider);
|
|
51232
|
+
}
|
|
51233
|
+
if (this.config.memoryIntegration?.enabled !== false && serviceConfig.memorySearchProvider) {
|
|
51234
|
+
this.memoryProvider = new MemoryInstructionProvider(
|
|
51235
|
+
serviceConfig.memorySearchProvider,
|
|
51236
|
+
{
|
|
51237
|
+
enabled: true,
|
|
51238
|
+
maxEntries: this.config.memoryIntegration?.maxEntries ?? 5,
|
|
51239
|
+
minRelevance: this.config.memoryIntegration?.minRelevance ?? 0.5
|
|
51240
|
+
}
|
|
51241
|
+
);
|
|
51242
|
+
this.injector.registerProvider(this.memoryProvider);
|
|
51243
|
+
}
|
|
51244
|
+
if (this.config.sessionIntegration?.enabled !== false) {
|
|
51245
|
+
this.sessionProvider = new SessionInstructionProvider(
|
|
51246
|
+
serviceConfig.sessionStateProvider,
|
|
51247
|
+
{
|
|
51248
|
+
enabled: true,
|
|
51249
|
+
showCollaboration: this.config.sessionIntegration?.showCollaboration ?? true,
|
|
51250
|
+
showProgress: true,
|
|
51251
|
+
reminderFrequency: 5,
|
|
51252
|
+
showHandoffContext: true
|
|
51253
|
+
}
|
|
51254
|
+
);
|
|
51255
|
+
this.injector.registerProvider(this.sessionProvider);
|
|
51256
|
+
}
|
|
51257
|
+
if (this.config.agentTemplates?.enabled !== false) {
|
|
51258
|
+
if (serviceConfig.agentDomain) {
|
|
51259
|
+
this.agentInjector.setDomain(serviceConfig.agentDomain);
|
|
51260
|
+
}
|
|
51261
|
+
this.injector.registerProvider(this.agentInjector);
|
|
51262
|
+
}
|
|
51263
|
+
}
|
|
51264
|
+
/**
|
|
51265
|
+
* Set the current agent domain for agent-specific instructions
|
|
51266
|
+
*/
|
|
51267
|
+
setAgentDomain(domain) {
|
|
51268
|
+
this.agentInjector.setDomain(domain);
|
|
51269
|
+
logger.debug("Agent domain set", { domain });
|
|
51270
|
+
}
|
|
51271
|
+
/**
|
|
51272
|
+
* Set the memory search provider
|
|
51273
|
+
*/
|
|
51274
|
+
setMemoryProvider(provider) {
|
|
51275
|
+
if (this.memoryProvider) {
|
|
51276
|
+
this.memoryProvider.setSearchProvider(provider);
|
|
51277
|
+
} else if (this.config.memoryIntegration?.enabled !== false) {
|
|
51278
|
+
this.memoryProvider = new MemoryInstructionProvider(provider, {
|
|
51279
|
+
enabled: true,
|
|
51280
|
+
maxEntries: this.config.memoryIntegration?.maxEntries ?? 5,
|
|
51281
|
+
minRelevance: this.config.memoryIntegration?.minRelevance ?? 0.5
|
|
51282
|
+
});
|
|
51283
|
+
this.injector.registerProvider(this.memoryProvider);
|
|
51284
|
+
}
|
|
51285
|
+
}
|
|
51286
|
+
/**
|
|
51287
|
+
* Set the session state provider
|
|
51288
|
+
*/
|
|
51289
|
+
setSessionProvider(provider) {
|
|
51290
|
+
if (this.sessionProvider) {
|
|
51291
|
+
this.sessionProvider.setStateProvider(provider);
|
|
51292
|
+
}
|
|
51293
|
+
}
|
|
51294
|
+
/**
|
|
51295
|
+
* Update the current todo list
|
|
51296
|
+
*/
|
|
51297
|
+
updateTodos(todos) {
|
|
51298
|
+
this.currentTodos = todos;
|
|
51299
|
+
}
|
|
51300
|
+
/**
|
|
51301
|
+
* Set the workflow mode
|
|
51302
|
+
*
|
|
51303
|
+
* @throws Error if mode is not a valid WorkflowMode
|
|
51304
|
+
*/
|
|
51305
|
+
setWorkflowMode(mode) {
|
|
51306
|
+
if (!isValidWorkflowMode(mode)) {
|
|
51307
|
+
throw new Error(`Invalid workflow mode: ${mode}. Valid modes: default, plan, iterate, review`);
|
|
51308
|
+
}
|
|
51309
|
+
this.workflowModeManager.setMode(mode);
|
|
51310
|
+
logger.debug("Workflow mode set", { mode });
|
|
51311
|
+
}
|
|
51312
|
+
/**
|
|
51313
|
+
* Get current workflow mode
|
|
51314
|
+
*/
|
|
51315
|
+
getWorkflowMode() {
|
|
51316
|
+
return this.workflowModeManager.getCurrentMode();
|
|
51317
|
+
}
|
|
51318
|
+
/**
|
|
51319
|
+
* Check if a tool is allowed in current workflow mode
|
|
51320
|
+
*/
|
|
51321
|
+
isToolAllowed(toolName) {
|
|
51322
|
+
return this.workflowModeManager.isToolAllowed(toolName);
|
|
51323
|
+
}
|
|
51324
|
+
/**
|
|
51325
|
+
* Filter tools based on current workflow mode
|
|
51326
|
+
*/
|
|
51327
|
+
filterTools(tools) {
|
|
51328
|
+
return this.workflowModeManager.filterTools(tools);
|
|
51329
|
+
}
|
|
51330
|
+
/**
|
|
51331
|
+
* Increment turn count (called after each agent response)
|
|
51332
|
+
*/
|
|
51333
|
+
incrementTurn() {
|
|
51334
|
+
this.turnCount++;
|
|
51335
|
+
this.workflowModeManager.updateTurnCount(this.turnCount);
|
|
51336
|
+
}
|
|
51337
|
+
/**
|
|
51338
|
+
* Get current turn count
|
|
51339
|
+
*/
|
|
51340
|
+
getTurnCount() {
|
|
51341
|
+
return this.turnCount;
|
|
51342
|
+
}
|
|
51343
|
+
/**
|
|
51344
|
+
* Generate and inject instructions for the current context
|
|
51345
|
+
*/
|
|
51346
|
+
async injectInstructions(options = {}) {
|
|
51347
|
+
const context = {
|
|
51348
|
+
todos: this.currentTodos,
|
|
51349
|
+
turnCount: this.turnCount,
|
|
51350
|
+
workflowMode: this.workflowModeManager.getCurrentMode(),
|
|
51351
|
+
currentTask: options.task,
|
|
51352
|
+
agentName: options.agentName,
|
|
51353
|
+
sessionId: options.sessionId,
|
|
51354
|
+
parentAgent: options.parentAgent
|
|
51355
|
+
};
|
|
51356
|
+
const result = await this.injector.inject(context);
|
|
51357
|
+
logger.debug("Instructions injected", {
|
|
51358
|
+
instructionCount: result.instructions.length,
|
|
51359
|
+
tokensUsed: result.allocation.tokensUsed,
|
|
51360
|
+
hasInstructions: result.hasInstructions
|
|
51361
|
+
});
|
|
51362
|
+
return {
|
|
51363
|
+
content: result.formattedText,
|
|
51364
|
+
instructions: result.instructions,
|
|
51365
|
+
tokenCount: result.allocation.tokensUsed,
|
|
51366
|
+
applied: result.hasInstructions
|
|
51367
|
+
};
|
|
51368
|
+
}
|
|
51369
|
+
/**
|
|
51370
|
+
* Format instructions as system reminder tags
|
|
51371
|
+
*/
|
|
51372
|
+
formatAsSystemReminder(content) {
|
|
51373
|
+
if (!content || content.trim().length === 0) {
|
|
51374
|
+
return "";
|
|
51375
|
+
}
|
|
51376
|
+
return `<system-reminder>
|
|
51377
|
+
${content}
|
|
51378
|
+
</system-reminder>`;
|
|
51379
|
+
}
|
|
51380
|
+
/**
|
|
51381
|
+
* Get debug information about current orchestration state
|
|
51382
|
+
*/
|
|
51383
|
+
getDebugInfo() {
|
|
51384
|
+
const budgetConfig = this.tokenBudgetManager.getConfig();
|
|
51385
|
+
const providers = this.injector.getProviders().map((p) => p.name);
|
|
51386
|
+
return {
|
|
51387
|
+
turnCount: this.turnCount,
|
|
51388
|
+
workflowMode: this.workflowModeManager.getCurrentMode(),
|
|
51389
|
+
todoCount: this.currentTodos.length,
|
|
51390
|
+
providers,
|
|
51391
|
+
tokenBudget: {
|
|
51392
|
+
used: 0,
|
|
51393
|
+
// Would need to track this
|
|
51394
|
+
total: budgetConfig.maxTotal,
|
|
51395
|
+
remaining: budgetConfig.maxTotal
|
|
51396
|
+
}
|
|
51397
|
+
};
|
|
51398
|
+
}
|
|
51399
|
+
/**
|
|
51400
|
+
* Reset all state (for new conversations)
|
|
51401
|
+
*/
|
|
51402
|
+
reset() {
|
|
51403
|
+
this.turnCount = 0;
|
|
51404
|
+
this.currentTodos = [];
|
|
51405
|
+
this.workflowModeManager.reset();
|
|
51406
|
+
this.agentInjector.reset();
|
|
51407
|
+
this.injector.clearCache();
|
|
51408
|
+
if (this.todoProvider) {
|
|
51409
|
+
this.todoProvider.reset();
|
|
51410
|
+
}
|
|
51411
|
+
if (this.memoryProvider) {
|
|
51412
|
+
this.memoryProvider.clearCache();
|
|
51413
|
+
}
|
|
51414
|
+
if (this.sessionProvider) {
|
|
51415
|
+
this.sessionProvider.reset();
|
|
51416
|
+
}
|
|
51417
|
+
logger.debug("OrchestrationService reset");
|
|
51418
|
+
}
|
|
51419
|
+
/**
|
|
51420
|
+
* Update configuration
|
|
51421
|
+
*/
|
|
51422
|
+
updateConfig(updates) {
|
|
51423
|
+
this.config = {
|
|
51424
|
+
...this.config,
|
|
51425
|
+
...updates,
|
|
51426
|
+
tokenBudget: updates.tokenBudget ? { ...this.config.tokenBudget, ...updates.tokenBudget } : this.config.tokenBudget,
|
|
51427
|
+
todoIntegration: updates.todoIntegration ? { ...this.config.todoIntegration, ...updates.todoIntegration } : this.config.todoIntegration,
|
|
51428
|
+
memoryIntegration: updates.memoryIntegration ? { ...this.config.memoryIntegration, ...updates.memoryIntegration } : this.config.memoryIntegration,
|
|
51429
|
+
sessionIntegration: updates.sessionIntegration ? { ...this.config.sessionIntegration, ...updates.sessionIntegration } : this.config.sessionIntegration,
|
|
51430
|
+
agentTemplates: updates.agentTemplates ? { ...this.config.agentTemplates, ...updates.agentTemplates } : this.config.agentTemplates
|
|
51431
|
+
};
|
|
51432
|
+
if (updates.tokenBudget) {
|
|
51433
|
+
this.tokenBudgetManager.updateConfig(this.config.tokenBudget);
|
|
51434
|
+
}
|
|
51435
|
+
this.injector.updateConfig(updates);
|
|
51436
|
+
if (updates.todoIntegration && this.todoProvider) {
|
|
51437
|
+
const current = this.todoProvider.getConfig();
|
|
51438
|
+
this.todoProvider.updateConfig({
|
|
51439
|
+
enabled: updates.todoIntegration.enabled ?? current.enabled,
|
|
51440
|
+
reminderFrequency: updates.todoIntegration.reminderFrequency ?? current.reminderFrequency,
|
|
51441
|
+
compactMode: updates.todoIntegration.compactMode ?? current.compactMode
|
|
51442
|
+
});
|
|
51443
|
+
}
|
|
51444
|
+
if (updates.memoryIntegration && this.memoryProvider) {
|
|
51445
|
+
const current = this.memoryProvider.getConfig();
|
|
51446
|
+
this.memoryProvider.updateConfig({
|
|
51447
|
+
enabled: updates.memoryIntegration.enabled ?? current.enabled,
|
|
51448
|
+
maxEntries: updates.memoryIntegration.maxEntries ?? current.maxEntries,
|
|
51449
|
+
minRelevance: updates.memoryIntegration.minRelevance ?? current.minRelevance
|
|
51450
|
+
});
|
|
51451
|
+
}
|
|
51452
|
+
if (updates.sessionIntegration && this.sessionProvider) {
|
|
51453
|
+
const current = this.sessionProvider.getConfig();
|
|
51454
|
+
this.sessionProvider.updateConfig({
|
|
51455
|
+
enabled: updates.sessionIntegration.enabled ?? current.enabled,
|
|
51456
|
+
showCollaboration: updates.sessionIntegration.showCollaboration ?? current.showCollaboration
|
|
51457
|
+
});
|
|
51458
|
+
}
|
|
51459
|
+
if (updates.agentTemplates) {
|
|
51460
|
+
const agentUpdates = {};
|
|
51461
|
+
if (updates.agentTemplates.enabled !== void 0) {
|
|
51462
|
+
agentUpdates.enabled = updates.agentTemplates.enabled;
|
|
51463
|
+
}
|
|
51464
|
+
if (updates.agentTemplates.reminderFrequency !== void 0) {
|
|
51465
|
+
agentUpdates.reminderFrequency = updates.agentTemplates.reminderFrequency;
|
|
51466
|
+
}
|
|
51467
|
+
this.agentInjector.updateConfig(agentUpdates);
|
|
51468
|
+
}
|
|
51469
|
+
logger.debug("OrchestrationService config updated", { updates });
|
|
51470
|
+
}
|
|
51471
|
+
/**
|
|
51472
|
+
* Get current configuration
|
|
51473
|
+
*/
|
|
51474
|
+
getConfig() {
|
|
51475
|
+
return { ...this.config };
|
|
51476
|
+
}
|
|
51477
|
+
};
|
|
51478
|
+
|
|
51479
|
+
// src/cli/commands/debug-instructions.ts
|
|
51480
|
+
var debugInstructionsCommand = {
|
|
51481
|
+
command: "debug:instructions",
|
|
51482
|
+
describe: "Show current embedded instructions state (v11.3.0)",
|
|
51483
|
+
builder: (yargs2) => {
|
|
51484
|
+
return yargs2.option("tokens", {
|
|
51485
|
+
alias: "t",
|
|
51486
|
+
describe: "Show token budget details",
|
|
51487
|
+
type: "boolean",
|
|
51488
|
+
default: false
|
|
51489
|
+
}).option("providers", {
|
|
51490
|
+
alias: "p",
|
|
51491
|
+
describe: "Show registered instruction providers",
|
|
51492
|
+
type: "boolean",
|
|
51493
|
+
default: false
|
|
51494
|
+
}).option("templates", {
|
|
51495
|
+
describe: "Show available agent templates",
|
|
51496
|
+
type: "boolean",
|
|
51497
|
+
default: false
|
|
51498
|
+
}).option("agent", {
|
|
51499
|
+
alias: "a",
|
|
51500
|
+
describe: "Show template for specific agent domain",
|
|
51501
|
+
type: "string"
|
|
51502
|
+
}).option("verbose", {
|
|
51503
|
+
alias: "v",
|
|
51504
|
+
describe: "Show verbose output",
|
|
51505
|
+
type: "boolean",
|
|
51506
|
+
default: false
|
|
51507
|
+
}).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");
|
|
51508
|
+
},
|
|
51509
|
+
handler: async (argv) => {
|
|
51510
|
+
try {
|
|
51511
|
+
if (argv.tokens) {
|
|
51512
|
+
displayTokenBudget(argv.verbose);
|
|
51513
|
+
return;
|
|
51514
|
+
}
|
|
51515
|
+
if (argv.providers) {
|
|
51516
|
+
displayProviders(argv.verbose);
|
|
51517
|
+
return;
|
|
51518
|
+
}
|
|
51519
|
+
if (argv.templates) {
|
|
51520
|
+
displayAgentTemplates(argv.verbose);
|
|
51521
|
+
return;
|
|
51522
|
+
}
|
|
51523
|
+
if (argv.agent) {
|
|
51524
|
+
displayAgentTemplate(argv.agent, argv.verbose);
|
|
51525
|
+
return;
|
|
51526
|
+
}
|
|
51527
|
+
displayOverallState(argv.verbose);
|
|
51528
|
+
} catch (error) {
|
|
51529
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
51530
|
+
console.error(chalk5.red.bold(`
|
|
51531
|
+
\u274C Error: ${err.message}
|
|
51532
|
+
`));
|
|
51533
|
+
logger.error("Debug instructions command failed", { error: err.message });
|
|
51534
|
+
process.exit(1);
|
|
51535
|
+
}
|
|
51536
|
+
}
|
|
51537
|
+
};
|
|
51538
|
+
function displayOverallState(verbose) {
|
|
51539
|
+
console.log(chalk5.blue.bold("\n\u{1F50D} Embedded Instructions Debug Info\n"));
|
|
51540
|
+
console.log(chalk5.dim("\u2550".repeat(60)));
|
|
51541
|
+
const service = new OrchestrationService();
|
|
51542
|
+
const debugInfo = service.getDebugInfo();
|
|
51543
|
+
console.log(chalk5.cyan("\n\u{1F4CA} Current State"));
|
|
51544
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51545
|
+
console.log(` Turn count: ${chalk5.yellow(debugInfo.turnCount)}`);
|
|
51546
|
+
console.log(` Workflow mode: ${chalk5.cyan(debugInfo.workflowMode)}`);
|
|
51547
|
+
console.log(` Active todos: ${chalk5.yellow(debugInfo.todoCount)}`);
|
|
51548
|
+
console.log(` Registered providers: ${chalk5.green(debugInfo.providers.length)}`);
|
|
51549
|
+
console.log(chalk5.cyan("\n\u{1F4B0} Token Budget"));
|
|
51550
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51551
|
+
console.log(` Used: ${chalk5.yellow(debugInfo.tokenBudget.used)} / ${debugInfo.tokenBudget.total}`);
|
|
51552
|
+
const usagePercent = Math.round(debugInfo.tokenBudget.used / debugInfo.tokenBudget.total * 100);
|
|
51553
|
+
const barLength = 30;
|
|
51554
|
+
const filledLength = Math.round(usagePercent / 100 * barLength);
|
|
51555
|
+
const bar = "\u2588".repeat(filledLength) + "\u2591".repeat(barLength - filledLength);
|
|
51556
|
+
const barColor = usagePercent > 80 ? chalk5.red : usagePercent > 50 ? chalk5.yellow : chalk5.green;
|
|
51557
|
+
console.log(` ${barColor(bar)} ${usagePercent}%`);
|
|
51558
|
+
if (debugInfo.providers.length > 0) {
|
|
51559
|
+
console.log(chalk5.cyan("\n\u{1F50C} Active Providers"));
|
|
51560
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51561
|
+
debugInfo.providers.forEach((provider, index) => {
|
|
51562
|
+
console.log(` ${index + 1}. ${chalk5.green(provider)}`);
|
|
51563
|
+
});
|
|
51564
|
+
}
|
|
51565
|
+
console.log(chalk5.cyan("\n\u{1F504} Workflow Modes"));
|
|
51566
|
+
console.log(chalk5.dim("\u2500".repeat(40)));
|
|
51567
|
+
Object.keys(WORKFLOW_MODES).forEach((mode) => {
|
|
51568
|
+
const isCurrent = mode === debugInfo.workflowMode;
|
|
51569
|
+
const prefix = isCurrent ? chalk5.green("\u25BA") : " ";
|
|
51570
|
+
const modeText = isCurrent ? chalk5.green.bold(mode) : chalk5.gray(mode);
|
|
51571
|
+
console.log(` ${prefix} ${modeText}`);
|
|
51572
|
+
});
|
|
51573
|
+
console.log(chalk5.dim("\n" + "\u2550".repeat(60)));
|
|
51574
|
+
console.log(chalk5.gray("\nUse --tokens, --providers, or --templates for detailed info.\n"));
|
|
51575
|
+
}
|
|
51576
|
+
function displayTokenBudget(verbose) {
|
|
51577
|
+
console.log(chalk5.blue.bold("\n\u{1F4B0} Token Budget Details\n"));
|
|
51578
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
51579
|
+
const budgetManager = new TokenBudgetManager();
|
|
51580
|
+
const config = budgetManager.getConfig();
|
|
51581
|
+
console.log(`
|
|
51582
|
+
Total budget: ${chalk5.cyan(config.maxTotal)} tokens`);
|
|
51583
|
+
console.log(` Critical reserve: ${chalk5.yellow(config.criticalReserve)} tokens`);
|
|
51584
|
+
console.log(` Available: ${chalk5.green(config.maxTotal - config.criticalReserve)} tokens`);
|
|
51585
|
+
console.log(chalk5.cyan("\n Per-Type Allocations:"));
|
|
51586
|
+
const typeDescriptions = {
|
|
51587
|
+
task: "Todo/task reminders",
|
|
51588
|
+
memory: "Memory context",
|
|
51589
|
+
session: "Session state",
|
|
51590
|
+
delegation: "Agent delegation hints",
|
|
51591
|
+
mode: "Workflow mode instructions",
|
|
51592
|
+
context: "Context-aware boosted reminders"
|
|
51593
|
+
};
|
|
51594
|
+
Object.entries(config.perType).forEach(([type, budget]) => {
|
|
51595
|
+
console.log(` \u2022 ${chalk5.cyan(type)}: ${budget} tokens`);
|
|
51596
|
+
if (verbose && typeDescriptions[type]) {
|
|
51597
|
+
console.log(chalk5.gray(` ${typeDescriptions[type]}`));
|
|
51598
|
+
}
|
|
51599
|
+
});
|
|
51600
|
+
console.log(chalk5.cyan("\n Token Estimation:"));
|
|
51601
|
+
console.log(chalk5.gray(" ~4 characters = 1 token (approximation)"));
|
|
51602
|
+
console.log(chalk5.gray(" Actual usage may vary by content"));
|
|
51603
|
+
console.log(chalk5.dim("\n\u2500".repeat(50)));
|
|
51604
|
+
console.log();
|
|
51605
|
+
}
|
|
51606
|
+
function displayProviders(verbose) {
|
|
51607
|
+
console.log(chalk5.blue.bold("\n\u{1F50C} Instruction Providers\n"));
|
|
51608
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
51609
|
+
const providers = [
|
|
51610
|
+
{
|
|
51611
|
+
name: "TodoInstructionProvider",
|
|
51612
|
+
description: "Generates task reminders from todo list",
|
|
51613
|
+
triggers: "Todo state changes, periodic reminders",
|
|
51614
|
+
priority: "high"
|
|
51615
|
+
},
|
|
51616
|
+
{
|
|
51617
|
+
name: "MemoryInstructionProvider",
|
|
51618
|
+
description: "Injects relevant context from memory",
|
|
51619
|
+
triggers: "Task keywords, memory relevance",
|
|
51620
|
+
priority: "normal"
|
|
51621
|
+
},
|
|
51622
|
+
{
|
|
51623
|
+
name: "SessionInstructionProvider",
|
|
51624
|
+
description: "Shows multi-agent collaboration state",
|
|
51625
|
+
triggers: "Session changes, periodic reminders",
|
|
51626
|
+
priority: "normal"
|
|
51627
|
+
},
|
|
51628
|
+
{
|
|
51629
|
+
name: "AgentInstructionInjector",
|
|
51630
|
+
description: "Domain-specific reminders and delegation hints",
|
|
51631
|
+
triggers: "Agent domain, task keywords",
|
|
51632
|
+
priority: "normal"
|
|
51633
|
+
},
|
|
51634
|
+
{
|
|
51635
|
+
name: "WorkflowModeManager",
|
|
51636
|
+
description: "Mode-specific instructions and tool filtering",
|
|
51637
|
+
triggers: "Mode changes",
|
|
51638
|
+
priority: "high"
|
|
51639
|
+
}
|
|
51640
|
+
];
|
|
51641
|
+
providers.forEach((provider, index) => {
|
|
51642
|
+
console.log(`
|
|
51643
|
+
${index + 1}. ${chalk5.cyan.bold(provider.name)}`);
|
|
51644
|
+
console.log(chalk5.gray(` ${provider.description}`));
|
|
51645
|
+
if (verbose) {
|
|
51646
|
+
console.log(` Triggers: ${chalk5.yellow(provider.triggers)}`);
|
|
51647
|
+
console.log(` Priority: ${chalk5.green(provider.priority)}`);
|
|
51648
|
+
}
|
|
51649
|
+
});
|
|
51650
|
+
console.log(chalk5.dim("\n\u2500".repeat(50)));
|
|
51651
|
+
console.log();
|
|
51652
|
+
}
|
|
51653
|
+
function displayAgentTemplates(verbose) {
|
|
51654
|
+
console.log(chalk5.blue.bold("\n\u{1F4CB} Agent Instruction Templates\n"));
|
|
51655
|
+
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
51656
|
+
for (const [domain, template] of Object.entries(AGENT_TEMPLATES)) {
|
|
51657
|
+
console.log(`
|
|
51658
|
+
${chalk5.cyan.bold(template.displayName)} (${domain})`);
|
|
51659
|
+
if (verbose) {
|
|
51660
|
+
console.log(chalk5.gray(` Reminders: ${template.domainReminders.length}`));
|
|
51661
|
+
console.log(chalk5.gray(` Checklist items: ${template.qualityChecklist.length}`));
|
|
51662
|
+
console.log(chalk5.gray(` Delegation triggers: ${template.delegationTriggers.length}`));
|
|
51663
|
+
console.log(chalk5.gray(` Anti-patterns: ${template.antiPatterns.length}`));
|
|
51664
|
+
console.log(chalk5.gray(` Best practices: ${template.bestPractices.length}`));
|
|
51665
|
+
}
|
|
51666
|
+
}
|
|
51667
|
+
console.log(chalk5.dim("\n\u2500".repeat(50)));
|
|
51668
|
+
console.log(chalk5.gray("\nUse --agent <domain> to see template details.\n"));
|
|
51669
|
+
}
|
|
51670
|
+
function displayAgentTemplate(domain, verbose) {
|
|
51671
|
+
const template = AGENT_TEMPLATES[domain];
|
|
51672
|
+
if (!template) {
|
|
51673
|
+
console.error(chalk5.red.bold(`
|
|
51674
|
+
\u274C Unknown agent domain: ${domain}
|
|
51675
|
+
`));
|
|
51676
|
+
console.log(chalk5.gray("Available domains:"));
|
|
51677
|
+
Object.keys(AGENT_TEMPLATES).forEach((d) => {
|
|
51678
|
+
console.log(chalk5.cyan(` \u2022 ${d}`));
|
|
51679
|
+
});
|
|
51680
|
+
console.log();
|
|
51681
|
+
process.exit(1);
|
|
51682
|
+
}
|
|
51683
|
+
console.log(chalk5.blue.bold(`
|
|
51684
|
+
\u{1F4CB} ${template.displayName} Agent Template
|
|
51685
|
+
`));
|
|
51686
|
+
console.log(chalk5.dim("\u2550".repeat(60)));
|
|
51687
|
+
console.log(chalk5.cyan("\n\u{1F514} Domain Reminders:"));
|
|
51688
|
+
template.domainReminders.forEach((reminder, i) => {
|
|
51689
|
+
console.log(` ${i + 1}. ${reminder}`);
|
|
51690
|
+
});
|
|
51691
|
+
console.log(chalk5.cyan("\n\u2705 Quality Checklist:"));
|
|
51692
|
+
template.qualityChecklist.forEach((item, i) => {
|
|
51693
|
+
console.log(` ${i + 1}. ${item}`);
|
|
51694
|
+
});
|
|
51695
|
+
if (template.delegationTriggers.length > 0) {
|
|
51696
|
+
console.log(chalk5.cyan("\n\u{1F500} Delegation Triggers:"));
|
|
51697
|
+
template.delegationTriggers.forEach((trigger, i) => {
|
|
51698
|
+
console.log(` ${i + 1}. \u2192 ${chalk5.yellow(trigger.suggestedAgent)}`);
|
|
51699
|
+
console.log(chalk5.gray(` Keywords: ${trigger.keywords.join(", ")}`));
|
|
51700
|
+
if (verbose) {
|
|
51701
|
+
console.log(chalk5.gray(` Reason: ${trigger.reason}`));
|
|
51702
|
+
}
|
|
51703
|
+
});
|
|
51704
|
+
}
|
|
51705
|
+
if (verbose && template.antiPatterns.length > 0) {
|
|
51706
|
+
console.log(chalk5.red("\n\u26A0\uFE0F Anti-Patterns to Avoid:"));
|
|
51707
|
+
template.antiPatterns.forEach((pattern, i) => {
|
|
51708
|
+
console.log(` ${i + 1}. ${pattern}`);
|
|
51709
|
+
});
|
|
51710
|
+
}
|
|
51711
|
+
if (verbose && template.bestPractices.length > 0) {
|
|
51712
|
+
console.log(chalk5.green("\n\u2728 Best Practices:"));
|
|
51713
|
+
template.bestPractices.forEach((practice, i) => {
|
|
51714
|
+
console.log(` ${i + 1}. ${practice}`);
|
|
51715
|
+
});
|
|
51716
|
+
}
|
|
51717
|
+
console.log(chalk5.dim("\n\u2550".repeat(60)));
|
|
51718
|
+
console.log();
|
|
51719
|
+
}
|
|
51720
|
+
|
|
51721
|
+
// src/cli/commands/shortcuts.ts
|
|
51722
|
+
init_esm_shims();
|
|
51723
|
+
init_logger();
|
|
51724
|
+
async function runAxCommand(args) {
|
|
51725
|
+
return new Promise((resolve13, reject) => {
|
|
51726
|
+
const nodeExe = process.argv[0];
|
|
51727
|
+
const cliScript = process.argv[1];
|
|
51728
|
+
if (!nodeExe || !cliScript) {
|
|
51729
|
+
reject(new Error("Cannot determine CLI path"));
|
|
51730
|
+
return;
|
|
51731
|
+
}
|
|
51732
|
+
const child = spawn(nodeExe, [cliScript, ...args], {
|
|
51733
|
+
stdio: "inherit",
|
|
51734
|
+
env: process.env
|
|
51735
|
+
});
|
|
51736
|
+
child.on("close", (code) => {
|
|
51737
|
+
if (code === 0) {
|
|
51738
|
+
resolve13();
|
|
51739
|
+
} else {
|
|
51740
|
+
reject(new Error(`Command exited with code ${code}`));
|
|
51741
|
+
}
|
|
51742
|
+
});
|
|
51743
|
+
child.on("error", reject);
|
|
51744
|
+
});
|
|
51745
|
+
}
|
|
51746
|
+
var planCommand = {
|
|
51747
|
+
command: "plan [task]",
|
|
51748
|
+
describe: "Enter plan mode and explore/plan a task (shortcut for ax mode plan + ax run)",
|
|
51749
|
+
builder: (yargs2) => {
|
|
51750
|
+
return yargs2.positional("task", {
|
|
51751
|
+
describe: "Task to plan (optional - if not provided, just sets mode)",
|
|
51752
|
+
type: "string"
|
|
51753
|
+
}).option("agent", {
|
|
51754
|
+
alias: "a",
|
|
51755
|
+
describe: "Agent to use (auto-selects if not specified)",
|
|
51756
|
+
type: "string"
|
|
51757
|
+
}).option("provider", {
|
|
51758
|
+
alias: "p",
|
|
51759
|
+
describe: "Override provider",
|
|
51760
|
+
type: "string"
|
|
51761
|
+
}).option("verbose", {
|
|
51762
|
+
alias: "v",
|
|
51763
|
+
describe: "Verbose output",
|
|
51764
|
+
type: "boolean",
|
|
51765
|
+
default: false
|
|
51766
|
+
}).option("quiet", {
|
|
51767
|
+
alias: "q",
|
|
51768
|
+
describe: "Quiet output",
|
|
51769
|
+
type: "boolean",
|
|
51770
|
+
default: false
|
|
51771
|
+
}).example("$0 plan", "Enter plan mode").example('$0 plan "design auth system"', "Plan a task with auto-selected agent").example('$0 plan "design API" --agent architecture', "Plan with specific agent");
|
|
51772
|
+
},
|
|
51773
|
+
handler: async (argv) => {
|
|
51774
|
+
try {
|
|
51775
|
+
const saved = await saveModeState("plan", {
|
|
51776
|
+
setBy: "shortcut",
|
|
51777
|
+
reason: "ax plan command"
|
|
51778
|
+
});
|
|
51779
|
+
if (!saved) {
|
|
51780
|
+
logger.warn("Failed to persist mode state, continuing anyway");
|
|
51781
|
+
}
|
|
51782
|
+
if (!argv.quiet) {
|
|
51783
|
+
console.log(chalk5.cyan.bold("\n\u{1F4CB} Plan Mode Activated\n"));
|
|
51784
|
+
console.log(chalk5.gray("Read-only exploration mode - no file modifications allowed"));
|
|
51785
|
+
console.log(chalk5.gray("Use `ax mode default` to exit plan mode\n"));
|
|
51786
|
+
}
|
|
51787
|
+
if (argv.task) {
|
|
51788
|
+
const runArgs = ["run"];
|
|
51789
|
+
if (argv.agent) runArgs.push(argv.agent);
|
|
51790
|
+
runArgs.push(argv.task);
|
|
51791
|
+
if (argv.provider) runArgs.push("--provider", argv.provider);
|
|
51792
|
+
if (argv.verbose) runArgs.push("--verbose");
|
|
51793
|
+
if (argv.quiet) runArgs.push("--quiet");
|
|
51794
|
+
await runAxCommand(runArgs);
|
|
51795
|
+
} else {
|
|
51796
|
+
console.log(chalk5.gray('No task specified. Use `ax run <agent> "task"` to run in plan mode.'));
|
|
51797
|
+
}
|
|
51798
|
+
logger.info("Plan shortcut executed", { task: argv.task, agent: argv.agent });
|
|
51799
|
+
} catch (error) {
|
|
51800
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
51801
|
+
console.error(chalk5.red.bold(`
|
|
51802
|
+
\u274C Error: ${err.message}
|
|
51803
|
+
`));
|
|
51804
|
+
process.exit(1);
|
|
51805
|
+
}
|
|
51806
|
+
}
|
|
51807
|
+
};
|
|
51808
|
+
var iterateCommand = {
|
|
51809
|
+
command: "iterate [task]",
|
|
51810
|
+
describe: "Enter iterate mode and run a task autonomously (shortcut for ax mode iterate + ax run --iterate)",
|
|
51811
|
+
builder: (yargs2) => {
|
|
51812
|
+
return yargs2.positional("task", {
|
|
51813
|
+
describe: "Task to execute (optional - if not provided, just sets mode)",
|
|
51814
|
+
type: "string"
|
|
51815
|
+
}).option("agent", {
|
|
51816
|
+
alias: "a",
|
|
51817
|
+
describe: "Agent to use (auto-selects if not specified)",
|
|
51818
|
+
type: "string"
|
|
51819
|
+
}).option("timeout", {
|
|
51820
|
+
alias: "t",
|
|
51821
|
+
describe: "Max duration in minutes",
|
|
51822
|
+
type: "number"
|
|
51823
|
+
}).option("max-tokens", {
|
|
51824
|
+
describe: "Max total tokens",
|
|
51825
|
+
type: "number"
|
|
51826
|
+
}).option("provider", {
|
|
51827
|
+
alias: "p",
|
|
51828
|
+
describe: "Override provider",
|
|
51829
|
+
type: "string"
|
|
51830
|
+
}).option("verbose", {
|
|
51831
|
+
alias: "v",
|
|
51832
|
+
describe: "Verbose output",
|
|
51833
|
+
type: "boolean",
|
|
51834
|
+
default: false
|
|
51835
|
+
}).option("quiet", {
|
|
51836
|
+
alias: "q",
|
|
51837
|
+
describe: "Quiet output",
|
|
51838
|
+
type: "boolean",
|
|
51839
|
+
default: false
|
|
51840
|
+
}).example("$0 iterate", "Enter iterate mode").example('$0 iterate "implement auth"', "Run task in iterate mode").example('$0 iterate "fix bug" --agent backend', "Iterate with specific agent");
|
|
51841
|
+
},
|
|
51842
|
+
handler: async (argv) => {
|
|
51843
|
+
try {
|
|
51844
|
+
const saved = await saveModeState("iterate", {
|
|
51845
|
+
setBy: "shortcut",
|
|
51846
|
+
reason: "ax iterate command"
|
|
51847
|
+
});
|
|
51848
|
+
if (!saved) {
|
|
51849
|
+
logger.warn("Failed to persist mode state, continuing anyway");
|
|
51850
|
+
}
|
|
51851
|
+
if (!argv.quiet) {
|
|
51852
|
+
console.log(chalk5.cyan.bold("\n\u{1F504} Iterate Mode Activated\n"));
|
|
51853
|
+
console.log(chalk5.gray("Autonomous execution mode - agent will work continuously"));
|
|
51854
|
+
console.log(chalk5.gray("Use `ax mode default` to exit iterate mode\n"));
|
|
51855
|
+
}
|
|
51856
|
+
if (argv.task) {
|
|
51857
|
+
const runArgs = ["run"];
|
|
51858
|
+
if (argv.agent) runArgs.push(argv.agent);
|
|
51859
|
+
runArgs.push(argv.task);
|
|
51860
|
+
runArgs.push("--iterate");
|
|
51861
|
+
if (argv.timeout) runArgs.push("--iterate-timeout", String(argv.timeout));
|
|
51862
|
+
if (argv.maxTokens) runArgs.push("--iterate-max-tokens", String(argv.maxTokens));
|
|
51863
|
+
if (argv.provider) runArgs.push("--provider", argv.provider);
|
|
51864
|
+
if (argv.verbose) runArgs.push("--verbose");
|
|
51865
|
+
if (argv.quiet) runArgs.push("--quiet");
|
|
51866
|
+
await runAxCommand(runArgs);
|
|
51867
|
+
} else {
|
|
51868
|
+
console.log(chalk5.gray('No task specified. Use `ax run <agent> "task"` to run in iterate mode.'));
|
|
51869
|
+
}
|
|
51870
|
+
logger.info("Iterate shortcut executed", { task: argv.task, agent: argv.agent });
|
|
51871
|
+
} catch (error) {
|
|
51872
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
51873
|
+
console.error(chalk5.red.bold(`
|
|
51874
|
+
\u274C Error: ${err.message}
|
|
51875
|
+
`));
|
|
51876
|
+
process.exit(1);
|
|
51877
|
+
}
|
|
51878
|
+
}
|
|
51879
|
+
};
|
|
51880
|
+
var reviewCommand = {
|
|
51881
|
+
command: "review [path]",
|
|
51882
|
+
describe: "Enter review mode and analyze code (shortcut for ax mode review + ax run quality)",
|
|
51883
|
+
builder: (yargs2) => {
|
|
51884
|
+
return yargs2.positional("path", {
|
|
51885
|
+
describe: "Path to review (file or directory)",
|
|
51886
|
+
type: "string"
|
|
51887
|
+
}).option("agent", {
|
|
51888
|
+
alias: "a",
|
|
51889
|
+
describe: "Agent to use (defaults to quality)",
|
|
51890
|
+
type: "string",
|
|
51891
|
+
default: "quality"
|
|
51892
|
+
}).option("provider", {
|
|
51893
|
+
alias: "p",
|
|
51894
|
+
describe: "Override provider",
|
|
51895
|
+
type: "string"
|
|
51896
|
+
}).option("verbose", {
|
|
51897
|
+
alias: "v",
|
|
51898
|
+
describe: "Verbose output",
|
|
51899
|
+
type: "boolean",
|
|
51900
|
+
default: false
|
|
51901
|
+
}).option("quiet", {
|
|
51902
|
+
alias: "q",
|
|
51903
|
+
describe: "Quiet output",
|
|
51904
|
+
type: "boolean",
|
|
51905
|
+
default: false
|
|
51906
|
+
}).example("$0 review", "Enter review mode").example("$0 review src/core/", "Review a directory").example("$0 review src/api.ts", "Review a specific file");
|
|
51907
|
+
},
|
|
51908
|
+
handler: async (argv) => {
|
|
51909
|
+
try {
|
|
51910
|
+
const saved = await saveModeState("review", {
|
|
51911
|
+
setBy: "shortcut",
|
|
51912
|
+
reason: "ax review command"
|
|
51913
|
+
});
|
|
51914
|
+
if (!saved) {
|
|
51915
|
+
logger.warn("Failed to persist mode state, continuing anyway");
|
|
51916
|
+
}
|
|
51917
|
+
if (!argv.quiet) {
|
|
51918
|
+
console.log(chalk5.cyan.bold("\n\u{1F50D} Review Mode Activated\n"));
|
|
51919
|
+
console.log(chalk5.gray("Code review mode - analyzing for quality, security, and best practices"));
|
|
51920
|
+
console.log(chalk5.gray("Use `ax mode default` to exit review mode\n"));
|
|
51921
|
+
}
|
|
51922
|
+
if (argv.path) {
|
|
51923
|
+
const task = `Review the code at ${argv.path} for quality, security, and best practices`;
|
|
51924
|
+
const runArgs = ["run", argv.agent || "quality", task];
|
|
51925
|
+
if (argv.provider) runArgs.push("--provider", argv.provider);
|
|
51926
|
+
if (argv.verbose) runArgs.push("--verbose");
|
|
51927
|
+
if (argv.quiet) runArgs.push("--quiet");
|
|
51928
|
+
await runAxCommand(runArgs);
|
|
51929
|
+
} else {
|
|
51930
|
+
console.log(chalk5.gray('No path specified. Use `ax run quality "Review <path>"` to review code.'));
|
|
51931
|
+
}
|
|
51932
|
+
logger.info("Review shortcut executed", { path: argv.path, agent: argv.agent });
|
|
51933
|
+
} catch (error) {
|
|
51934
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
51935
|
+
console.error(chalk5.red.bold(`
|
|
51936
|
+
\u274C Error: ${err.message}
|
|
51937
|
+
`));
|
|
51938
|
+
process.exit(1);
|
|
51939
|
+
}
|
|
51940
|
+
}
|
|
51941
|
+
};
|
|
51942
|
+
|
|
48522
51943
|
// src/cli/index.ts
|
|
48523
51944
|
installExitHandlers();
|
|
48524
51945
|
var VERSION2 = getVersion();
|
|
@@ -48541,7 +51962,7 @@ globalTracker.mark("cli_start");
|
|
|
48541
51962
|
type: "string",
|
|
48542
51963
|
description: "Path to custom config file",
|
|
48543
51964
|
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();
|
|
51965
|
+
}).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).command(planCommand).command(iterateCommand).command(reviewCommand).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
51966
|
globalTracker.mark("yargs_parse_end");
|
|
48546
51967
|
globalTracker.measure("yargs_parsing", "yargs_parse_start", "yargs_parse_end");
|
|
48547
51968
|
globalTracker.mark("options_setup_start");
|