@compilr-dev/sdk 0.2.16 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/agent.js CHANGED
@@ -1,11 +1,20 @@
1
1
  /**
2
2
  * CompilrAgent — high-level wrapper around @compilr-dev/agents Agent
3
3
  */
4
- import { Agent, ContextManager, } from '@compilr-dev/agents';
4
+ import { Agent, ContextManager, createSuggestTool, } from '@compilr-dev/agents';
5
5
  import { resolveProvider } from './provider.js';
6
6
  import { resolvePreset } from './presets/index.js';
7
7
  import { assembleTools, deduplicateTools } from './tools.js';
8
8
  import { getContextWindow } from './models.js';
9
+ // Capability loading imports
10
+ import { TOOL_GROUPS } from './team/tool-config.js';
11
+ import { CAPABILITY_PACKS } from './capabilities/packs.js';
12
+ import { CapabilityManager } from './capabilities/manager.js';
13
+ import { CapabilityContext } from './capabilities/context.js';
14
+ import { createCapabilityHook } from './capabilities/hook.js';
15
+ import { createLoadCapabilityTool } from './capabilities/load-tool.js';
16
+ import { resolveProfileGroups, resolveUpfrontGroups } from './capabilities/profile-resolver.js';
17
+ import { MetaToolsRegistry, createMetaTools } from './meta-tools/registry.js';
9
18
  /**
10
19
  * Convert an AgentRunResult to our simplified RunResult
11
20
  */
@@ -77,6 +86,8 @@ class CompilrAgentImpl {
77
86
  agent;
78
87
  abortController;
79
88
  totalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
89
+ /** Meta-tools fallback handler (set when capabilities.enabled) */
90
+ _metaToolsFallback;
80
91
  constructor(config) {
81
92
  this.abortController = new AbortController();
82
93
  // Resolve provider
@@ -98,8 +109,13 @@ class CompilrAgentImpl {
98
109
  else {
99
110
  systemPrompt = preset.systemPrompt;
100
111
  }
101
- // Assemble tools
102
- const tools = deduplicateTools(assembleTools(preset, config?.tools));
112
+ // Assemble all tools from preset + config
113
+ let allTools = deduplicateTools(assembleTools(preset, config?.tools));
114
+ // Replace default suggest tool with callback-wired version when onSuggest is provided
115
+ if (config?.onSuggest) {
116
+ const wiredSuggest = createSuggestTool({ onSuggest: config.onSuggest });
117
+ allTools = allTools.map((t) => t.definition.name === 'suggest' ? wiredSuggest : t);
118
+ }
103
119
  // Build context manager if configured
104
120
  let contextManager;
105
121
  if (config?.context) {
@@ -114,6 +130,110 @@ class CompilrAgentImpl {
114
130
  // Build agent config
115
131
  const permissionsConfig = buildPermissions(config?.permissions, preset.defaultPermissions, config?.permissionRules, config?.includeDefaultRules);
116
132
  const guardrailsConfig = buildGuardrails(config?.guardrails);
133
+ // Merge hooks: user-provided + capability hook (if enabled)
134
+ const capabilityHooks = [];
135
+ let finalTools = allTools;
136
+ // --- Dynamic Capability Loading ---
137
+ if (config?.capabilities?.enabled) {
138
+ const capConfig = config.capabilities;
139
+ // 1. Resolve profile → groups → upfront groups
140
+ const profileGroups = resolveProfileGroups(capConfig.profile ?? 'full');
141
+ const upfrontGroups = resolveUpfrontGroups(profileGroups);
142
+ // 2. Create capability manager
143
+ const manager = new CapabilityManager({
144
+ profileGroups,
145
+ packs: CAPABILITY_PACKS,
146
+ upfrontGroups,
147
+ });
148
+ // 3. Build direct-tier tool name set (tools in upfront groups)
149
+ const directToolNames = new Set();
150
+ for (const groupId of upfrontGroups) {
151
+ const group = TOOL_GROUPS[groupId];
152
+ for (const toolName of group.tools) {
153
+ directToolNames.add(toolName);
154
+ }
155
+ }
156
+ // 4. Split tools into direct (registered on Agent) and meta (registry)
157
+ const directTools = [];
158
+ const metaRegistryTools = [];
159
+ for (const tool of allTools) {
160
+ const t = tool;
161
+ if (directToolNames.has(t.definition.name)) {
162
+ directTools.push(t);
163
+ }
164
+ else {
165
+ metaRegistryTools.push(t);
166
+ }
167
+ }
168
+ // 5. Initialize meta-tools registry
169
+ const registry = new MetaToolsRegistry();
170
+ const additionalTools = capConfig.additionalTools ?? [];
171
+ registry.initialize([...metaRegistryTools, ...additionalTools]);
172
+ // 6. Compute orphan tools (in registry but not in any capability pack)
173
+ const packedToolNames = new Set();
174
+ for (const pack of Object.values(CAPABILITY_PACKS)) {
175
+ for (const toolName of pack.tools) {
176
+ packedToolNames.add(toolName);
177
+ }
178
+ }
179
+ const orphanTools = registry
180
+ .getRegisteredTools()
181
+ .map((t) => t.definition.name)
182
+ .filter((name) => !packedToolNames.has(name));
183
+ // 7. Create capability context with filter sync
184
+ const capCtx = new CapabilityContext({
185
+ manager,
186
+ orphanTools,
187
+ onFilterUpdate: (allowed) => {
188
+ registry.setFilter(allowed);
189
+ },
190
+ });
191
+ capCtx.syncFilter();
192
+ // 8. Create meta-tools (get_tool_info) + fallback handler
193
+ const metaTools = createMetaTools(registry, {
194
+ onFilteredTool: (name) => capCtx.onFilteredTool(name),
195
+ });
196
+ // 9. Assemble final tool list: direct + get_tool_info + load_capability
197
+ finalTools = [...directTools, metaTools.getToolInfoTool];
198
+ if (manager.hasLoadablePacks()) {
199
+ finalTools.push(createLoadCapabilityTool(manager));
200
+ }
201
+ // 10. Create BeforeLLM hook for dynamic prompt assembly
202
+ const basePrompt = systemPrompt ?? '';
203
+ const capHook = createCapabilityHook(capCtx, basePrompt, {
204
+ maxAutoLoadsPerTurn: capConfig.maxAutoLoadsPerTurn,
205
+ conditionalModules: capConfig.conditionalModules,
206
+ staticSections: capConfig.staticSections,
207
+ getToolIndex: (allowedNames) => {
208
+ registry.setFilter(allowedNames);
209
+ return registry.getToolIndexForSystemPrompt();
210
+ },
211
+ });
212
+ capabilityHooks.push(capHook);
213
+ // Store registry for fallback handler setup (after Agent creation)
214
+ this._metaToolsFallback = metaTools.createFallback({
215
+ onFilteredTool: (name) => capCtx.onFilteredTool(name),
216
+ });
217
+ }
218
+ else {
219
+ // Legacy mode: register all tools directly (no capability loading)
220
+ finalTools = allTools;
221
+ // Include additional tools if provided (even without capabilities)
222
+ if (config?.capabilities?.additionalTools) {
223
+ finalTools = [...finalTools, ...config.capabilities.additionalTools];
224
+ }
225
+ }
226
+ // Merge hooks: capability hook + user-provided hooks
227
+ const mergedHooks = { ...config?.hooks };
228
+ if (capabilityHooks.length > 0) {
229
+ const existingBeforeLLM = config?.hooks?.beforeLLM;
230
+ const existingHooks = existingBeforeLLM
231
+ ? Array.isArray(existingBeforeLLM)
232
+ ? existingBeforeLLM
233
+ : [existingBeforeLLM]
234
+ : [];
235
+ mergedHooks.beforeLLM = [...existingHooks, ...capabilityHooks];
236
+ }
117
237
  this.agent = new Agent({
118
238
  provider,
119
239
  systemPrompt,
@@ -121,7 +241,7 @@ class CompilrAgentImpl {
121
241
  toolTimeoutMs: config?.toolTimeoutMs,
122
242
  contextManager,
123
243
  autoContextManagement: contextManager !== undefined,
124
- hooks: config?.hooks,
244
+ hooks: mergedHooks,
125
245
  pins: {},
126
246
  permissions: {
127
247
  defaultLevel: permissionsConfig.defaultLevel,
@@ -142,8 +262,12 @@ class CompilrAgentImpl {
142
262
  }
143
263
  },
144
264
  });
145
- // Register tools (cast AnyTool[] → Tool[] for the Agent API)
146
- this.agent.registerTools(tools);
265
+ // Register tools
266
+ this.agent.registerTools(finalTools);
267
+ // Set fallback handler for meta-tools (if capabilities enabled)
268
+ if (this._metaToolsFallback) {
269
+ this.agent.getToolRegistry().setFallbackHandler(this._metaToolsFallback);
270
+ }
147
271
  }
148
272
  async run(message, options) {
149
273
  const result = await this.agent.run(message, {
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Auto-Detect Capabilities — scans agent messages for "Tool not found"
3
+ * errors and auto-loads the corresponding capability packs.
4
+ */
5
+ import type { Message } from '@compilr-dev/agents';
6
+ import type { CapabilityManager } from './manager.js';
7
+ export interface AutoDetectResult {
8
+ /** Pack IDs that were auto-loaded */
9
+ loaded: string[];
10
+ /** Forbidden tool names with suggested agents */
11
+ forbidden: Array<{
12
+ toolName: string;
13
+ packId: string;
14
+ suggestedAgent?: string;
15
+ }>;
16
+ }
17
+ /**
18
+ * Scan recent messages for "Tool not found: X" errors and auto-load
19
+ * the corresponding capability packs (max N per turn, loadable only).
20
+ * Also detects forbidden tool access for handoff suggestions.
21
+ */
22
+ export declare function autoDetectCapabilities(manager: CapabilityManager, messages: Message[], maxLoads?: number): AutoDetectResult;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Auto-Detect Capabilities — scans agent messages for "Tool not found"
3
+ * errors and auto-loads the corresponding capability packs.
4
+ */
5
+ /**
6
+ * Scan recent messages for "Tool not found: X" errors and auto-load
7
+ * the corresponding capability packs (max N per turn, loadable only).
8
+ * Also detects forbidden tool access for handoff suggestions.
9
+ */
10
+ export function autoDetectCapabilities(manager, messages, maxLoads = 2) {
11
+ const result = { loaded: [], forbidden: [] };
12
+ const toolNotFoundPattern = /Tool not found: (\w+)/;
13
+ // Find the most recent user message (contains the last turn's tool results)
14
+ for (let i = messages.length - 1; i >= 0; i--) {
15
+ const msg = messages[i];
16
+ if (msg.role !== 'user' || typeof msg.content === 'string')
17
+ continue;
18
+ // Scan this message's tool_result blocks for "Tool not found" errors
19
+ for (const block of msg.content) {
20
+ if (block.type !== 'tool_result' || !block.isError || !block.content)
21
+ continue;
22
+ // Extract text from tool_result content (may be string or structured)
23
+ const rawContent = block.content;
24
+ const content = typeof rawContent === 'string' ? rawContent : String(rawContent);
25
+ const match = toolNotFoundPattern.exec(content);
26
+ if (!match)
27
+ continue;
28
+ const toolName = match[1];
29
+ const packId = manager.findPackForTool(toolName);
30
+ if (!packId || manager.isLoaded(packId))
31
+ continue;
32
+ const tier = manager.getTier(packId);
33
+ if (tier === 'loadable' && result.loaded.length < maxLoads) {
34
+ manager.load(packId, 'auto-detect');
35
+ result.loaded.push(packId);
36
+ }
37
+ else if (tier === 'forbidden') {
38
+ result.forbidden.push({
39
+ toolName,
40
+ packId,
41
+ suggestedAgent: manager.getSuggestedAgent(packId),
42
+ });
43
+ }
44
+ }
45
+ // Only scan the most recent user message
46
+ break;
47
+ }
48
+ return result;
49
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * CapabilityContext — encapsulates the CapabilityManager + meta-tool
3
+ * filter synchronization for a single agent.
4
+ *
5
+ * Replaces the CLI's global setCapabilityManager/getCapabilityManager
6
+ * pattern with a per-agent instance.
7
+ */
8
+ import type { CapabilityManager } from './manager.js';
9
+ export interface CapabilityContextConfig {
10
+ manager: CapabilityManager;
11
+ /**
12
+ * Tools in the meta-registry that aren't in any capability pack.
13
+ * These are always visible regardless of which packs are loaded.
14
+ */
15
+ orphanTools: string[];
16
+ /**
17
+ * Callback to update the meta-tool filter with allowed tool names.
18
+ * Called whenever loaded packs change (auto-detect, auto-load, manual load).
19
+ */
20
+ onFilterUpdate: (allowedTools: string[]) => void;
21
+ }
22
+ export declare class CapabilityContext {
23
+ readonly manager: CapabilityManager;
24
+ private readonly orphanTools;
25
+ private readonly onFilterUpdate;
26
+ constructor(config: CapabilityContextConfig);
27
+ /**
28
+ * Update the meta-tool filter to match current loaded state.
29
+ * Call after loading packs or during BeforeLLM hook.
30
+ */
31
+ syncFilter(): void;
32
+ /**
33
+ * Get all currently allowed tool names (loaded packs + orphans).
34
+ */
35
+ getAllowedToolNames(): string[];
36
+ /**
37
+ * Auto-load callback for meta-registry fallback.
38
+ *
39
+ * When the agent tries to call a tool that's in the meta-registry
40
+ * but filtered out, this callback loads the corresponding pack
41
+ * and updates the filter so the tool can be retried.
42
+ *
43
+ * @returns true if the tool was successfully loaded (retry the call)
44
+ */
45
+ onFilteredTool(toolName: string): boolean;
46
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * CapabilityContext — encapsulates the CapabilityManager + meta-tool
3
+ * filter synchronization for a single agent.
4
+ *
5
+ * Replaces the CLI's global setCapabilityManager/getCapabilityManager
6
+ * pattern with a per-agent instance.
7
+ */
8
+ export class CapabilityContext {
9
+ manager;
10
+ orphanTools;
11
+ onFilterUpdate;
12
+ constructor(config) {
13
+ this.manager = config.manager;
14
+ this.orphanTools = config.orphanTools;
15
+ this.onFilterUpdate = config.onFilterUpdate;
16
+ }
17
+ /**
18
+ * Update the meta-tool filter to match current loaded state.
19
+ * Call after loading packs or during BeforeLLM hook.
20
+ */
21
+ syncFilter() {
22
+ const activeTools = this.manager.getActiveToolNames();
23
+ this.onFilterUpdate([...activeTools, ...this.orphanTools]);
24
+ }
25
+ /**
26
+ * Get all currently allowed tool names (loaded packs + orphans).
27
+ */
28
+ getAllowedToolNames() {
29
+ return [...this.manager.getActiveToolNames(), ...this.orphanTools];
30
+ }
31
+ /**
32
+ * Auto-load callback for meta-registry fallback.
33
+ *
34
+ * When the agent tries to call a tool that's in the meta-registry
35
+ * but filtered out, this callback loads the corresponding pack
36
+ * and updates the filter so the tool can be retried.
37
+ *
38
+ * @returns true if the tool was successfully loaded (retry the call)
39
+ */
40
+ onFilteredTool(toolName) {
41
+ const packId = this.manager.findPackForTool(toolName);
42
+ if (!packId || this.manager.isLoaded(packId))
43
+ return false;
44
+ if (this.manager.getTier(packId) !== 'loadable')
45
+ return false;
46
+ this.manager.load(packId, 'auto-load');
47
+ this.syncFilter();
48
+ return true;
49
+ }
50
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Capability Hook — BeforeLLM hook that dynamically rebuilds the
3
+ * system prompt based on loaded capability packs.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Auto-detect "Tool not found" in recent messages → auto-load packs
7
+ * 2. Sync meta-tool filter with loaded state
8
+ * 3. Rebuild system prompt with dynamic sections (modules, snippets, catalog)
9
+ * 4. Preserve anchor blocks from agent library injection
10
+ * 5. Inject forbidden tool boundary hints as messages
11
+ */
12
+ import type { Message, BeforeLLMHookResult } from '@compilr-dev/agents';
13
+ import type { CapabilityContext } from './context.js';
14
+ /**
15
+ * A conditional system prompt module that gets included
16
+ * when certain capability packs are loaded.
17
+ */
18
+ export interface ConditionalModule {
19
+ /** Module content to append to the system prompt */
20
+ content: string;
21
+ /** Include when ANY of these prompt module IDs are active */
22
+ whenModuleActive: string[];
23
+ }
24
+ export interface CapabilityHookConfig {
25
+ /** Max packs to auto-load per turn from "Tool not found" detection */
26
+ maxAutoLoadsPerTurn?: number;
27
+ /** Conditional prompt modules to include based on loaded packs */
28
+ conditionalModules?: ConditionalModule[];
29
+ /**
30
+ * Callback to generate the filtered tool index section.
31
+ * Receives the list of currently allowed tool names.
32
+ * Should return a string to append to the system prompt (e.g., meta-tool index).
33
+ */
34
+ getToolIndex?: (allowedToolNames: string[]) => string;
35
+ /**
36
+ * Static prompt section to always include (e.g., meta-tools protocol).
37
+ * Appended before conditional modules.
38
+ */
39
+ staticSections?: string[];
40
+ }
41
+ /**
42
+ * Create a BeforeLLM hook that dynamically manages the system prompt
43
+ * based on loaded capabilities.
44
+ *
45
+ * @param ctx - CapabilityContext for this agent
46
+ * @param basePrompt - Base system prompt (without dynamic sections)
47
+ * @param config - Optional configuration
48
+ */
49
+ export declare function createCapabilityHook(ctx: CapabilityContext, basePrompt: string, config?: CapabilityHookConfig): (hookCtx: {
50
+ messages: Message[];
51
+ systemPrompt: string;
52
+ }) => BeforeLLMHookResult;
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Capability Hook — BeforeLLM hook that dynamically rebuilds the
3
+ * system prompt based on loaded capability packs.
4
+ *
5
+ * Responsibilities:
6
+ * 1. Auto-detect "Tool not found" in recent messages → auto-load packs
7
+ * 2. Sync meta-tool filter with loaded state
8
+ * 3. Rebuild system prompt with dynamic sections (modules, snippets, catalog)
9
+ * 4. Preserve anchor blocks from agent library injection
10
+ * 5. Inject forbidden tool boundary hints as messages
11
+ */
12
+ import { autoDetectCapabilities } from './auto-detect.js';
13
+ import { generateCapabilityCatalog } from './catalog.js';
14
+ /**
15
+ * Create a BeforeLLM hook that dynamically manages the system prompt
16
+ * based on loaded capabilities.
17
+ *
18
+ * @param ctx - CapabilityContext for this agent
19
+ * @param basePrompt - Base system prompt (without dynamic sections)
20
+ * @param config - Optional configuration
21
+ */
22
+ export function createCapabilityHook(ctx, basePrompt, config) {
23
+ const maxAutoLoads = config?.maxAutoLoadsPerTurn ?? 2;
24
+ const conditionalModules = config?.conditionalModules ?? [];
25
+ const staticSections = config?.staticSections ?? [];
26
+ const getToolIndex = config?.getToolIndex;
27
+ return (hookCtx) => {
28
+ const manager = ctx.manager;
29
+ // 1. Auto-detect capability needs from tool failures (safety net)
30
+ let forbiddenHints = [];
31
+ if (manager.hasLoadablePacks() || hookCtx.messages.length > 1) {
32
+ const detected = autoDetectCapabilities(manager, hookCtx.messages, maxAutoLoads);
33
+ if (detected.forbidden.length > 0) {
34
+ forbiddenHints = detected.forbidden.map((f) => {
35
+ const agentHint = f.suggestedAgent
36
+ ? ` Consider using handoff("${f.suggestedAgent}", "Need ${f.packId} access for ${f.toolName}").`
37
+ : '';
38
+ return `[System] Tool "${f.toolName}" requires ${f.packId} capability which is outside your tool profile.${agentHint}`;
39
+ });
40
+ }
41
+ }
42
+ // 2. Sync meta-tool filter with current loaded state
43
+ ctx.syncFilter();
44
+ // 3. Build dynamic system prompt sections
45
+ const dynamicSections = [];
46
+ // Static sections (e.g., meta-tools protocol)
47
+ for (const section of staticSections) {
48
+ dynamicSections.push(section);
49
+ }
50
+ // Conditional modules based on loaded packs
51
+ const activeModuleIds = manager.getActivePromptModuleIds();
52
+ for (const mod of conditionalModules) {
53
+ if (mod.whenModuleActive.some((id) => activeModuleIds.has(id))) {
54
+ dynamicSections.push(mod.content);
55
+ }
56
+ }
57
+ // Prompt snippets from loaded packs
58
+ const snippets = manager.getActivePromptSnippets();
59
+ if (snippets.length > 0) {
60
+ dynamicSections.push('## Active Tool Capabilities\n' + snippets.join('\n'));
61
+ }
62
+ // Filtered tool index
63
+ if (getToolIndex) {
64
+ const allowedTools = ctx.getAllowedToolNames();
65
+ dynamicSections.push(getToolIndex(allowedTools));
66
+ }
67
+ // Capability catalog (if loadable packs remain)
68
+ if (manager.hasLoadablePacks()) {
69
+ const catalog = manager.getCatalog();
70
+ const catalogSection = generateCapabilityCatalog(catalog, manager.getLoadedPackIds());
71
+ if (catalogSection) {
72
+ dynamicSections.push(catalogSection);
73
+ }
74
+ }
75
+ // 4. Preserve anchors from the current system prompt.
76
+ // The agents library injects anchors into systemContent BEFORE this hook runs.
77
+ // We must extract and re-append them since we rebuild from basePrompt.
78
+ const anchorsBlock = extractAnchorsBlock(hookCtx.systemPrompt);
79
+ const hookResult = {
80
+ systemPrompt: basePrompt + '\n\n' + dynamicSections.join('\n\n') + anchorsBlock,
81
+ };
82
+ // 5. Inject forbidden boundary messages (handoff suggestions)
83
+ if (forbiddenHints.length > 0) {
84
+ const hintContent = forbiddenHints.join('\n');
85
+ const hintMessage = { role: 'user', content: hintContent };
86
+ hookResult.messages = [...hookCtx.messages, hintMessage];
87
+ }
88
+ return hookResult;
89
+ };
90
+ }
91
+ /**
92
+ * Extract the anchors block from a system prompt.
93
+ * The agents library injects "## Active Anchors (Critical Information)"
94
+ * before BeforeLLM hooks run. We need to preserve it when rebuilding.
95
+ */
96
+ function extractAnchorsBlock(systemPrompt) {
97
+ const anchorMarker = '## Active Anchors (Critical Information)';
98
+ const anchorIdx = systemPrompt.indexOf(anchorMarker);
99
+ if (anchorIdx <= 0)
100
+ return '';
101
+ // Find the preceding "---" separator
102
+ const separatorBefore = systemPrompt.lastIndexOf('---', anchorIdx);
103
+ const startIdx = separatorBefore > 0 ? separatorBefore : anchorIdx;
104
+ // Find the end: either the next "---" after the anchor block, or end of string
105
+ const afterAnchor = systemPrompt.indexOf('\n\n---\n\n', anchorIdx);
106
+ if (afterAnchor > 0) {
107
+ return '\n\n' + systemPrompt.substring(startIdx, afterAnchor + 7);
108
+ }
109
+ return '\n\n' + systemPrompt.substring(startIdx);
110
+ }
@@ -12,3 +12,10 @@ export { CapabilityManager } from './manager.js';
12
12
  export type { CapabilityManagerConfig } from './manager.js';
13
13
  export { createLoadCapabilityTool } from './load-tool.js';
14
14
  export { generateCapabilityCatalog } from './catalog.js';
15
+ export { CapabilityContext } from './context.js';
16
+ export type { CapabilityContextConfig } from './context.js';
17
+ export { createCapabilityHook } from './hook.js';
18
+ export type { CapabilityHookConfig, ConditionalModule } from './hook.js';
19
+ export { autoDetectCapabilities } from './auto-detect.js';
20
+ export type { AutoDetectResult } from './auto-detect.js';
21
+ export { resolveProfileGroups, resolveUpfrontGroups } from './profile-resolver.js';
@@ -14,3 +14,11 @@ export { CapabilityManager } from './manager.js';
14
14
  export { createLoadCapabilityTool } from './load-tool.js';
15
15
  // Catalog generator
16
16
  export { generateCapabilityCatalog } from './catalog.js';
17
+ // Context — per-agent capability state + filter sync
18
+ export { CapabilityContext } from './context.js';
19
+ // Hook — BeforeLLM hook for dynamic prompt assembly
20
+ export { createCapabilityHook } from './hook.js';
21
+ // Auto-detection — scan messages for "Tool not found" errors
22
+ export { autoDetectCapabilities } from './auto-detect.js';
23
+ // Profile resolver — convert profiles/tool lists to group IDs
24
+ export { resolveProfileGroups, resolveUpfrontGroups } from './profile-resolver.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Profile Resolver — converts tool profiles or custom tool lists
3
+ * into capability group IDs for the CapabilityManager.
4
+ */
5
+ import { type ToolProfile } from '../team/tool-config.js';
6
+ /**
7
+ * Convert a profile name or custom tool list into capability group IDs.
8
+ *
9
+ * @param profile - A named profile ('full', 'developer', etc.) or a custom tool name list
10
+ * @returns Array of group IDs that the profile allows
11
+ */
12
+ export declare function resolveProfileGroups(profile: ToolProfile | string[]): string[];
13
+ /**
14
+ * Determine which groups should be loaded upfront (direct tier).
15
+ * Upfront = groups marked as 'direct' tier AND in the agent's profile.
16
+ */
17
+ export declare function resolveUpfrontGroups(profileGroups: string[]): string[];
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Profile Resolver — converts tool profiles or custom tool lists
3
+ * into capability group IDs for the CapabilityManager.
4
+ */
5
+ import { TOOL_GROUPS, TOOL_PROFILES } from '../team/tool-config.js';
6
+ /**
7
+ * Convert a profile name or custom tool list into capability group IDs.
8
+ *
9
+ * @param profile - A named profile ('full', 'developer', etc.) or a custom tool name list
10
+ * @returns Array of group IDs that the profile allows
11
+ */
12
+ export function resolveProfileGroups(profile) {
13
+ if (typeof profile === 'string') {
14
+ // Named profile — look up in TOOL_PROFILES
15
+ const groups = TOOL_PROFILES[profile];
16
+ return [...groups];
17
+ }
18
+ // Custom tool list — find groups that contain at least one of these tools
19
+ const toolSet = new Set(profile);
20
+ const groups = [];
21
+ for (const [groupId, group] of Object.entries(TOOL_GROUPS)) {
22
+ if (group.tools.some((t) => toolSet.has(t))) {
23
+ groups.push(groupId);
24
+ }
25
+ }
26
+ return groups;
27
+ }
28
+ /**
29
+ * Determine which groups should be loaded upfront (direct tier).
30
+ * Upfront = groups marked as 'direct' tier AND in the agent's profile.
31
+ */
32
+ export function resolveUpfrontGroups(profileGroups) {
33
+ const profileSet = new Set(profileGroups);
34
+ return Object.entries(TOOL_GROUPS)
35
+ .filter(([, group]) => group.tier === 'direct')
36
+ .map(([id]) => id)
37
+ .filter((id) => profileSet.has(id));
38
+ }
package/dist/config.d.ts CHANGED
@@ -3,6 +3,49 @@
3
3
  */
4
4
  import type { LLMProvider, Message, Tool, ToolPermission, HooksConfig, AnchorInput, AgentEvent, ToolExecutionResult } from '@compilr-dev/agents';
5
5
  import type { Preset } from './presets/types.js';
6
+ import type { ToolProfile } from './team/tool-config.js';
7
+ import type { ConditionalModule } from './capabilities/hook.js';
8
+ /**
9
+ * Dynamic capability loading configuration.
10
+ *
11
+ * When enabled, tools are loaded on-demand instead of all upfront,
12
+ * reducing token usage by ~50-60% on initial turns.
13
+ */
14
+ export interface CapabilitiesConfig {
15
+ /** Enable dynamic capability loading. Default: false (all tools upfront) */
16
+ enabled: boolean;
17
+ /**
18
+ * Tool profile — determines which capability packs are available.
19
+ * Named profile ('full', 'developer', etc.) or custom tool name list.
20
+ * Default: 'full'
21
+ */
22
+ profile?: ToolProfile | string[];
23
+ /**
24
+ * Whether to enable meta-tools mode (get_tool_info + registry fallback).
25
+ * Loadable tools go through the meta-registry instead of being declared directly.
26
+ * Default: true when capabilities.enabled is true
27
+ */
28
+ metaTools?: boolean;
29
+ /**
30
+ * Max packs to auto-load per turn when "Tool not found" detected.
31
+ * Default: 2
32
+ */
33
+ maxAutoLoadsPerTurn?: number;
34
+ /**
35
+ * Additional tools to include that aren't in any capability pack
36
+ * (e.g., MCP tools, platform tools). Always available.
37
+ */
38
+ additionalTools?: Tool[];
39
+ /**
40
+ * Conditional prompt modules to include based on loaded packs.
41
+ * Default: git-safety, platform-tool-hints, factory-tool-hints
42
+ */
43
+ conditionalModules?: ConditionalModule[];
44
+ /**
45
+ * Static prompt sections to always include (e.g., meta-tools protocol).
46
+ */
47
+ staticSections?: string[];
48
+ }
6
49
  /**
7
50
  * Supported provider types for auto-detection
8
51
  */
@@ -147,6 +190,22 @@ export interface CompilrAgentConfig {
147
190
  hooks?: HooksConfig;
148
191
  /** Context management configuration */
149
192
  context?: ContextConfig;
193
+ /**
194
+ * Callback for the suggest tool. When provided, the default no-op suggest
195
+ * tool is replaced with one that calls this callback.
196
+ * The suggestion appears as ghost text in the UI input area.
197
+ */
198
+ onSuggest?: (event: {
199
+ type: 'suggest';
200
+ action: string;
201
+ reason?: string;
202
+ }) => void;
203
+ /**
204
+ * Dynamic capability loading configuration.
205
+ * When enabled, tools are loaded on-demand for token efficiency.
206
+ * Omit or set enabled: false for the legacy all-tools-upfront mode.
207
+ */
208
+ capabilities?: CapabilitiesConfig;
150
209
  }
151
210
  /**
152
211
  * High-level agent interface
package/dist/index.d.ts CHANGED
@@ -34,7 +34,7 @@
34
34
  * ```
35
35
  */
36
36
  export { createCompilrAgent } from './agent.js';
37
- export type { CompilrAgentConfig, CompilrAgent, RunOptions, RunResult, ToolCallRecord, ToolConfig, UsageInfo, ProviderType, PermissionCallback, GuardrailConfig, ContextConfig, } from './config.js';
37
+ export type { CompilrAgentConfig, CompilrAgent, RunOptions, RunResult, ToolCallRecord, ToolConfig, UsageInfo, ProviderType, PermissionCallback, GuardrailConfig, ContextConfig, CapabilitiesConfig, } from './config.js';
38
38
  export { AgentTeam, TeamAgent, SharedContextManager, ArtifactStore, DelegationTracker, ContextResolver, } from './team/index.js';
39
39
  export type { AgentTeamConfig, TeamAgentConfig, ITeamPersistence, IArtifactStorage, ISessionRegistry, CustomAgentDefinition, ToolConfig as TeamToolConfig, ToolTier, ToolGroup, ProfileInfo, } from './team/index.js';
40
40
  export type { AgentRole, RoleMetadata, ToolProfile, MascotExpression, BackgroundSessionInfo, SerializedTeam, SerializedTeamAgent, TeamMetadata, TeamEvent, TeamEventType, TeamEventHandler, Artifact, ArtifactType as TeamArtifactType, ArtifactSummary as TeamArtifactSummary, CreateArtifactOptions, UpdateArtifactOptions, SerializedArtifact, SharedContext, SharedProjectInfo, SharedTeamInfo, TeamRosterEntry, TeamActivity, TeamActivityType, SharedDecision, TokenBudget, SerializedSharedContext, ParsedMention, ParsedInput, ResolvedMention, ResolveOptions, ResolutionSource, Delegation, DelegationStatus, DelegationResult, CompletionEvent, CreateDelegationOptions, DelegationStats, DelegationTrackerEvents, SkillToolRequirement, } from './team/index.js';
@@ -49,8 +49,8 @@ export { type ModelTier, type TierInfo, type ProviderModelMap, MODEL_TIERS, TIER
49
49
  export { assembleTools, deduplicateTools } from './tools.js';
50
50
  export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, } from './meta-tools/index.js';
51
51
  export type { MetaToolStats, MetaTools, FallbackOptions } from './meta-tools/index.js';
52
- export { CapabilityManager, CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds, createLoadCapabilityTool, generateCapabilityCatalog, } from './capabilities/index.js';
53
- export type { CapabilityPack, CapabilityTier, LoadedCapability, CapabilityCatalogEntry, CapabilityLoadResult, CapabilityManagerConfig, } from './capabilities/index.js';
52
+ export { CapabilityManager, CapabilityContext, createCapabilityHook, autoDetectCapabilities, resolveProfileGroups, resolveUpfrontGroups, CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds, createLoadCapabilityTool, generateCapabilityCatalog, } from './capabilities/index.js';
53
+ export type { CapabilityPack, CapabilityTier, LoadedCapability, CapabilityCatalogEntry, CapabilityLoadResult, CapabilityManagerConfig, CapabilityContextConfig, CapabilityHookConfig, ConditionalModule, AutoDetectResult, } from './capabilities/index.js';
54
54
  export { SystemPromptBuilder, buildSystemPrompt, detectGitRepository, getModuleStats, ALL_MODULES, IDENTITY_MODULE, STYLE_MODULE, TASK_EXECUTION_MODULE, TODO_MANAGEMENT_MODULE, TOOL_USAGE_DIRECT_MODULE, TOOL_USAGE_HINTS_MODULE, PLATFORM_TOOL_HINTS_MODULE, FACTORY_TOOL_HINTS_MODULE, TOOL_USAGE_META_MODULE, DELEGATION_MODULE, GIT_SAFETY_MODULE, SUGGEST_MODULE, IMPORTANT_RULES_MODULE, VISUAL_OUTPUT_MODULE, ENVIRONMENT_MODULE, shouldIncludeModule, getEstimatedTokensForConditions, getTotalEstimatedTokens, } from './system-prompt/index.js';
55
55
  export type { SystemPromptContext, BuildResult, SystemPromptModule, ModuleConditions, } from './system-prompt/index.js';
56
56
  export type { ProjectType, ProjectStatus, RepoPattern, WorkflowMode, LifecycleState, WorkItemType, WorkItemStatus, WorkItemPriority, GuidedStep, DocumentType, PlanStatus, Project, WorkItem, ProjectDocument, Plan, PlanSummary, PlanWithWorkItem, HistoryEntry, CreateProjectInput, UpdateProjectInput, ProjectListOptions, CreateWorkItemInput, UpdateWorkItemInput, QueryWorkItemsInput, CreateDocumentInput, UpdateDocumentInput, CreatePlanInput, UpdatePlanInput, ListPlansOptions, WorkItemQueryResult, ProjectListResult, BulkCreateItem, WorkItemComment, CreateCommentInput, UpdateCommentInput, IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, ICommentRepository, IAnchorService, IArtifactService, IEpisodeService, AnchorData, ArtifactType, ArtifactData, ArtifactSummaryData, WorkEpisode, ProjectWorkSummary, PlatformContext, PlatformToolsConfig, PlatformHooks, StepCriteria, } from './platform/index.js';
package/dist/index.js CHANGED
@@ -96,6 +96,14 @@ export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, }
96
96
  export {
97
97
  // Manager
98
98
  CapabilityManager,
99
+ // Context (per-agent state + filter sync)
100
+ CapabilityContext,
101
+ // Hook (BeforeLLM dynamic prompt assembly)
102
+ createCapabilityHook,
103
+ // Auto-detection (tool-not-found scanning)
104
+ autoDetectCapabilities,
105
+ // Profile resolution
106
+ resolveProfileGroups, resolveUpfrontGroups,
99
107
  // Pack definitions
100
108
  CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds,
101
109
  // Self-loading tool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.2.16",
3
+ "version": "0.3.1",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",