cyrus-edge-worker 0.0.19 → 0.0.20
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/AgentSessionManager.d.ts +3 -3
- package/dist/AgentSessionManager.d.ts.map +1 -1
- package/dist/AgentSessionManager.js +111 -102
- package/dist/AgentSessionManager.js.map +1 -1
- package/dist/EdgeWorker.d.ts +3 -3
- package/dist/EdgeWorker.d.ts.map +1 -1
- package/dist/EdgeWorker.js +199 -186
- package/dist/EdgeWorker.js.map +1 -1
- package/dist/SharedApplicationServer.d.ts +1 -3
- package/dist/SharedApplicationServer.d.ts.map +1 -1
- package/dist/SharedApplicationServer.js +63 -60
- package/dist/SharedApplicationServer.js.map +1 -1
- package/dist/SharedWebhookServer.d.ts.map +1 -1
- package/dist/SharedWebhookServer.js +32 -32
- package/dist/SharedWebhookServer.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +12 -12
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LinearClient } from
|
|
2
|
-
import type {
|
|
3
|
-
import type { CyrusAgentSession, CyrusAgentSessionEntry, IssueMinimal, SerializedCyrusAgentSession, SerializedCyrusAgentSessionEntry, Workspace } from
|
|
1
|
+
import { type LinearClient } from "@linear/sdk";
|
|
2
|
+
import type { ClaudeRunner, SDKMessage, SDKResultMessage, SDKSystemMessage } from "cyrus-claude-runner";
|
|
3
|
+
import type { CyrusAgentSession, CyrusAgentSessionEntry, IssueMinimal, SerializedCyrusAgentSession, SerializedCyrusAgentSessionEntry, Workspace } from "cyrus-core";
|
|
4
4
|
/**
|
|
5
5
|
* Manages Linear Agent Sessions integration with Claude Code SDK
|
|
6
6
|
* Transforms Claude streaming messages into Agent Session format
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentSessionManager.d.ts","sourceRoot":"","sources":["../src/AgentSessionManager.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"AgentSessionManager.d.ts","sourceRoot":"","sources":["../src/AgentSessionManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LinearDocument } from
|
|
1
|
+
import { LinearDocument } from "@linear/sdk";
|
|
2
2
|
/**
|
|
3
3
|
* Manages Linear Agent Sessions integration with Claude Code SDK
|
|
4
4
|
* Transforms Claude streaming messages into Agent Session format
|
|
@@ -29,7 +29,7 @@ export class AgentSessionManager {
|
|
|
29
29
|
updatedAt: Date.now(),
|
|
30
30
|
issueId,
|
|
31
31
|
issue: issueMinimal,
|
|
32
|
-
workspace: workspace
|
|
32
|
+
workspace: workspace,
|
|
33
33
|
};
|
|
34
34
|
// Store locally
|
|
35
35
|
this.sessions.set(linearAgentActivitySessionId, agentSession);
|
|
@@ -59,9 +59,9 @@ export class AgentSessionManager {
|
|
|
59
59
|
*/
|
|
60
60
|
async createSessionEntry(_linearAgentActivitySessionId, sdkMessage) {
|
|
61
61
|
// Extract tool info if this is an assistant message
|
|
62
|
-
const toolInfo = sdkMessage.type ===
|
|
62
|
+
const toolInfo = sdkMessage.type === "assistant" ? this.extractToolInfo(sdkMessage) : null;
|
|
63
63
|
// Extract tool_use_id if this is a user message with tool_result
|
|
64
|
-
const toolResultId = sdkMessage.type ===
|
|
64
|
+
const toolResultId = sdkMessage.type === "user" ? this.extractToolResultId(sdkMessage) : null;
|
|
65
65
|
const sessionEntry = {
|
|
66
66
|
claudeSessionId: sdkMessage.session_id,
|
|
67
67
|
type: sdkMessage.type,
|
|
@@ -72,12 +72,12 @@ export class AgentSessionManager {
|
|
|
72
72
|
...(toolInfo && {
|
|
73
73
|
toolUseId: toolInfo.id,
|
|
74
74
|
toolName: toolInfo.name,
|
|
75
|
-
toolInput: toolInfo.input
|
|
75
|
+
toolInput: toolInfo.input,
|
|
76
76
|
}),
|
|
77
77
|
...(toolResultId && {
|
|
78
|
-
toolUseId: toolResultId
|
|
79
|
-
})
|
|
80
|
-
}
|
|
78
|
+
toolUseId: toolResultId,
|
|
79
|
+
}),
|
|
80
|
+
},
|
|
81
81
|
};
|
|
82
82
|
// DON'T store locally yet - wait until we actually post to Linear
|
|
83
83
|
return sessionEntry;
|
|
@@ -93,27 +93,27 @@ export class AgentSessionManager {
|
|
|
93
93
|
}
|
|
94
94
|
const todos = data.todos;
|
|
95
95
|
// Keep original order but add status indicators
|
|
96
|
-
let formatted =
|
|
96
|
+
let formatted = "\n";
|
|
97
97
|
todos.forEach((todo, index) => {
|
|
98
|
-
let statusEmoji =
|
|
99
|
-
if (todo.status ===
|
|
100
|
-
statusEmoji =
|
|
98
|
+
let statusEmoji = "";
|
|
99
|
+
if (todo.status === "completed") {
|
|
100
|
+
statusEmoji = "✅ ";
|
|
101
101
|
}
|
|
102
|
-
else if (todo.status ===
|
|
103
|
-
statusEmoji =
|
|
102
|
+
else if (todo.status === "in_progress") {
|
|
103
|
+
statusEmoji = "🔄 ";
|
|
104
104
|
}
|
|
105
|
-
else if (todo.status ===
|
|
106
|
-
statusEmoji =
|
|
105
|
+
else if (todo.status === "pending") {
|
|
106
|
+
statusEmoji = "⏳ ";
|
|
107
107
|
}
|
|
108
108
|
formatted += `${statusEmoji}${todo.content}`;
|
|
109
109
|
if (index < todos.length - 1) {
|
|
110
|
-
formatted +=
|
|
110
|
+
formatted += "\n";
|
|
111
111
|
}
|
|
112
112
|
});
|
|
113
113
|
return formatted;
|
|
114
114
|
}
|
|
115
115
|
catch (error) {
|
|
116
|
-
console.error(
|
|
116
|
+
console.error("[AgentSessionManager] Failed to format TodoWrite parameter:", error);
|
|
117
117
|
return jsonContent;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
@@ -128,16 +128,16 @@ export class AgentSessionManager {
|
|
|
128
128
|
}
|
|
129
129
|
// Clear any active Task when session completes
|
|
130
130
|
this.activeTasksBySession.delete(linearAgentActivitySessionId);
|
|
131
|
-
const status = resultMessage.subtype ===
|
|
131
|
+
const status = resultMessage.subtype === "success"
|
|
132
132
|
? LinearDocument.AgentSessionStatus.Complete
|
|
133
133
|
: LinearDocument.AgentSessionStatus.Error;
|
|
134
134
|
// Update session status and metadata
|
|
135
135
|
await this.updateSessionStatus(linearAgentActivitySessionId, status, {
|
|
136
136
|
totalCostUsd: resultMessage.total_cost_usd,
|
|
137
|
-
usage: resultMessage.usage
|
|
137
|
+
usage: resultMessage.usage,
|
|
138
138
|
});
|
|
139
139
|
// Add result entry if present
|
|
140
|
-
if (
|
|
140
|
+
if ("result" in resultMessage && resultMessage.result) {
|
|
141
141
|
await this.addResultEntry(linearAgentActivitySessionId, resultMessage);
|
|
142
142
|
}
|
|
143
143
|
}
|
|
@@ -147,8 +147,8 @@ export class AgentSessionManager {
|
|
|
147
147
|
async handleClaudeMessage(linearAgentActivitySessionId, message) {
|
|
148
148
|
try {
|
|
149
149
|
switch (message.type) {
|
|
150
|
-
case
|
|
151
|
-
if (message.subtype ===
|
|
150
|
+
case "system":
|
|
151
|
+
if (message.subtype === "init") {
|
|
152
152
|
this.updateAgentSessionWithClaudeSessionId(linearAgentActivitySessionId, message);
|
|
153
153
|
// Post model notification thought
|
|
154
154
|
const systemMessage = message;
|
|
@@ -157,15 +157,17 @@ export class AgentSessionManager {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
break;
|
|
160
|
-
case
|
|
160
|
+
case "user": {
|
|
161
161
|
const userEntry = await this.createSessionEntry(linearAgentActivitySessionId, message);
|
|
162
162
|
await this.syncEntryToLinear(userEntry, linearAgentActivitySessionId);
|
|
163
163
|
break;
|
|
164
|
-
|
|
164
|
+
}
|
|
165
|
+
case "assistant": {
|
|
165
166
|
const assistantEntry = await this.createSessionEntry(linearAgentActivitySessionId, message);
|
|
166
167
|
await this.syncEntryToLinear(assistantEntry, linearAgentActivitySessionId);
|
|
167
168
|
break;
|
|
168
|
-
|
|
169
|
+
}
|
|
170
|
+
case "result":
|
|
169
171
|
await this.completeSession(linearAgentActivitySessionId, message);
|
|
170
172
|
break;
|
|
171
173
|
default:
|
|
@@ -198,12 +200,12 @@ export class AgentSessionManager {
|
|
|
198
200
|
async addResultEntry(linearAgentActivitySessionId, resultMessage) {
|
|
199
201
|
const resultEntry = {
|
|
200
202
|
claudeSessionId: resultMessage.session_id,
|
|
201
|
-
type:
|
|
202
|
-
content:
|
|
203
|
+
type: "result",
|
|
204
|
+
content: "result" in resultMessage ? resultMessage.result : "",
|
|
203
205
|
metadata: {
|
|
204
206
|
timestamp: Date.now(),
|
|
205
207
|
durationMs: resultMessage.duration_ms,
|
|
206
|
-
isError: resultMessage.is_error
|
|
208
|
+
isError: resultMessage.is_error,
|
|
207
209
|
},
|
|
208
210
|
};
|
|
209
211
|
// DON'T store locally - syncEntryToLinear will do it
|
|
@@ -214,38 +216,38 @@ export class AgentSessionManager {
|
|
|
214
216
|
* Extract content from Claude message
|
|
215
217
|
*/
|
|
216
218
|
extractContent(sdkMessage) {
|
|
217
|
-
const message = sdkMessage.type ===
|
|
219
|
+
const message = sdkMessage.type === "user"
|
|
218
220
|
? sdkMessage.message
|
|
219
221
|
: sdkMessage.message;
|
|
220
|
-
if (typeof message.content ===
|
|
222
|
+
if (typeof message.content === "string") {
|
|
221
223
|
return message.content;
|
|
222
224
|
}
|
|
223
225
|
if (Array.isArray(message.content)) {
|
|
224
226
|
return message.content
|
|
225
227
|
.map((block) => {
|
|
226
|
-
if (block.type ===
|
|
228
|
+
if (block.type === "text") {
|
|
227
229
|
return block.text;
|
|
228
230
|
}
|
|
229
|
-
else if (block.type ===
|
|
231
|
+
else if (block.type === "tool_use") {
|
|
230
232
|
// For tool use blocks, return the input as JSON string
|
|
231
233
|
return JSON.stringify(block.input, null, 2);
|
|
232
234
|
}
|
|
233
|
-
else if (block.type ===
|
|
235
|
+
else if (block.type === "tool_result") {
|
|
234
236
|
// For tool_result blocks, extract just the text content
|
|
235
237
|
if (Array.isArray(block.content)) {
|
|
236
238
|
return block.content
|
|
237
|
-
.filter((contentBlock) => contentBlock.type ===
|
|
239
|
+
.filter((contentBlock) => contentBlock.type === "text")
|
|
238
240
|
.map((contentBlock) => contentBlock.text)
|
|
239
|
-
.join(
|
|
241
|
+
.join("\n");
|
|
240
242
|
}
|
|
241
|
-
return
|
|
243
|
+
return "";
|
|
242
244
|
}
|
|
243
|
-
return
|
|
245
|
+
return "";
|
|
244
246
|
})
|
|
245
247
|
.filter(Boolean)
|
|
246
|
-
.join(
|
|
248
|
+
.join("\n");
|
|
247
249
|
}
|
|
248
|
-
return
|
|
250
|
+
return "";
|
|
249
251
|
}
|
|
250
252
|
/**
|
|
251
253
|
* Extract tool information from Claude assistant message
|
|
@@ -253,12 +255,15 @@ export class AgentSessionManager {
|
|
|
253
255
|
extractToolInfo(sdkMessage) {
|
|
254
256
|
const message = sdkMessage.message;
|
|
255
257
|
if (Array.isArray(message.content)) {
|
|
256
|
-
const toolUse = message.content.find((block) => block.type ===
|
|
257
|
-
if (toolUse &&
|
|
258
|
+
const toolUse = message.content.find((block) => block.type === "tool_use");
|
|
259
|
+
if (toolUse &&
|
|
260
|
+
"id" in toolUse &&
|
|
261
|
+
"name" in toolUse &&
|
|
262
|
+
"input" in toolUse) {
|
|
258
263
|
return {
|
|
259
264
|
id: toolUse.id,
|
|
260
265
|
name: toolUse.name,
|
|
261
|
-
input: toolUse.input
|
|
266
|
+
input: toolUse.input,
|
|
262
267
|
};
|
|
263
268
|
}
|
|
264
269
|
}
|
|
@@ -270,8 +275,8 @@ export class AgentSessionManager {
|
|
|
270
275
|
extractToolResultId(sdkMessage) {
|
|
271
276
|
const message = sdkMessage.message;
|
|
272
277
|
if (Array.isArray(message.content)) {
|
|
273
|
-
const toolResult = message.content.find((block) => block.type ===
|
|
274
|
-
if (toolResult &&
|
|
278
|
+
const toolResult = message.content.find((block) => block.type === "tool_result");
|
|
279
|
+
if (toolResult && "tool_use_id" in toolResult) {
|
|
275
280
|
return toolResult.tool_use_id;
|
|
276
281
|
}
|
|
277
282
|
}
|
|
@@ -294,12 +299,12 @@ export class AgentSessionManager {
|
|
|
294
299
|
// Build activity content based on entry type
|
|
295
300
|
let content;
|
|
296
301
|
switch (entry.type) {
|
|
297
|
-
case
|
|
302
|
+
case "user": {
|
|
298
303
|
const activeTaskId = this.activeTasksBySession.get(linearAgentActivitySessionId);
|
|
299
304
|
if (activeTaskId && activeTaskId === entry.metadata?.toolUseId) {
|
|
300
305
|
content = {
|
|
301
|
-
type:
|
|
302
|
-
body: `✅ Task Completed\n\n\n\n${entry.content}\n\n---\n\n
|
|
306
|
+
type: "thought",
|
|
307
|
+
body: `✅ Task Completed\n\n\n\n${entry.content}\n\n---\n\n`,
|
|
303
308
|
};
|
|
304
309
|
this.activeTasksBySession.delete(linearAgentActivitySessionId);
|
|
305
310
|
}
|
|
@@ -309,28 +314,29 @@ export class AgentSessionManager {
|
|
|
309
314
|
return;
|
|
310
315
|
}
|
|
311
316
|
break;
|
|
312
|
-
|
|
317
|
+
}
|
|
318
|
+
case "assistant":
|
|
313
319
|
// Assistant messages can be thoughts or responses
|
|
314
320
|
if (entry.metadata?.toolUseId) {
|
|
315
|
-
const toolName = entry.metadata.toolName ||
|
|
321
|
+
const toolName = entry.metadata.toolName || "Tool";
|
|
316
322
|
// Special handling for TodoWrite tool - treat as thought instead of action
|
|
317
|
-
if (toolName ===
|
|
323
|
+
if (toolName === "TodoWrite") {
|
|
318
324
|
const formattedTodos = this.formatTodoWriteParameter(entry.content);
|
|
319
325
|
content = {
|
|
320
|
-
type:
|
|
321
|
-
body: formattedTodos
|
|
326
|
+
type: "thought",
|
|
327
|
+
body: formattedTodos,
|
|
322
328
|
};
|
|
323
329
|
}
|
|
324
|
-
else if (toolName ===
|
|
330
|
+
else if (toolName === "Task") {
|
|
325
331
|
// Special handling for Task tool - add start marker and track active task
|
|
326
|
-
|
|
327
|
-
|
|
332
|
+
const parameter = entry.content;
|
|
333
|
+
const displayName = toolName;
|
|
328
334
|
// Track this as the active Task for this session
|
|
329
335
|
if (entry.metadata?.toolUseId) {
|
|
330
336
|
this.activeTasksBySession.set(linearAgentActivitySessionId, entry.metadata.toolUseId);
|
|
331
337
|
}
|
|
332
338
|
content = {
|
|
333
|
-
type:
|
|
339
|
+
type: "action",
|
|
334
340
|
action: displayName,
|
|
335
341
|
parameter: parameter,
|
|
336
342
|
// result will be added later when we get tool result
|
|
@@ -338,7 +344,7 @@ export class AgentSessionManager {
|
|
|
338
344
|
}
|
|
339
345
|
else {
|
|
340
346
|
// Other tools - check if they're within an active Task
|
|
341
|
-
|
|
347
|
+
const parameter = entry.content;
|
|
342
348
|
let displayName = toolName;
|
|
343
349
|
if (entry.metadata?.parentToolUseId) {
|
|
344
350
|
const activeTaskId = this.activeTasksBySession.get(linearAgentActivitySessionId);
|
|
@@ -347,7 +353,7 @@ export class AgentSessionManager {
|
|
|
347
353
|
}
|
|
348
354
|
}
|
|
349
355
|
content = {
|
|
350
|
-
type:
|
|
356
|
+
type: "action",
|
|
351
357
|
action: displayName,
|
|
352
358
|
parameter: parameter,
|
|
353
359
|
// result will be added later when we get tool result
|
|
@@ -357,50 +363,52 @@ export class AgentSessionManager {
|
|
|
357
363
|
else {
|
|
358
364
|
// Regular assistant message - create a thought
|
|
359
365
|
// Check if this message contains the last message marker
|
|
360
|
-
if (entry.content.includes(
|
|
366
|
+
if (entry.content.includes("___LAST_MESSAGE_MARKER___")) {
|
|
361
367
|
console.log(`[AgentSessionManager] Skipping assistant message with last message marker - will be posted as response later`);
|
|
362
368
|
return; // Skip posting this as a thought
|
|
363
369
|
}
|
|
364
370
|
content = {
|
|
365
|
-
type:
|
|
366
|
-
body: entry.content
|
|
371
|
+
type: "thought",
|
|
372
|
+
body: entry.content,
|
|
367
373
|
};
|
|
368
374
|
}
|
|
369
375
|
break;
|
|
370
|
-
case
|
|
376
|
+
case "system":
|
|
371
377
|
// System messages are thoughts
|
|
372
378
|
content = {
|
|
373
|
-
type:
|
|
374
|
-
body: entry.content
|
|
379
|
+
type: "thought",
|
|
380
|
+
body: entry.content,
|
|
375
381
|
};
|
|
376
382
|
break;
|
|
377
|
-
case
|
|
383
|
+
case "result":
|
|
378
384
|
// Result messages can be responses or errors
|
|
379
385
|
if (entry.metadata?.isError) {
|
|
380
386
|
content = {
|
|
381
|
-
type:
|
|
382
|
-
body: entry.content
|
|
387
|
+
type: "error",
|
|
388
|
+
body: entry.content,
|
|
383
389
|
};
|
|
384
390
|
}
|
|
385
391
|
else {
|
|
386
392
|
// Strip the last message marker from the response
|
|
387
|
-
const cleanedContent = entry.content
|
|
393
|
+
const cleanedContent = entry.content
|
|
394
|
+
.replace(/___LAST_MESSAGE_MARKER___/g, "")
|
|
395
|
+
.trim();
|
|
388
396
|
content = {
|
|
389
|
-
type:
|
|
390
|
-
body: cleanedContent
|
|
397
|
+
type: "response",
|
|
398
|
+
body: cleanedContent,
|
|
391
399
|
};
|
|
392
400
|
}
|
|
393
401
|
break;
|
|
394
402
|
default:
|
|
395
403
|
// Default to thought
|
|
396
404
|
content = {
|
|
397
|
-
type:
|
|
398
|
-
body: entry.content
|
|
405
|
+
type: "thought",
|
|
406
|
+
body: entry.content,
|
|
399
407
|
};
|
|
400
408
|
}
|
|
401
409
|
const activityInput = {
|
|
402
410
|
agentSessionId: session.linearAgentActivitySessionId, // Use the Linear session ID
|
|
403
|
-
content
|
|
411
|
+
content,
|
|
404
412
|
};
|
|
405
413
|
const result = await this.linearClient.createAgentActivity(activityInput);
|
|
406
414
|
if (result.success && result.agentActivity) {
|
|
@@ -432,7 +440,7 @@ export class AgentSessionManager {
|
|
|
432
440
|
* Get all active sessions
|
|
433
441
|
*/
|
|
434
442
|
getActiveSessions() {
|
|
435
|
-
return Array.from(this.sessions.values()).filter(session => session.status === LinearDocument.AgentSessionStatus.Active);
|
|
443
|
+
return Array.from(this.sessions.values()).filter((session) => session.status === LinearDocument.AgentSessionStatus.Active);
|
|
436
444
|
}
|
|
437
445
|
/**
|
|
438
446
|
* Add or update ClaudeRunner for a session
|
|
@@ -452,7 +460,7 @@ export class AgentSessionManager {
|
|
|
452
460
|
*/
|
|
453
461
|
getAllClaudeRunners() {
|
|
454
462
|
return Array.from(this.sessions.values())
|
|
455
|
-
.map(session => session.claudeRunner)
|
|
463
|
+
.map((session) => session.claudeRunner)
|
|
456
464
|
.filter((runner) => runner !== undefined);
|
|
457
465
|
}
|
|
458
466
|
/**
|
|
@@ -460,21 +468,22 @@ export class AgentSessionManager {
|
|
|
460
468
|
*/
|
|
461
469
|
getClaudeRunnersForIssue(issueId) {
|
|
462
470
|
return Array.from(this.sessions.values())
|
|
463
|
-
.filter(session => session.issueId === issueId)
|
|
464
|
-
.map(session => session.claudeRunner)
|
|
471
|
+
.filter((session) => session.issueId === issueId)
|
|
472
|
+
.map((session) => session.claudeRunner)
|
|
465
473
|
.filter((runner) => runner !== undefined);
|
|
466
474
|
}
|
|
467
475
|
/**
|
|
468
476
|
* Get sessions by issue ID
|
|
469
477
|
*/
|
|
470
478
|
getSessionsByIssueId(issueId) {
|
|
471
|
-
return Array.from(this.sessions.values()).filter(session => session.issueId === issueId);
|
|
479
|
+
return Array.from(this.sessions.values()).filter((session) => session.issueId === issueId);
|
|
472
480
|
}
|
|
473
481
|
/**
|
|
474
482
|
* Get active sessions by issue ID
|
|
475
483
|
*/
|
|
476
484
|
getActiveSessionsByIssueId(issueId) {
|
|
477
|
-
return Array.from(this.sessions.values()).filter(session => session.issueId === issueId &&
|
|
485
|
+
return Array.from(this.sessions.values()).filter((session) => session.issueId === issueId &&
|
|
486
|
+
session.status === LinearDocument.AgentSessionStatus.Active);
|
|
478
487
|
}
|
|
479
488
|
/**
|
|
480
489
|
* Get all sessions
|
|
@@ -495,9 +504,9 @@ export class AgentSessionManager {
|
|
|
495
504
|
const result = await this.linearClient.createAgentActivity({
|
|
496
505
|
agentSessionId: session.linearAgentActivitySessionId,
|
|
497
506
|
content: {
|
|
498
|
-
type:
|
|
499
|
-
body
|
|
500
|
-
}
|
|
507
|
+
type: "thought",
|
|
508
|
+
body,
|
|
509
|
+
},
|
|
501
510
|
});
|
|
502
511
|
if (result.success) {
|
|
503
512
|
console.log(`[AgentSessionManager] Created thought activity for session ${sessionId}`);
|
|
@@ -521,16 +530,16 @@ export class AgentSessionManager {
|
|
|
521
530
|
}
|
|
522
531
|
try {
|
|
523
532
|
const content = {
|
|
524
|
-
type:
|
|
533
|
+
type: "action",
|
|
525
534
|
action,
|
|
526
|
-
parameter
|
|
535
|
+
parameter,
|
|
527
536
|
};
|
|
528
537
|
if (result !== undefined) {
|
|
529
538
|
content.result = result;
|
|
530
539
|
}
|
|
531
540
|
const response = await this.linearClient.createAgentActivity({
|
|
532
541
|
agentSessionId: session.linearAgentActivitySessionId,
|
|
533
|
-
content
|
|
542
|
+
content,
|
|
534
543
|
});
|
|
535
544
|
if (response.success) {
|
|
536
545
|
console.log(`[AgentSessionManager] Created action activity for session ${sessionId}`);
|
|
@@ -556,9 +565,9 @@ export class AgentSessionManager {
|
|
|
556
565
|
const result = await this.linearClient.createAgentActivity({
|
|
557
566
|
agentSessionId: session.linearAgentActivitySessionId,
|
|
558
567
|
content: {
|
|
559
|
-
type:
|
|
560
|
-
body
|
|
561
|
-
}
|
|
568
|
+
type: "response",
|
|
569
|
+
body,
|
|
570
|
+
},
|
|
562
571
|
});
|
|
563
572
|
if (result.success) {
|
|
564
573
|
console.log(`[AgentSessionManager] Created response activity for session ${sessionId}`);
|
|
@@ -584,9 +593,9 @@ export class AgentSessionManager {
|
|
|
584
593
|
const result = await this.linearClient.createAgentActivity({
|
|
585
594
|
agentSessionId: session.linearAgentActivitySessionId,
|
|
586
595
|
content: {
|
|
587
|
-
type:
|
|
588
|
-
body
|
|
589
|
-
}
|
|
596
|
+
type: "error",
|
|
597
|
+
body,
|
|
598
|
+
},
|
|
590
599
|
});
|
|
591
600
|
if (result.success) {
|
|
592
601
|
console.log(`[AgentSessionManager] Created error activity for session ${sessionId}`);
|
|
@@ -612,9 +621,9 @@ export class AgentSessionManager {
|
|
|
612
621
|
const result = await this.linearClient.createAgentActivity({
|
|
613
622
|
agentSessionId: session.linearAgentActivitySessionId,
|
|
614
623
|
content: {
|
|
615
|
-
type:
|
|
616
|
-
body
|
|
617
|
-
}
|
|
624
|
+
type: "elicitation",
|
|
625
|
+
body,
|
|
626
|
+
},
|
|
618
627
|
});
|
|
619
628
|
if (result.success) {
|
|
620
629
|
console.log(`[AgentSessionManager] Created elicitation activity for session ${sessionId}`);
|
|
@@ -633,7 +642,7 @@ export class AgentSessionManager {
|
|
|
633
642
|
cleanup(olderThanMs = 24 * 60 * 60 * 1000) {
|
|
634
643
|
const cutoff = Date.now() - olderThanMs;
|
|
635
644
|
for (const [sessionId, session] of this.sessions.entries()) {
|
|
636
|
-
if ((session.status ===
|
|
645
|
+
if ((session.status === "complete" || session.status === "error") &&
|
|
637
646
|
session.updatedAt < cutoff) {
|
|
638
647
|
this.sessions.delete(sessionId);
|
|
639
648
|
this.entries.delete(sessionId);
|
|
@@ -650,12 +659,12 @@ export class AgentSessionManager {
|
|
|
650
659
|
// Serialize sessions
|
|
651
660
|
for (const [sessionId, session] of this.sessions.entries()) {
|
|
652
661
|
// Exclude claudeRunner from serialization as it's not serializable
|
|
653
|
-
const { claudeRunner, ...serializableSession } = session;
|
|
662
|
+
const { claudeRunner: _claudeRunner, ...serializableSession } = session;
|
|
654
663
|
sessions[sessionId] = serializableSession;
|
|
655
664
|
}
|
|
656
665
|
// Serialize entries
|
|
657
666
|
for (const [sessionId, sessionEntries] of this.entries.entries()) {
|
|
658
|
-
entries[sessionId] = sessionEntries.map(entry => ({
|
|
667
|
+
entries[sessionId] = sessionEntries.map((entry) => ({
|
|
659
668
|
...entry,
|
|
660
669
|
}));
|
|
661
670
|
}
|
|
@@ -677,7 +686,7 @@ export class AgentSessionManager {
|
|
|
677
686
|
}
|
|
678
687
|
// Restore entries
|
|
679
688
|
for (const [sessionId, entriesData] of Object.entries(serializedEntries)) {
|
|
680
|
-
const sessionEntries = entriesData.map(entryData => ({
|
|
689
|
+
const sessionEntries = entriesData.map((entryData) => ({
|
|
681
690
|
...entryData,
|
|
682
691
|
}));
|
|
683
692
|
this.entries.set(sessionId, sessionEntries);
|
|
@@ -692,9 +701,9 @@ export class AgentSessionManager {
|
|
|
692
701
|
const result = await this.linearClient.createAgentActivity({
|
|
693
702
|
agentSessionId: linearAgentActivitySessionId,
|
|
694
703
|
content: {
|
|
695
|
-
type:
|
|
696
|
-
body: `Using model: ${model}
|
|
697
|
-
}
|
|
704
|
+
type: "thought",
|
|
705
|
+
body: `Using model: ${model}`,
|
|
706
|
+
},
|
|
698
707
|
});
|
|
699
708
|
if (result.success) {
|
|
700
709
|
console.log(`[AgentSessionManager] Posted model notification for session ${linearAgentActivitySessionId} (model: ${model})`);
|