assistme 0.1.14 → 0.1.15
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.
|
@@ -315,6 +315,21 @@ async function failTask(messageId, errorMessage) {
|
|
|
315
315
|
});
|
|
316
316
|
if (error) log.error(`Failed to update task status: ${error.message}`);
|
|
317
317
|
}
|
|
318
|
+
async function getConversationHistory(conversationId, excludeMessageId, limit = 20) {
|
|
319
|
+
const sb = getSupabase();
|
|
320
|
+
const { data, error } = await sb.from("conversation_messages").select("id, role, content, status, metadata, created_at").eq("conversation_id", conversationId).in("status", ["completed", "failed"]).neq("id", excludeMessageId).order("created_at", { ascending: false }).limit(limit);
|
|
321
|
+
if (error) {
|
|
322
|
+
log.debug(`Failed to fetch conversation history: ${error.message}`);
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
const rows = data || [];
|
|
326
|
+
return rows.reverse().map((row) => {
|
|
327
|
+
const prompt = row.metadata?.prompt || "";
|
|
328
|
+
const content = row.content || "";
|
|
329
|
+
const response = row.status === "failed" ? `[Task failed] ${content}` : content;
|
|
330
|
+
return { prompt, response };
|
|
331
|
+
}).filter((entry) => entry.prompt && entry.response);
|
|
332
|
+
}
|
|
318
333
|
var eventSequence = 0;
|
|
319
334
|
function resetEventSequence() {
|
|
320
335
|
eventSequence = 0;
|
|
@@ -371,6 +386,7 @@ export {
|
|
|
371
386
|
claimTask,
|
|
372
387
|
completeTask,
|
|
373
388
|
failTask,
|
|
389
|
+
getConversationHistory,
|
|
374
390
|
resetEventSequence,
|
|
375
391
|
emitEvent,
|
|
376
392
|
emitEvents
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
failTask,
|
|
11
11
|
getConfig,
|
|
12
12
|
getConfigPath,
|
|
13
|
+
getConversationHistory,
|
|
13
14
|
getCurrentUserId,
|
|
14
15
|
getOrCreateCliConversation,
|
|
15
16
|
getSupabase,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
setLogLevel,
|
|
25
26
|
setSessionBusy,
|
|
26
27
|
updateHeartbeat
|
|
27
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-ERK6A6GH.js";
|
|
28
29
|
|
|
29
30
|
// src/index.ts
|
|
30
31
|
import { Command } from "commander";
|
|
@@ -3009,9 +3010,13 @@ Guidelines:
|
|
|
3009
3010
|
- When you learn something about the user (preferences, habits), use memory_store to remember it
|
|
3010
3011
|
|
|
3011
3012
|
Workspace path: {workspace_path}`;
|
|
3013
|
+
var MAX_HISTORY_ENTRIES = 10;
|
|
3014
|
+
var MAX_RESPONSE_LENGTH = 1500;
|
|
3012
3015
|
var TaskProcessor = class {
|
|
3013
3016
|
memoryManager = null;
|
|
3014
3017
|
skillManager;
|
|
3018
|
+
/** In-memory conversation history, keyed by conversation_id */
|
|
3019
|
+
historyCache = /* @__PURE__ */ new Map();
|
|
3015
3020
|
constructor() {
|
|
3016
3021
|
this.skillManager = new SkillManager();
|
|
3017
3022
|
this.skillManager.load();
|
|
@@ -3050,6 +3055,28 @@ var TaskProcessor = class {
|
|
|
3050
3055
|
for (const s of matchedSkills) {
|
|
3051
3056
|
usedSkillNames.push(s.name);
|
|
3052
3057
|
}
|
|
3058
|
+
let history = [];
|
|
3059
|
+
try {
|
|
3060
|
+
history = await getConversationHistory(task.conversation_id, task.id, MAX_HISTORY_ENTRIES);
|
|
3061
|
+
} catch {
|
|
3062
|
+
log.debug("DB conversation history unavailable, using in-memory cache");
|
|
3063
|
+
}
|
|
3064
|
+
if (history.length === 0) {
|
|
3065
|
+
history = this.historyCache.get(task.conversation_id) || [];
|
|
3066
|
+
}
|
|
3067
|
+
if (history.length > 0) {
|
|
3068
|
+
log.info(`Loaded ${history.length} message(s) from conversation history`);
|
|
3069
|
+
let historyPrompt = "\n\n## Conversation History\nThe following is the history of previous messages in this conversation. Use this context to maintain continuity and understand references to earlier tasks.\n\n";
|
|
3070
|
+
for (const entry of history) {
|
|
3071
|
+
historyPrompt += `User: ${entry.prompt}
|
|
3072
|
+
`;
|
|
3073
|
+
const truncated = entry.response.length > MAX_RESPONSE_LENGTH ? entry.response.slice(0, MAX_RESPONSE_LENGTH) + "\u2026" : entry.response;
|
|
3074
|
+
historyPrompt += `Assistant: ${truncated}
|
|
3075
|
+
|
|
3076
|
+
`;
|
|
3077
|
+
}
|
|
3078
|
+
systemPrompt += historyPrompt;
|
|
3079
|
+
}
|
|
3053
3080
|
const browserServer = createBrowserMcpServer();
|
|
3054
3081
|
const agentToolsServer = createAgentToolsServer({
|
|
3055
3082
|
memoryManager: this.memoryManager,
|
|
@@ -3171,6 +3198,12 @@ var TaskProcessor = class {
|
|
|
3171
3198
|
});
|
|
3172
3199
|
await emitEvent(task.id, "status_change", { status: "completed" });
|
|
3173
3200
|
log.success("Task completed.");
|
|
3201
|
+
const convHistory = this.historyCache.get(task.conversation_id) || [];
|
|
3202
|
+
convHistory.push({ prompt: task.prompt, response: finalResponse });
|
|
3203
|
+
if (convHistory.length > MAX_HISTORY_ENTRIES * 2) {
|
|
3204
|
+
convHistory.splice(0, convHistory.length - MAX_HISTORY_ENTRIES * 2);
|
|
3205
|
+
}
|
|
3206
|
+
this.historyCache.set(task.conversation_id, convHistory);
|
|
3174
3207
|
if (this.memoryManager && finalResponse) {
|
|
3175
3208
|
const mm = this.memoryManager;
|
|
3176
3209
|
const taskIdRef = task.id;
|
|
@@ -3571,7 +3604,7 @@ program.command("start", { isDefault: true }).description("Start the agent and l
|
|
|
3571
3604
|
program.command("status").description("Check the status of the current agent session").action(async () => {
|
|
3572
3605
|
try {
|
|
3573
3606
|
const userId = await getCurrentUserId();
|
|
3574
|
-
const { getSupabase: getSupabase2 } = await import("./supabase-
|
|
3607
|
+
const { getSupabase: getSupabase2 } = await import("./supabase-5QTM5WBI.js");
|
|
3575
3608
|
const sb = getSupabase2();
|
|
3576
3609
|
const { data: sessions } = await sb.from("agent_sessions").select("*").eq("user_id", userId).in("status", ["online", "busy"]).order("started_at", { ascending: false }).limit(5);
|
|
3577
3610
|
if (!sessions || sessions.length === 0) {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
emitEvents,
|
|
10
10
|
endSession,
|
|
11
11
|
failTask,
|
|
12
|
+
getConversationHistory,
|
|
12
13
|
getCurrentUserId,
|
|
13
14
|
getOrCreateCliConversation,
|
|
14
15
|
getSupabase,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
resetEventSequence,
|
|
20
21
|
setSessionBusy,
|
|
21
22
|
updateHeartbeat
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-ERK6A6GH.js";
|
|
23
24
|
export {
|
|
24
25
|
CLI_AGENT_ID,
|
|
25
26
|
DAYBOX_AGENT_ID,
|
|
@@ -31,6 +32,7 @@ export {
|
|
|
31
32
|
emitEvents,
|
|
32
33
|
endSession,
|
|
33
34
|
failTask,
|
|
35
|
+
getConversationHistory,
|
|
34
36
|
getCurrentUserId,
|
|
35
37
|
getOrCreateCliConversation,
|
|
36
38
|
getSupabase,
|
package/package.json
CHANGED
package/src/agent/processor.ts
CHANGED
|
@@ -8,10 +8,12 @@ import {
|
|
|
8
8
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
9
9
|
import {
|
|
10
10
|
type AgentTask,
|
|
11
|
+
type HistoryEntry,
|
|
11
12
|
completeTask,
|
|
12
13
|
failTask,
|
|
13
14
|
emitEvent,
|
|
14
15
|
resetEventSequence,
|
|
16
|
+
getConversationHistory,
|
|
15
17
|
} from "../db/supabase.js";
|
|
16
18
|
import { getConfig } from "../utils/config.js";
|
|
17
19
|
import { log, newCorrelationId, setCorrelationId } from "../utils/logger.js";
|
|
@@ -84,9 +86,14 @@ Guidelines:
|
|
|
84
86
|
|
|
85
87
|
Workspace path: {workspace_path}`;
|
|
86
88
|
|
|
89
|
+
const MAX_HISTORY_ENTRIES = 10;
|
|
90
|
+
const MAX_RESPONSE_LENGTH = 1500;
|
|
91
|
+
|
|
87
92
|
export class TaskProcessor {
|
|
88
93
|
private memoryManager: MemoryManager | null = null;
|
|
89
94
|
private skillManager: SkillManager;
|
|
95
|
+
/** In-memory conversation history, keyed by conversation_id */
|
|
96
|
+
private historyCache: Map<string, HistoryEntry[]> = new Map();
|
|
90
97
|
|
|
91
98
|
constructor() {
|
|
92
99
|
this.skillManager = new SkillManager();
|
|
@@ -146,6 +153,34 @@ export class TaskProcessor {
|
|
|
146
153
|
usedSkillNames.push(s.name);
|
|
147
154
|
}
|
|
148
155
|
|
|
156
|
+
// Inject conversation history for multi-turn context
|
|
157
|
+
let history: HistoryEntry[] = [];
|
|
158
|
+
try {
|
|
159
|
+
history = await getConversationHistory(task.conversation_id, task.id, MAX_HISTORY_ENTRIES);
|
|
160
|
+
} catch {
|
|
161
|
+
log.debug("DB conversation history unavailable, using in-memory cache");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Fall back to in-memory cache if DB returned nothing
|
|
165
|
+
if (history.length === 0) {
|
|
166
|
+
history = this.historyCache.get(task.conversation_id) || [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (history.length > 0) {
|
|
170
|
+
log.info(`Loaded ${history.length} message(s) from conversation history`);
|
|
171
|
+
let historyPrompt =
|
|
172
|
+
"\n\n## Conversation History\nThe following is the history of previous messages in this conversation. Use this context to maintain continuity and understand references to earlier tasks.\n\n";
|
|
173
|
+
for (const entry of history) {
|
|
174
|
+
historyPrompt += `User: ${entry.prompt}\n`;
|
|
175
|
+
const truncated =
|
|
176
|
+
entry.response.length > MAX_RESPONSE_LENGTH
|
|
177
|
+
? entry.response.slice(0, MAX_RESPONSE_LENGTH) + "…"
|
|
178
|
+
: entry.response;
|
|
179
|
+
historyPrompt += `Assistant: ${truncated}\n\n`;
|
|
180
|
+
}
|
|
181
|
+
systemPrompt += historyPrompt;
|
|
182
|
+
}
|
|
183
|
+
|
|
149
184
|
// Create MCP servers for custom tools
|
|
150
185
|
const browserServer = createBrowserMcpServer();
|
|
151
186
|
const agentToolsServer = createAgentToolsServer({
|
|
@@ -291,6 +326,15 @@ export class TaskProcessor {
|
|
|
291
326
|
await emitEvent(task.id, "status_change", { status: "completed" });
|
|
292
327
|
log.success("Task completed.");
|
|
293
328
|
|
|
329
|
+
// Save to in-memory conversation history cache
|
|
330
|
+
const convHistory = this.historyCache.get(task.conversation_id) || [];
|
|
331
|
+
convHistory.push({ prompt: task.prompt, response: finalResponse });
|
|
332
|
+
// Keep only the most recent entries
|
|
333
|
+
if (convHistory.length > MAX_HISTORY_ENTRIES * 2) {
|
|
334
|
+
convHistory.splice(0, convHistory.length - MAX_HISTORY_ENTRIES * 2);
|
|
335
|
+
}
|
|
336
|
+
this.historyCache.set(task.conversation_id, convHistory);
|
|
337
|
+
|
|
294
338
|
// ── Post-task extraction (fire-and-forget, non-blocking) ──────
|
|
295
339
|
|
|
296
340
|
// Auto-extract memories using LLM
|
package/src/db/supabase.ts
CHANGED
|
@@ -329,6 +329,55 @@ export async function failTask(
|
|
|
329
329
|
if (error) log.error(`Failed to update task status: ${error.message}`);
|
|
330
330
|
}
|
|
331
331
|
|
|
332
|
+
// ── Conversation History ─────────────────────────────────────────────
|
|
333
|
+
|
|
334
|
+
export interface HistoryEntry {
|
|
335
|
+
prompt: string;
|
|
336
|
+
response: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Fetch completed messages from a conversation to build history context.
|
|
341
|
+
* Returns messages in chronological order (oldest first).
|
|
342
|
+
*/
|
|
343
|
+
export async function getConversationHistory(
|
|
344
|
+
conversationId: string,
|
|
345
|
+
excludeMessageId: string,
|
|
346
|
+
limit: number = 20
|
|
347
|
+
): Promise<HistoryEntry[]> {
|
|
348
|
+
const sb = getSupabase();
|
|
349
|
+
|
|
350
|
+
const { data, error } = await sb
|
|
351
|
+
.from("conversation_messages")
|
|
352
|
+
.select("id, role, content, status, metadata, created_at")
|
|
353
|
+
.eq("conversation_id", conversationId)
|
|
354
|
+
.in("status", ["completed", "failed"])
|
|
355
|
+
.neq("id", excludeMessageId)
|
|
356
|
+
.order("created_at", { ascending: false })
|
|
357
|
+
.limit(limit);
|
|
358
|
+
|
|
359
|
+
if (error) {
|
|
360
|
+
log.debug(`Failed to fetch conversation history: ${error.message}`);
|
|
361
|
+
return [];
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const rows = (data || []) as Array<Record<string, unknown>>;
|
|
365
|
+
|
|
366
|
+
return rows
|
|
367
|
+
.reverse() // chronological order (oldest first)
|
|
368
|
+
.map((row) => {
|
|
369
|
+
const prompt =
|
|
370
|
+
((row.metadata as Record<string, unknown>)?.prompt as string) || "";
|
|
371
|
+
const content = (row.content as string) || "";
|
|
372
|
+
const response =
|
|
373
|
+
row.status === "failed"
|
|
374
|
+
? `[Task failed] ${content}`
|
|
375
|
+
: content;
|
|
376
|
+
return { prompt, response };
|
|
377
|
+
})
|
|
378
|
+
.filter((entry) => entry.prompt && entry.response);
|
|
379
|
+
}
|
|
380
|
+
|
|
332
381
|
// ── Event Streaming ─────────────────────────────────────────────────
|
|
333
382
|
|
|
334
383
|
export type EventType =
|