oricore 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/dist/agent/agent/agentManager.d.ts +38 -0
- package/dist/agent/agent/builtin/common.d.ts +5 -0
- package/dist/agent/agent/builtin/explore.d.ts +5 -0
- package/dist/agent/agent/builtin/general-purpose.d.ts +5 -0
- package/dist/agent/agent/builtin/index.d.ts +5 -0
- package/dist/agent/agent/executor.d.ts +2 -0
- package/dist/agent/agent/types.d.ts +98 -0
- package/dist/api/engine.d.ts +213 -0
- package/dist/communication/index.d.ts +4 -0
- package/dist/communication/messageBus.d.ts +71 -0
- package/dist/core/at.d.ts +26 -0
- package/dist/core/backgroundTaskManager.d.ts +27 -0
- package/dist/core/compact.d.ts +9 -0
- package/dist/core/config.d.ts +103 -0
- package/dist/core/constants.d.ts +32 -0
- package/dist/core/context.d.ts +57 -0
- package/dist/core/globalData.d.ts +21 -0
- package/dist/core/history.d.ts +24 -0
- package/dist/core/ide.d.ts +103 -0
- package/dist/core/jsonl.d.ts +37 -0
- package/dist/core/llmsContext.d.ts +14 -0
- package/dist/core/loop.d.ts +82 -0
- package/dist/core/message.d.ts +132 -0
- package/dist/core/model.d.ts +79 -0
- package/dist/core/output-style/builtin/default.d.ts +2 -0
- package/dist/core/output-style/builtin/explanatory.d.ts +2 -0
- package/dist/core/output-style/builtin/index.d.ts +6 -0
- package/dist/core/output-style/builtin/miao.d.ts +2 -0
- package/dist/core/output-style/builtin/minimal.d.ts +2 -0
- package/dist/core/output-style/types.d.ts +6 -0
- package/dist/core/outputFormat.d.ts +29 -0
- package/dist/core/outputStyle.d.ts +43 -0
- package/dist/core/paths.d.ts +20 -0
- package/dist/core/planSystemPrompt.d.ts +5 -0
- package/dist/core/plugin.d.ts +138 -0
- package/dist/core/project.d.ts +64 -0
- package/dist/core/promptCache.d.ts +3 -0
- package/dist/core/query.d.ts +14 -0
- package/dist/core/rules.d.ts +8 -0
- package/dist/core/systemPrompt.d.ts +9 -0
- package/dist/core/thinking-config.d.ts +3 -0
- package/dist/core/usage.d.ts +14 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +144432 -0
- package/dist/mcp/mcp.d.ts +49 -0
- package/dist/modes/builtin.d.ts +34 -0
- package/dist/modes/index.d.ts +8 -0
- package/dist/modes/registry.d.ts +18 -0
- package/dist/modes/types.d.ts +51 -0
- package/dist/platform/index.d.ts +5 -0
- package/dist/platform/node.d.ts +28 -0
- package/dist/platform/types.d.ts +41 -0
- package/dist/session/session.d.ts +43 -0
- package/dist/skill/skill.d.ts +79 -0
- package/dist/tools/tool.d.ts +119 -0
- package/dist/tools/tools/askUserQuestion.d.ts +48 -0
- package/dist/tools/tools/bash.d.ts +43 -0
- package/dist/tools/tools/edit.d.ts +9 -0
- package/dist/tools/tools/fetch.d.ts +9 -0
- package/dist/tools/tools/glob.d.ts +7 -0
- package/dist/tools/tools/grep.d.ts +22 -0
- package/dist/tools/tools/ls.d.ts +6 -0
- package/dist/tools/tools/read.d.ts +9 -0
- package/dist/tools/tools/skill.d.ts +7 -0
- package/dist/tools/tools/task.d.ts +14 -0
- package/dist/tools/tools/todo.d.ts +37 -0
- package/dist/tools/tools/write.d.ts +7 -0
- package/dist/utils/apiKeyRotation.d.ts +2 -0
- package/dist/utils/applyEdit.d.ts +17 -0
- package/dist/utils/background-detection.d.ts +2 -0
- package/dist/utils/dotenv.d.ts +9 -0
- package/dist/utils/env.d.ts +6 -0
- package/dist/utils/error.d.ts +11 -0
- package/dist/utils/execFileNoThrow.d.ts +8 -0
- package/dist/utils/files.d.ts +10 -0
- package/dist/utils/git.d.ts +163 -0
- package/dist/utils/ide.d.ts +27 -0
- package/dist/utils/ignore.d.ts +6 -0
- package/dist/utils/isLocal.d.ts +1 -0
- package/dist/utils/language.d.ts +9 -0
- package/dist/utils/list.d.ts +20 -0
- package/dist/utils/mergeSystemMessagesMiddleware.d.ts +2 -0
- package/dist/utils/messageNormalization.d.ts +22 -0
- package/dist/utils/path.d.ts +34 -0
- package/dist/utils/prependSystemMessageMiddleware.d.ts +2 -0
- package/dist/utils/project.d.ts +1 -0
- package/dist/utils/proxy.d.ts +18 -0
- package/dist/utils/randomUUID.d.ts +5 -0
- package/dist/utils/renderSessionMarkdown.d.ts +10 -0
- package/dist/utils/ripgrep.d.ts +16 -0
- package/dist/utils/safeFrontMatter.d.ts +11 -0
- package/dist/utils/safeParseJson.d.ts +1 -0
- package/dist/utils/safeStringify.d.ts +1 -0
- package/dist/utils/sanitizeAIResponse.d.ts +30 -0
- package/dist/utils/setTerminalTitle.d.ts +1 -0
- package/dist/utils/shell-execution.d.ts +44 -0
- package/dist/utils/string.d.ts +8 -0
- package/dist/utils/symbols.d.ts +14 -0
- package/dist/utils/system-encoding.d.ts +40 -0
- package/dist/utils/tokenCounter.d.ts +8 -0
- package/dist/utils/username.d.ts +1 -0
- package/package.json +106 -0
- package/src/agent/agent/agentManager.test.ts +124 -0
- package/src/agent/agent/agentManager.ts +372 -0
- package/src/agent/agent/builtin/common.ts +20 -0
- package/src/agent/agent/builtin/explore.ts +53 -0
- package/src/agent/agent/builtin/general-purpose.ts +38 -0
- package/src/agent/agent/builtin/index.ts +13 -0
- package/src/agent/agent/executor.test.ts +339 -0
- package/src/agent/agent/executor.ts +224 -0
- package/src/agent/agent/types.ts +119 -0
- package/src/api/engine.ts +466 -0
- package/src/communication/index.ts +18 -0
- package/src/communication/messageBus.ts +393 -0
- package/src/core/at.ts +315 -0
- package/src/core/backgroundTaskManager.ts +129 -0
- package/src/core/compact.ts +95 -0
- package/src/core/config.ts +441 -0
- package/src/core/constants.ts +82 -0
- package/src/core/context.ts +214 -0
- package/src/core/globalData.ts +77 -0
- package/src/core/history.ts +323 -0
- package/src/core/ide.ts +325 -0
- package/src/core/jsonl.ts +100 -0
- package/src/core/llmsContext.ts +117 -0
- package/src/core/loop.ts +638 -0
- package/src/core/message.ts +304 -0
- package/src/core/model.ts +2198 -0
- package/src/core/output-style/builtin/default.ts +9 -0
- package/src/core/output-style/builtin/explanatory.ts +22 -0
- package/src/core/output-style/builtin/index.ts +19 -0
- package/src/core/output-style/builtin/miao.ts +22 -0
- package/src/core/output-style/builtin/minimal.ts +8 -0
- package/src/core/output-style/types.ts +6 -0
- package/src/core/outputFormat.ts +93 -0
- package/src/core/outputStyle.ts +255 -0
- package/src/core/paths.ts +161 -0
- package/src/core/planSystemPrompt.ts +46 -0
- package/src/core/plugin.ts +299 -0
- package/src/core/project.ts +492 -0
- package/src/core/promptCache.ts +32 -0
- package/src/core/query.ts +46 -0
- package/src/core/rules.ts +56 -0
- package/src/core/systemPrompt.ts +176 -0
- package/src/core/thinking-config.ts +98 -0
- package/src/core/usage.ts +68 -0
- package/src/index.ts +39 -0
- package/src/mcp/mcp.ts +637 -0
- package/src/modes/builtin.ts +305 -0
- package/src/modes/index.ts +22 -0
- package/src/modes/registry.ts +39 -0
- package/src/modes/types.ts +56 -0
- package/src/platform/index.ts +6 -0
- package/src/platform/node.ts +108 -0
- package/src/platform/types.ts +54 -0
- package/src/plugins/index.ts +15 -0
- package/src/session/session.ts +187 -0
- package/src/skill/skill.ts +702 -0
- package/src/tools/tool.ts +378 -0
- package/src/tools/tools/askUserQuestion.ts +134 -0
- package/src/tools/tools/bash.test.ts +425 -0
- package/src/tools/tools/bash.ts +999 -0
- package/src/tools/tools/edit.ts +86 -0
- package/src/tools/tools/fetch.ts +129 -0
- package/src/tools/tools/glob.ts +69 -0
- package/src/tools/tools/grep.test.ts +194 -0
- package/src/tools/tools/grep.ts +358 -0
- package/src/tools/tools/ls.ts +51 -0
- package/src/tools/tools/read.test.ts +169 -0
- package/src/tools/tools/read.ts +284 -0
- package/src/tools/tools/skill.ts +73 -0
- package/src/tools/tools/task.test.ts +262 -0
- package/src/tools/tools/task.ts +284 -0
- package/src/tools/tools/todo.ts +269 -0
- package/src/tools/tools/write.ts +71 -0
- package/src/types.d.ts +18 -0
- package/src/utils/apiKeyRotation.test.ts +70 -0
- package/src/utils/apiKeyRotation.ts +24 -0
- package/src/utils/applyEdit.test.ts +388 -0
- package/src/utils/applyEdit.ts +547 -0
- package/src/utils/background-detection.test.ts +61 -0
- package/src/utils/background-detection.ts +58 -0
- package/src/utils/dotenv.ts +26 -0
- package/src/utils/env.ts +90 -0
- package/src/utils/error.ts +38 -0
- package/src/utils/execFileNoThrow.ts +49 -0
- package/src/utils/files.ts +93 -0
- package/src/utils/git.ts +1152 -0
- package/src/utils/ide.ts +279 -0
- package/src/utils/ignore.ts +275 -0
- package/src/utils/isLocal.ts +6 -0
- package/src/utils/language.ts +33 -0
- package/src/utils/list.ts +200 -0
- package/src/utils/mergeSystemMessagesMiddleware.ts +32 -0
- package/src/utils/messageNormalization.test.ts +401 -0
- package/src/utils/messageNormalization.ts +168 -0
- package/src/utils/path.ts +98 -0
- package/src/utils/prependSystemMessageMiddleware.ts +16 -0
- package/src/utils/project.ts +32 -0
- package/src/utils/proxy.ts +102 -0
- package/src/utils/randomUUID.ts +11 -0
- package/src/utils/renderSessionMarkdown.ts +175 -0
- package/src/utils/ripgrep.ts +189 -0
- package/src/utils/safeFrontMatter.test.ts +118 -0
- package/src/utils/safeFrontMatter.ts +68 -0
- package/src/utils/safeParseJson.ts +7 -0
- package/src/utils/safeStringify.ts +10 -0
- package/src/utils/sanitizeAIResponse.test.ts +135 -0
- package/src/utils/sanitizeAIResponse.ts +55 -0
- package/src/utils/setTerminalTitle.ts +7 -0
- package/src/utils/shell-execution.test.ts +237 -0
- package/src/utils/shell-execution.ts +279 -0
- package/src/utils/string.ts +13 -0
- package/src/utils/symbols.ts +18 -0
- package/src/utils/system-encoding.test.ts +164 -0
- package/src/utils/system-encoding.ts +296 -0
- package/src/utils/tokenCounter.test.ts +38 -0
- package/src/utils/tokenCounter.ts +19 -0
- package/src/utils/username.ts +21 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AGENT_TYPE } from '../../../core/constants';
|
|
2
|
+
import type { Context } from '../../../core/context';
|
|
3
|
+
import { type AgentDefinition, AgentSource } from '../types';
|
|
4
|
+
import { CONTEXT_NOTES, TASK_TOOL_NAME } from './common';
|
|
5
|
+
|
|
6
|
+
export function createGeneralPurposeAgent(opts: {
|
|
7
|
+
context: Context;
|
|
8
|
+
}): AgentDefinition {
|
|
9
|
+
const { context } = opts;
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
agentType: AGENT_TYPE.GENERAL_PURPOSE,
|
|
13
|
+
|
|
14
|
+
whenToUse: `General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.`,
|
|
15
|
+
|
|
16
|
+
systemPrompt: `You are an AI coding assistant. Given the user's message, use the tools available to complete the task. Do what has been asked; nothing more, nothing less. When you complete the task simply respond with a detailed writeup.
|
|
17
|
+
|
|
18
|
+
Your strengths:
|
|
19
|
+
- Searching for code, configurations, and patterns across large codebases
|
|
20
|
+
- Analyzing multiple files to understand system architecture
|
|
21
|
+
- Investigating complex questions that require exploring many files
|
|
22
|
+
- Performing multi-step research tasks
|
|
23
|
+
|
|
24
|
+
Guidelines:
|
|
25
|
+
- For file searches: Use grep or glob when you need to search broadly. Use read when you know the specific file path.
|
|
26
|
+
- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.
|
|
27
|
+
- Be thorough: Check multiple locations, consider different naming conventions, look for related files.
|
|
28
|
+
- NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one.
|
|
29
|
+
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested.
|
|
30
|
+
|
|
31
|
+
${CONTEXT_NOTES}`,
|
|
32
|
+
|
|
33
|
+
model: context.config.model,
|
|
34
|
+
source: AgentSource.BuiltIn,
|
|
35
|
+
disallowedTools: [TASK_TOOL_NAME],
|
|
36
|
+
forkContext: false,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Context } from '../../../core/context';
|
|
2
|
+
import type { AgentDefinition } from '../types';
|
|
3
|
+
import { createExploreAgent } from './explore';
|
|
4
|
+
import { createGeneralPurposeAgent } from './general-purpose';
|
|
5
|
+
|
|
6
|
+
export function getBuiltinAgents(opts: {
|
|
7
|
+
context: Context;
|
|
8
|
+
}): AgentDefinition[] {
|
|
9
|
+
return [
|
|
10
|
+
createExploreAgent(opts),
|
|
11
|
+
createGeneralPurposeAgent(opts),
|
|
12
|
+
];
|
|
13
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { Context } from '../../core/context';
|
|
3
|
+
import type { Tool } from '../../tools/tool';
|
|
4
|
+
import { executeAgent } from './executor';
|
|
5
|
+
import { type AgentDefinition, AgentSource } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Integration tests for executeAgent
|
|
9
|
+
*
|
|
10
|
+
* Note: Most comprehensive testing requires mocking the Project class,
|
|
11
|
+
* which has proven complex with Vitest. The core functionality is tested
|
|
12
|
+
* through:
|
|
13
|
+
* 1. The basic error handling test below
|
|
14
|
+
* 2. Manual testing in the development environment
|
|
15
|
+
* 3. End-to-end tests in the full application context
|
|
16
|
+
*
|
|
17
|
+
* Key behaviors tested manually:
|
|
18
|
+
* - onToolApprove callback propagation
|
|
19
|
+
* - Custom logPath usage
|
|
20
|
+
* - Model inheritance from context
|
|
21
|
+
* - Message metadata enhancement
|
|
22
|
+
* - Tool filtering
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
describe('executeAgent', () => {
|
|
26
|
+
test('should return error if agent has no available tools', async () => {
|
|
27
|
+
const context = await Context.create({
|
|
28
|
+
cwd: process.cwd(),
|
|
29
|
+
productName: 'test',
|
|
30
|
+
version: '1.0.0',
|
|
31
|
+
argvConfig: {},
|
|
32
|
+
plugins: [],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const definition: AgentDefinition = {
|
|
36
|
+
agentType: 'Test',
|
|
37
|
+
whenToUse: 'Test',
|
|
38
|
+
systemPrompt: 'Test',
|
|
39
|
+
model: 'test-model',
|
|
40
|
+
source: AgentSource.BuiltIn,
|
|
41
|
+
disallowedTools: ['read', 'write', 'glob', 'grep'],
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const result = await executeAgent({
|
|
45
|
+
definition,
|
|
46
|
+
prompt: 'Test',
|
|
47
|
+
tools: [{ name: 'read' } as Tool, { name: 'write' } as Tool],
|
|
48
|
+
context,
|
|
49
|
+
cwd: '/test',
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
expect(result.status).toBe('failed');
|
|
53
|
+
expect(result.content).toContain('no available tools');
|
|
54
|
+
|
|
55
|
+
await context.destroy();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('should throw error if no model is specified and definition model is missing', async () => {
|
|
59
|
+
const context = await Context.create({
|
|
60
|
+
cwd: process.cwd(),
|
|
61
|
+
productName: 'test',
|
|
62
|
+
version: '1.0.0',
|
|
63
|
+
argvConfig: { model: undefined },
|
|
64
|
+
plugins: [],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const definition: AgentDefinition = {
|
|
68
|
+
agentType: 'Test',
|
|
69
|
+
whenToUse: 'Test',
|
|
70
|
+
systemPrompt: 'Test system prompt',
|
|
71
|
+
model: '', // Empty model
|
|
72
|
+
source: AgentSource.BuiltIn,
|
|
73
|
+
tools: ['*'],
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const result = await executeAgent({
|
|
77
|
+
definition,
|
|
78
|
+
prompt: 'Test prompt',
|
|
79
|
+
tools: [{ name: 'test-tool' } as Tool],
|
|
80
|
+
context,
|
|
81
|
+
cwd: '/test',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
expect(result.status).toBe('failed');
|
|
85
|
+
expect(result.content).toContain('No model specified');
|
|
86
|
+
|
|
87
|
+
await context.destroy();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('should throw error if agentType is missing', async () => {
|
|
91
|
+
const context = await Context.create({
|
|
92
|
+
cwd: process.cwd(),
|
|
93
|
+
productName: 'test',
|
|
94
|
+
version: '1.0.0',
|
|
95
|
+
argvConfig: {},
|
|
96
|
+
plugins: [],
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const definition: AgentDefinition = {
|
|
100
|
+
agentType: '',
|
|
101
|
+
whenToUse: 'Test',
|
|
102
|
+
systemPrompt: 'Test system prompt',
|
|
103
|
+
model: 'test-model',
|
|
104
|
+
source: AgentSource.BuiltIn,
|
|
105
|
+
tools: ['*'],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const result = await executeAgent({
|
|
109
|
+
definition,
|
|
110
|
+
prompt: 'Test prompt',
|
|
111
|
+
tools: [{ name: 'test-tool' } as Tool],
|
|
112
|
+
context,
|
|
113
|
+
cwd: '/test',
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(result.status).toBe('failed');
|
|
117
|
+
expect(result.content).toContain('must have agentType');
|
|
118
|
+
|
|
119
|
+
await context.destroy();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test('should throw error if systemPrompt is missing', async () => {
|
|
123
|
+
const context = await Context.create({
|
|
124
|
+
cwd: process.cwd(),
|
|
125
|
+
productName: 'test',
|
|
126
|
+
version: '1.0.0',
|
|
127
|
+
argvConfig: {},
|
|
128
|
+
plugins: [],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const definition: AgentDefinition = {
|
|
132
|
+
agentType: 'Test',
|
|
133
|
+
whenToUse: 'Test',
|
|
134
|
+
systemPrompt: '',
|
|
135
|
+
model: 'test-model',
|
|
136
|
+
source: AgentSource.BuiltIn,
|
|
137
|
+
tools: ['*'],
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = await executeAgent({
|
|
141
|
+
definition,
|
|
142
|
+
prompt: 'Test prompt',
|
|
143
|
+
tools: [{ name: 'test-tool' } as Tool],
|
|
144
|
+
context,
|
|
145
|
+
cwd: '/test',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
expect(result.status).toBe('failed');
|
|
149
|
+
expect(result.content).toContain('must have systemPrompt');
|
|
150
|
+
|
|
151
|
+
await context.destroy();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('resolveAgentModel', () => {
|
|
155
|
+
test('should use explicit model from options (priority 1)', async () => {
|
|
156
|
+
const context = await Context.create({
|
|
157
|
+
cwd: process.cwd(),
|
|
158
|
+
productName: 'test',
|
|
159
|
+
version: '1.0.0',
|
|
160
|
+
argvConfig: {
|
|
161
|
+
model: 'global-model',
|
|
162
|
+
agent: {
|
|
163
|
+
explore: { model: 'config-explore-model' },
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
plugins: [],
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const definition: AgentDefinition = {
|
|
170
|
+
agentType: 'explore',
|
|
171
|
+
whenToUse: 'Test',
|
|
172
|
+
systemPrompt: 'Test system prompt',
|
|
173
|
+
model: 'definition-model',
|
|
174
|
+
source: AgentSource.BuiltIn,
|
|
175
|
+
tools: ['read'],
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const result = await executeAgent({
|
|
179
|
+
definition,
|
|
180
|
+
prompt: 'Test prompt',
|
|
181
|
+
tools: [{ name: 'read' } as Tool],
|
|
182
|
+
context,
|
|
183
|
+
model: 'explicit-model', // This should take priority
|
|
184
|
+
cwd: '/test',
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// The execution will fail because we don't have real tools set up,
|
|
188
|
+
// but we can verify the model was attempted to be used
|
|
189
|
+
expect(result.status).toBe('failed');
|
|
190
|
+
|
|
191
|
+
await context.destroy();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('should use config agent model (priority 2)', async () => {
|
|
195
|
+
const context = await Context.create({
|
|
196
|
+
cwd: process.cwd(),
|
|
197
|
+
productName: 'test',
|
|
198
|
+
version: '1.0.0',
|
|
199
|
+
argvConfig: {
|
|
200
|
+
model: 'global-model',
|
|
201
|
+
agent: {
|
|
202
|
+
explore: { model: 'config-explore-model' },
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
plugins: [],
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const definition: AgentDefinition = {
|
|
209
|
+
agentType: 'explore',
|
|
210
|
+
whenToUse: 'Test',
|
|
211
|
+
systemPrompt: 'Test system prompt',
|
|
212
|
+
model: 'definition-model',
|
|
213
|
+
source: AgentSource.BuiltIn,
|
|
214
|
+
tools: ['read'],
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const result = await executeAgent({
|
|
218
|
+
definition,
|
|
219
|
+
prompt: 'Test prompt',
|
|
220
|
+
tools: [{ name: 'read' } as Tool],
|
|
221
|
+
context,
|
|
222
|
+
// No explicit model provided
|
|
223
|
+
cwd: '/test',
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// config.agent.explore.model should be used
|
|
227
|
+
expect(result.status).toBe('failed');
|
|
228
|
+
|
|
229
|
+
await context.destroy();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('should use agent definition model (priority 3)', async () => {
|
|
233
|
+
const context = await Context.create({
|
|
234
|
+
cwd: process.cwd(),
|
|
235
|
+
productName: 'test',
|
|
236
|
+
version: '1.0.0',
|
|
237
|
+
argvConfig: {
|
|
238
|
+
model: 'global-model',
|
|
239
|
+
// No agent config
|
|
240
|
+
},
|
|
241
|
+
plugins: [],
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const definition: AgentDefinition = {
|
|
245
|
+
agentType: 'explore',
|
|
246
|
+
whenToUse: 'Test',
|
|
247
|
+
systemPrompt: 'Test system prompt',
|
|
248
|
+
model: 'definition-model',
|
|
249
|
+
source: AgentSource.BuiltIn,
|
|
250
|
+
tools: ['read'],
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const result = await executeAgent({
|
|
254
|
+
definition,
|
|
255
|
+
prompt: 'Test prompt',
|
|
256
|
+
tools: [{ name: 'read' } as Tool],
|
|
257
|
+
context,
|
|
258
|
+
cwd: '/test',
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// definition.model should be used
|
|
262
|
+
expect(result.status).toBe('failed');
|
|
263
|
+
|
|
264
|
+
await context.destroy();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test('should fallback to global model (priority 4)', async () => {
|
|
268
|
+
const context = await Context.create({
|
|
269
|
+
cwd: process.cwd(),
|
|
270
|
+
productName: 'test',
|
|
271
|
+
version: '1.0.0',
|
|
272
|
+
argvConfig: {
|
|
273
|
+
model: 'global-model',
|
|
274
|
+
},
|
|
275
|
+
plugins: [],
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const definition: AgentDefinition = {
|
|
279
|
+
agentType: 'explore',
|
|
280
|
+
whenToUse: 'Test',
|
|
281
|
+
systemPrompt: 'Test system prompt',
|
|
282
|
+
model: '', // Empty model in definition
|
|
283
|
+
source: AgentSource.BuiltIn,
|
|
284
|
+
tools: ['read'],
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const result = await executeAgent({
|
|
288
|
+
definition,
|
|
289
|
+
prompt: 'Test prompt',
|
|
290
|
+
tools: [{ name: 'read' } as Tool],
|
|
291
|
+
context,
|
|
292
|
+
cwd: '/test',
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// global model should be used
|
|
296
|
+
expect(result.status).toBe('failed');
|
|
297
|
+
|
|
298
|
+
await context.destroy();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test('should handle MODEL_INHERIT correctly', async () => {
|
|
302
|
+
const context = await Context.create({
|
|
303
|
+
cwd: process.cwd(),
|
|
304
|
+
productName: 'test',
|
|
305
|
+
version: '1.0.0',
|
|
306
|
+
argvConfig: {
|
|
307
|
+
model: 'global-model',
|
|
308
|
+
agent: {
|
|
309
|
+
explore: { model: 'inherit' },
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
plugins: [],
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const definition: AgentDefinition = {
|
|
316
|
+
agentType: 'explore',
|
|
317
|
+
whenToUse: 'Test',
|
|
318
|
+
systemPrompt: 'Test system prompt',
|
|
319
|
+
model: 'inherit',
|
|
320
|
+
source: AgentSource.BuiltIn,
|
|
321
|
+
tools: ['read'],
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const result = await executeAgent({
|
|
325
|
+
definition,
|
|
326
|
+
prompt: 'Test prompt',
|
|
327
|
+
tools: [{ name: 'read' } as Tool],
|
|
328
|
+
context,
|
|
329
|
+
model: 'inherit',
|
|
330
|
+
cwd: '/test',
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Should skip 'inherit' values and fallback to global-model
|
|
334
|
+
expect(result.status).toBe('failed');
|
|
335
|
+
|
|
336
|
+
await context.destroy();
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
});
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { Context } from '../../core/context';
|
|
2
|
+
import type { NormalizedMessage } from '../../core/message';
|
|
3
|
+
import { PluginHookType } from '../../core/plugin';
|
|
4
|
+
import { Project } from '../../core/project';
|
|
5
|
+
import { Session } from '../../session/session';
|
|
6
|
+
import type { Tool } from '../../tools/tool';
|
|
7
|
+
import type {
|
|
8
|
+
AgentDefinition,
|
|
9
|
+
AgentExecuteOptions,
|
|
10
|
+
AgentExecutionResult,
|
|
11
|
+
} from './types';
|
|
12
|
+
|
|
13
|
+
enum AgentStatus {
|
|
14
|
+
Completed = 'completed',
|
|
15
|
+
Failed = 'failed',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Resolve model
|
|
19
|
+
const MODEL_INHERIT = 'inherit';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the model for an agent with the following priority:
|
|
23
|
+
* 1. Model explicitly passed in options
|
|
24
|
+
* 2. Model configured in config.agent.{agentType}.model
|
|
25
|
+
* 3. Model defined in agent definition
|
|
26
|
+
* 4. Global model from context.config.model (fallback)
|
|
27
|
+
*/
|
|
28
|
+
function resolveAgentModel(
|
|
29
|
+
agentType: string,
|
|
30
|
+
options: AgentExecuteOptions,
|
|
31
|
+
definition: AgentDefinition,
|
|
32
|
+
context: Context,
|
|
33
|
+
): string {
|
|
34
|
+
// Priority 1: Explicit model from options
|
|
35
|
+
if (options.model && options.model !== MODEL_INHERIT) {
|
|
36
|
+
return options.model;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Priority 2: Config agent-specific model
|
|
40
|
+
const configModel = context.config.agent?.[agentType]?.model;
|
|
41
|
+
if (configModel && configModel !== MODEL_INHERIT) {
|
|
42
|
+
return configModel;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Priority 3: Agent definition model
|
|
46
|
+
if (definition.model && definition.model !== MODEL_INHERIT) {
|
|
47
|
+
return definition.model;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Priority 4: Global fallback
|
|
51
|
+
return context.config.model;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function executeAgent(
|
|
55
|
+
options: AgentExecuteOptions,
|
|
56
|
+
): Promise<AgentExecutionResult> {
|
|
57
|
+
const {
|
|
58
|
+
definition,
|
|
59
|
+
prompt,
|
|
60
|
+
tools,
|
|
61
|
+
context,
|
|
62
|
+
signal,
|
|
63
|
+
onMessage,
|
|
64
|
+
onToolApprove,
|
|
65
|
+
resume,
|
|
66
|
+
} = options;
|
|
67
|
+
|
|
68
|
+
const startTime = Date.now();
|
|
69
|
+
|
|
70
|
+
const agentId = (() => {
|
|
71
|
+
if (resume) {
|
|
72
|
+
return resume;
|
|
73
|
+
}
|
|
74
|
+
return Session.createSessionId();
|
|
75
|
+
})();
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// Validate Agent definition
|
|
79
|
+
if (!definition.agentType) {
|
|
80
|
+
throw new Error('Agent definition must have agentType');
|
|
81
|
+
}
|
|
82
|
+
if (!definition.systemPrompt) {
|
|
83
|
+
throw new Error(`Agent '${definition.agentType}' must have systemPrompt`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Filter tools
|
|
87
|
+
const filteredToolList = filterTools(tools, definition);
|
|
88
|
+
|
|
89
|
+
if (filteredToolList.length === 0) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Agent '${definition.agentType}' has no available tools after filtering.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Resolve model using priority-based resolution
|
|
96
|
+
const modelName = resolveAgentModel(
|
|
97
|
+
definition.agentType,
|
|
98
|
+
options,
|
|
99
|
+
definition,
|
|
100
|
+
context,
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (!modelName) {
|
|
104
|
+
throw new Error(`No model specified for agent '${definition.agentType}'`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Create Project instance with agent log path
|
|
108
|
+
const project = new Project({
|
|
109
|
+
sessionId: `agent-${agentId}`,
|
|
110
|
+
parentSessionId: options.parentSessionId,
|
|
111
|
+
context,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Execute using Project.send
|
|
115
|
+
const result = await project.sendWithSystemPromptAndTools(prompt, {
|
|
116
|
+
model: modelName,
|
|
117
|
+
systemPrompt: definition.systemPrompt,
|
|
118
|
+
tools: filteredToolList,
|
|
119
|
+
signal,
|
|
120
|
+
skipStopHook: true,
|
|
121
|
+
onMessage: async ({ message }) => {
|
|
122
|
+
// Add agent metadata
|
|
123
|
+
const enhancedMessage: NormalizedMessage = {
|
|
124
|
+
...message,
|
|
125
|
+
metadata: {
|
|
126
|
+
...(message.metadata || {}),
|
|
127
|
+
agentId,
|
|
128
|
+
agentType: definition.agentType,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
if (onMessage) {
|
|
133
|
+
try {
|
|
134
|
+
await onMessage(enhancedMessage, agentId, modelName);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('[executeAgent] Failed to send message:', error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
onToolApprove,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Handle result
|
|
144
|
+
let executionResult: AgentExecutionResult;
|
|
145
|
+
if (result.success) {
|
|
146
|
+
executionResult = {
|
|
147
|
+
status: AgentStatus.Completed,
|
|
148
|
+
agentId,
|
|
149
|
+
content: extractFinalContent(result.data),
|
|
150
|
+
totalToolCalls: result.metadata?.toolCallsCount || 0,
|
|
151
|
+
totalDuration: Date.now() - startTime,
|
|
152
|
+
model: modelName,
|
|
153
|
+
usage: {
|
|
154
|
+
inputTokens: result.data.usage?.promptTokens || 0,
|
|
155
|
+
outputTokens: result.data.usage?.completionTokens || 0,
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
} else {
|
|
159
|
+
executionResult = {
|
|
160
|
+
status: AgentStatus.Failed,
|
|
161
|
+
agentId,
|
|
162
|
+
content: `Agent execution failed: ${result.error.message}`,
|
|
163
|
+
totalToolCalls: 0,
|
|
164
|
+
totalDuration: Date.now() - startTime,
|
|
165
|
+
model: modelName,
|
|
166
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
await context.apply({
|
|
171
|
+
hook: 'subagentStop',
|
|
172
|
+
args: [
|
|
173
|
+
{
|
|
174
|
+
parentSessionId: options.parentSessionId || '',
|
|
175
|
+
agentId,
|
|
176
|
+
agentType: definition.agentType,
|
|
177
|
+
result: executionResult,
|
|
178
|
+
usage: executionResult.usage,
|
|
179
|
+
totalToolCalls: executionResult.totalToolCalls,
|
|
180
|
+
totalDuration: executionResult.totalDuration,
|
|
181
|
+
model: modelName,
|
|
182
|
+
},
|
|
183
|
+
],
|
|
184
|
+
type: PluginHookType.Series,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return executionResult;
|
|
188
|
+
} catch (error) {
|
|
189
|
+
return {
|
|
190
|
+
status: AgentStatus.Failed,
|
|
191
|
+
agentId,
|
|
192
|
+
content: `Agent execution error: ${error instanceof Error ? error.message : String(error)}`,
|
|
193
|
+
totalToolCalls: 0,
|
|
194
|
+
totalDuration: Date.now() - startTime,
|
|
195
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function extractFinalContent(data: Record<string, unknown>): string {
|
|
201
|
+
if (data.text && typeof data.text === 'string') {
|
|
202
|
+
return data.text;
|
|
203
|
+
}
|
|
204
|
+
if (data.content && typeof data.content === 'string') {
|
|
205
|
+
return data.content;
|
|
206
|
+
}
|
|
207
|
+
return 'Agent completed successfully';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function filterTools(allTools: Tool[], agentDef: AgentDefinition): Tool[] {
|
|
211
|
+
const { tools, disallowedTools } = agentDef;
|
|
212
|
+
const disallowedSet = new Set(disallowedTools || []);
|
|
213
|
+
const hasWildcard =
|
|
214
|
+
tools === undefined || (tools.length === 1 && tools[0] === '*');
|
|
215
|
+
|
|
216
|
+
if (hasWildcard) {
|
|
217
|
+
return allTools.filter((tool) => !disallowedSet.has(tool.name));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const allowedSet = new Set(tools);
|
|
221
|
+
return allTools.filter(
|
|
222
|
+
(tool) => allowedSet.has(tool.name) && !disallowedSet.has(tool.name),
|
|
223
|
+
);
|
|
224
|
+
}
|