@probelabs/probe 0.6.0-rc201 → 0.6.0-rc202
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 +31 -1
- package/bin/binaries/probe-v0.6.0-rc202-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc202-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc202-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc202-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc202-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.d.ts +11 -1
- package/build/agent/ProbeAgent.js +310 -14
- package/build/agent/index.js +8615 -394
- package/build/agent/probeTool.js +2 -2
- package/build/agent/schemaUtils.js +37 -18
- package/build/agent/shared/prompts.js +17 -0
- package/build/agent/skills/formatting.js +23 -0
- package/build/agent/skills/parser.js +162 -0
- package/build/agent/skills/registry.js +185 -0
- package/build/agent/skills/tools.js +65 -0
- package/build/agent/tools.js +44 -0
- package/build/delegate.js +27 -7
- package/build/tools/common.js +17 -4
- package/build/tools/system-message.js +4 -4
- package/build/tools/vercel.js +243 -36
- package/cjs/agent/ProbeAgent.cjs +14990 -7892
- package/cjs/index.cjs +15003 -7905
- package/index.d.ts +8 -0
- package/package.json +2 -1
- package/scripts/postinstall.js +10 -4
- package/src/agent/ProbeAgent.d.ts +11 -1
- package/src/agent/ProbeAgent.js +310 -14
- package/src/agent/index.js +21 -1
- package/src/agent/probeTool.js +2 -2
- package/src/agent/schemaUtils.js +37 -18
- package/src/agent/shared/prompts.js +17 -0
- package/src/agent/skills/formatting.js +23 -0
- package/src/agent/skills/parser.js +162 -0
- package/src/agent/skills/registry.js +185 -0
- package/src/agent/skills/tools.js +65 -0
- package/src/agent/tools.js +44 -0
- package/src/delegate.js +27 -7
- package/src/tools/common.js +17 -4
- package/src/tools/system-message.js +4 -4
- package/src/tools/vercel.js +243 -36
- package/bin/binaries/probe-v0.6.0-rc201-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc201-x86_64-unknown-linux-musl.tar.gz +0 -0
package/README.md
CHANGED
|
@@ -140,6 +140,36 @@ export MODEL_NAME=claude-3-5-sonnet-20241022
|
|
|
140
140
|
- **Token tracking** - Monitor usage and costs
|
|
141
141
|
- **Configurable personas** - Engineer, architect, code-review, and more
|
|
142
142
|
|
|
143
|
+
### Agent Skills (repo-local)
|
|
144
|
+
|
|
145
|
+
ProbeAgent can discover and activate Agent Skills stored inside your repository. Place skills under:
|
|
146
|
+
- `.claude/skills/<skill-name>/SKILL.md`
|
|
147
|
+
- `.codex/skills/<skill-name>/SKILL.md`
|
|
148
|
+
- `skills/<skill-name>/SKILL.md`
|
|
149
|
+
- `.skills/<skill-name>/SKILL.md`
|
|
150
|
+
|
|
151
|
+
`SKILL.md` should contain YAML frontmatter followed by Markdown instructions. Example:
|
|
152
|
+
|
|
153
|
+
```markdown
|
|
154
|
+
---
|
|
155
|
+
name: onboarding
|
|
156
|
+
description: Help new engineers understand the repo structure and conventions.
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
Use this skill to explain key modules, build steps, and common workflows.
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Then in the agent loop you can call:
|
|
163
|
+
```xml
|
|
164
|
+
<listSkills></listSkills>
|
|
165
|
+
```
|
|
166
|
+
or:
|
|
167
|
+
```xml
|
|
168
|
+
<useSkill>
|
|
169
|
+
<name>onboarding</name>
|
|
170
|
+
</useSkill>
|
|
171
|
+
```
|
|
172
|
+
|
|
143
173
|
### Retry and Fallback Support
|
|
144
174
|
|
|
145
175
|
ProbeAgent includes comprehensive retry and fallback capabilities for maximum reliability:
|
|
@@ -821,4 +851,4 @@ probe mcp --timeout 60
|
|
|
821
851
|
|
|
822
852
|
## Related Projects
|
|
823
853
|
|
|
824
|
-
- [probe](https://github.com/probelabs/probe) - The core probe code search tool
|
|
854
|
+
- [probe](https://github.com/probelabs/probe) - The core probe code search tool
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -14,11 +14,13 @@ export interface ProbeAgentOptions {
|
|
|
14
14
|
/** Alias for customPrompt. More intuitive naming for system prompts. */
|
|
15
15
|
systemPrompt?: string;
|
|
16
16
|
/** Predefined prompt type (persona) */
|
|
17
|
-
promptType?: 'code-explorer' | 'engineer' | 'code-review' | 'support' | 'architect';
|
|
17
|
+
promptType?: 'code-explorer' | 'code-searcher' | 'engineer' | 'code-review' | 'support' | 'architect';
|
|
18
18
|
/** Allow the use of the 'implement' tool for code editing */
|
|
19
19
|
allowEdit?: boolean;
|
|
20
20
|
/** Enable the delegate tool for task distribution to subagents */
|
|
21
21
|
enableDelegate?: boolean;
|
|
22
|
+
/** Architecture context filename to embed from repo root (defaults to AGENTS.md with CLAUDE.md fallback; ARCHITECTURE.md is always included when present) */
|
|
23
|
+
architectureFileName?: string;
|
|
22
24
|
/** Enable bash tool for command execution */
|
|
23
25
|
enableBash?: boolean;
|
|
24
26
|
/** Bash tool configuration (allow/deny patterns) */
|
|
@@ -36,6 +38,8 @@ export interface ProbeAgentOptions {
|
|
|
36
38
|
};
|
|
37
39
|
/** Search directory path */
|
|
38
40
|
path?: string;
|
|
41
|
+
/** Use a delegated code-search subagent for the search tool (default: true) */
|
|
42
|
+
searchDelegate?: boolean;
|
|
39
43
|
/** Force specific AI provider */
|
|
40
44
|
provider?: 'anthropic' | 'openai' | 'google' | 'bedrock';
|
|
41
45
|
/** Override model name */
|
|
@@ -64,6 +68,12 @@ export interface ProbeAgentOptions {
|
|
|
64
68
|
disableMermaidValidation?: boolean;
|
|
65
69
|
/** Disable automatic JSON validation and fixing (prevents infinite recursion in JsonFixingAgent) */
|
|
66
70
|
disableJsonValidation?: boolean;
|
|
71
|
+
/** Enable agent skills discovery and activation */
|
|
72
|
+
enableSkills?: boolean;
|
|
73
|
+
/** Disable agent skills (overrides enableSkills) */
|
|
74
|
+
disableSkills?: boolean;
|
|
75
|
+
/** Skill directories to scan relative to repo root */
|
|
76
|
+
skillDirs?: string[];
|
|
67
77
|
/** Custom prompt to run after attempt_completion for validation/review (runs before mermaid/JSON validation) */
|
|
68
78
|
completionPrompt?: string;
|
|
69
79
|
}
|
|
@@ -12,7 +12,7 @@ import { streamText } from 'ai';
|
|
|
12
12
|
import { randomUUID } from 'crypto';
|
|
13
13
|
import { EventEmitter } from 'events';
|
|
14
14
|
import { existsSync } from 'fs';
|
|
15
|
-
import { readFile, stat } from 'fs/promises';
|
|
15
|
+
import { readFile, stat, readdir } from 'fs/promises';
|
|
16
16
|
import { resolve, isAbsolute, dirname, basename, normalize, sep } from 'path';
|
|
17
17
|
import { TokenCounter } from './tokenCounter.js';
|
|
18
18
|
import { InMemoryStorageAdapter } from './storage/InMemoryStorageAdapter.js';
|
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
bashToolDefinition,
|
|
28
28
|
listFilesToolDefinition,
|
|
29
29
|
searchFilesToolDefinition,
|
|
30
|
+
listSkillsToolDefinition,
|
|
31
|
+
useSkillToolDefinition,
|
|
30
32
|
readImageToolDefinition,
|
|
31
33
|
attemptCompletionToolDefinition,
|
|
32
34
|
implementToolDefinition,
|
|
@@ -61,6 +63,9 @@ import {
|
|
|
61
63
|
parseHybridXmlToolCall,
|
|
62
64
|
loadMCPConfigurationFromPath
|
|
63
65
|
} from './mcp/index.js';
|
|
66
|
+
import { SkillRegistry } from './skills/registry.js';
|
|
67
|
+
import { formatAvailableSkillsXml } from './skills/formatting.js';
|
|
68
|
+
import { createSkillToolInstances } from './skills/tools.js';
|
|
64
69
|
import { RetryManager, createRetryManagerFromEnv } from './RetryManager.js';
|
|
65
70
|
import { FallbackManager, createFallbackManagerFromEnv, buildFallbackProvidersFromEnv } from './FallbackManager.js';
|
|
66
71
|
import { handleContextLimitError } from './contextCompactor.js';
|
|
@@ -91,19 +96,24 @@ export class ProbeAgent {
|
|
|
91
96
|
* @param {string} [options.sessionId] - Optional session ID
|
|
92
97
|
* @param {string} [options.customPrompt] - Custom prompt to replace the default system message
|
|
93
98
|
* @param {string} [options.systemPrompt] - Alias for customPrompt; takes precedence when both are provided
|
|
94
|
-
* @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
|
|
99
|
+
* @param {string} [options.promptType] - Predefined prompt type (code-explorer, code-searcher, architect, code-review, support)
|
|
95
100
|
* @param {boolean} [options.allowEdit=false] - Allow the use of the 'implement' tool
|
|
96
101
|
* @param {boolean} [options.enableDelegate=false] - Enable the delegate tool for task distribution to subagents
|
|
102
|
+
* @param {string} [options.architectureFileName] - Architecture context filename to embed from repo root (defaults to AGENTS.md with CLAUDE.md fallback; ARCHITECTURE.md is always included when present)
|
|
97
103
|
* @param {string} [options.path] - Search directory path
|
|
98
104
|
* @param {string} [options.cwd] - Working directory for resolving relative paths (independent of allowedFolders)
|
|
99
105
|
* @param {string} [options.provider] - Force specific AI provider
|
|
100
106
|
* @param {string} [options.model] - Override model name
|
|
101
107
|
* @param {boolean} [options.debug] - Enable debug mode
|
|
102
108
|
* @param {boolean} [options.outline] - Enable outline-xml format for search results
|
|
109
|
+
* @param {boolean} [options.searchDelegate=true] - Use a delegated code-search subagent for the search tool
|
|
103
110
|
* @param {number} [options.maxResponseTokens] - Maximum tokens for AI responses
|
|
104
111
|
* @param {number} [options.maxIterations] - Maximum tool iterations (overrides MAX_TOOL_ITERATIONS env var)
|
|
105
112
|
* @param {boolean} [options.disableMermaidValidation=false] - Disable automatic mermaid diagram validation and fixing
|
|
106
113
|
* @param {boolean} [options.disableJsonValidation=false] - Disable automatic JSON validation and fixing (prevents infinite recursion in JsonFixingAgent)
|
|
114
|
+
* @param {boolean} [options.enableSkills=true] - Enable agent skills discovery and activation
|
|
115
|
+
* @param {boolean} [options.disableSkills=false] - Disable agent skills (overrides enableSkills)
|
|
116
|
+
* @param {Array<string>} [options.skillDirs] - Skill directories to scan relative to repo root
|
|
107
117
|
* @param {boolean} [options.enableMcp=false] - Enable MCP tool integration
|
|
108
118
|
* @param {string} [options.mcpConfigPath] - Path to MCP configuration file
|
|
109
119
|
* @param {Object} [options.mcpConfig] - MCP configuration object (overrides mcpConfigPath)
|
|
@@ -138,6 +148,7 @@ export class ProbeAgent {
|
|
|
138
148
|
this.cancelled = false;
|
|
139
149
|
this.tracer = options.tracer || null;
|
|
140
150
|
this.outline = !!options.outline;
|
|
151
|
+
this.searchDelegate = options.searchDelegate !== undefined ? !!options.searchDelegate : true;
|
|
141
152
|
this.maxResponseTokens = options.maxResponseTokens || (() => {
|
|
142
153
|
const val = parseInt(process.env.MAX_RESPONSE_TOKENS || '0', 10);
|
|
143
154
|
if (isNaN(val) || val < 0 || val > 200000) {
|
|
@@ -148,6 +159,16 @@ export class ProbeAgent {
|
|
|
148
159
|
this.maxIterations = options.maxIterations || null;
|
|
149
160
|
this.disableMermaidValidation = !!options.disableMermaidValidation;
|
|
150
161
|
this.disableJsonValidation = !!options.disableJsonValidation;
|
|
162
|
+
this.enableSkills = options.disableSkills ? false : (options.enableSkills !== undefined ? !!options.enableSkills : true);
|
|
163
|
+
if (Array.isArray(options.skillDirs)) {
|
|
164
|
+
this.skillDirs = options.skillDirs;
|
|
165
|
+
} else if (typeof options.skillDirs === 'string') {
|
|
166
|
+
this.skillDirs = options.skillDirs.split(',').map(dir => dir.trim()).filter(Boolean);
|
|
167
|
+
} else {
|
|
168
|
+
this.skillDirs = null;
|
|
169
|
+
}
|
|
170
|
+
this.skillsRegistry = null;
|
|
171
|
+
this.activeSkills = new Map();
|
|
151
172
|
|
|
152
173
|
// Completion prompt for post-completion validation/review
|
|
153
174
|
this.completionPrompt = options.completionPrompt || null;
|
|
@@ -176,6 +197,15 @@ export class ProbeAgent {
|
|
|
176
197
|
this.enableBash = !!options.enableBash;
|
|
177
198
|
this.bashConfig = options.bashConfig || {};
|
|
178
199
|
|
|
200
|
+
// Architecture context configuration
|
|
201
|
+
const configuredArchitectureFileName =
|
|
202
|
+
typeof options.architectureFileName === 'string' && options.architectureFileName.trim()
|
|
203
|
+
? options.architectureFileName
|
|
204
|
+
: null;
|
|
205
|
+
this.architectureFileName = configuredArchitectureFileName;
|
|
206
|
+
this.architectureContext = null;
|
|
207
|
+
this._architectureContextLoaded = false;
|
|
208
|
+
|
|
179
209
|
// Search configuration - support both path (single) and allowedFolders (array)
|
|
180
210
|
if (options.allowedFolders && Array.isArray(options.allowedFolders)) {
|
|
181
211
|
this.allowedFolders = options.allowedFolders;
|
|
@@ -201,6 +231,7 @@ export class ProbeAgent {
|
|
|
201
231
|
console.log(`[DEBUG] Generated session ID for agent: ${this.sessionId}`);
|
|
202
232
|
console.log(`[DEBUG] Maximum tool iterations configured: ${MAX_TOOL_ITERATIONS}`);
|
|
203
233
|
console.log(`[DEBUG] Allow Edit (implement tool): ${this.allowEdit}`);
|
|
234
|
+
console.log(`[DEBUG] Search delegation enabled: ${this.searchDelegate}`);
|
|
204
235
|
}
|
|
205
236
|
|
|
206
237
|
// Initialize tools
|
|
@@ -437,11 +468,16 @@ export class ProbeAgent {
|
|
|
437
468
|
cwd: this.cwd || (this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd()),
|
|
438
469
|
allowedFolders: this.allowedFolders,
|
|
439
470
|
outline: this.outline,
|
|
471
|
+
searchDelegate: this.searchDelegate,
|
|
440
472
|
allowEdit: this.allowEdit,
|
|
441
473
|
enableDelegate: this.enableDelegate,
|
|
442
474
|
enableBash: this.enableBash,
|
|
443
475
|
bashConfig: this.bashConfig,
|
|
476
|
+
tracer: this.tracer,
|
|
444
477
|
allowedTools: this.allowedTools,
|
|
478
|
+
architectureFileName: this.architectureFileName,
|
|
479
|
+
provider: this.clientApiProvider,
|
|
480
|
+
model: this.clientApiModel,
|
|
445
481
|
isToolAllowed
|
|
446
482
|
};
|
|
447
483
|
|
|
@@ -475,6 +511,21 @@ export class ProbeAgent {
|
|
|
475
511
|
this.toolImplementations.searchFiles = searchFilesToolInstance;
|
|
476
512
|
}
|
|
477
513
|
|
|
514
|
+
if (this.enableSkills) {
|
|
515
|
+
const registry = this._getSkillsRegistry();
|
|
516
|
+
const { listSkillsToolInstance, useSkillToolInstance } = createSkillToolInstances({
|
|
517
|
+
registry,
|
|
518
|
+
activeSkills: this.activeSkills
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
if (isToolAllowed('listSkills')) {
|
|
522
|
+
this.toolImplementations.listSkills = listSkillsToolInstance;
|
|
523
|
+
}
|
|
524
|
+
if (isToolAllowed('useSkill')) {
|
|
525
|
+
this.toolImplementations.useSkill = useSkillToolInstance;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
478
529
|
// Image loading tool
|
|
479
530
|
if (isToolAllowed('readImage')) {
|
|
480
531
|
this.toolImplementations.readImage = {
|
|
@@ -1043,7 +1094,7 @@ export class ProbeAgent {
|
|
|
1043
1094
|
|
|
1044
1095
|
// For Claude Code, use a cleaner system prompt without XML formatting
|
|
1045
1096
|
// since it has native MCP support for tools
|
|
1046
|
-
const systemPrompt =
|
|
1097
|
+
const systemPrompt = await this.getClaudeNativeSystemPrompt();
|
|
1047
1098
|
|
|
1048
1099
|
this.engine = await createEnhancedClaudeCLIEngine({
|
|
1049
1100
|
agent: this, // Pass reference to ProbeAgent for tool access
|
|
@@ -1074,7 +1125,7 @@ export class ProbeAgent {
|
|
|
1074
1125
|
|
|
1075
1126
|
// For Codex CLI, use a cleaner system prompt without XML formatting
|
|
1076
1127
|
// since it has native MCP support for tools
|
|
1077
|
-
const systemPrompt =
|
|
1128
|
+
const systemPrompt = await this.getCodexNativeSystemPrompt();
|
|
1078
1129
|
|
|
1079
1130
|
this.engine = await createCodexEngine({
|
|
1080
1131
|
agent: this, // Pass reference to ProbeAgent for tool access
|
|
@@ -1535,11 +1586,207 @@ export class ProbeAgent {
|
|
|
1535
1586
|
}
|
|
1536
1587
|
}
|
|
1537
1588
|
|
|
1589
|
+
/**
|
|
1590
|
+
* Load architecture context from repository root (case-insensitive filename match)
|
|
1591
|
+
* @returns {Promise<Object|null>} Architecture context with { name, path, content, sources, primarySource, guidanceSource, architectureSource } or null
|
|
1592
|
+
*/
|
|
1593
|
+
async loadArchitectureContext() {
|
|
1594
|
+
if (this._architectureContextLoaded) {
|
|
1595
|
+
return this.architectureContext;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
const rootDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
|
|
1599
|
+
const configuredName =
|
|
1600
|
+
typeof this.architectureFileName === 'string' ? this.architectureFileName.trim() : '';
|
|
1601
|
+
const hasConfiguredName = !!configuredName;
|
|
1602
|
+
let guidanceCandidates = [];
|
|
1603
|
+
|
|
1604
|
+
if (hasConfiguredName) {
|
|
1605
|
+
const targetName = basename(configuredName);
|
|
1606
|
+
|
|
1607
|
+
// Only allow simple filenames (no path separators or traversal)
|
|
1608
|
+
if (
|
|
1609
|
+
configuredName !== targetName ||
|
|
1610
|
+
configuredName.includes('/') ||
|
|
1611
|
+
configuredName.includes('\\') ||
|
|
1612
|
+
configuredName.includes('..') ||
|
|
1613
|
+
isAbsolute(configuredName)
|
|
1614
|
+
) {
|
|
1615
|
+
console.warn(`[WARN] Invalid architectureFileName (must be a simple filename): ${configuredName}`);
|
|
1616
|
+
} else if (targetName) {
|
|
1617
|
+
const targetLower = targetName.toLowerCase();
|
|
1618
|
+
if (targetLower === 'agents.md') {
|
|
1619
|
+
guidanceCandidates = ['agents.md', 'claude.md'];
|
|
1620
|
+
} else {
|
|
1621
|
+
guidanceCandidates = [targetName];
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
} else {
|
|
1625
|
+
guidanceCandidates = ['agents.md', 'claude.md'];
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
if (!existsSync(rootDirectory)) {
|
|
1629
|
+
this._architectureContextLoaded = true;
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
let entries;
|
|
1634
|
+
try {
|
|
1635
|
+
entries = await readdir(rootDirectory, { withFileTypes: true });
|
|
1636
|
+
} catch (error) {
|
|
1637
|
+
this.architectureContext = null;
|
|
1638
|
+
if (error && (error.code === 'EACCES' || error.code === 'EPERM')) {
|
|
1639
|
+
console.warn(`[WARN] Cannot read architecture context directory: ${rootDirectory} (${error.code})`);
|
|
1640
|
+
} else if (this.debug) {
|
|
1641
|
+
console.log(`[DEBUG] Could not list architecture context directory: ${error.message}`);
|
|
1642
|
+
}
|
|
1643
|
+
return null;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
const entryByLower = new Map();
|
|
1647
|
+
for (const entry of entries) {
|
|
1648
|
+
if (entry.isSymbolicLink()) {
|
|
1649
|
+
continue;
|
|
1650
|
+
}
|
|
1651
|
+
if (!entry.isFile()) {
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
entryByLower.set(entry.name.toLowerCase(), entry);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
let guidanceMatch = null;
|
|
1658
|
+
for (const candidateName of guidanceCandidates) {
|
|
1659
|
+
const entry = entryByLower.get(candidateName.toLowerCase());
|
|
1660
|
+
if (entry) {
|
|
1661
|
+
guidanceMatch = entry;
|
|
1662
|
+
break;
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
const architectureMatch = entryByLower.get('architecture.md');
|
|
1667
|
+
const guidanceKey = guidanceMatch ? guidanceMatch.name.toLowerCase() : null;
|
|
1668
|
+
const architectureKey = architectureMatch ? architectureMatch.name.toLowerCase() : null;
|
|
1669
|
+
|
|
1670
|
+
if (!guidanceMatch && !architectureMatch) {
|
|
1671
|
+
this._architectureContextLoaded = true;
|
|
1672
|
+
return null;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
const uniqueEntries = [];
|
|
1676
|
+
const seen = new Set();
|
|
1677
|
+
const pushEntry = (entry) => {
|
|
1678
|
+
if (!entry) return;
|
|
1679
|
+
const key = entry.name.toLowerCase();
|
|
1680
|
+
if (seen.has(key)) return;
|
|
1681
|
+
seen.add(key);
|
|
1682
|
+
uniqueEntries.push(entry);
|
|
1683
|
+
};
|
|
1684
|
+
|
|
1685
|
+
pushEntry(guidanceMatch);
|
|
1686
|
+
pushEntry(architectureMatch);
|
|
1687
|
+
|
|
1688
|
+
const contexts = [];
|
|
1689
|
+
for (const entry of uniqueEntries) {
|
|
1690
|
+
const filePath = resolve(rootDirectory, entry.name);
|
|
1691
|
+
try {
|
|
1692
|
+
const content = await readFile(filePath, 'utf8');
|
|
1693
|
+
let kind = 'other';
|
|
1694
|
+
const entryKey = entry.name.toLowerCase();
|
|
1695
|
+
if (guidanceKey && entryKey === guidanceKey) {
|
|
1696
|
+
kind = 'guidance';
|
|
1697
|
+
} else if (architectureKey && entryKey === architectureKey) {
|
|
1698
|
+
kind = 'architecture';
|
|
1699
|
+
}
|
|
1700
|
+
contexts.push({
|
|
1701
|
+
name: entry.name,
|
|
1702
|
+
path: filePath,
|
|
1703
|
+
content,
|
|
1704
|
+
kind
|
|
1705
|
+
});
|
|
1706
|
+
} catch (error) {
|
|
1707
|
+
if (error && (error.code === 'EACCES' || error.code === 'EPERM')) {
|
|
1708
|
+
console.warn(`[WARN] Cannot read architecture context file: ${filePath} (${error.code})`);
|
|
1709
|
+
} else if (error && error.code === 'ENOENT') {
|
|
1710
|
+
if (this.debug) {
|
|
1711
|
+
console.log(`[DEBUG] Architecture context file disappeared: ${filePath}`);
|
|
1712
|
+
}
|
|
1713
|
+
} else {
|
|
1714
|
+
console.warn(`[WARN] Failed to read architecture context file: ${filePath} (${error.message})`);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
if (!contexts.length) {
|
|
1720
|
+
this.architectureContext = null;
|
|
1721
|
+
this._architectureContextLoaded = true;
|
|
1722
|
+
return null;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
const guidanceSource = contexts.find((context) => context.kind === 'guidance') || null;
|
|
1726
|
+
const architectureSource = contexts.find((context) => context.kind === 'architecture') || null;
|
|
1727
|
+
const primarySource = guidanceSource || architectureSource || contexts[0];
|
|
1728
|
+
|
|
1729
|
+
this.architectureContext = {
|
|
1730
|
+
name: primarySource?.name || null,
|
|
1731
|
+
path: primarySource?.path || null,
|
|
1732
|
+
content: contexts.map((context) => context.content).join('\n\n'),
|
|
1733
|
+
sources: contexts,
|
|
1734
|
+
primarySource,
|
|
1735
|
+
guidanceSource,
|
|
1736
|
+
architectureSource
|
|
1737
|
+
};
|
|
1738
|
+
this._architectureContextLoaded = true;
|
|
1739
|
+
|
|
1740
|
+
return this.architectureContext;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Format architecture context for prompt inclusion
|
|
1745
|
+
* @returns {string} Architecture section or empty string
|
|
1746
|
+
*/
|
|
1747
|
+
getArchitectureSection() {
|
|
1748
|
+
if (!this.architectureContext?.content) {
|
|
1749
|
+
return '';
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
return `\n\n# Architecture\n\n${this.architectureContext.content}\n`;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
_getSkillsRepoRoot() {
|
|
1756
|
+
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
1757
|
+
return resolve(this.allowedFolders[0]);
|
|
1758
|
+
}
|
|
1759
|
+
return process.cwd();
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
_getSkillsRegistry() {
|
|
1763
|
+
if (!this.skillsRegistry) {
|
|
1764
|
+
this.skillsRegistry = new SkillRegistry({
|
|
1765
|
+
repoRoot: this._getSkillsRepoRoot(),
|
|
1766
|
+
skillDirs: this.skillDirs || undefined,
|
|
1767
|
+
debug: this.debug
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
return this.skillsRegistry;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
async _loadSkillsMetadata() {
|
|
1774
|
+
if (!this.enableSkills) return [];
|
|
1775
|
+
return await this._getSkillsRegistry().loadSkills();
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
async _getAvailableSkillsXml() {
|
|
1779
|
+
const skills = await this._loadSkillsMetadata();
|
|
1780
|
+
if (!skills.length) return '';
|
|
1781
|
+
return formatAvailableSkillsXml(skills);
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1538
1784
|
/**
|
|
1539
1785
|
* Get system prompt for Claude native engines (CLI/SDK) without XML formatting
|
|
1540
1786
|
* These engines have native MCP support and don't need XML instructions
|
|
1541
1787
|
*/
|
|
1542
|
-
getClaudeNativeSystemPrompt() {
|
|
1788
|
+
async getClaudeNativeSystemPrompt() {
|
|
1789
|
+
await this.loadArchitectureContext();
|
|
1543
1790
|
let systemPrompt = '';
|
|
1544
1791
|
|
|
1545
1792
|
// Add persona/role if configured
|
|
@@ -1564,10 +1811,17 @@ export class ProbeAgent {
|
|
|
1564
1811
|
systemPrompt += `\n- bash: Execute bash commands for system operations`;
|
|
1565
1812
|
}
|
|
1566
1813
|
|
|
1814
|
+
const searchGuidance = this.searchDelegate
|
|
1815
|
+
? '1. Start with search to retrieve extracted code blocks'
|
|
1816
|
+
: '1. Start with search to find relevant code patterns';
|
|
1817
|
+
const extractGuidance = this.searchDelegate
|
|
1818
|
+
? '2. Use extract only if you need more context or a full file'
|
|
1819
|
+
: '2. Use extract to get detailed context when needed';
|
|
1820
|
+
|
|
1567
1821
|
systemPrompt += `\n
|
|
1568
1822
|
When exploring code:
|
|
1569
|
-
|
|
1570
|
-
|
|
1823
|
+
${searchGuidance}
|
|
1824
|
+
${extractGuidance}
|
|
1571
1825
|
3. Prefer focused, specific searches over broad queries
|
|
1572
1826
|
4. Combine multiple tools to build complete understanding`;
|
|
1573
1827
|
|
|
@@ -1584,13 +1838,17 @@ When exploring code:
|
|
|
1584
1838
|
systemPrompt += '```\n' + this.fileList + '\n```\n';
|
|
1585
1839
|
}
|
|
1586
1840
|
|
|
1841
|
+
// Add architecture context if available
|
|
1842
|
+
systemPrompt += this.getArchitectureSection();
|
|
1843
|
+
|
|
1587
1844
|
return systemPrompt;
|
|
1588
1845
|
}
|
|
1589
1846
|
|
|
1590
1847
|
/**
|
|
1591
1848
|
* Get system prompt for Codex CLI (similar to Claude but optimized for Codex)
|
|
1592
1849
|
*/
|
|
1593
|
-
getCodexNativeSystemPrompt() {
|
|
1850
|
+
async getCodexNativeSystemPrompt() {
|
|
1851
|
+
await this.loadArchitectureContext();
|
|
1594
1852
|
let systemPrompt = '';
|
|
1595
1853
|
|
|
1596
1854
|
// Add persona/role if configured
|
|
@@ -1615,10 +1873,17 @@ When exploring code:
|
|
|
1615
1873
|
systemPrompt += `\n- bash: Execute bash commands for system operations`;
|
|
1616
1874
|
}
|
|
1617
1875
|
|
|
1876
|
+
const searchGuidance = this.searchDelegate
|
|
1877
|
+
? '1. Start with search to retrieve extracted code blocks'
|
|
1878
|
+
: '1. Start with search to find relevant code patterns';
|
|
1879
|
+
const extractGuidance = this.searchDelegate
|
|
1880
|
+
? '2. Use extract only if you need more context or a full file'
|
|
1881
|
+
: '2. Use extract to get detailed context when needed';
|
|
1882
|
+
|
|
1618
1883
|
systemPrompt += `\n
|
|
1619
1884
|
When exploring code:
|
|
1620
|
-
|
|
1621
|
-
|
|
1885
|
+
${searchGuidance}
|
|
1886
|
+
${extractGuidance}
|
|
1622
1887
|
3. Prefer focused, specific searches over broad queries
|
|
1623
1888
|
4. Combine multiple tools to build complete understanding`;
|
|
1624
1889
|
|
|
@@ -1635,6 +1900,9 @@ When exploring code:
|
|
|
1635
1900
|
systemPrompt += '```\n' + this.fileList + '\n```\n';
|
|
1636
1901
|
}
|
|
1637
1902
|
|
|
1903
|
+
// Add architecture context if available
|
|
1904
|
+
systemPrompt += this.getArchitectureSection();
|
|
1905
|
+
|
|
1638
1906
|
return systemPrompt;
|
|
1639
1907
|
}
|
|
1640
1908
|
|
|
@@ -1676,7 +1944,10 @@ When exploring code:
|
|
|
1676
1944
|
|
|
1677
1945
|
// Core tools (filtered by allowedTools)
|
|
1678
1946
|
if (isToolAllowed('search')) {
|
|
1679
|
-
|
|
1947
|
+
const searchDefinition = this.searchDelegate
|
|
1948
|
+
? `${searchToolDefinition}\n**Note:** This search tool delegates code searching to a dedicated subagent and returns extracted code blocks. Use extract only to expand context or if search returns no code.`
|
|
1949
|
+
: searchToolDefinition;
|
|
1950
|
+
toolDefinitions += `${searchDefinition}\n`;
|
|
1680
1951
|
}
|
|
1681
1952
|
if (isToolAllowed('query')) {
|
|
1682
1953
|
toolDefinitions += `${queryToolDefinition}\n`;
|
|
@@ -1690,6 +1961,12 @@ When exploring code:
|
|
|
1690
1961
|
if (isToolAllowed('searchFiles')) {
|
|
1691
1962
|
toolDefinitions += `${searchFilesToolDefinition}\n`;
|
|
1692
1963
|
}
|
|
1964
|
+
if (this.enableSkills && isToolAllowed('listSkills')) {
|
|
1965
|
+
toolDefinitions += `${listSkillsToolDefinition}\n`;
|
|
1966
|
+
}
|
|
1967
|
+
if (this.enableSkills && isToolAllowed('useSkill')) {
|
|
1968
|
+
toolDefinitions += `${useSkillToolDefinition}\n`;
|
|
1969
|
+
}
|
|
1693
1970
|
if (isToolAllowed('readImage')) {
|
|
1694
1971
|
toolDefinitions += `${readImageToolDefinition}\n`;
|
|
1695
1972
|
}
|
|
@@ -1778,12 +2055,12 @@ I need to find code related to error handling in the search module. The most app
|
|
|
1778
2055
|
10. If your previous response was already correct and complete, you may use \`<attempt_complete>\` as a shorthand.
|
|
1779
2056
|
|
|
1780
2057
|
Available Tools:
|
|
1781
|
-
- search: Search code using keyword queries.
|
|
2058
|
+
- search: Search code using keyword queries${this.searchDelegate ? ' (returns extracted code blocks via a dedicated subagent)' : ''}.
|
|
1782
2059
|
- query: Search code using structural AST patterns.
|
|
1783
2060
|
- extract: Extract specific code blocks or lines from files.
|
|
1784
2061
|
- listFiles: List files and directories in a specified location.
|
|
1785
2062
|
- searchFiles: Find files matching a glob pattern with recursive search capability.
|
|
1786
|
-
- readImage: Read and load an image file for AI analysis.
|
|
2063
|
+
${this.enableSkills ? '- listSkills: List available agent skills discovered in the repository.\n- useSkill: Load and activate a specific skill\'s instructions.\n' : ''}- readImage: Read and load an image file for AI analysis.
|
|
1787
2064
|
${this.allowEdit ? '- implement: Implement a feature or fix a bug using aider.\n- edit: Edit files using exact string replacement.\n- create: Create new files with specified content.\n' : ''}${this.enableDelegate ? '- delegate: Delegate big distinct tasks to specialized probe subagents.\n' : ''}${this.enableBash ? '- bash: Execute bash commands for system operations.\n' : ''}
|
|
1788
2065
|
- attempt_completion: Finalize the task and provide the result to the user.
|
|
1789
2066
|
- attempt_complete: Quick completion using previous response (shorthand).
|
|
@@ -1795,7 +2072,7 @@ Follow these instructions carefully:
|
|
|
1795
2072
|
1. Analyze the user's request.
|
|
1796
2073
|
2. Use <thinking></thinking> tags to analyze the situation and determine the appropriate tool for each step.
|
|
1797
2074
|
3. Use the available tools step-by-step to fulfill the request.
|
|
1798
|
-
4. You should always prefer the \`search\` tool for code-related questions. Read full files only if really necessary.
|
|
2075
|
+
4. You should always prefer the \`search\` tool for code-related questions.${this.searchDelegate ? ' It already returns extracted code blocks; use \`extract\` only to expand context or read full files.' : ' Read full files only if really necessary.'}
|
|
1799
2076
|
5. Ensure to get really deep and understand the full picture before answering.
|
|
1800
2077
|
6. You MUST respond with exactly ONE tool call per message, using the specified XML format, until the task is complete.
|
|
1801
2078
|
7. Wait for the tool execution result (provided in the next user message in a <tool_result> block) before proceeding to the next step.
|
|
@@ -1841,6 +2118,14 @@ Follow these instructions carefully:
|
|
|
1841
2118
|
// Add Tool Definitions
|
|
1842
2119
|
systemMessage += `\n# Tools Available\n${toolDefinitions}\n`;
|
|
1843
2120
|
|
|
2121
|
+
// Add available skills (metadata only)
|
|
2122
|
+
if (this.enableSkills) {
|
|
2123
|
+
const skillsXml = await this._getAvailableSkillsXml();
|
|
2124
|
+
if (skillsXml) {
|
|
2125
|
+
systemMessage += `\n# Available Skills\n${skillsXml}\n\nTo use a skill, call the useSkill tool with its name.\n`;
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
|
|
1844
2129
|
// Add MCP tools if available (filtered by allowedTools)
|
|
1845
2130
|
if (this.mcpBridge && this.mcpBridge.getToolNames().length > 0) {
|
|
1846
2131
|
const allMcpTools = this.mcpBridge.getToolNames();
|
|
@@ -1876,6 +2161,10 @@ Follow these instructions carefully:
|
|
|
1876
2161
|
systemMessage += `\n# Repository Structure\n\nYou are working with a repository located at: ${searchDirectory}\n\n`;
|
|
1877
2162
|
}
|
|
1878
2163
|
|
|
2164
|
+
// Add architecture context if available
|
|
2165
|
+
await this.loadArchitectureContext();
|
|
2166
|
+
systemMessage += this.getArchitectureSection();
|
|
2167
|
+
|
|
1879
2168
|
if (this.allowedFolders.length > 0) {
|
|
1880
2169
|
systemMessage += `\n**Important**: For security reasons, you can only search within these allowed folders: ${this.allowedFolders.join(', ')}\n\n`;
|
|
1881
2170
|
}
|
|
@@ -2330,6 +2619,8 @@ Follow these instructions carefully:
|
|
|
2330
2619
|
if (this.allowedTools.isEnabled('extract')) validTools.push('extract');
|
|
2331
2620
|
if (this.allowedTools.isEnabled('listFiles')) validTools.push('listFiles');
|
|
2332
2621
|
if (this.allowedTools.isEnabled('searchFiles')) validTools.push('searchFiles');
|
|
2622
|
+
if (this.enableSkills && this.allowedTools.isEnabled('listSkills')) validTools.push('listSkills');
|
|
2623
|
+
if (this.enableSkills && this.allowedTools.isEnabled('useSkill')) validTools.push('useSkill');
|
|
2333
2624
|
if (this.allowedTools.isEnabled('readImage')) validTools.push('readImage');
|
|
2334
2625
|
// Always allow attempt_completion - it's a completion signal, not a tool
|
|
2335
2626
|
// This ensures agents can complete even when disableTools: true is set (fixes #333)
|
|
@@ -2518,6 +2809,7 @@ Follow these instructions carefully:
|
|
|
2518
2809
|
path: this.searchPath, // Inherit search path
|
|
2519
2810
|
provider: this.apiType, // Inherit AI provider (string identifier)
|
|
2520
2811
|
model: this.model, // Inherit model
|
|
2812
|
+
searchDelegate: this.searchDelegate,
|
|
2521
2813
|
debug: this.debug,
|
|
2522
2814
|
tracer: this.tracer
|
|
2523
2815
|
};
|
|
@@ -3371,6 +3663,7 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
3371
3663
|
promptType: this.promptType,
|
|
3372
3664
|
allowEdit: this.allowEdit,
|
|
3373
3665
|
enableDelegate: this.enableDelegate,
|
|
3666
|
+
architectureFileName: this.architectureFileName,
|
|
3374
3667
|
path: this.allowedFolders[0], // Use first allowed folder as primary path
|
|
3375
3668
|
allowedFolders: [...this.allowedFolders],
|
|
3376
3669
|
cwd: this.cwd, // Preserve explicit working directory
|
|
@@ -3378,11 +3671,14 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
3378
3671
|
model: this.clientApiModel,
|
|
3379
3672
|
debug: this.debug,
|
|
3380
3673
|
outline: this.outline,
|
|
3674
|
+
searchDelegate: this.searchDelegate,
|
|
3381
3675
|
maxResponseTokens: this.maxResponseTokens,
|
|
3382
3676
|
maxIterations: this.maxIterations,
|
|
3383
3677
|
disableMermaidValidation: this.disableMermaidValidation,
|
|
3384
3678
|
disableJsonValidation: this.disableJsonValidation,
|
|
3385
3679
|
completionPrompt: this.completionPrompt,
|
|
3680
|
+
enableSkills: this.enableSkills,
|
|
3681
|
+
skillDirs: this.skillDirs ? [...this.skillDirs] : null,
|
|
3386
3682
|
allowedTools: allowedToolsArray,
|
|
3387
3683
|
enableMcp: !!this.mcpBridge,
|
|
3388
3684
|
mcpConfig: this.mcpConfig,
|