@northflare/runner 0.0.13 → 0.0.16
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 +8 -5
- package/bin/northflare-runner +44 -16
- package/dist/components/claude-sdk-manager.d.ts +3 -3
- package/dist/components/claude-sdk-manager.d.ts.map +1 -1
- package/dist/components/claude-sdk-manager.js +80 -111
- package/dist/components/claude-sdk-manager.js.map +1 -1
- package/dist/components/codex-sdk-manager.d.ts +15 -6
- package/dist/components/codex-sdk-manager.d.ts.map +1 -1
- package/dist/components/codex-sdk-manager.js +128 -97
- package/dist/components/codex-sdk-manager.js.map +1 -1
- package/dist/components/enhanced-repository-manager.d.ts +2 -2
- package/dist/components/enhanced-repository-manager.d.ts.map +1 -1
- package/dist/components/enhanced-repository-manager.js +68 -75
- package/dist/components/enhanced-repository-manager.js.map +1 -1
- package/dist/components/message-handler-sse.d.ts +1 -1
- package/dist/components/message-handler-sse.d.ts.map +1 -1
- package/dist/components/message-handler-sse.js +205 -97
- package/dist/components/message-handler-sse.js.map +1 -1
- package/dist/components/{claude-manager.d.ts → northflare-agent-sdk-manager.d.ts} +17 -14
- package/dist/components/northflare-agent-sdk-manager.d.ts.map +1 -0
- package/dist/components/northflare-agent-sdk-manager.js +1456 -0
- package/dist/components/northflare-agent-sdk-manager.js.map +1 -0
- package/dist/components/repository-manager.d.ts +2 -2
- package/dist/components/repository-manager.d.ts.map +1 -1
- package/dist/components/repository-manager.js +34 -74
- package/dist/components/repository-manager.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -79
- package/dist/index.js.map +1 -1
- package/dist/runner-sse.d.ts +22 -5
- package/dist/runner-sse.d.ts.map +1 -1
- package/dist/runner-sse.js +95 -74
- package/dist/runner-sse.js.map +1 -1
- package/dist/services/RunnerAPIClient.d.ts +1 -1
- package/dist/services/RunnerAPIClient.d.ts.map +1 -1
- package/dist/services/RunnerAPIClient.js +3 -7
- package/dist/services/RunnerAPIClient.js.map +1 -1
- package/dist/services/SSEClient.js +5 -9
- package/dist/services/SSEClient.js.map +1 -1
- package/dist/types/claude.d.ts +16 -2
- package/dist/types/claude.d.ts.map +1 -1
- package/dist/types/claude.js +1 -2
- package/dist/types/claude.js.map +1 -1
- package/dist/types/index.d.ts +5 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -19
- package/dist/types/index.js.map +1 -1
- package/dist/types/messages.js +1 -2
- package/dist/types/messages.js.map +1 -1
- package/dist/types/runner-interface.d.ts +8 -4
- package/dist/types/runner-interface.d.ts.map +1 -1
- package/dist/types/runner-interface.js +1 -2
- package/dist/types/runner-interface.js.map +1 -1
- package/dist/utils/StateManager.js +12 -19
- package/dist/utils/StateManager.js.map +1 -1
- package/dist/utils/config.d.ts +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +19 -26
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/console.js +3 -6
- package/dist/utils/console.js.map +1 -1
- package/dist/utils/debug.js +1 -4
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/expand-env.js +1 -4
- package/dist/utils/expand-env.js.map +1 -1
- package/dist/utils/inactivity-timeout.d.ts +19 -0
- package/dist/utils/inactivity-timeout.d.ts.map +1 -0
- package/dist/utils/inactivity-timeout.js +72 -0
- package/dist/utils/inactivity-timeout.js.map +1 -0
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +24 -35
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/model.d.ts +3 -1
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +18 -4
- package/dist/utils/model.js.map +1 -1
- package/dist/utils/status-line.d.ts +1 -0
- package/dist/utils/status-line.d.ts.map +1 -1
- package/dist/utils/status-line.js +25 -18
- package/dist/utils/status-line.js.map +1 -1
- package/dist/utils/tool-response-sanitizer.js +6 -10
- package/dist/utils/tool-response-sanitizer.js.map +1 -1
- package/lib/codex-sdk/dist/index.d.ts +1 -1
- package/lib/codex-sdk/dist/samples/basic_streaming.d.ts +3 -0
- package/lib/codex-sdk/dist/samples/basic_streaming.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/basic_streaming.js +81 -0
- package/lib/codex-sdk/dist/samples/basic_streaming.js.map +1 -0
- package/lib/codex-sdk/dist/samples/helpers.d.ts +2 -0
- package/lib/codex-sdk/dist/samples/helpers.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/helpers.js +6 -0
- package/lib/codex-sdk/dist/samples/helpers.js.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output.d.ts +3 -0
- package/lib/codex-sdk/dist/samples/structured_output.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output.js +17 -0
- package/lib/codex-sdk/dist/samples/structured_output.js.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.d.ts +3 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.d.ts.map +1 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.js +16 -0
- package/lib/codex-sdk/dist/samples/structured_output_zod.js.map +1 -0
- package/lib/codex-sdk/dist/tsup.config.d.ts +3 -0
- package/lib/codex-sdk/dist/tsup.config.js +12 -0
- package/package.json +9 -4
- package/scripts/verify-openrouter-agent.ts +163 -0
- package/dist/collections/runner-messages.d.ts +0 -52
- package/dist/collections/runner-messages.d.ts.map +0 -1
- package/dist/collections/runner-messages.js +0 -161
- package/dist/collections/runner-messages.js.map +0 -1
- package/dist/components/claude-manager.d.ts.map +0 -1
- package/dist/components/claude-manager.js +0 -783
- package/dist/components/claude-manager.js.map +0 -1
- package/dist/components/message-handler.d.ts +0 -35
- package/dist/components/message-handler.d.ts.map +0 -1
- package/dist/components/message-handler.js +0 -689
- package/dist/components/message-handler.js.map +0 -1
- package/dist/runner.d.ts +0 -51
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js +0 -530
- package/dist/runner.js.map +0 -1
|
@@ -1,783 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* ClaudeManager - Manages Claude conversations using claude-code-sdk-ts
|
|
4
|
-
*
|
|
5
|
-
* This component handles stateful conversation lifecycle management, maintaining
|
|
6
|
-
* persistent conversation instances indexed by taskId. It integrates with the
|
|
7
|
-
* Claude SDK to manage sessions, handle MCP server configurations, and coordinate
|
|
8
|
-
* with the orchestrator for authentication and notifications.
|
|
9
|
-
*/
|
|
10
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
11
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
12
|
-
};
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.ClaudeManager = void 0;
|
|
15
|
-
const claude_code_sdk_ts_1 = require("@botanicastudios/claude-code-sdk-ts");
|
|
16
|
-
const status_line_1 = require("../utils/status-line");
|
|
17
|
-
const console_1 = require("../utils/console");
|
|
18
|
-
const expand_env_1 = require("../utils/expand-env");
|
|
19
|
-
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
20
|
-
class ClaudeManager {
|
|
21
|
-
runner;
|
|
22
|
-
repositoryManager;
|
|
23
|
-
constructor(runner, repositoryManager) {
|
|
24
|
-
this.runner = runner;
|
|
25
|
-
this.repositoryManager = repositoryManager;
|
|
26
|
-
// Log debug mode status
|
|
27
|
-
if (process.env["DEBUG"] === "true") {
|
|
28
|
-
console_1.console.log("[ClaudeManager] DEBUG MODE ENABLED - Claude SDK will log verbose output");
|
|
29
|
-
}
|
|
30
|
-
// Note: MCP host configuration is passed from orchestrator
|
|
31
|
-
// Runner does not define its own MCP tools
|
|
32
|
-
this.setupInternalMcpServer();
|
|
33
|
-
}
|
|
34
|
-
setupInternalMcpServer() {
|
|
35
|
-
// Runner does not define its own MCP tools
|
|
36
|
-
// All MCP tool configuration is passed from orchestrator in conversation config
|
|
37
|
-
}
|
|
38
|
-
async startConversation(conversationObjectType, conversationObjectId, config, initialMessages, conversationData) {
|
|
39
|
-
// Returns conversation context
|
|
40
|
-
// Greenfield: conversationData.id is required as the authoritative DB conversation ID
|
|
41
|
-
if (!conversationData?.id) {
|
|
42
|
-
throw new Error("startConversation requires conversationData with a valid conversation.id");
|
|
43
|
-
}
|
|
44
|
-
// Use sessionId from config if resuming, or agentSessionId from conversationData if available
|
|
45
|
-
const agentSessionId = config.sessionId || conversationData.agentSessionId || "";
|
|
46
|
-
const conversationId = conversationData.id;
|
|
47
|
-
const context = {
|
|
48
|
-
conversationId,
|
|
49
|
-
agentSessionId, // Will be updated by onSessionId callback for new conversations
|
|
50
|
-
conversationObjectType,
|
|
51
|
-
conversationObjectId,
|
|
52
|
-
taskId: conversationObjectType === "Task" ? conversationObjectId : undefined,
|
|
53
|
-
workspaceId: config.workspaceId,
|
|
54
|
-
status: "starting",
|
|
55
|
-
config,
|
|
56
|
-
startedAt: new Date(),
|
|
57
|
-
lastActivityAt: new Date(),
|
|
58
|
-
// Add conversation details if provided
|
|
59
|
-
model: conversationData?.model || "sonnet",
|
|
60
|
-
globalInstructions: conversationData?.globalInstructions || "",
|
|
61
|
-
workspaceInstructions: conversationData?.workspaceInstructions || "",
|
|
62
|
-
permissionsMode: conversationData?.permissionsMode || "all",
|
|
63
|
-
};
|
|
64
|
-
// Store with conversation.id as the key
|
|
65
|
-
this.runner.activeConversations_.set(conversationId, context);
|
|
66
|
-
console_1.console.log(`[ClaudeManager] Stored conversation context:`, {
|
|
67
|
-
conversationId,
|
|
68
|
-
agentSessionId: context.agentSessionId,
|
|
69
|
-
conversationObjectType: context.conversationObjectType,
|
|
70
|
-
conversationObjectId: context.conversationObjectId,
|
|
71
|
-
mapSize: this.runner.activeConversations_.size,
|
|
72
|
-
allKeys: Array.from(this.runner.activeConversations_.keys()),
|
|
73
|
-
});
|
|
74
|
-
const workspaceId = config.workspaceId;
|
|
75
|
-
// Checkout repository if specified
|
|
76
|
-
let workspacePath;
|
|
77
|
-
// Check if this is a local workspace by looking for runnerRepoPath in config
|
|
78
|
-
if (config.runnerRepoPath) {
|
|
79
|
-
// Local workspace - use the provided path directly
|
|
80
|
-
workspacePath = config.runnerRepoPath;
|
|
81
|
-
console_1.console.log(`Using local workspace path: ${workspacePath}`);
|
|
82
|
-
// For task conversations in local workspaces, create a local task handle
|
|
83
|
-
if (conversationObjectType === "Task") {
|
|
84
|
-
const taskHandle = await this.repositoryManager.createLocalTaskHandle(conversationObjectId, workspacePath);
|
|
85
|
-
// Store task handle information in context for later use
|
|
86
|
-
context.taskHandle = taskHandle;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else if (conversationObjectType === "Task" &&
|
|
90
|
-
config.repository &&
|
|
91
|
-
workspaceId) {
|
|
92
|
-
// Use task-specific worktree for task conversations
|
|
93
|
-
console_1.console.log(`[ClaudeManager] Creating task worktree with repository config:`, {
|
|
94
|
-
conversationObjectId,
|
|
95
|
-
workspaceId,
|
|
96
|
-
repository: config.repository,
|
|
97
|
-
hasUrl: !!config.repository.url,
|
|
98
|
-
url: config.repository.url,
|
|
99
|
-
branch: config.repository.branch,
|
|
100
|
-
type: config.repository.type,
|
|
101
|
-
});
|
|
102
|
-
// Check if repository.url is missing
|
|
103
|
-
if (!config.repository.url) {
|
|
104
|
-
throw new Error(`Repository URL is missing in config for task ${conversationObjectId}. Repository config: ${JSON.stringify(config.repository)}`);
|
|
105
|
-
}
|
|
106
|
-
const taskHandle = await this.repositoryManager.createTaskWorktree(conversationObjectId, workspaceId, config.repository.url, config.repository.branch, config.githubToken);
|
|
107
|
-
workspacePath = taskHandle.worktreePath;
|
|
108
|
-
// Store task handle information in context for later use
|
|
109
|
-
context.taskHandle = taskHandle;
|
|
110
|
-
}
|
|
111
|
-
else if (config.repository && workspaceId) {
|
|
112
|
-
// Check if it's a local repository
|
|
113
|
-
if (config.repository.type === "local" && config.repository.localPath) {
|
|
114
|
-
// Use the local path directly
|
|
115
|
-
workspacePath = config.repository.localPath;
|
|
116
|
-
console_1.console.log(`Using local repository path: ${workspacePath}`);
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
// Fall back to workspace-based checkout for non-task conversations
|
|
120
|
-
workspacePath = await this.repositoryManager.checkoutRepository(workspaceId, config.repository.url, config.repository.branch, config.githubToken);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
else if (workspaceId) {
|
|
124
|
-
workspacePath = await this.repositoryManager.getWorkspacePath(workspaceId);
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
// Default workspace path when no workspaceId is provided
|
|
128
|
-
workspacePath = process.cwd();
|
|
129
|
-
}
|
|
130
|
-
// Fetch GitHub tokens from orchestrator API if we have a workspaceId
|
|
131
|
-
const githubToken = workspaceId
|
|
132
|
-
? await this.fetchGithubTokens(workspaceId)
|
|
133
|
-
: undefined;
|
|
134
|
-
// Generate TOOL_TOKEN for MCP tools authentication
|
|
135
|
-
let toolToken;
|
|
136
|
-
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
|
137
|
-
const runnerToken = process.env["CLAUDETTE_RUNNER_TOKEN"];
|
|
138
|
-
const runnerUid = this.runner.getRunnerUid();
|
|
139
|
-
if (runnerToken && runnerUid && context.conversationId) {
|
|
140
|
-
// Sign JWT with runner's token
|
|
141
|
-
toolToken = jsonwebtoken_1.default.sign({
|
|
142
|
-
conversationId: context.conversationId,
|
|
143
|
-
runnerUid: runnerUid,
|
|
144
|
-
}, runnerToken, {
|
|
145
|
-
expiresIn: "60m", // 60 minutes expiry
|
|
146
|
-
});
|
|
147
|
-
console_1.console.log("[ClaudeManager] Generated TOOL_TOKEN for MCP authentication");
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
console_1.console.warn("[ClaudeManager] Unable to generate TOOL_TOKEN - missing required data");
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
// Build claude conversation
|
|
154
|
-
const builder = (0, claude_code_sdk_ts_1.claude)()
|
|
155
|
-
.withExecutable(require.resolve("@anthropic-ai/claude-code/cli.js"))
|
|
156
|
-
.withEnv({
|
|
157
|
-
ANTHROPIC_API_KEY: config.anthropicApiKey || "",
|
|
158
|
-
...(githubToken && { GITHUB_TOKEN: githubToken }),
|
|
159
|
-
})
|
|
160
|
-
.withModel(context.model)
|
|
161
|
-
.inDirectory(workspacePath)
|
|
162
|
-
.skipPermissions(); // Runner manages permissions
|
|
163
|
-
// Enable debug logging when DEBUG is set
|
|
164
|
-
if (process.env["DEBUG"] === "true") {
|
|
165
|
-
console_1.console.log("[ClaudeManager] Enabling claude-code-sdk debug logging");
|
|
166
|
-
console_1.console.log("[ClaudeManager] CLI path:", require.resolve("@anthropic-ai/claude-code/cli.js"));
|
|
167
|
-
console_1.console.log("[ClaudeManager] Working directory:", workspacePath);
|
|
168
|
-
console_1.console.log("[ClaudeManager] Model:", context.model);
|
|
169
|
-
const debugLogger = new claude_code_sdk_ts_1.ConsoleLogger(claude_code_sdk_ts_1.LogLevel.TRACE, "[Claude SDK]");
|
|
170
|
-
builder.withLogger(debugLogger);
|
|
171
|
-
// Also enable debug mode on the CLI connection to capture stderr/stdout
|
|
172
|
-
builder.debug(true);
|
|
173
|
-
}
|
|
174
|
-
// Add session ID if resuming
|
|
175
|
-
if (config.sessionId) {
|
|
176
|
-
builder.withSessionId(config.sessionId);
|
|
177
|
-
}
|
|
178
|
-
// Configure MCP servers from orchestrator
|
|
179
|
-
if (config.mcpServers) {
|
|
180
|
-
console_1.console.log("[ClaudeManager] MCP servers configuration:", JSON.stringify(config.mcpServers, null, 2));
|
|
181
|
-
// Pass MCP configuration directly from orchestrator to Claude SDK
|
|
182
|
-
// The runner does not define or modify MCP tools
|
|
183
|
-
const expandedMcpServers = (0, expand_env_1.expandEnv)(config.mcpServers, {
|
|
184
|
-
TOOL_TOKEN: toolToken,
|
|
185
|
-
});
|
|
186
|
-
builder.withMCP(expandedMcpServers);
|
|
187
|
-
}
|
|
188
|
-
// Append system prompts if we have conversation instructions
|
|
189
|
-
if (context.globalInstructions || context.workspaceInstructions) {
|
|
190
|
-
const combinedInstructions = [
|
|
191
|
-
context.globalInstructions,
|
|
192
|
-
context.workspaceInstructions,
|
|
193
|
-
]
|
|
194
|
-
.filter(Boolean)
|
|
195
|
-
.join("\n\n");
|
|
196
|
-
if (combinedInstructions) {
|
|
197
|
-
builder.appendSystemPrompt(combinedInstructions);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
// Apply read-only restrictions if requested
|
|
201
|
-
if (context.permissionsMode === "read") {
|
|
202
|
-
builder.denyTools("Write", "Edit", "MultiEdit", "Bash", "KillBash", "NotebookEdit", "ExitPlanMode");
|
|
203
|
-
console_1.console.log("[ClaudeManager] Applied read-only mode tool restrictions");
|
|
204
|
-
}
|
|
205
|
-
// Set up process completion handler
|
|
206
|
-
builder.onProcessComplete(async (exitCode, error) => {
|
|
207
|
-
// Exit code 143 (SIGTERM) is expected when we stop a conversation
|
|
208
|
-
const isExpectedTermination = exitCode === 143 &&
|
|
209
|
-
(context.status === "stopped" || context.status === "stopping");
|
|
210
|
-
if ((error || exitCode !== 0) && !isExpectedTermination) {
|
|
211
|
-
// Log detailed error information
|
|
212
|
-
console_1.console.error(`[ClaudeManager] Claude process failed`, {
|
|
213
|
-
exitCode,
|
|
214
|
-
errorMessage: error?.message,
|
|
215
|
-
errorStack: error?.stack,
|
|
216
|
-
conversationId: context.conversationId,
|
|
217
|
-
agentSessionId: context.agentSessionId,
|
|
218
|
-
workspacePath,
|
|
219
|
-
model: context.model,
|
|
220
|
-
conversationStatus: context.status,
|
|
221
|
-
});
|
|
222
|
-
// Create a more detailed error message
|
|
223
|
-
const errorMessage = error?.message || `Process exited with code ${exitCode}`;
|
|
224
|
-
const errorDetails = {
|
|
225
|
-
exitCode,
|
|
226
|
-
errorStack: error?.stack,
|
|
227
|
-
workspacePath,
|
|
228
|
-
model: context.model,
|
|
229
|
-
sessionId: context.agentSessionId,
|
|
230
|
-
conversationId: context.conversationId,
|
|
231
|
-
conversationStatus: context.status,
|
|
232
|
-
timestamp: new Date().toISOString(),
|
|
233
|
-
};
|
|
234
|
-
await this.runner.notify("error.report", {
|
|
235
|
-
conversationId: context.conversationId,
|
|
236
|
-
conversationObjectType: context.conversationObjectType,
|
|
237
|
-
conversationObjectId: context.conversationObjectId,
|
|
238
|
-
agentSessionId: context.agentSessionId,
|
|
239
|
-
errorType: "process_exit",
|
|
240
|
-
message: errorMessage,
|
|
241
|
-
details: errorDetails,
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
else if (isExpectedTermination) {
|
|
245
|
-
console_1.console.log(`[ClaudeManager] Claude process terminated as expected (conversation.stop)`, {
|
|
246
|
-
exitCode,
|
|
247
|
-
conversationId: context.conversationId,
|
|
248
|
-
agentSessionId: context.agentSessionId,
|
|
249
|
-
conversationStatus: context.status,
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
// Notify orchestrator that conversation ended
|
|
253
|
-
await this.runner.notify("conversation.end", {
|
|
254
|
-
conversationId: context.conversationId,
|
|
255
|
-
conversationObjectType: context.conversationObjectType,
|
|
256
|
-
conversationObjectId: context.conversationObjectId,
|
|
257
|
-
agentSessionId: context.agentSessionId,
|
|
258
|
-
isError: exitCode !== 0,
|
|
259
|
-
errorMessage: error?.message,
|
|
260
|
-
});
|
|
261
|
-
// Clean up conversation from active conversations
|
|
262
|
-
console_1.console.log(`[ClaudeManager] Removing conversation from active map:`, {
|
|
263
|
-
conversationId: context.conversationId,
|
|
264
|
-
agentSessionId: context.agentSessionId,
|
|
265
|
-
mapSizeBefore: this.runner.activeConversations_.size,
|
|
266
|
-
});
|
|
267
|
-
this.runner.activeConversations_.delete(context.conversationId);
|
|
268
|
-
// Update status line
|
|
269
|
-
status_line_1.statusLineManager.updateActiveCount(this.runner.activeConversations_.size);
|
|
270
|
-
});
|
|
271
|
-
// Create conversation instance
|
|
272
|
-
const conversation = builder.asConversation();
|
|
273
|
-
// Store conversation instance in context for reuse
|
|
274
|
-
context.conversation = conversation;
|
|
275
|
-
// Set up session ID callback - this is where we get the real agentSessionId
|
|
276
|
-
conversation.onSessionId(async (agentSessionId) => {
|
|
277
|
-
if (!agentSessionId)
|
|
278
|
-
return;
|
|
279
|
-
// Check if this is a new session ID
|
|
280
|
-
const oldSessionId = context.agentSessionId;
|
|
281
|
-
if (oldSessionId !== agentSessionId) {
|
|
282
|
-
// Update context with new session ID
|
|
283
|
-
context.agentSessionId = agentSessionId;
|
|
284
|
-
context.status = "active";
|
|
285
|
-
// Note: We don't need to update the Map key since we're using conversation.id now
|
|
286
|
-
// Notify orchestrator of session change
|
|
287
|
-
await this.runner.notify("agentSessionId.changed", {
|
|
288
|
-
conversationId: context.conversationId,
|
|
289
|
-
conversationObjectType,
|
|
290
|
-
conversationObjectId,
|
|
291
|
-
oldAgentSessionId: oldSessionId,
|
|
292
|
-
newAgentSessionId: agentSessionId,
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
// Set up streaming message handler
|
|
297
|
-
const messageHandler = async (message, sessionId) => {
|
|
298
|
-
await this.handleStreamedMessage(context, message, sessionId);
|
|
299
|
-
};
|
|
300
|
-
conversation.stream(messageHandler);
|
|
301
|
-
// Note: Error handling is done via process completion handler
|
|
302
|
-
// The Claude SDK doesn't have an onError method on conversations
|
|
303
|
-
// Send initial messages
|
|
304
|
-
try {
|
|
305
|
-
for (const message of initialMessages) {
|
|
306
|
-
const initialText = this.normalizeToText(message.content);
|
|
307
|
-
conversation.send({
|
|
308
|
-
type: "text",
|
|
309
|
-
text: initialText,
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
console_1.console.log(`Started conversation for ${conversationObjectType} ${conversationObjectId} in workspace ${workspacePath}`);
|
|
313
|
-
// Return the conversation context directly
|
|
314
|
-
return context;
|
|
315
|
-
}
|
|
316
|
-
catch (error) {
|
|
317
|
-
// Handle startup errors
|
|
318
|
-
await this._handleConversationError(context, error);
|
|
319
|
-
throw error;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
async stopConversation(agentSessionId, context) {
|
|
323
|
-
if (context && context.conversation) {
|
|
324
|
-
context.status = "stopping";
|
|
325
|
-
try {
|
|
326
|
-
// Mark conversation as stopped BEFORE ending to prevent race conditions
|
|
327
|
-
context.status = "stopped";
|
|
328
|
-
// Properly end the conversation using the SDK
|
|
329
|
-
await context.conversation.end();
|
|
330
|
-
}
|
|
331
|
-
catch (error) {
|
|
332
|
-
console_1.console.error(`Error ending conversation ${agentSessionId}:`, error);
|
|
333
|
-
}
|
|
334
|
-
// Clean up conversation reference
|
|
335
|
-
delete context.conversation;
|
|
336
|
-
}
|
|
337
|
-
console_1.console.log(`Stopped conversation ${agentSessionId} for ${context.conversationObjectType} ${context.conversationObjectId}`);
|
|
338
|
-
}
|
|
339
|
-
async resumeConversation(conversationObjectType, conversationObjectId, agentSessionId, config, conversationData, resumeMessage) {
|
|
340
|
-
console_1.console.log(`[ClaudeManager] Resuming conversation ${agentSessionId}`);
|
|
341
|
-
// Resume is handled by starting a new conversation with the existing session ID
|
|
342
|
-
const context = await this.startConversation(conversationObjectType, conversationObjectId, { ...config, sessionId: agentSessionId }, [], // Don't send initial messages
|
|
343
|
-
conversationData);
|
|
344
|
-
// After starting the conversation with the sessionId, we need to send a message
|
|
345
|
-
// to actually trigger the Claude process to continue
|
|
346
|
-
if (context.conversation) {
|
|
347
|
-
try {
|
|
348
|
-
// Use the provided resume message or default to system instruction
|
|
349
|
-
const messageToSend = resumeMessage ||
|
|
350
|
-
"<system-instructions>Please continue</system-instructions>";
|
|
351
|
-
console_1.console.log(`[ClaudeManager] Sending resume message to conversation ${agentSessionId}`);
|
|
352
|
-
context.conversation.send({
|
|
353
|
-
type: "text",
|
|
354
|
-
text: messageToSend,
|
|
355
|
-
});
|
|
356
|
-
}
|
|
357
|
-
catch (error) {
|
|
358
|
-
console_1.console.error(`[ClaudeManager] Error sending resume message:`, error);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return context.agentSessionId;
|
|
362
|
-
}
|
|
363
|
-
async sendUserMessage(conversationId, content, config, conversationObjectType, conversationObjectId, conversation) {
|
|
364
|
-
console_1.console.log(`[ClaudeManager] sendUserMessage called with:`, {
|
|
365
|
-
conversationId,
|
|
366
|
-
conversationObjectType,
|
|
367
|
-
conversationObjectId,
|
|
368
|
-
hasConfig: !!config,
|
|
369
|
-
hasConversation: !!conversation,
|
|
370
|
-
activeConversations: this.runner.activeConversations_.size,
|
|
371
|
-
});
|
|
372
|
-
// Find by conversationId only
|
|
373
|
-
let context = this.runner.getConversationContext(conversationId);
|
|
374
|
-
console_1.console.log(`[ClaudeManager] Lookup by conversationId result:`, {
|
|
375
|
-
found: !!context,
|
|
376
|
-
conversationId: context?.conversationId,
|
|
377
|
-
agentSessionId: context?.agentSessionId,
|
|
378
|
-
});
|
|
379
|
-
if (!context && conversation) {
|
|
380
|
-
// Use provided conversation details
|
|
381
|
-
try {
|
|
382
|
-
const conversationDetails = conversation;
|
|
383
|
-
// For task conversations, fetch the task config to get repository information
|
|
384
|
-
let taskConfig = {};
|
|
385
|
-
if (conversationDetails.objectType === "Task" ||
|
|
386
|
-
conversationDetails.objectType === "task") {
|
|
387
|
-
try {
|
|
388
|
-
const taskConfigResponse = await this.runner.sendToOrchestrator({
|
|
389
|
-
jsonrpc: "2.0",
|
|
390
|
-
id: `task-config-${Date.now()}`,
|
|
391
|
-
method: "task.getConfig",
|
|
392
|
-
params: { taskId: conversationDetails.objectId },
|
|
393
|
-
});
|
|
394
|
-
if (taskConfigResponse?.result) {
|
|
395
|
-
taskConfig = taskConfigResponse.result;
|
|
396
|
-
console_1.console.log(`[ClaudeManager] Fetched task config with repository:`, {
|
|
397
|
-
hasRepository: !!taskConfigResponse.result.repository,
|
|
398
|
-
repositoryType: taskConfigResponse.result.repository?.type,
|
|
399
|
-
repositoryPath: taskConfigResponse.result.repository?.localPath,
|
|
400
|
-
hasAccessKey: !!taskConfigResponse.result.accessKey,
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
catch (error) {
|
|
405
|
-
console_1.console.error(`[ClaudeManager] Failed to fetch task config:`, error);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
// Bind to existing session if present; do not send a resume message here
|
|
409
|
-
const startConfig = {
|
|
410
|
-
anthropicApiKey: config?.anthropicApiKey || process.env["ANTHROPIC_API_KEY"] || "",
|
|
411
|
-
model: conversationDetails.model,
|
|
412
|
-
systemPrompt: config?.systemPrompt,
|
|
413
|
-
permissionsMode: conversationDetails.permissionsMode,
|
|
414
|
-
accessKey: taskConfig?.accessKey || config?.accessKey || "",
|
|
415
|
-
workspaceId: conversationDetails.workspaceId,
|
|
416
|
-
...taskConfig,
|
|
417
|
-
...config,
|
|
418
|
-
...(conversationDetails.agentSessionId
|
|
419
|
-
? { sessionId: conversationDetails.agentSessionId }
|
|
420
|
-
: {}),
|
|
421
|
-
};
|
|
422
|
-
// Start the SDK conversation (no initial messages); this attaches to existing session when provided
|
|
423
|
-
await this.startConversation(conversationDetails.objectType, conversationDetails.objectId, startConfig, [], conversationDetails);
|
|
424
|
-
// Refresh context after start/resume
|
|
425
|
-
context = this.runner.getConversationContext(conversationId);
|
|
426
|
-
}
|
|
427
|
-
catch (error) {
|
|
428
|
-
console_1.console.error(`Failed to fetch conversation ${conversationId}:`, error);
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
if (!context) {
|
|
432
|
-
throw new Error(`No active or fetchable conversation found for ${conversationId}`);
|
|
433
|
-
}
|
|
434
|
-
try {
|
|
435
|
-
// Send immediately when a conversation instance exists; no need to wait for "active"
|
|
436
|
-
if (!context.conversation) {
|
|
437
|
-
throw new Error(`No conversation instance found for conversation ${context.conversationId}`);
|
|
438
|
-
}
|
|
439
|
-
// Guard: Don't send messages if conversation is stopped or stopping
|
|
440
|
-
const conversationStatus = context.status;
|
|
441
|
-
if (conversationStatus === "stopped" ||
|
|
442
|
-
conversationStatus === "stopping") {
|
|
443
|
-
console_1.console.warn(`Attempted to send message to stopped/stopping conversation ${context.conversationId}`, {
|
|
444
|
-
status: context.status,
|
|
445
|
-
conversationObjectType: context.conversationObjectType,
|
|
446
|
-
conversationObjectId: context.conversationObjectId,
|
|
447
|
-
});
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
// Normalize arbitrary content into a plain string for the CLI
|
|
451
|
-
const normalizedText = this.normalizeToText(content);
|
|
452
|
-
if (process.env["DEBUG"] === "true") {
|
|
453
|
-
console_1.console.log("[ClaudeManager] Normalized follow-up content", {
|
|
454
|
-
originalType: typeof content,
|
|
455
|
-
isArray: Array.isArray(content) || undefined,
|
|
456
|
-
normalizedPreview: typeof normalizedText === "string"
|
|
457
|
-
? normalizedText.slice(0, 160)
|
|
458
|
-
: String(normalizedText).slice(0, 160),
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
console_1.console.log("[ClaudeManager] Normalized follow-up content", typeof normalizedText, normalizedText);
|
|
462
|
-
context.conversation.send({
|
|
463
|
-
type: "text",
|
|
464
|
-
text: normalizedText,
|
|
465
|
-
});
|
|
466
|
-
// Update last activity timestamp
|
|
467
|
-
context.lastActivityAt = new Date();
|
|
468
|
-
console_1.console.log(`Sent user message to conversation ${context.conversationId} (agentSessionId: ${context.agentSessionId}, status: ${context.status})`);
|
|
469
|
-
}
|
|
470
|
-
catch (error) {
|
|
471
|
-
// Handle errors properly
|
|
472
|
-
await this._handleConversationError(context, error);
|
|
473
|
-
throw error; // Re-throw to maintain the same behavior
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
async fetchGithubTokens(workspaceId) {
|
|
477
|
-
try {
|
|
478
|
-
const response = await fetch(`${this.runner.config_.orchestratorUrl}/api/runner/tokens?workspaceId=${workspaceId}`, {
|
|
479
|
-
method: "GET",
|
|
480
|
-
headers: {
|
|
481
|
-
Authorization: `Bearer ${process.env["CLAUDETTE_RUNNER_TOKEN"]}`,
|
|
482
|
-
},
|
|
483
|
-
});
|
|
484
|
-
if (!response.ok) {
|
|
485
|
-
console_1.console.error(`Failed to fetch GitHub tokens: ${response.status}`);
|
|
486
|
-
return undefined;
|
|
487
|
-
}
|
|
488
|
-
const data = (await response.json());
|
|
489
|
-
return data.githubToken;
|
|
490
|
-
}
|
|
491
|
-
catch (error) {
|
|
492
|
-
console_1.console.error("Error fetching GitHub tokens:", error);
|
|
493
|
-
return undefined;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
async _handleConversationError(context, error) {
|
|
497
|
-
const errorType = this.classifyError(error);
|
|
498
|
-
// Notify orchestrator
|
|
499
|
-
await this.runner.notify("error.report", {
|
|
500
|
-
conversationId: context.conversationId,
|
|
501
|
-
conversationObjectType: context.conversationObjectType,
|
|
502
|
-
conversationObjectId: context.conversationObjectId,
|
|
503
|
-
agentSessionId: context.agentSessionId,
|
|
504
|
-
errorType,
|
|
505
|
-
message: error.message,
|
|
506
|
-
details: {
|
|
507
|
-
stack: error.stack,
|
|
508
|
-
timestamp: new Date(),
|
|
509
|
-
},
|
|
510
|
-
});
|
|
511
|
-
// Conversation continues on error - no automatic cleanup
|
|
512
|
-
console_1.console.error(`Conversation error for ${context.conversationObjectType} ${context.conversationObjectId}:`, error);
|
|
513
|
-
}
|
|
514
|
-
classifyError(error) {
|
|
515
|
-
if (error.message.includes("process exited")) {
|
|
516
|
-
return "process_exit";
|
|
517
|
-
}
|
|
518
|
-
else if (error.message.includes("model")) {
|
|
519
|
-
return "model_error";
|
|
520
|
-
}
|
|
521
|
-
else if (error.message.includes("tool")) {
|
|
522
|
-
return "tool_error";
|
|
523
|
-
}
|
|
524
|
-
else if (error.message.includes("permission")) {
|
|
525
|
-
return "permission_error";
|
|
526
|
-
}
|
|
527
|
-
else if (error.message.includes("timeout")) {
|
|
528
|
-
return "timeout_error";
|
|
529
|
-
}
|
|
530
|
-
return "unknown_error";
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Normalize arbitrary content shapes into a plain string for the CLI
|
|
534
|
-
*/
|
|
535
|
-
normalizeToText(value) {
|
|
536
|
-
if (typeof value === "string")
|
|
537
|
-
return value;
|
|
538
|
-
if (value == null)
|
|
539
|
-
return "";
|
|
540
|
-
if (typeof value === "object") {
|
|
541
|
-
// Common simple shapes
|
|
542
|
-
if (typeof value.text === "string")
|
|
543
|
-
return value.text;
|
|
544
|
-
if (typeof value.text === "object" &&
|
|
545
|
-
value.text &&
|
|
546
|
-
typeof value.text.text === "string")
|
|
547
|
-
return value.text.text;
|
|
548
|
-
if (typeof value.content === "string")
|
|
549
|
-
return value.content;
|
|
550
|
-
// Array of blocks: [{ type: 'text', text: '...' }, ...]
|
|
551
|
-
if (Array.isArray(value)) {
|
|
552
|
-
const texts = value
|
|
553
|
-
.map((b) => b && b.type === "text" && typeof b.text === "string" ? b.text : null)
|
|
554
|
-
.filter((t) => !!t);
|
|
555
|
-
if (texts.length)
|
|
556
|
-
return texts.join(" ");
|
|
557
|
-
}
|
|
558
|
-
// Nested message shapes
|
|
559
|
-
if (typeof value.message === "object" &&
|
|
560
|
-
value.message &&
|
|
561
|
-
typeof value.message.text === "string") {
|
|
562
|
-
return value.message.text;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
try {
|
|
566
|
-
return JSON.stringify(value);
|
|
567
|
-
}
|
|
568
|
-
catch {
|
|
569
|
-
return String(value);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
async handleStreamedMessage(context, message, sessionId) {
|
|
573
|
-
// Guard: Don't process messages if conversation is stopped or stopping
|
|
574
|
-
const status = context.status;
|
|
575
|
-
if (status === "stopped" || status === "stopping") {
|
|
576
|
-
console_1.console.log(`Ignoring message for stopped/stopping conversation ${context.conversationId}`, {
|
|
577
|
-
status: context.status,
|
|
578
|
-
messageType: message.type,
|
|
579
|
-
});
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
try {
|
|
583
|
-
console_1.console.log(`Received streamed message for ${context.conversationObjectType} ${context.conversationObjectId}`, {
|
|
584
|
-
type: message.type,
|
|
585
|
-
});
|
|
586
|
-
// Build structured content based on message type
|
|
587
|
-
let messageType = message.type;
|
|
588
|
-
let subtype;
|
|
589
|
-
let structuredContent = {};
|
|
590
|
-
let isError = false;
|
|
591
|
-
// Extract content based on message type
|
|
592
|
-
switch (message.type) {
|
|
593
|
-
case "assistant": {
|
|
594
|
-
const assistantMsg = message;
|
|
595
|
-
if (assistantMsg.content) {
|
|
596
|
-
// Extract text content from content blocks
|
|
597
|
-
const textBlocks = assistantMsg.content.filter((b) => b.type === "text");
|
|
598
|
-
const textContent = textBlocks.map((b) => b.text).join("");
|
|
599
|
-
// Extract tool calls
|
|
600
|
-
const toolUseBlocks = assistantMsg.content.filter((b) => b.type === "tool_use");
|
|
601
|
-
const toolCalls = toolUseBlocks.length > 0
|
|
602
|
-
? toolUseBlocks.map((b) => ({
|
|
603
|
-
id: b.id,
|
|
604
|
-
name: b.name,
|
|
605
|
-
arguments: b.input,
|
|
606
|
-
}))
|
|
607
|
-
: undefined;
|
|
608
|
-
structuredContent = {
|
|
609
|
-
text: textContent,
|
|
610
|
-
toolCalls,
|
|
611
|
-
timestamp: new Date().toISOString(),
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
break;
|
|
615
|
-
}
|
|
616
|
-
case "thinking": {
|
|
617
|
-
// Map thinking to assistant with subtype
|
|
618
|
-
messageType = "assistant";
|
|
619
|
-
subtype = "thinking";
|
|
620
|
-
const thinkingMsg = message;
|
|
621
|
-
structuredContent = {
|
|
622
|
-
text: thinkingMsg.content || "",
|
|
623
|
-
timestamp: new Date().toISOString(),
|
|
624
|
-
};
|
|
625
|
-
break;
|
|
626
|
-
}
|
|
627
|
-
case "tool_use": {
|
|
628
|
-
// Tool call request - map to assistant
|
|
629
|
-
messageType = "assistant";
|
|
630
|
-
subtype = "tool_use";
|
|
631
|
-
const toolUseMsg = message;
|
|
632
|
-
structuredContent = {
|
|
633
|
-
toolCalls: [
|
|
634
|
-
{
|
|
635
|
-
id: toolUseMsg.id,
|
|
636
|
-
name: toolUseMsg.name,
|
|
637
|
-
arguments: toolUseMsg.input,
|
|
638
|
-
},
|
|
639
|
-
],
|
|
640
|
-
timestamp: new Date().toISOString(),
|
|
641
|
-
};
|
|
642
|
-
break;
|
|
643
|
-
}
|
|
644
|
-
case "tool_result": {
|
|
645
|
-
// Tool execution result - map to tool_result
|
|
646
|
-
messageType = "tool_result";
|
|
647
|
-
subtype = "tool_result";
|
|
648
|
-
const toolResultMsg = message;
|
|
649
|
-
structuredContent = {
|
|
650
|
-
toolResults: [
|
|
651
|
-
{
|
|
652
|
-
toolCallId: toolResultMsg.tool_use_id,
|
|
653
|
-
result: toolResultMsg.content,
|
|
654
|
-
isError: toolResultMsg.is_error || false,
|
|
655
|
-
},
|
|
656
|
-
],
|
|
657
|
-
timestamp: new Date().toISOString(),
|
|
658
|
-
};
|
|
659
|
-
break;
|
|
660
|
-
}
|
|
661
|
-
case "result": {
|
|
662
|
-
const resultMsg = message;
|
|
663
|
-
structuredContent = {
|
|
664
|
-
text: resultMsg.content || resultMsg.result || "",
|
|
665
|
-
timestamp: new Date().toISOString(),
|
|
666
|
-
};
|
|
667
|
-
break;
|
|
668
|
-
}
|
|
669
|
-
case "user": {
|
|
670
|
-
const userMsg = message;
|
|
671
|
-
// Check if content is already an array (e.g., tool results)
|
|
672
|
-
if (Array.isArray(userMsg.content)) {
|
|
673
|
-
// Check if this is a tool result by examining content
|
|
674
|
-
const hasToolResult = userMsg.content.some((item) => item && typeof item === "object" && item.type === "tool_result");
|
|
675
|
-
if (hasToolResult) {
|
|
676
|
-
// This is a tool result - change message type
|
|
677
|
-
messageType = "tool_result";
|
|
678
|
-
subtype = "tool_result";
|
|
679
|
-
}
|
|
680
|
-
// Pass the array directly as structured content
|
|
681
|
-
structuredContent = userMsg.content;
|
|
682
|
-
}
|
|
683
|
-
else if (typeof userMsg.content === "string") {
|
|
684
|
-
// String content - wrap in text object
|
|
685
|
-
structuredContent = {
|
|
686
|
-
text: userMsg.content,
|
|
687
|
-
timestamp: new Date().toISOString(),
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
else {
|
|
691
|
-
// Other object content - preserve as is
|
|
692
|
-
structuredContent = userMsg.content || {};
|
|
693
|
-
}
|
|
694
|
-
break;
|
|
695
|
-
}
|
|
696
|
-
case "system": {
|
|
697
|
-
const systemMsg = message;
|
|
698
|
-
structuredContent = {
|
|
699
|
-
text: systemMsg.content || "",
|
|
700
|
-
timestamp: new Date().toISOString(),
|
|
701
|
-
};
|
|
702
|
-
break;
|
|
703
|
-
}
|
|
704
|
-
case "error": {
|
|
705
|
-
const errorMsg = message;
|
|
706
|
-
messageType = "system";
|
|
707
|
-
subtype = "error";
|
|
708
|
-
isError = true;
|
|
709
|
-
structuredContent = {
|
|
710
|
-
text: errorMsg.message || errorMsg.error || "Unknown error",
|
|
711
|
-
errorType: errorMsg.error_type || "unknown",
|
|
712
|
-
errorDetails: {
|
|
713
|
-
stack: errorMsg.stack,
|
|
714
|
-
code: errorMsg.code,
|
|
715
|
-
context: errorMsg,
|
|
716
|
-
},
|
|
717
|
-
timestamp: new Date().toISOString(),
|
|
718
|
-
};
|
|
719
|
-
break;
|
|
720
|
-
}
|
|
721
|
-
default: {
|
|
722
|
-
// Unknown message type - log and send as assistant
|
|
723
|
-
const unknownMsg = message;
|
|
724
|
-
console_1.console.warn(`Unknown message type: ${unknownMsg.type}`, message);
|
|
725
|
-
messageType = "assistant";
|
|
726
|
-
structuredContent = {
|
|
727
|
-
text: JSON.stringify(message),
|
|
728
|
-
timestamp: new Date().toISOString(),
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
// Generate a unique message ID
|
|
733
|
-
const messageId = `${context.agentSessionId}-${Date.now()}-${Math.random()
|
|
734
|
-
.toString(36)
|
|
735
|
-
.substr(2, 9)}`;
|
|
736
|
-
// Send agent message to orchestrator with structured content
|
|
737
|
-
// Skip if conversation is stopping/stopped to avoid race conditions
|
|
738
|
-
const currentStatus = context.status;
|
|
739
|
-
if (currentStatus !== "stopped" && currentStatus !== "stopping") {
|
|
740
|
-
await this.runner.notify("message.agent", {
|
|
741
|
-
conversationId: context.conversationId,
|
|
742
|
-
conversationObjectType: context.conversationObjectType,
|
|
743
|
-
conversationObjectId: context.conversationObjectId,
|
|
744
|
-
agentSessionId: context.agentSessionId,
|
|
745
|
-
type: messageType,
|
|
746
|
-
subtype,
|
|
747
|
-
content: Array.isArray(structuredContent)
|
|
748
|
-
? structuredContent
|
|
749
|
-
: [structuredContent],
|
|
750
|
-
messageId,
|
|
751
|
-
isError,
|
|
752
|
-
});
|
|
753
|
-
}
|
|
754
|
-
// Tool calls are now handled directly by Claude through the MCP server
|
|
755
|
-
// We just log that we saw them but don't intercept or process them
|
|
756
|
-
if (structuredContent.toolCalls &&
|
|
757
|
-
structuredContent.toolCalls.length > 0) {
|
|
758
|
-
console_1.console.log(`Claude is making ${structuredContent.toolCalls.length} tool call(s) via MCP`, {
|
|
759
|
-
conversationObjectId: context.conversationObjectId,
|
|
760
|
-
toolNames: structuredContent.toolCalls.map((tc) => tc.name),
|
|
761
|
-
});
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
catch (error) {
|
|
765
|
-
// Check if this is a transport error due to stopped conversation
|
|
766
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
767
|
-
const isTransportError = errorMessage.includes("Cannot read properties of undefined") ||
|
|
768
|
-
errorMessage.includes("stdout") ||
|
|
769
|
-
errorMessage.includes("transport");
|
|
770
|
-
const statusCheck = context.status;
|
|
771
|
-
if (isTransportError &&
|
|
772
|
-
(statusCheck === "stopped" || statusCheck === "stopping")) {
|
|
773
|
-
// This is expected when conversation is stopped - just log it
|
|
774
|
-
console_1.console.log(`Transport error for stopped/stopping conversation ${context.conversationId} (expected):`, errorMessage);
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
console_1.console.error(`Error handling streamed message for ${context.conversationObjectType} ${context.conversationObjectId}:`, error);
|
|
778
|
-
await this._handleConversationError(context, error);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
exports.ClaudeManager = ClaudeManager;
|
|
783
|
-
//# sourceMappingURL=claude-manager.js.map
|