@compilr-dev/cli 0.5.17 → 0.6.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/dist/.tsbuildinfo.app +1 -1
- package/dist/.tsbuildinfo.data +1 -1
- package/dist/.tsbuildinfo.domain +1 -1
- package/dist/agent.d.ts +41 -111
- package/dist/agent.js +238 -390
- package/dist/commands-v2/handlers/project.d.ts +1 -0
- package/dist/commands-v2/handlers/project.js +36 -2
- package/dist/commands-v2/handlers/team.js +23 -3
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/entitlements/index.d.ts +23 -0
- package/dist/entitlements/index.js +110 -0
- package/dist/guide/cli-guide-entries.d.ts +15 -0
- package/dist/guide/cli-guide-entries.js +99 -0
- package/dist/guide/index.d.ts +5 -4
- package/dist/guide/index.js +4 -3
- package/dist/guide/shared-content.js +188 -21
- package/dist/handlers/permission-handler.js +10 -3
- package/dist/index.js +18 -0
- package/dist/repl-v2.d.ts +16 -0
- package/dist/repl-v2.js +51 -17
- package/dist/tools/db-tools.d.ts +1 -1
- package/dist/tools/platform-adapter.d.ts +1 -1
- package/dist/tools/platform-adapter.js +6 -1
- package/dist/tools.js +6 -1
- package/dist/ui/overlay/impl/app-model-overlay-v2.d.ts +57 -0
- package/dist/ui/overlay/impl/app-model-overlay-v2.js +232 -0
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +23 -1
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +203 -47
- package/dist/ui/overlay/impl/model-overlay-v2.js +2 -2
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +2 -2
- package/dist/ui/overlay/impl/new-overlay-v2.js +10 -17
- package/dist/ui/overlay/impl/team-overlay-v2.js +2 -2
- package/dist/ui/overlay/index.d.ts +1 -0
- package/dist/ui/overlay/index.js +1 -0
- package/package.json +4 -4
package/dist/agent.js
CHANGED
|
@@ -1,45 +1,108 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent Configuration
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* and
|
|
4
|
+
* Thin wrapper around createCompilrAgent() from @compilr-dev/sdk.
|
|
5
|
+
* Handles CLI-specific concerns: credential resolution, system prompt
|
|
6
|
+
* assembly, subagent callbacks, and token estimates.
|
|
7
7
|
*/
|
|
8
8
|
import { log } from './foundation/logger.js';
|
|
9
|
-
import {
|
|
9
|
+
import { createCompilrAgent, createTaskTool, defaultAgentTypes, TOOL_SETS, BUILTIN_GUARDRAILS, } from '@compilr-dev/sdk';
|
|
10
10
|
import { isAutoCompactEnabled, isDelegationEnabled, getSetting } from './settings/index.js';
|
|
11
11
|
import { getApiKey } from './utils/credentials.js';
|
|
12
|
-
import { createToolRegistry, createMinimalToolRegistry, getDirectTools, getMetaTools, initializeMetaTools, getToolIndexForSystemPrompt, getFilteredToolIndexForSystemPrompt, getToolStats, setMetaToolFilter, createToolFallback, getRegisteredMetaTools, } from './tools.js';
|
|
13
|
-
// TOOL_GROUPS no longer needed — profile resolution moved to SDK
|
|
14
|
-
import { setCapabilityManager } from './multi-agent/capability-loader.js';
|
|
15
12
|
import { getAgentRegistry } from './agents/registry.js';
|
|
16
13
|
import { SystemPromptBuilder } from './system-prompt/index.js';
|
|
17
|
-
import { getDefaultModelForTier
|
|
14
|
+
import { getDefaultModelForTier } from './models/index.js';
|
|
18
15
|
import { PROVIDER_METADATA } from './models/providers.js';
|
|
19
16
|
import { setStaticEstimates, estimateTokens, estimateJsonTokens, } from './utils/token-tracker.js';
|
|
20
17
|
import { createFileLockCheckHook, createFileLockAcquireHook } from './multi-agent/file-lock-hook.js';
|
|
21
18
|
import { getActiveProject } from './tools/project-db.js';
|
|
19
|
+
import { allDbTools, allFactoryTools } from './tools/db-tools.js';
|
|
20
|
+
import { createGuideTool } from '@compilr-dev/sdk';
|
|
21
|
+
import { CLI_GUIDE_ENTRIES } from './guide/cli-guide-entries.js';
|
|
22
|
+
const cliGuideTool = createGuideTool({
|
|
23
|
+
environment: 'cli',
|
|
24
|
+
additionalEntries: CLI_GUIDE_ENTRIES,
|
|
25
|
+
});
|
|
26
|
+
import { defineTool, createSuccessResult } from '@compilr-dev/agents';
|
|
27
|
+
/** Create plan_submit and plan_mode_exit tools if callbacks are provided */
|
|
28
|
+
function buildPlanModeTools(callbacks) {
|
|
29
|
+
if (!callbacks || !callbacks.onPlanSubmit || !callbacks.onPlanModeExit)
|
|
30
|
+
return [];
|
|
31
|
+
const onSubmit = callbacks.onPlanSubmit;
|
|
32
|
+
const onExit = callbacks.onPlanModeExit;
|
|
33
|
+
const planSubmitTool = defineTool({
|
|
34
|
+
name: 'plan_submit',
|
|
35
|
+
description: 'Submit a plan for user approval. Call when your plan is ready for review. ' +
|
|
36
|
+
'The user will choose to approve, revise, or reject. On approval, write tools are unlocked.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
plan_id: { type: 'number', description: 'ID of the plan to submit' },
|
|
41
|
+
summary: { type: 'string', description: 'One-line summary of the plan' },
|
|
42
|
+
},
|
|
43
|
+
required: ['plan_id'],
|
|
44
|
+
},
|
|
45
|
+
execute: async (input) => {
|
|
46
|
+
const result = await onSubmit({ planId: input.plan_id, summary: input.summary });
|
|
47
|
+
const messages = {
|
|
48
|
+
'approve-auto': 'Plan approved. Auto-accept mode enabled. Proceed with implementation.',
|
|
49
|
+
approve: 'Plan approved. Proceed with implementation.',
|
|
50
|
+
revise: `Plan needs revision. Feedback: ${result.feedback ?? 'No specific feedback.'}`,
|
|
51
|
+
reject: 'Plan rejected.',
|
|
52
|
+
};
|
|
53
|
+
return createSuccessResult({ action: result.action, message: messages[result.action] });
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
const planModeExitTool = defineTool({
|
|
57
|
+
name: 'plan_mode_exit',
|
|
58
|
+
description: 'Exit plan mode without a plan. Use when the task is simple enough to implement directly.',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
reason: { type: 'string', description: 'Brief reason for exiting plan mode' },
|
|
63
|
+
},
|
|
64
|
+
required: ['reason'],
|
|
65
|
+
},
|
|
66
|
+
execute: async (input) => {
|
|
67
|
+
await onExit({ reason: input.reason });
|
|
68
|
+
return createSuccessResult({ message: `Exited plan mode: ${input.reason}. Full tools now available.` });
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
return [planSubmitTool, planModeExitTool];
|
|
72
|
+
}
|
|
22
73
|
/**
|
|
23
74
|
* Default permission rules for potentially dangerous operations
|
|
24
|
-
* Note: Tool names are lowercase (bash, write_file, edit, git_commit)
|
|
25
75
|
*/
|
|
26
76
|
const DEFAULT_PERMISSION_RULES = [
|
|
27
|
-
// File writes need approval each time (user can see diff before approving)
|
|
28
77
|
{ toolName: 'write_file', level: 'once', description: 'Write/create files' },
|
|
29
78
|
{ toolName: 'edit', level: 'once', description: 'Edit file contents' },
|
|
30
|
-
// Git operations that modify state
|
|
31
79
|
{ toolName: 'git_commit', level: 'once', description: 'Create git commit' },
|
|
32
80
|
{ toolName: 'git_branch', level: 'once', description: 'Create/delete git branches' },
|
|
33
|
-
// Shell commands need approval each time
|
|
34
81
|
{ toolName: 'bash', level: 'once', description: 'Execute shell command' },
|
|
35
|
-
// Project runners (can have side effects)
|
|
36
82
|
{ toolName: 'run_tests', level: 'once', description: 'Run test suite' },
|
|
37
83
|
{ toolName: 'run_lint', level: 'once', description: 'Run linter (may auto-fix)' },
|
|
38
|
-
// Note: backlog_write removed - use workitem_* tools which modify database
|
|
39
84
|
];
|
|
85
|
+
/** Delegation config for tool result auto-summarization */
|
|
86
|
+
const CLI_DELEGATION_CONFIG = {
|
|
87
|
+
enabled: true,
|
|
88
|
+
delegationThreshold: 8000,
|
|
89
|
+
summaryMaxTokens: 800,
|
|
90
|
+
resultTTL: 600_000,
|
|
91
|
+
maxStoredResults: 50,
|
|
92
|
+
strategy: 'auto',
|
|
93
|
+
toolOverrides: {
|
|
94
|
+
bash: { threshold: 12000 },
|
|
95
|
+
grep: { threshold: 4000 },
|
|
96
|
+
git_diff: { threshold: 6000 },
|
|
97
|
+
get_tool_info: { enabled: false },
|
|
98
|
+
list_tools: { enabled: false },
|
|
99
|
+
ask_user: { enabled: false },
|
|
100
|
+
ask_user_simple: { enabled: false },
|
|
101
|
+
todo_read: { enabled: false },
|
|
102
|
+
},
|
|
103
|
+
};
|
|
40
104
|
/**
|
|
41
105
|
* Get permission info for a tool by name.
|
|
42
|
-
* Returns undefined if the tool doesn't require special permission (always allowed).
|
|
43
106
|
*/
|
|
44
107
|
export function getToolPermissionInfo(toolName) {
|
|
45
108
|
const rule = DEFAULT_PERMISSION_RULES.find(r => r.toolName === toolName);
|
|
@@ -53,7 +116,6 @@ export function getToolPermissionInfo(toolName) {
|
|
|
53
116
|
}
|
|
54
117
|
/**
|
|
55
118
|
* Get information about built-in guardrails.
|
|
56
|
-
* Used for displaying guardrail info in /help or status overlays.
|
|
57
119
|
*/
|
|
58
120
|
export function getBuiltinGuardrailInfo() {
|
|
59
121
|
return BUILTIN_GUARDRAILS.map((g) => ({
|
|
@@ -66,21 +128,16 @@ export function getBuiltinGuardrailInfo() {
|
|
|
66
128
|
}
|
|
67
129
|
/**
|
|
68
130
|
* Merges built-in agent types with custom agents from registry.
|
|
69
|
-
* Custom agents get safe read-only tools by default.
|
|
70
131
|
*/
|
|
71
132
|
function getMergedAgentTypes() {
|
|
72
133
|
const registry = getAgentRegistry();
|
|
73
134
|
const customAgents = registry.getCustomAgents();
|
|
74
|
-
// Start with default agent types (library now has correct tool names)
|
|
75
135
|
const mergedTypes = { ...defaultAgentTypes };
|
|
76
|
-
// Add custom agents from registry
|
|
77
136
|
for (const agent of customAgents) {
|
|
78
137
|
mergedTypes[agent.name] = {
|
|
79
138
|
description: agent.description,
|
|
80
139
|
systemPrompt: agent.systemPrompt,
|
|
81
140
|
defaultModel: agent.model === 'inherit' ? undefined : agent.model,
|
|
82
|
-
// Safe read-only tools for custom agents (using library's TOOL_SETS)
|
|
83
|
-
// Type assertion needed because TOOL_SETS typing might not be exported correctly
|
|
84
141
|
allowedTools: Array.isArray(TOOL_SETS.READ_ONLY) ? [...(TOOL_SETS.READ_ONLY)] : [],
|
|
85
142
|
maxIterations: 10,
|
|
86
143
|
contextMode: 'inherit-summary',
|
|
@@ -88,189 +145,52 @@ function getMergedAgentTypes() {
|
|
|
88
145
|
}
|
|
89
146
|
return mergedTypes;
|
|
90
147
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* Resolves CLI-specific concerns (credentials, settings) then delegates
|
|
94
|
-
* provider instantiation to the SDK's createProviderFromType().
|
|
95
|
-
*/
|
|
96
|
-
function createProvider(options) {
|
|
148
|
+
// ─── Provider Resolution (CLI-specific credentials) ─────────────────────────
|
|
149
|
+
function resolveProviderConfig(options) {
|
|
97
150
|
const providerType = options.provider ?? 'claude';
|
|
98
|
-
const quiet = options.quiet ?? false;
|
|
99
151
|
const meta = PROVIDER_METADATA[providerType];
|
|
100
|
-
// 1. Resolve API key from CLI credential store
|
|
101
152
|
const apiKey = meta.requiresKey ? getApiKey(meta.credentialKey) : undefined;
|
|
102
153
|
if (!apiKey && meta.requiresKey) {
|
|
103
154
|
throw new Error(`${meta.displayName} API key not found.\n` +
|
|
104
155
|
`Run /keys to set it, or: export ${meta.envVar}=...` +
|
|
105
156
|
(providerType === 'claude' ? '\nOr use --provider ollama for local models.' : ''));
|
|
106
157
|
}
|
|
107
|
-
// 2. Resolve model (from options or registry default for balanced tier)
|
|
108
158
|
const model = options.model ?? getDefaultModelForTier(providerType, 'balanced')?.id;
|
|
109
|
-
// 3. Resolve Ollama base URL from settings
|
|
110
159
|
const baseUrl = providerType === 'ollama'
|
|
111
160
|
? ((typeof getSetting('ollamaBaseUrl') === 'string'
|
|
112
161
|
? getSetting('ollamaBaseUrl')
|
|
113
|
-
: undefined) ??
|
|
114
|
-
process.env.OLLAMA_BASE_URL ??
|
|
115
|
-
'http://localhost:11434')
|
|
116
|
-
: undefined;
|
|
117
|
-
// 4. Log (unless quiet)
|
|
118
|
-
if (!quiet)
|
|
119
|
-
console.log(`Using ${meta.displayName} with model: ${model ?? 'default'}`);
|
|
120
|
-
if (!quiet && providerType === 'ollama' && baseUrl !== 'http://localhost:11434') {
|
|
121
|
-
console.log(` Ollama server: ${baseUrl ?? ''}`);
|
|
122
|
-
}
|
|
123
|
-
// 5. Delegate to SDK (with tiktoken-based token estimator for debug payload)
|
|
124
|
-
return createProviderFromType(providerType, {
|
|
125
|
-
model,
|
|
126
|
-
apiKey: apiKey ?? undefined,
|
|
127
|
-
baseUrl,
|
|
128
|
-
siteName: providerType === 'openrouter' ? 'compilr-cli' : undefined,
|
|
129
|
-
estimateTokens,
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
// =============================================================================
|
|
133
|
-
// Dynamic Capability Loading Helpers
|
|
134
|
-
// =============================================================================
|
|
135
|
-
/**
|
|
136
|
-
* Derive profile group IDs from a tool filter (array of tool names).
|
|
137
|
-
* A group is included if any of its tools are in the filter.
|
|
138
|
-
*/
|
|
139
|
-
// getProfileGroupsFromToolFilter → replaced by resolveProfileGroups from SDK
|
|
140
|
-
// autoDetectCapabilities → replaced by autoDetectCapabilities from SDK
|
|
141
|
-
// createCapabilityHook → replaced by createCapabilityHook + CapabilityContext from SDK
|
|
142
|
-
/**
|
|
143
|
-
* Creates an Agent instance configured with all tools.
|
|
144
|
-
*/
|
|
145
|
-
export function createAgent(options = {}) {
|
|
146
|
-
const provider = createProvider(options);
|
|
147
|
-
// Create context manager with model-specific limits
|
|
148
|
-
// Uses library defaults: compact at 50%, summarize at 90%, emergency at 95%
|
|
149
|
-
// Auto-compact can be disabled via settings (requires restart)
|
|
150
|
-
const autoCompact = isAutoCompactEnabled();
|
|
151
|
-
const contextManager = new ContextManager({
|
|
152
|
-
provider,
|
|
153
|
-
config: {
|
|
154
|
-
maxContextTokens: getModelContextWindow(options.model ?? '', options.provider),
|
|
155
|
-
// If auto-compact disabled, set threshold to 100% (never triggers)
|
|
156
|
-
compaction: autoCompact
|
|
157
|
-
? DEFAULT_CONTEXT_CONFIG.compaction
|
|
158
|
-
: {
|
|
159
|
-
...DEFAULT_CONTEXT_CONFIG.compaction,
|
|
160
|
-
triggerThreshold: 1.0, // Never auto-trigger
|
|
161
|
-
triggerInterval: Number.MAX_SAFE_INTEGER, // Never interval-trigger
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
});
|
|
165
|
-
// Create event handler for verbose mode
|
|
166
|
-
const onEvent = options.verbose
|
|
167
|
-
? (event) => {
|
|
168
|
-
if (event.type === 'tool_start') {
|
|
169
|
-
log.debug({ component: 'agent', tool: event.name }, 'Tool starting');
|
|
170
|
-
}
|
|
171
|
-
else if (event.type === 'tool_end') {
|
|
172
|
-
log.debug({ component: 'agent', tool: event.name }, 'Tool done');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
162
|
+
: undefined) ?? process.env.OLLAMA_BASE_URL ?? 'http://localhost:11434')
|
|
175
163
|
: undefined;
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// includeWarmTools=true moves 11 warm tools into meta-registry (hot-tools mode)
|
|
181
|
-
const useMetaTools = options.enableMetaTools && !options.minimal;
|
|
182
|
-
if (useMetaTools) {
|
|
183
|
-
initializeMetaTools(true);
|
|
184
|
-
}
|
|
185
|
-
// ==========================================================================
|
|
186
|
-
// Dynamic Capability Loading
|
|
187
|
-
// When meta-tools are enabled, create a CapabilityManager to control which
|
|
188
|
-
// tools and prompt modules are active per-turn.
|
|
189
|
-
// ==========================================================================
|
|
190
|
-
let capabilityManager;
|
|
191
|
-
let capabilityContext;
|
|
192
|
-
let orphanToolNames = [];
|
|
193
|
-
if (useMetaTools) {
|
|
194
|
-
// Use SDK's profile resolver instead of local implementation
|
|
195
|
-
const profileGroups = options.toolFilter
|
|
196
|
-
? resolveProfileGroups(options.toolFilter)
|
|
197
|
-
: Object.keys(CAPABILITY_PACKS);
|
|
198
|
-
const upfrontGroupIds = resolveUpfrontGroups(profileGroups);
|
|
199
|
-
capabilityManager = new CapabilityManager({
|
|
200
|
-
profileGroups,
|
|
201
|
-
packs: CAPABILITY_PACKS,
|
|
202
|
-
upfrontGroups: upfrontGroupIds,
|
|
203
|
-
});
|
|
204
|
-
// Expose the capability manager for slash command handlers (Phase 3)
|
|
205
|
-
setCapabilityManager(capabilityManager);
|
|
206
|
-
// Compute orphan tools (meta-registry tools not in any capability pack)
|
|
207
|
-
const packedTools = new Set();
|
|
208
|
-
for (const pack of Object.values(CAPABILITY_PACKS)) {
|
|
209
|
-
for (const tool of pack.tools) {
|
|
210
|
-
packedTools.add(tool);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
const registered = getRegisteredMetaTools();
|
|
214
|
-
orphanToolNames = registered
|
|
215
|
-
.map((t) => t.definition.name)
|
|
216
|
-
.filter((name) => !packedTools.has(name));
|
|
217
|
-
// Create capability context (SDK) for filter sync + auto-load callback
|
|
218
|
-
capabilityContext = new CapabilityContext({
|
|
219
|
-
manager: capabilityManager,
|
|
220
|
-
orphanTools: orphanToolNames,
|
|
221
|
-
onFilterUpdate: (allowed) => { setMetaToolFilter(allowed); },
|
|
222
|
-
});
|
|
223
|
-
capabilityContext.syncFilter();
|
|
224
|
-
// Log stats (unless quiet mode)
|
|
225
|
-
if (!options.quiet) {
|
|
226
|
-
const stats = getToolStats();
|
|
227
|
-
const loadedPacks = capabilityManager.getLoadedPackIds();
|
|
228
|
-
const loadableCount = capabilityManager.getCatalog().length;
|
|
229
|
-
console.log(`[Meta-tools] Direct: ${String(stats.directTools)}, ` +
|
|
230
|
-
`Meta: ${String(stats.metaRegistryTools)}, ` +
|
|
231
|
-
`Est. savings: ~${String(stats.tokenSavings)} tokens`);
|
|
232
|
-
console.log(`[Capabilities] Upfront: ${String(loadedPacks.length)} packs, ` +
|
|
233
|
-
`Loadable: ${String(loadableCount)} packs`);
|
|
164
|
+
if (!options.quiet) {
|
|
165
|
+
log.info({ component: 'agent', provider: meta.displayName, model: model ?? 'default' }, 'Provider configured');
|
|
166
|
+
if (providerType === 'ollama' && baseUrl !== 'http://localhost:11434') {
|
|
167
|
+
log.info({ component: 'agent', baseUrl }, 'Ollama server');
|
|
234
168
|
}
|
|
235
169
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
let systemPrompt;
|
|
241
|
-
// Check if we should use minimal system prompt (for testing role identity)
|
|
170
|
+
return { provider: providerType, model, apiKey: apiKey ?? undefined, baseUrl };
|
|
171
|
+
}
|
|
172
|
+
// ─── System Prompt Assembly ─────────────────────────────────────────────────
|
|
173
|
+
function buildSystemPrompt(options) {
|
|
242
174
|
if (options.useMinimalSystemPrompt && options.systemPromptAddition) {
|
|
243
|
-
|
|
244
|
-
systemPrompt = options.systemPromptAddition;
|
|
175
|
+
return options.systemPromptAddition;
|
|
245
176
|
}
|
|
246
|
-
|
|
247
|
-
//
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const buildResult = promptBuilder.build();
|
|
264
|
-
systemPrompt = buildResult.prompt;
|
|
265
|
-
// Prepend role-specific system prompt (for team agents)
|
|
266
|
-
// The default identity module is already excluded via hasRoleIdentity flag
|
|
267
|
-
if (options.systemPromptAddition) {
|
|
268
|
-
// Extract role name from the role prompt (format: "# ROLE: ROLE_NAME")
|
|
269
|
-
const roleMatch = options.systemPromptAddition.match(/^#\s*ROLE:\s*(.+)$/m);
|
|
270
|
-
const roleName = roleMatch ? roleMatch[1].trim() : 'specialized team member';
|
|
271
|
-
// Put FULL role prompt at the END (recency effect is stronger than primacy)
|
|
272
|
-
// LLMs weight the end of context more heavily
|
|
273
|
-
const roleEnding = `
|
|
177
|
+
const promptBuilder = new SystemPromptBuilder({
|
|
178
|
+
enableMetaTools: false, // SDK handles capability-based prompt assembly
|
|
179
|
+
hasGit: undefined, // Auto-detect (SDK capability hook will override if needed)
|
|
180
|
+
projectName: options.projectName,
|
|
181
|
+
projectSlug: options.projectSlug,
|
|
182
|
+
projectId: options.projectId,
|
|
183
|
+
projectContext: options.projectContext,
|
|
184
|
+
guidedModeContext: options.guidedModeContext,
|
|
185
|
+
planModeContext: options.planModeContext,
|
|
186
|
+
hasRoleIdentity: !!options.systemPromptAddition,
|
|
187
|
+
});
|
|
188
|
+
let systemPrompt = promptBuilder.build().prompt;
|
|
189
|
+
// Wrap role identity at beginning AND end for team agents
|
|
190
|
+
if (options.systemPromptAddition) {
|
|
191
|
+
const roleMatch = options.systemPromptAddition.match(/^#\s*ROLE:\s*(.+)$/m);
|
|
192
|
+
const roleName = roleMatch ? roleMatch[1].trim() : 'specialized team member';
|
|
193
|
+
const roleEnding = `
|
|
274
194
|
|
|
275
195
|
---
|
|
276
196
|
|
|
@@ -279,113 +199,130 @@ export function createAgent(options = {}) {
|
|
|
279
199
|
${options.systemPromptAddition}
|
|
280
200
|
|
|
281
201
|
**CRITICAL**: When asked "what is your role?", "what are you?", or similar identity questions, your response should acknowledge your assigned role. For example: "In this team, I'm the ${roleName}" or "I'm operating as the ${roleName} in this session."`;
|
|
282
|
-
|
|
283
|
-
systemPrompt = options.systemPromptAddition + '\n\n' + systemPrompt + roleEnding;
|
|
284
|
-
}
|
|
202
|
+
systemPrompt = options.systemPromptAddition + '\n\n' + systemPrompt + roleEnding;
|
|
285
203
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
204
|
+
return systemPrompt;
|
|
205
|
+
}
|
|
206
|
+
// ─── Context Pressure Hook ──────────────────────────────────────────────────
|
|
207
|
+
function createContextPressureHook() {
|
|
208
|
+
return (ctx) => {
|
|
209
|
+
const msgCount = ctx.messages.length;
|
|
210
|
+
if (msgCount < 20)
|
|
211
|
+
return undefined;
|
|
212
|
+
let hint;
|
|
213
|
+
if (msgCount < 40) {
|
|
214
|
+
hint = `[Context: ~${String(msgCount)} messages] Consider task() for multi-file operations.`;
|
|
215
|
+
}
|
|
216
|
+
else if (msgCount < 60) {
|
|
217
|
+
hint = `[Context: ~${String(msgCount)} messages - HIGH] Prefer task() sub-agents for file reads and code search.`;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
hint = `[Context: ~${String(msgCount)} messages - CRITICAL] Use task() for ALL exploration. Do not read files directly.`;
|
|
221
|
+
}
|
|
222
|
+
const messages = [...ctx.messages];
|
|
223
|
+
messages.splice(1, 0, { role: 'user', content: hint });
|
|
224
|
+
return { messages };
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
// ─── Main Factory ───────────────────────────────────────────────────────────
|
|
228
|
+
/**
|
|
229
|
+
* Creates an Agent instance configured with all tools.
|
|
230
|
+
*
|
|
231
|
+
* Delegates to createCompilrAgent() from @compilr-dev/sdk for:
|
|
232
|
+
* - Provider creation, context management, observation masking
|
|
233
|
+
* - Smart windowing, tool output guards
|
|
234
|
+
* - Capability loading (meta-tools, dynamic prompt assembly)
|
|
235
|
+
* - Permission handling, guardrails, delegation
|
|
236
|
+
*
|
|
237
|
+
* CLI adds on top:
|
|
238
|
+
* - Credential resolution from CLI keystore
|
|
239
|
+
* - System prompt with project context and role identity
|
|
240
|
+
* - Subagent callbacks for UI updates
|
|
241
|
+
* - Token estimate logging
|
|
242
|
+
*/
|
|
243
|
+
export function createAgent(options = {}) {
|
|
244
|
+
const { provider, model, apiKey } = resolveProviderConfig(options);
|
|
245
|
+
const systemPrompt = buildSystemPrompt(options);
|
|
246
|
+
log.info({
|
|
247
|
+
component: 'agent',
|
|
248
|
+
provider,
|
|
249
|
+
model: model ?? 'default',
|
|
250
|
+
quiet: options.quiet ?? false,
|
|
251
|
+
metaTools: options.enableMetaTools ?? false,
|
|
252
|
+
projectName: options.projectName,
|
|
253
|
+
}, 'Creating agent');
|
|
254
|
+
// ── Create agent via SDK ──────────────────────────────────────────────────
|
|
255
|
+
const compilrAgent = createCompilrAgent({
|
|
289
256
|
provider,
|
|
257
|
+
model,
|
|
258
|
+
apiKey,
|
|
290
259
|
systemPrompt,
|
|
291
260
|
maxIterations: options.maxIterations ?? 50,
|
|
292
|
-
onEvent,
|
|
293
|
-
contextManager,
|
|
294
|
-
// Set tool timeout to 2 minutes (default is 30s which is too short for complex operations)
|
|
295
|
-
// Sub-agents inherit this timeout from the parent agent
|
|
296
261
|
toolTimeoutMs: 120000,
|
|
297
|
-
// Enable file tracking for context restoration hints
|
|
298
262
|
enableFileTracking: true,
|
|
299
|
-
|
|
263
|
+
logger: log,
|
|
264
|
+
// Permissions
|
|
300
265
|
permissions: options.onPermissionRequest
|
|
301
|
-
?
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
: undefined,
|
|
308
|
-
// Iteration limit handler - asks user if they want to continue
|
|
266
|
+
? options.onPermissionRequest
|
|
267
|
+
: 'auto',
|
|
268
|
+
permissionRules: DEFAULT_PERMISSION_RULES,
|
|
269
|
+
includeDefaultRules: true,
|
|
270
|
+
// Iteration limits
|
|
309
271
|
onIterationLimitReached: options.onIterationLimitReached,
|
|
310
|
-
//
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
? {
|
|
314
|
-
maxAnchors: 50,
|
|
315
|
-
maxTokens: 4000,
|
|
316
|
-
includeDefaults: true,
|
|
317
|
-
// Note: We manage persistence ourselves via project-anchors.ts
|
|
318
|
-
// Don't set persistPath - we load anchors manually below
|
|
319
|
-
}
|
|
272
|
+
// Pins / anchors
|
|
273
|
+
pins: options.enableAnchors
|
|
274
|
+
? { maxAnchors: 50, maxTokens: 4000, includeDefaults: true }
|
|
320
275
|
: undefined,
|
|
321
|
-
// Guardrails
|
|
322
|
-
// 15 built-in patterns: git destructive ops, rm -rf, DROP TABLE, secrets, etc.
|
|
276
|
+
// Guardrails
|
|
323
277
|
guardrails: options.enableGuardrails
|
|
324
|
-
? {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
278
|
+
? { includeDefaults: true }
|
|
279
|
+
: false,
|
|
280
|
+
// Delegation
|
|
281
|
+
delegation: isDelegationEnabled() ? CLI_DELEGATION_CONFIG : undefined,
|
|
282
|
+
// Context management
|
|
283
|
+
context: {
|
|
284
|
+
compactionThreshold: isAutoCompactEnabled() ? undefined : 1.0,
|
|
285
|
+
},
|
|
286
|
+
// Suggest tool
|
|
287
|
+
onSuggest: options.onSuggest,
|
|
288
|
+
// Verbose event handler
|
|
289
|
+
onEvent: options.verbose
|
|
290
|
+
? (event) => {
|
|
291
|
+
if (event.type === 'tool_start') {
|
|
292
|
+
log.debug({ component: 'agent', tool: event.name }, 'Tool starting');
|
|
293
|
+
}
|
|
294
|
+
else if (event.type === 'tool_end') {
|
|
295
|
+
log.debug({ component: 'agent', tool: event.name }, 'Tool done');
|
|
296
|
+
}
|
|
328
297
|
}
|
|
329
298
|
: undefined,
|
|
330
|
-
//
|
|
331
|
-
|
|
299
|
+
// Capability loading (replaces CLI's manual meta-tools wiring)
|
|
300
|
+
// Platform tools (DB, factory) + MCP + guide + plan mode tools
|
|
301
|
+
capabilities: (options.enableMetaTools && !options.minimal && !options.noTools)
|
|
332
302
|
? {
|
|
333
303
|
enabled: true,
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
grep: { threshold: 4000 },
|
|
343
|
-
git_diff: { threshold: 6000 },
|
|
344
|
-
// Never summarize — agent needs verbatim results
|
|
345
|
-
get_tool_info: { enabled: false },
|
|
346
|
-
list_tools: { enabled: false },
|
|
347
|
-
ask_user: { enabled: false },
|
|
348
|
-
ask_user_simple: { enabled: false },
|
|
349
|
-
todo_read: { enabled: false },
|
|
350
|
-
},
|
|
304
|
+
profile: options.toolFilter ?? 'full',
|
|
305
|
+
additionalTools: [
|
|
306
|
+
...allDbTools,
|
|
307
|
+
...allFactoryTools,
|
|
308
|
+
...(options.mcpTools ?? []),
|
|
309
|
+
cliGuideTool,
|
|
310
|
+
...buildPlanModeTools(options.planModeCallbacks),
|
|
311
|
+
],
|
|
351
312
|
}
|
|
352
|
-
:
|
|
353
|
-
|
|
313
|
+
: {
|
|
314
|
+
enabled: false,
|
|
315
|
+
additionalTools: [
|
|
316
|
+
...allDbTools,
|
|
317
|
+
...allFactoryTools,
|
|
318
|
+
...(options.mcpTools ?? []),
|
|
319
|
+
cliGuideTool,
|
|
320
|
+
...buildPlanModeTools(options.planModeCallbacks),
|
|
321
|
+
],
|
|
322
|
+
},
|
|
323
|
+
// CLI-specific hooks
|
|
354
324
|
hooks: {
|
|
355
|
-
beforeLLM: [
|
|
356
|
-
// Context pressure hook
|
|
357
|
-
(ctx) => {
|
|
358
|
-
const utilization = contextManager.getUtilization();
|
|
359
|
-
if (utilization < 0.3)
|
|
360
|
-
return undefined;
|
|
361
|
-
const pct = Math.round(utilization * 100);
|
|
362
|
-
let hint;
|
|
363
|
-
if (utilization < 0.6) {
|
|
364
|
-
hint = `[Context: ${String(pct)}%] Consider task() for multi-file operations.`;
|
|
365
|
-
}
|
|
366
|
-
else if (utilization < 0.8) {
|
|
367
|
-
hint = `[Context: ${String(pct)}% - HIGH] Prefer task() sub-agents for file reads and code search.`;
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
hint = `[Context: ${String(pct)}% - CRITICAL] Use task() for ALL exploration. Do not read files directly.`;
|
|
371
|
-
}
|
|
372
|
-
const messages = [...ctx.messages];
|
|
373
|
-
messages.splice(1, 0, { role: 'user', content: hint });
|
|
374
|
-
return { messages };
|
|
375
|
-
},
|
|
376
|
-
// Capability-aware system prompt assembly (SDK hook with auto-detection)
|
|
377
|
-
...(capabilityContext && baseSystemPrompt
|
|
378
|
-
? [createCapabilityHook(capabilityContext, baseSystemPrompt, {
|
|
379
|
-
staticSections: [TOOL_USAGE_META_MODULE.content],
|
|
380
|
-
conditionalModules: [
|
|
381
|
-
{ content: GIT_SAFETY_MODULE.content, whenModuleActive: ['git-safety'] },
|
|
382
|
-
{ content: PLATFORM_TOOL_HINTS_MODULE.content, whenModuleActive: ['platform-tool-hints'] },
|
|
383
|
-
{ content: FACTORY_TOOL_HINTS_MODULE.content, whenModuleActive: ['factory-tool-hints'] },
|
|
384
|
-
],
|
|
385
|
-
getToolIndex: (allowedNames) => getFilteredToolIndexForSystemPrompt(allowedNames),
|
|
386
|
-
})]
|
|
387
|
-
: []),
|
|
388
|
-
],
|
|
325
|
+
beforeLLM: [createContextPressureHook()],
|
|
389
326
|
beforeTool: [createFileLockCheckHook(getActiveProject)],
|
|
390
327
|
afterTool: [
|
|
391
328
|
createFileLockAcquireHook(getActiveProject),
|
|
@@ -393,7 +330,8 @@ ${options.systemPromptAddition}
|
|
|
393
330
|
],
|
|
394
331
|
},
|
|
395
332
|
});
|
|
396
|
-
|
|
333
|
+
const agent = compilrAgent.unwrap();
|
|
334
|
+
// ── Load persisted anchors ────────────────────────────────────────────────
|
|
397
335
|
if (options.enableAnchors && options.persistedAnchors) {
|
|
398
336
|
for (const anchor of options.persistedAnchors) {
|
|
399
337
|
agent.addPin({
|
|
@@ -402,112 +340,44 @@ ${options.systemPromptAddition}
|
|
|
402
340
|
priority: anchor.priority,
|
|
403
341
|
scope: anchor.scope,
|
|
404
342
|
tags: anchor.tags,
|
|
405
|
-
// Note: projectId is for our tracking, not needed by library
|
|
406
343
|
});
|
|
407
344
|
}
|
|
408
345
|
}
|
|
409
|
-
// Register
|
|
410
|
-
if (!options.noTools) {
|
|
411
|
-
// When meta-tools is enabled, use direct tools + meta-tools instead of all tools
|
|
412
|
-
let tools;
|
|
413
|
-
if (options.minimal) {
|
|
414
|
-
tools = createMinimalToolRegistry();
|
|
415
|
-
}
|
|
416
|
-
else if (options.enableMetaTools) {
|
|
417
|
-
// Hot-tools mode: only hot tools + get_tool_info (for schema introspection)
|
|
418
|
-
// Warm tools + meta-registry tools are accessed transparently via fallback handler
|
|
419
|
-
tools = [...getDirectTools(true), ...getMetaTools()];
|
|
420
|
-
// Add load_capability tool when the agent has loadable packs
|
|
421
|
-
if (capabilityManager?.hasLoadablePacks()) {
|
|
422
|
-
tools.push(createLoadCapabilityTool(capabilityManager));
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
// Legacy mode: all tools declared directly
|
|
427
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated -- Intentional for backward compatibility
|
|
428
|
-
tools = createToolRegistry();
|
|
429
|
-
}
|
|
430
|
-
// Apply tool filter if specified (filter direct tools)
|
|
431
|
-
if (options.toolFilter && options.toolFilter.length > 0) {
|
|
432
|
-
const allowedTools = new Set(options.toolFilter);
|
|
433
|
-
// get_tool_info and load_capability are always allowed
|
|
434
|
-
const alwaysAllowed = new Set(['get_tool_info', 'load_capability']);
|
|
435
|
-
tools = tools.filter((tool) => allowedTools.has(tool.definition.name) || alwaysAllowed.has(tool.definition.name));
|
|
436
|
-
// When capability loading is active, the BeforeLLM hook manages the meta-tool filter.
|
|
437
|
-
// Otherwise, set it to the full tool filter.
|
|
438
|
-
if (!capabilityManager) {
|
|
439
|
-
setMetaToolFilter(options.toolFilter);
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
else if (!capabilityManager) {
|
|
443
|
-
// No filter and no capability loading - clear any previous filter
|
|
444
|
-
setMetaToolFilter(null);
|
|
445
|
-
}
|
|
446
|
-
// Type assertion needed for tool registry compatibility
|
|
447
|
-
agent.registerTools(tools);
|
|
448
|
-
// Register MCP tools (from external MCP servers)
|
|
449
|
-
// These are registered as direct tools since their schemas are unknown at build time
|
|
450
|
-
if (options.mcpTools && options.mcpTools.length > 0) {
|
|
451
|
-
agent.registerTools(options.mcpTools);
|
|
452
|
-
}
|
|
453
|
-
// Set up transparent fallback to meta-registry
|
|
454
|
-
// When the agent calls a tool not in direct tools (e.g., workitem_add),
|
|
455
|
-
// the fallback handler checks the meta-registry and executes it.
|
|
456
|
-
if (options.enableMetaTools && !options.minimal) {
|
|
457
|
-
agent.getToolRegistry().setFallbackHandler(createToolFallback());
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
// Register Task tool for sub-agent spawning (only in full mode)
|
|
346
|
+
// ── Register subagent task tool (CLI-specific callbacks) ──────────────────
|
|
461
347
|
if (!options.minimal && !options.noTools) {
|
|
462
|
-
// Track active subagents to correlate spawn/complete/events
|
|
463
|
-
// Track active subagents by toolUseId for token counting
|
|
464
348
|
const activeSubagents = new Map();
|
|
465
|
-
// Provide a way for caller to clear tracking state between runs
|
|
466
349
|
if (options.onSubagentTrackingReady) {
|
|
467
|
-
options.onSubagentTrackingReady(() => {
|
|
468
|
-
activeSubagents.clear();
|
|
469
|
-
});
|
|
350
|
+
options.onSubagentTrackingReady(() => { activeSubagents.clear(); });
|
|
470
351
|
}
|
|
471
352
|
const taskTool = createTaskTool({
|
|
472
353
|
parentAgent: agent,
|
|
473
354
|
agentTypes: getMergedAgentTypes(),
|
|
474
355
|
enableEventStreaming: true,
|
|
475
|
-
defaultTimeout: 120000,
|
|
476
|
-
// Now uses toolUseId for direct correlation (no more FIFO matching!)
|
|
356
|
+
defaultTimeout: 120000,
|
|
477
357
|
onSpawn: (agentType, description, toolUseId) => {
|
|
478
358
|
if (options.verbose) {
|
|
479
359
|
log.debug({ component: 'agent', agentType, toolUseId }, 'Spawning sub-agent: %s', description);
|
|
480
360
|
}
|
|
481
|
-
// Immediately notify with toolUseId - no more queuing/matching!
|
|
482
361
|
if (toolUseId) {
|
|
483
362
|
activeSubagents.set(toolUseId, { agentType, tokenCount: 0 });
|
|
484
|
-
|
|
485
|
-
options.onSubagentStart(toolUseId, agentType, description);
|
|
486
|
-
}
|
|
363
|
+
options.onSubagentStart?.(toolUseId, agentType, description);
|
|
487
364
|
}
|
|
488
365
|
},
|
|
489
366
|
onComplete: (agentType, result, toolUseId) => {
|
|
490
367
|
if (options.verbose) {
|
|
491
368
|
log.debug({ component: 'agent', agentType, iterations: result.iterations }, 'Sub-agent completed');
|
|
492
369
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
options.onSubagentEnd(toolUseId, true, result.toolCalls);
|
|
370
|
+
if (toolUseId) {
|
|
371
|
+
options.onSubagentEnd?.(toolUseId, true, result.toolCalls);
|
|
496
372
|
activeSubagents.delete(toolUseId);
|
|
497
373
|
}
|
|
498
374
|
},
|
|
499
|
-
// Stream subagent events for live updates
|
|
500
375
|
onSubAgentEvent: (eventInfo) => {
|
|
501
376
|
const { toolUseId, event } = eventInfo;
|
|
502
|
-
// Handle tool events for live updates
|
|
503
377
|
if (event.type === 'tool_start' && toolUseId && event.name && options.onSubagentToolUse) {
|
|
504
|
-
// Extract tool name and input summary
|
|
505
|
-
const toolName = event.name;
|
|
506
|
-
let summary;
|
|
507
|
-
// Try to get a meaningful summary from input
|
|
508
378
|
const input = event.input;
|
|
379
|
+
let summary;
|
|
509
380
|
if (input) {
|
|
510
|
-
// Common patterns for tool input summaries
|
|
511
381
|
const path = input.path;
|
|
512
382
|
const pattern = input.pattern;
|
|
513
383
|
const command = input.command;
|
|
@@ -521,64 +391,42 @@ ${options.systemPromptAddition}
|
|
|
521
391
|
else if (typeof filePath === 'string')
|
|
522
392
|
summary = filePath;
|
|
523
393
|
}
|
|
524
|
-
options.onSubagentToolUse(toolUseId,
|
|
394
|
+
options.onSubagentToolUse(toolUseId, event.name, summary);
|
|
525
395
|
}
|
|
526
396
|
},
|
|
527
397
|
});
|
|
528
|
-
// Type assertion needed for task tool compatibility
|
|
529
398
|
agent.registerTool(taskTool);
|
|
530
|
-
//
|
|
531
|
-
const suggestTool = createSuggestTool({
|
|
532
|
-
onSuggest: options.onSuggest,
|
|
533
|
-
});
|
|
534
|
-
agent.registerTool(suggestTool);
|
|
399
|
+
// Note: suggest tool is already registered by createCompilrAgent via onSuggest config
|
|
535
400
|
}
|
|
536
|
-
//
|
|
537
|
-
// Calculate and store token estimates for debugging
|
|
538
|
-
// ==========================================================================
|
|
401
|
+
// ── Token estimate logging ────────────────────────────────────────────────
|
|
539
402
|
if (!options.quiet) {
|
|
540
|
-
|
|
403
|
+
const toolDefs = agent.getToolRegistry().getDefinitions();
|
|
541
404
|
let toolTokens = 0;
|
|
542
|
-
|
|
543
|
-
let toolsForEstimate = [];
|
|
544
|
-
if (!options.noTools) {
|
|
545
|
-
if (options.minimal) {
|
|
546
|
-
toolsForEstimate = createMinimalToolRegistry();
|
|
547
|
-
}
|
|
548
|
-
else if (options.enableMetaTools) {
|
|
549
|
-
toolsForEstimate = [...getDirectTools(true), ...getMetaTools()];
|
|
550
|
-
}
|
|
551
|
-
else {
|
|
552
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
553
|
-
toolsForEstimate = createToolRegistry();
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
for (const tool of toolsForEstimate) {
|
|
557
|
-
const def = tool.definition;
|
|
405
|
+
for (const def of toolDefs) {
|
|
558
406
|
toolTokens += estimateJsonTokens({
|
|
559
407
|
name: def.name,
|
|
560
408
|
description: def.description,
|
|
561
409
|
input_schema: def.inputSchema,
|
|
562
410
|
});
|
|
563
411
|
}
|
|
564
|
-
// Add task tool and suggest tool estimates (if registered)
|
|
565
|
-
if (!options.minimal && !options.noTools) {
|
|
566
|
-
// Task tool has a large description with all agent types
|
|
567
|
-
toolTokens += 700; // Approximate for task tool
|
|
568
|
-
toolTokens += 200; // Approximate for suggest tool
|
|
569
|
-
}
|
|
570
|
-
// Calculate estimates
|
|
571
412
|
const systemTokens = estimateTokens(systemPrompt);
|
|
572
413
|
const roleTokens = options.systemPromptAddition
|
|
573
|
-
? estimateTokens(options.systemPromptAddition) * 2
|
|
414
|
+
? estimateTokens(options.systemPromptAddition) * 2
|
|
574
415
|
: 0;
|
|
575
416
|
const contextTokens = estimateTokens(options.projectContext);
|
|
576
417
|
setStaticEstimates({
|
|
577
|
-
system: systemTokens - roleTokens,
|
|
418
|
+
system: systemTokens - roleTokens,
|
|
578
419
|
role: roleTokens,
|
|
579
420
|
tools: toolTokens,
|
|
580
421
|
context: contextTokens,
|
|
581
422
|
});
|
|
423
|
+
log.info({
|
|
424
|
+
component: 'agent',
|
|
425
|
+
toolCount: toolDefs.length,
|
|
426
|
+
systemTokens,
|
|
427
|
+
toolTokens,
|
|
428
|
+
contextTokens,
|
|
429
|
+
}, 'Agent created');
|
|
582
430
|
}
|
|
583
431
|
return agent;
|
|
584
432
|
}
|