@codemieai/code 0.0.34 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -5
- package/bin/codemie-claude-acp.js +21 -0
- package/bin/codemie.js +13 -0
- package/dist/agents/codemie-code/agent.d.ts +22 -4
- package/dist/agents/codemie-code/agent.d.ts.map +1 -1
- package/dist/agents/codemie-code/agent.js +291 -195
- package/dist/agents/codemie-code/agent.js.map +1 -1
- package/dist/agents/codemie-code/index.d.ts +1 -1
- package/dist/agents/codemie-code/index.d.ts.map +1 -1
- package/dist/agents/codemie-code/index.js +8 -5
- package/dist/agents/codemie-code/index.js.map +1 -1
- package/dist/agents/codemie-code/prompts.d.ts +8 -10
- package/dist/agents/codemie-code/prompts.d.ts.map +1 -1
- package/dist/agents/codemie-code/prompts.js +43 -16
- package/dist/agents/codemie-code/prompts.js.map +1 -1
- package/dist/agents/codemie-code/toolMetadata.d.ts.map +1 -1
- package/dist/agents/codemie-code/toolMetadata.js +9 -8
- package/dist/agents/codemie-code/toolMetadata.js.map +1 -1
- package/dist/agents/codemie-code/tools/assistant-invocation.d.ts +47 -0
- package/dist/agents/codemie-code/tools/assistant-invocation.d.ts.map +1 -0
- package/dist/agents/codemie-code/tools/assistant-invocation.js +129 -0
- package/dist/agents/codemie-code/tools/assistant-invocation.js.map +1 -0
- package/dist/agents/codemie-code/tools/index.d.ts +70 -4
- package/dist/agents/codemie-code/tools/index.d.ts.map +1 -1
- package/dist/agents/codemie-code/tools/index.js +57 -44
- package/dist/agents/codemie-code/tools/index.js.map +1 -1
- package/dist/agents/codemie-code/tools/planning.d.ts +6 -5
- package/dist/agents/codemie-code/tools/planning.d.ts.map +1 -1
- package/dist/agents/codemie-code/tools/planning.js +12 -10
- package/dist/agents/codemie-code/tools/planning.js.map +1 -1
- package/dist/agents/codemie-code/types.d.ts +24 -3
- package/dist/agents/codemie-code/types.d.ts.map +1 -1
- package/dist/agents/codemie-code/types.js +24 -0
- package/dist/agents/codemie-code/types.js.map +1 -1
- package/dist/agents/codemie-code/ui/autocomplete.d.ts +98 -0
- package/dist/agents/codemie-code/ui/autocomplete.d.ts.map +1 -0
- package/dist/agents/codemie-code/ui/autocomplete.js +145 -0
- package/dist/agents/codemie-code/ui/autocomplete.js.map +1 -0
- package/dist/agents/codemie-code/ui/keyHandlers.d.ts +112 -0
- package/dist/agents/codemie-code/ui/keyHandlers.d.ts.map +1 -0
- package/dist/agents/codemie-code/ui/keyHandlers.js +415 -0
- package/dist/agents/codemie-code/ui/keyHandlers.js.map +1 -0
- package/dist/agents/codemie-code/ui/mentions.d.ts +86 -0
- package/dist/agents/codemie-code/ui/mentions.d.ts.map +1 -0
- package/dist/agents/codemie-code/ui/mentions.js +122 -0
- package/dist/agents/codemie-code/ui/mentions.js.map +1 -0
- package/dist/agents/codemie-code/ui/terminalCodes.d.ts +38 -0
- package/dist/agents/codemie-code/ui/terminalCodes.d.ts.map +1 -0
- package/dist/agents/codemie-code/ui/terminalCodes.js +42 -0
- package/dist/agents/codemie-code/ui/terminalCodes.js.map +1 -0
- package/dist/agents/codemie-code/ui/todoPanel.d.ts.map +1 -1
- package/dist/agents/codemie-code/ui/todoPanel.js +3 -4
- package/dist/agents/codemie-code/ui/todoPanel.js.map +1 -1
- package/dist/agents/codemie-code/ui.d.ts +8 -7
- package/dist/agents/codemie-code/ui.d.ts.map +1 -1
- package/dist/agents/codemie-code/ui.js +87 -145
- package/dist/agents/codemie-code/ui.js.map +1 -1
- package/dist/agents/core/AgentCLI.d.ts +5 -0
- package/dist/agents/core/AgentCLI.d.ts.map +1 -1
- package/dist/agents/core/AgentCLI.js +22 -0
- package/dist/agents/core/AgentCLI.js.map +1 -1
- package/dist/agents/core/BaseAgentAdapter.d.ts.map +1 -1
- package/dist/agents/core/BaseAgentAdapter.js +58 -28
- package/dist/agents/core/BaseAgentAdapter.js.map +1 -1
- package/dist/agents/core/extension/BaseExtensionInstaller.d.ts +7 -1
- package/dist/agents/core/extension/BaseExtensionInstaller.d.ts.map +1 -1
- package/dist/agents/core/extension/BaseExtensionInstaller.js +58 -15
- package/dist/agents/core/extension/BaseExtensionInstaller.js.map +1 -1
- package/dist/agents/core/types.d.ts +17 -0
- package/dist/agents/core/types.d.ts.map +1 -1
- package/dist/agents/plugins/claude/claude-acp.plugin.d.ts +27 -0
- package/dist/agents/plugins/claude/claude-acp.plugin.d.ts.map +1 -0
- package/dist/agents/plugins/claude/claude-acp.plugin.js +63 -0
- package/dist/agents/plugins/claude/claude-acp.plugin.js.map +1 -0
- package/dist/agents/plugins/claude/claude-message-types.d.ts +1 -0
- package/dist/agents/plugins/claude/claude-message-types.d.ts.map +1 -1
- package/dist/agents/plugins/claude/claude.plugin.d.ts +1 -1
- package/dist/agents/plugins/claude/claude.plugin.d.ts.map +1 -1
- package/dist/agents/plugins/claude/claude.plugin.js +66 -29
- package/dist/agents/plugins/claude/claude.plugin.js.map +1 -1
- package/dist/agents/plugins/claude/claude.session.d.ts.map +1 -1
- package/dist/agents/plugins/claude/claude.session.js +14 -7
- package/dist/agents/plugins/claude/claude.session.js.map +1 -1
- package/dist/agents/plugins/claude/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/agents/plugins/claude/plugin/commands/codemie-subagents.md +4 -4
- package/dist/agents/plugins/claude/session/processors/claude.conversations-processor.d.ts.map +1 -1
- package/dist/agents/plugins/claude/session/processors/claude.conversations-processor.js +43 -8
- package/dist/agents/plugins/claude/session/processors/claude.conversations-processor.js.map +1 -1
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.d.ts.map +1 -1
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.js +68 -40
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.js.map +1 -1
- package/dist/agents/registry.d.ts +1 -1
- package/dist/agents/registry.d.ts.map +1 -1
- package/dist/agents/registry.js +3 -1
- package/dist/agents/registry.js.map +1 -1
- package/dist/cli/commands/assistants/chat.d.ts +11 -0
- package/dist/cli/commands/assistants/chat.d.ts.map +1 -0
- package/dist/cli/commands/assistants/chat.js +201 -0
- package/dist/cli/commands/assistants/chat.js.map +1 -0
- package/dist/cli/commands/assistants/constants.d.ts +81 -0
- package/dist/cli/commands/assistants/constants.d.ts.map +1 -0
- package/dist/cli/commands/assistants/constants.js +75 -0
- package/dist/cli/commands/assistants/constants.js.map +1 -0
- package/dist/cli/commands/assistants/generators/claude-agent-generator.d.ts +26 -0
- package/dist/cli/commands/assistants/generators/claude-agent-generator.d.ts.map +1 -0
- package/dist/cli/commands/assistants/generators/claude-agent-generator.js +115 -0
- package/dist/cli/commands/assistants/generators/claude-agent-generator.js.map +1 -0
- package/dist/cli/commands/assistants/index.d.ts +11 -0
- package/dist/cli/commands/assistants/index.d.ts.map +1 -0
- package/dist/cli/commands/assistants/index.js +28 -0
- package/dist/cli/commands/assistants/index.js.map +1 -0
- package/dist/cli/commands/assistants/list.d.ts +11 -0
- package/dist/cli/commands/assistants/list.d.ts.map +1 -0
- package/dist/cli/commands/assistants/list.js +323 -0
- package/dist/cli/commands/assistants/list.js.map +1 -0
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +18 -6
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/cli/commands/self-update.d.ts +3 -0
- package/dist/cli/commands/self-update.d.ts.map +1 -0
- package/dist/cli/commands/self-update.js +55 -0
- package/dist/cli/commands/self-update.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +8 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/env/types.d.ts +13 -0
- package/dist/env/types.d.ts.map +1 -1
- package/dist/env/types.js +1 -1
- package/dist/env/types.js.map +1 -1
- package/dist/utils/auth.d.ts +22 -0
- package/dist/utils/auth.d.ts.map +1 -0
- package/dist/utils/auth.js +50 -0
- package/dist/utils/auth.js.map +1 -0
- package/dist/utils/cli-updater.d.ts +70 -0
- package/dist/utils/cli-updater.d.ts.map +1 -0
- package/dist/utils/cli-updater.js +339 -0
- package/dist/utils/cli-updater.js.map +1 -0
- package/dist/utils/config.d.ts +6 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +13 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/native-installer.d.ts.map +1 -1
- package/dist/utils/native-installer.js +48 -17
- package/dist/utils/native-installer.js.map +1 -1
- package/dist/utils/processes.js +1 -1
- package/dist/utils/profile.d.ts +2 -0
- package/dist/utils/profile.d.ts.map +1 -1
- package/dist/utils/profile.js +5 -0
- package/dist/utils/profile.js.map +1 -1
- package/dist/utils/sdk-client.d.ts +15 -0
- package/dist/utils/sdk-client.d.ts.map +1 -0
- package/dist/utils/sdk-client.js +92 -0
- package/dist/utils/sdk-client.js.map +1 -0
- package/package.json +7 -2
- package/dist/agents/plugins/claude/plugin/commands/codemie-pr.md +0 -25
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Core LangGraph ReAct agent using LangChain v1.0+ with streaming support
|
|
5
5
|
*/
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
6
7
|
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
|
7
8
|
import { ChatOpenAI } from '@langchain/openai';
|
|
8
|
-
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
|
9
|
+
import { HumanMessage, SystemMessage, AIMessage } from '@langchain/core/messages';
|
|
10
|
+
import { EVENT_TYPES, CodeMieAgentError } from './types.js';
|
|
9
11
|
import { getSystemPrompt } from './prompts.js';
|
|
10
|
-
import { CodeMieAgentError } from './types.js';
|
|
11
12
|
import { extractToolMetadata } from './toolMetadata.js';
|
|
12
13
|
import { extractTokenUsageFromStreamChunk, extractTokenUsageFromFinalState } from './tokenUtils.js';
|
|
13
14
|
import { setGlobalToolEventCallback } from './tools/index.js';
|
|
@@ -16,6 +17,8 @@ import { sanitizeCookies, sanitizeAuthToken } from '../../utils/security.js';
|
|
|
16
17
|
import { HookExecutor } from '../../hooks/executor.js';
|
|
17
18
|
import { extractSkillPatterns } from '../../skills/utils/pattern-matcher.js';
|
|
18
19
|
import { SkillManager } from '../../skills/core/SkillManager.js';
|
|
20
|
+
import { parseAtMentionCommand } from './ui/mentions.js';
|
|
21
|
+
import { loadRegisteredAssistants } from '../../utils/config.js';
|
|
19
22
|
export class CodeMieAgent {
|
|
20
23
|
agent;
|
|
21
24
|
config;
|
|
@@ -46,6 +49,8 @@ export class CodeMieAgent {
|
|
|
46
49
|
this.config = config;
|
|
47
50
|
this.tools = tools;
|
|
48
51
|
this.skills = skills;
|
|
52
|
+
const sessionId = randomUUID();
|
|
53
|
+
logger.setSessionId(sessionId);
|
|
49
54
|
// Create the appropriate LLM based on provider
|
|
50
55
|
const llm = this.createLLM();
|
|
51
56
|
// Create LangGraph ReAct agent with system prompt (including skills if loaded)
|
|
@@ -81,6 +86,27 @@ export class CodeMieAgent {
|
|
|
81
86
|
logger.debug(`CodeMie Agent initialized with ${tools.length} tools`);
|
|
82
87
|
}
|
|
83
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Update tools after initialization (needed for tools that require conversation history)
|
|
91
|
+
*/
|
|
92
|
+
async updateTools(tools) {
|
|
93
|
+
this.tools = tools;
|
|
94
|
+
// Load registered assistants for system prompt
|
|
95
|
+
const assistants = await loadRegisteredAssistants();
|
|
96
|
+
// Recreate agent with new tools and assistant-aware prompt
|
|
97
|
+
const llm = this.createLLM();
|
|
98
|
+
this.agent = createReactAgent({
|
|
99
|
+
llm,
|
|
100
|
+
tools: this.tools,
|
|
101
|
+
messageModifier: getSystemPrompt(this.config.workingDirectory, [], assistants)
|
|
102
|
+
});
|
|
103
|
+
if (this.config.debug) {
|
|
104
|
+
logger.debug(`CodeMie Agent tools updated: ${tools.length} tools`);
|
|
105
|
+
if (assistants.length > 0) {
|
|
106
|
+
logger.debug(`Loaded ${assistants.length} assistants for system prompt:`, assistants.map(a => a.slug));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
84
110
|
/**
|
|
85
111
|
* Create the appropriate LLM instance based on provider configuration
|
|
86
112
|
*/
|
|
@@ -155,7 +181,7 @@ export class CodeMieAgent {
|
|
|
155
181
|
model: this.config.model,
|
|
156
182
|
apiKey: this.config.authToken,
|
|
157
183
|
configuration: {
|
|
158
|
-
baseURL: this.config.baseUrl
|
|
184
|
+
baseURL: this.config.baseUrl === 'bedrock' ? undefined : this.config.baseUrl,
|
|
159
185
|
// Add client tracking header to all Bedrock requests
|
|
160
186
|
fetch: async (input, init) => {
|
|
161
187
|
const updatedInit = {
|
|
@@ -183,7 +209,7 @@ export class CodeMieAgent {
|
|
|
183
209
|
baseURL
|
|
184
210
|
};
|
|
185
211
|
// Check if we have SSO cookies to inject (following codemie-ide-plugin pattern)
|
|
186
|
-
const ssoCookies =
|
|
212
|
+
const ssoCookies = globalThis.codemieSSOCookies;
|
|
187
213
|
if (this.config.debug) {
|
|
188
214
|
logger.debug(`SSO Cookies available:`, sanitizeCookies(ssoCookies));
|
|
189
215
|
logger.debug(`Auth token:`, sanitizeAuthToken(this.config.authToken));
|
|
@@ -289,6 +315,70 @@ export class CodeMieAgent {
|
|
|
289
315
|
content: content
|
|
290
316
|
});
|
|
291
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Handle @ mention invocation result by updating history and emitting events
|
|
320
|
+
* @param message - Original user message
|
|
321
|
+
* @param images - Optional images from user
|
|
322
|
+
* @param atMentionResult - Result from preprocessAtMention
|
|
323
|
+
* @param onEvent - Event callback
|
|
324
|
+
*/
|
|
325
|
+
handleAtMentionResult(message, images, atMentionResult, onEvent) {
|
|
326
|
+
const userMessage = this.createHumanMessage(message, images);
|
|
327
|
+
this.conversationHistory.push(userMessage);
|
|
328
|
+
const assistantMessage = new AIMessage({
|
|
329
|
+
content: atMentionResult.response || 'No response from assistant'
|
|
330
|
+
});
|
|
331
|
+
this.conversationHistory.push(assistantMessage);
|
|
332
|
+
onEvent({ type: EVENT_TYPES.THINKING_END });
|
|
333
|
+
onEvent({ type: EVENT_TYPES.CONTENT_CHUNK, content: atMentionResult.response });
|
|
334
|
+
onEvent({ type: EVENT_TYPES.COMPLETE });
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Preprocess message to detect @ mentions and invoke assistants directly
|
|
338
|
+
* Returns { handled: true, response: string, assistantSlug: string } if @ mention was processed,
|
|
339
|
+
* or { handled: false } if no @ mention found
|
|
340
|
+
*/
|
|
341
|
+
async preprocessAtMention(message, onEvent) {
|
|
342
|
+
// Use shared mention pattern from mentions module
|
|
343
|
+
const parsed = parseAtMentionCommand(message);
|
|
344
|
+
if (!parsed) {
|
|
345
|
+
return { handled: false };
|
|
346
|
+
}
|
|
347
|
+
const { assistantSlug, message: assistantMessage } = parsed;
|
|
348
|
+
try {
|
|
349
|
+
// Find the invoke_assistant tool
|
|
350
|
+
const invokeTool = this.tools.find(tool => tool.name === 'invoke_assistant');
|
|
351
|
+
if (!invokeTool) {
|
|
352
|
+
if (this.config.debug) {
|
|
353
|
+
logger.debug('@ mention detected but invoke_assistant tool not available');
|
|
354
|
+
}
|
|
355
|
+
return { handled: false };
|
|
356
|
+
}
|
|
357
|
+
if (this.config.debug) {
|
|
358
|
+
logger.debug(`Preprocessing @ mention: @${assistantSlug} "${assistantMessage.substring(0, 50)}..."`);
|
|
359
|
+
}
|
|
360
|
+
// Emit thinking_start with assistant info
|
|
361
|
+
onEvent({ type: EVENT_TYPES.THINKING_START });
|
|
362
|
+
// Invoke the assistant tool directly
|
|
363
|
+
const response = await invokeTool.invoke({
|
|
364
|
+
assistantSlug,
|
|
365
|
+
message: assistantMessage,
|
|
366
|
+
includeHistory: false // Default to no history for @ mentions (can be made configurable)
|
|
367
|
+
});
|
|
368
|
+
return { handled: true, response: String(response), assistantSlug };
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
if (this.config.debug) {
|
|
372
|
+
logger.debug('@ mention preprocessing failed:', error);
|
|
373
|
+
}
|
|
374
|
+
// Return error as response but mark as handled
|
|
375
|
+
return {
|
|
376
|
+
handled: true,
|
|
377
|
+
response: `Failed to invoke assistant @${assistantSlug}: ${error instanceof Error ? error.message : String(error)}`,
|
|
378
|
+
assistantSlug
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
292
382
|
/**
|
|
293
383
|
* Stream a chat interaction with the agent
|
|
294
384
|
*/
|
|
@@ -308,7 +398,7 @@ export class CodeMieAgent {
|
|
|
308
398
|
// Set up global tool event callback for progress reporting
|
|
309
399
|
setGlobalToolEventCallback((event) => {
|
|
310
400
|
onEvent({
|
|
311
|
-
type:
|
|
401
|
+
type: EVENT_TYPES.TOOL_CALL_PROGRESS,
|
|
312
402
|
toolName: event.toolName,
|
|
313
403
|
toolProgress: event.progress
|
|
314
404
|
});
|
|
@@ -323,214 +413,220 @@ export class CodeMieAgent {
|
|
|
323
413
|
}
|
|
324
414
|
streamAborted = true;
|
|
325
415
|
abortController.abort();
|
|
326
|
-
onEvent({ type:
|
|
416
|
+
onEvent({ type: EVENT_TYPES.ERROR, error: 'Stream interrupted by user (Ctrl+C)' });
|
|
327
417
|
};
|
|
328
418
|
process.once('SIGINT', sigintHandler);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
419
|
+
if (this.config.debug) {
|
|
420
|
+
logger.debug(`Processing message: ${message.substring(0, 100)}...`);
|
|
421
|
+
}
|
|
422
|
+
// Execute SessionStart hooks (only on first message)
|
|
423
|
+
if (this.hookExecutor && this.conversationHistory.length === 0) {
|
|
424
|
+
try {
|
|
425
|
+
const sessionStartResult = await this.hookExecutor.executeSessionStart();
|
|
426
|
+
// Handle blocking decision
|
|
427
|
+
if (sessionStartResult.decision === 'block') {
|
|
428
|
+
const reason = sessionStartResult.reason || 'Session blocked by SessionStart hook';
|
|
429
|
+
const context = sessionStartResult.additionalContext;
|
|
430
|
+
// Check if we should retry (exit code 2 behavior)
|
|
431
|
+
if (context && this.hookLoopCounter < (this.getMaxHookRetries())) {
|
|
432
|
+
this.hookLoopCounter++;
|
|
433
|
+
logger.warn(`SessionStart hook blocked (attempt ${this.hookLoopCounter}/${this.getMaxHookRetries()})`);
|
|
434
|
+
// Build feedback message
|
|
435
|
+
const hookFeedback = [reason, context].filter(Boolean).join('\n\n');
|
|
436
|
+
// Clear hook cache for retry
|
|
437
|
+
this.hookExecutor.clearCache();
|
|
438
|
+
// Retry with feedback
|
|
439
|
+
return this.chatStream(`[Hook feedback]: ${hookFeedback}`, onEvent, images);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
// Max retries reached or no feedback - block session
|
|
443
|
+
if (this.hookLoopCounter >= this.getMaxHookRetries()) {
|
|
444
|
+
logger.error(`SessionStart hook blocked after ${this.hookLoopCounter} attempts - aborting session`);
|
|
445
|
+
onEvent({
|
|
446
|
+
type: 'error',
|
|
447
|
+
error: `Session blocked after ${this.hookLoopCounter} attempts: ${reason}`
|
|
448
|
+
});
|
|
351
449
|
}
|
|
352
450
|
else {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
error: `Session blocked after ${this.hookLoopCounter} attempts: ${reason}`
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
else {
|
|
362
|
-
logger.warn('SessionStart hook blocked session start');
|
|
363
|
-
onEvent({
|
|
364
|
-
type: 'error',
|
|
365
|
-
error: reason
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
return; // Exit without starting session
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
// Inject hook output as system context
|
|
372
|
-
if (sessionStartResult.additionalContext) {
|
|
373
|
-
if (this.config.debug) {
|
|
374
|
-
logger.debug('SessionStart hook provided context, injecting into conversation');
|
|
451
|
+
logger.warn('SessionStart hook blocked session start');
|
|
452
|
+
onEvent({
|
|
453
|
+
type: 'error',
|
|
454
|
+
error: reason
|
|
455
|
+
});
|
|
375
456
|
}
|
|
376
|
-
//
|
|
377
|
-
const systemMessage = new SystemMessage(`[SessionStart Hook Output]:\n${sessionStartResult.additionalContext}`);
|
|
378
|
-
this.conversationHistory.push(systemMessage);
|
|
457
|
+
return; // Exit without starting session
|
|
379
458
|
}
|
|
380
459
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
// Execute UserPromptSubmit hooks
|
|
387
|
-
if (this.hookExecutor && message.trim()) {
|
|
388
|
-
try {
|
|
389
|
-
const hookResult = await this.hookExecutor.executeUserPromptSubmit(message);
|
|
390
|
-
// Handle blocking decision
|
|
391
|
-
if (hookResult.decision === 'block') {
|
|
392
|
-
logger.warn('UserPromptSubmit hook blocked prompt');
|
|
393
|
-
onEvent({
|
|
394
|
-
type: 'error',
|
|
395
|
-
error: hookResult.reason || 'Prompt blocked by hook'
|
|
396
|
-
});
|
|
397
|
-
return; // Exit without processing
|
|
398
|
-
}
|
|
399
|
-
// Add context to conversation
|
|
400
|
-
if (hookResult.additionalContext) {
|
|
401
|
-
if (this.config.debug) {
|
|
402
|
-
logger.debug('UserPromptSubmit hook provided context');
|
|
403
|
-
}
|
|
404
|
-
// Prepend context to the message
|
|
405
|
-
message = `${hookResult.additionalContext}\n\n${message}`;
|
|
460
|
+
// Inject hook output as system context
|
|
461
|
+
if (sessionStartResult.additionalContext) {
|
|
462
|
+
if (this.config.debug) {
|
|
463
|
+
logger.debug('SessionStart hook provided context, injecting into conversation');
|
|
406
464
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
// Continue execution
|
|
465
|
+
// Add SessionStart output as system message before user message
|
|
466
|
+
const systemMessage = new SystemMessage(`[SessionStart Hook Output]:\n${sessionStartResult.additionalContext}`);
|
|
467
|
+
this.conversationHistory.push(systemMessage);
|
|
411
468
|
}
|
|
412
469
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
try {
|
|
417
|
-
// Load skills with inventory
|
|
418
|
-
const skillsWithInventory = await this.loadDetectedSkills(patternResult.patterns);
|
|
419
|
-
if (skillsWithInventory.length > 0) {
|
|
420
|
-
// Format and inject as system message
|
|
421
|
-
const skillContent = this.formatSkillsForInjection(skillsWithInventory);
|
|
422
|
-
const skillSystemMessage = new SystemMessage(`[Skill Invocation Detected]\n\n${skillContent}`);
|
|
423
|
-
this.conversationHistory.push(skillSystemMessage);
|
|
424
|
-
if (this.config.debug) {
|
|
425
|
-
logger.debug(`Injected ${skillsWithInventory.length} skills: ${skillsWithInventory.map((s) => s.skill.metadata.name).join(', ')}`);
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
catch (error) {
|
|
430
|
-
// Non-blocking: Log error but continue
|
|
431
|
-
logger.warn('Failed to load skills for pattern injection:', error);
|
|
432
|
-
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
logger.error(`SessionStart hook failed: ${error}`);
|
|
472
|
+
// Continue session start (fail open)
|
|
433
473
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
// Check if stream was aborted
|
|
451
|
-
if (streamAborted || abortController.signal.aborted) {
|
|
474
|
+
}
|
|
475
|
+
// Execute UserPromptSubmit hooks
|
|
476
|
+
if (this.hookExecutor && message.trim()) {
|
|
477
|
+
try {
|
|
478
|
+
const hookResult = await this.hookExecutor.executeUserPromptSubmit(message);
|
|
479
|
+
// Handle blocking decision
|
|
480
|
+
if (hookResult.decision === 'block') {
|
|
481
|
+
logger.warn('UserPromptSubmit hook blocked prompt');
|
|
482
|
+
onEvent({
|
|
483
|
+
type: 'error',
|
|
484
|
+
error: hookResult.reason || 'Prompt blocked by hook'
|
|
485
|
+
});
|
|
486
|
+
return; // Exit without processing
|
|
487
|
+
}
|
|
488
|
+
// Add context to conversation
|
|
489
|
+
if (hookResult.additionalContext) {
|
|
452
490
|
if (this.config.debug) {
|
|
453
|
-
logger.debug('
|
|
491
|
+
logger.debug('UserPromptSubmit hook provided context');
|
|
454
492
|
}
|
|
455
|
-
|
|
493
|
+
// Prepend context to the message
|
|
494
|
+
message = `${hookResult.additionalContext}\n\n${message}`;
|
|
456
495
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
logger.error(`UserPromptSubmit hook failed: ${error}`);
|
|
499
|
+
// Continue execution
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
// Detect skill patterns in message
|
|
503
|
+
const patternResult = extractSkillPatterns(message);
|
|
504
|
+
if (patternResult.hasPatterns) {
|
|
505
|
+
try {
|
|
506
|
+
// Load skills with inventory
|
|
507
|
+
const skillsWithInventory = await this.loadDetectedSkills(patternResult.patterns);
|
|
508
|
+
if (skillsWithInventory.length > 0) {
|
|
509
|
+
// Format and inject as system message
|
|
510
|
+
const skillContent = this.formatSkillsForInjection(skillsWithInventory);
|
|
511
|
+
const skillSystemMessage = new SystemMessage(`[Skill Invocation Detected]\n\n${skillContent}`);
|
|
512
|
+
this.conversationHistory.push(skillSystemMessage);
|
|
465
513
|
if (this.config.debug) {
|
|
466
|
-
logger.debug(`
|
|
514
|
+
logger.debug(`Injected ${skillsWithInventory.length} skills: ${skillsWithInventory.map((s) => s.skill.metadata.name).join(', ')}`);
|
|
467
515
|
}
|
|
468
516
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
// Non-blocking: Log error but continue
|
|
520
|
+
logger.warn('Failed to load skills for pattern injection:', error);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
// Preprocess @ mentions before normal agent processing
|
|
524
|
+
const atMentionResult = await this.preprocessAtMention(message, onEvent);
|
|
525
|
+
if (atMentionResult.handled) {
|
|
526
|
+
this.handleAtMentionResult(message, images, atMentionResult, onEvent);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
// Add user message to conversation history (with optional images)
|
|
530
|
+
const userMessage = this.createHumanMessage(message, images);
|
|
531
|
+
this.conversationHistory.push(userMessage);
|
|
532
|
+
// Notify start of thinking
|
|
533
|
+
onEvent({ type: EVENT_TYPES.THINKING_START });
|
|
534
|
+
// Start the first LLM call step
|
|
535
|
+
currentStep = this.startLLMStep();
|
|
536
|
+
// Create the stream with conversation history
|
|
537
|
+
const stream = await this.agent.stream({ messages: this.conversationHistory }, {
|
|
538
|
+
streamMode: 'updates',
|
|
539
|
+
recursionLimit: 50,
|
|
540
|
+
signal: abortController.signal // Add abort signal for stream cancellation
|
|
541
|
+
});
|
|
542
|
+
let hasContent = false;
|
|
543
|
+
// Process stream chunks with interruption handling
|
|
544
|
+
for await (const chunk of stream) {
|
|
545
|
+
// Check if stream was aborted
|
|
546
|
+
if (streamAborted || abortController.signal.aborted) {
|
|
547
|
+
if (this.config.debug) {
|
|
548
|
+
logger.debug('Stream processing aborted');
|
|
549
|
+
}
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
// Try to extract token usage from stream chunk
|
|
553
|
+
const tokenUsage = extractTokenUsageFromStreamChunk(chunk, this.config.model, this.config.provider);
|
|
554
|
+
if (tokenUsage && currentStep?.type === 'llm_call') {
|
|
555
|
+
// Update current step with token usage
|
|
556
|
+
currentStep.tokenUsage = tokenUsage;
|
|
557
|
+
this.updateStatsWithTokenUsage(tokenUsage);
|
|
558
|
+
// Store token usage to associate with next tool call
|
|
559
|
+
this.currentLLMTokenUsage = tokenUsage;
|
|
560
|
+
if (this.config.debug) {
|
|
561
|
+
logger.debug(`Token usage: ${tokenUsage.inputTokens} in, ${tokenUsage.outputTokens} out`);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
await this.processStreamChunk(chunk, onEvent, (toolStarted) => {
|
|
565
|
+
if (toolStarted) {
|
|
566
|
+
// Complete current LLM step if it exists
|
|
567
|
+
if (currentStep?.type === 'llm_call') {
|
|
484
568
|
this.completeStep(currentStep);
|
|
485
569
|
currentStep = null;
|
|
486
|
-
this.stats.successfulTools++;
|
|
487
|
-
currentToolCall = null;
|
|
488
|
-
// Start new LLM step for next reasoning cycle (processing tool result)
|
|
489
|
-
currentStep = this.startLLMStep();
|
|
490
|
-
}
|
|
491
|
-
});
|
|
492
|
-
// Check if we have content
|
|
493
|
-
if (chunk.agent?.messages) {
|
|
494
|
-
const lastMessage = chunk.agent.messages.at(-1);
|
|
495
|
-
if (lastMessage?.content && !hasContent) {
|
|
496
|
-
hasContent = true;
|
|
497
570
|
}
|
|
571
|
+
// Start tool execution step
|
|
572
|
+
currentStep = this.startToolStep(toolStarted);
|
|
573
|
+
currentToolCall = toolStarted;
|
|
574
|
+
this.stats.toolCalls++;
|
|
575
|
+
}
|
|
576
|
+
else if (currentToolCall && currentStep) {
|
|
577
|
+
// Complete tool step
|
|
578
|
+
currentStep.toolSuccess = true;
|
|
579
|
+
this.completeStep(currentStep);
|
|
580
|
+
currentStep = null;
|
|
581
|
+
this.stats.successfulTools++;
|
|
582
|
+
currentToolCall = null;
|
|
583
|
+
// Start new LLM step for next reasoning cycle (processing tool result)
|
|
584
|
+
currentStep = this.startLLMStep();
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
// Check if we have content
|
|
588
|
+
if (chunk.agent?.messages) {
|
|
589
|
+
const lastMessage = chunk.agent.messages.at(-1);
|
|
590
|
+
if (lastMessage?.content && !hasContent) {
|
|
591
|
+
hasContent = true;
|
|
498
592
|
}
|
|
499
593
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
594
|
+
}
|
|
595
|
+
// Complete any remaining step
|
|
596
|
+
if (currentStep) {
|
|
597
|
+
this.completeStep(currentStep);
|
|
598
|
+
}
|
|
599
|
+
// Update conversation history with final messages and try to extract any missed token usage
|
|
600
|
+
try {
|
|
601
|
+
const finalState = await this.agent.getState();
|
|
602
|
+
if (finalState?.messages) {
|
|
603
|
+
this.conversationHistory = finalState.messages;
|
|
604
|
+
// Try to extract token usage from final state if we missed it during streaming
|
|
605
|
+
const finalTokenUsage = extractTokenUsageFromFinalState(finalState, this.config.model, this.config.provider);
|
|
606
|
+
if (finalTokenUsage && this.currentExecutionSteps.length > 0) {
|
|
607
|
+
// Find the last LLM step that doesn't have token usage
|
|
608
|
+
for (let i = this.currentExecutionSteps.length - 1; i >= 0; i--) {
|
|
609
|
+
const step = this.currentExecutionSteps[i];
|
|
610
|
+
if (step.type === 'llm_call' && !step.tokenUsage) {
|
|
611
|
+
step.tokenUsage = finalTokenUsage;
|
|
612
|
+
this.updateStatsWithTokenUsage(finalTokenUsage);
|
|
613
|
+
break;
|
|
520
614
|
}
|
|
521
615
|
}
|
|
522
616
|
}
|
|
523
617
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
618
|
+
}
|
|
619
|
+
catch {
|
|
620
|
+
// If getState fails, continue without updating history
|
|
621
|
+
if (this.config.debug) {
|
|
622
|
+
logger.debug('Could not get final state, continuing...');
|
|
529
623
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
624
|
+
}
|
|
625
|
+
// Finalize execution statistics
|
|
626
|
+
this.stats.executionTime = Date.now() - startTime;
|
|
627
|
+
this.stats.executionSteps = [...this.currentExecutionSteps];
|
|
628
|
+
// Execute Stop hooks
|
|
629
|
+
try {
|
|
534
630
|
if (this.hookExecutor) {
|
|
535
631
|
try {
|
|
536
632
|
const stopHookResult = await this.hookExecutor.executeStop(this.currentExecutionSteps, {
|
|
@@ -593,8 +689,8 @@ export class CodeMieAgent {
|
|
|
593
689
|
}
|
|
594
690
|
}
|
|
595
691
|
// Notify thinking end and completion
|
|
596
|
-
onEvent({ type:
|
|
597
|
-
onEvent({ type:
|
|
692
|
+
onEvent({ type: EVENT_TYPES.THINKING_END });
|
|
693
|
+
onEvent({ type: EVENT_TYPES.COMPLETE });
|
|
598
694
|
if (this.config.debug) {
|
|
599
695
|
logger.debug(`Agent completed in ${this.stats.executionTime}ms`);
|
|
600
696
|
logger.debug(`Total tokens: ${this.stats.totalTokens} (${this.stats.inputTokens} in, ${this.stats.outputTokens} out)`);
|
|
@@ -613,7 +709,7 @@ export class CodeMieAgent {
|
|
|
613
709
|
logger.debug('Stream aborted by user');
|
|
614
710
|
}
|
|
615
711
|
onEvent({
|
|
616
|
-
type:
|
|
712
|
+
type: EVENT_TYPES.ERROR,
|
|
617
713
|
error: 'Operation interrupted by user'
|
|
618
714
|
});
|
|
619
715
|
return; // Don't throw error for user interruptions
|
|
@@ -626,7 +722,7 @@ export class CodeMieAgent {
|
|
|
626
722
|
logger.debug(`Model: ${this.config.model}`);
|
|
627
723
|
}
|
|
628
724
|
onEvent({
|
|
629
|
-
type:
|
|
725
|
+
type: EVENT_TYPES.ERROR,
|
|
630
726
|
error: errorMessage
|
|
631
727
|
});
|
|
632
728
|
throw new CodeMieAgentError(`Agent execution failed: ${errorMessage}`, 'EXECUTION_ERROR', { originalError: error, stats: this.stats });
|
|
@@ -656,7 +752,7 @@ export class CodeMieAgent {
|
|
|
656
752
|
// Stream content chunks
|
|
657
753
|
if (lastMessage?.content && typeof lastMessage.content === 'string') {
|
|
658
754
|
onEvent({
|
|
659
|
-
type:
|
|
755
|
+
type: EVENT_TYPES.CONTENT_CHUNK,
|
|
660
756
|
content: lastMessage.content
|
|
661
757
|
});
|
|
662
758
|
}
|
|
@@ -697,7 +793,7 @@ export class CodeMieAgent {
|
|
|
697
793
|
// Use tool name as key since LangGraph may not preserve IDs consistently
|
|
698
794
|
this.toolCallArgs.set(toolCall.name, toolCall.args);
|
|
699
795
|
onEvent({
|
|
700
|
-
type:
|
|
796
|
+
type: EVENT_TYPES.TOOL_CALL_START,
|
|
701
797
|
toolName: toolCall.name,
|
|
702
798
|
toolArgs: toolCall.args
|
|
703
799
|
});
|
|
@@ -758,7 +854,7 @@ export class CodeMieAgent {
|
|
|
758
854
|
}
|
|
759
855
|
}
|
|
760
856
|
onEvent({
|
|
761
|
-
type:
|
|
857
|
+
type: EVENT_TYPES.TOOL_CALL_RESULT,
|
|
762
858
|
toolName,
|
|
763
859
|
result,
|
|
764
860
|
toolMetadata
|
|
@@ -775,7 +871,7 @@ export class CodeMieAgent {
|
|
|
775
871
|
}
|
|
776
872
|
// Don't throw here, just log - let the main stream continue
|
|
777
873
|
onEvent({
|
|
778
|
-
type:
|
|
874
|
+
type: EVENT_TYPES.ERROR,
|
|
779
875
|
error: `Stream processing error: ${error instanceof Error ? error.message : String(error)}`
|
|
780
876
|
});
|
|
781
877
|
}
|
|
@@ -903,7 +999,7 @@ export class CodeMieAgent {
|
|
|
903
999
|
}
|
|
904
1000
|
else {
|
|
905
1001
|
// Check if the previous step was a tool execution
|
|
906
|
-
const prevStep = this.currentExecutionSteps
|
|
1002
|
+
const prevStep = this.currentExecutionSteps.at(-1);
|
|
907
1003
|
llmContext = (prevStep?.type === 'tool_execution') ? 'processing_tool_result' : 'final_response';
|
|
908
1004
|
}
|
|
909
1005
|
const step = {
|