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-QXT7DH44.js";
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-QU7MFNDI.js");
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-QXT7DH44.js";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assistme",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "AssistMe CLI Agent - AI-powered assistant that controls your real browser",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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
@@ -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 =