@hasna/mementos 0.8.0 → 0.9.0

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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Auto-resolve agent_id and project_id from session metadata.
3
+ * When a session is ingested without explicit agent/project context,
4
+ * try to detect them from available metadata fields.
5
+ */
6
+ import type { Database } from "bun:sqlite";
7
+ export interface AutoResolveResult {
8
+ agentId: string | null;
9
+ projectId: string | null;
10
+ confidence: "high" | "low" | "none";
11
+ method: string;
12
+ }
13
+ /**
14
+ * Attempt to resolve agent_id and project_id from metadata fields.
15
+ *
16
+ * Strategy:
17
+ * 1. If metadata.agentName matches an existing agent → agentId = agent.id, confidence=high
18
+ * 2. If metadata.workingDir matches a registered project path → projectId = project.id, confidence=high
19
+ * 3. If metadata.gitRemote contains a repo name that matches a project name → confidence=low
20
+ * 4. Otherwise confidence=none
21
+ */
22
+ export declare function autoResolveAgentProject(metadata: {
23
+ workingDir?: string;
24
+ agentName?: string;
25
+ gitRemote?: string;
26
+ sessionSource?: string;
27
+ }, db?: Database): AutoResolveResult;
28
+ //# sourceMappingURL=session-auto-resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-auto-resolve.d.ts","sourceRoot":"","sources":["../../src/lib/session-auto-resolve.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAQ3C,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE;IACR,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,EACD,EAAE,CAAC,EAAE,QAAQ,GACZ,iBAAiB,CAsFnB"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Session transcript processor.
3
+ * Takes a full session transcript, chunks it, calls LLM to extract memories,
4
+ * saves extracted memories tagged with session_id + source.
5
+ * All failures are silently caught — never throws.
6
+ */
7
+ import type { Database } from "bun:sqlite";
8
+ export interface ChunkResult {
9
+ chunkIndex: number;
10
+ memoriesExtracted: number;
11
+ }
12
+ export interface ProcessingResult {
13
+ jobId: string;
14
+ chunksProcessed: number;
15
+ memoriesExtracted: number;
16
+ errors: string[];
17
+ }
18
+ /**
19
+ * Split a transcript into chunks with overlap.
20
+ */
21
+ export declare function chunkTranscript(transcript: string, chunkSize?: number, overlap?: number): string[];
22
+ /**
23
+ * Extract memories from a single chunk using the available LLM provider.
24
+ * Returns the count of memories saved.
25
+ */
26
+ export declare function extractMemoriesFromChunk(chunk: string, context: {
27
+ sessionId: string;
28
+ agentId?: string;
29
+ projectId?: string;
30
+ source?: string;
31
+ }, db?: Database): Promise<number>;
32
+ /**
33
+ * Process a session memory job end-to-end.
34
+ * Fetches the job, marks it processing, chunks transcript, extracts memories.
35
+ * Updates job status to completed or failed.
36
+ */
37
+ export declare function processSessionJob(jobId: string, db?: Database): Promise<ProcessingResult>;
38
+ //# sourceMappingURL=session-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-processor.d.ts","sourceRoot":"","sources":["../../src/lib/session-processor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAa3C,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAaD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,SAAS,SAAO,EAChB,OAAO,SAAM,GACZ,MAAM,EAAE,CAeV;AAMD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,EACD,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,MAAM,CAAC,CAyHjB;AAMD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAAC,gBAAgB,CAAC,CA+F3B"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Background queue for session memory job processing.
3
+ * Polls for pending jobs every 5 seconds, processes one at a time (concurrency=1).
4
+ * Fire-and-forget: enqueueSessionJob() returns immediately, processing happens async.
5
+ */
6
+ export interface SessionQueueStats {
7
+ pending: number;
8
+ processing: number;
9
+ completed: number;
10
+ failed: number;
11
+ }
12
+ /**
13
+ * Enqueue a job ID for processing. Fire-and-forget.
14
+ * The background worker will pick it up within the next polling interval.
15
+ */
16
+ export declare function enqueueSessionJob(jobId: string): void;
17
+ /**
18
+ * Get in-memory queue stats.
19
+ * Note: pending/completed/failed counts come from DB when a full scan is needed;
20
+ * this returns a lightweight in-memory snapshot.
21
+ */
22
+ export declare function getSessionQueueStats(): SessionQueueStats;
23
+ /**
24
+ * Start the background polling worker.
25
+ * Idempotent — safe to call multiple times (only starts once).
26
+ */
27
+ export declare function startSessionQueueWorker(): void;
28
+ //# sourceMappingURL=session-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-queue.d.ts","sourceRoot":"","sources":["../../src/lib/session-queue.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAUH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAeD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAMrD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,iBAAiB,CA6BxD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAQ9C"}
package/dist/mcp/index.js CHANGED
@@ -491,7 +491,30 @@ var init_database = __esm(() => {
491
491
  CREATE INDEX IF NOT EXISTS idx_webhook_hooks_type ON webhook_hooks(type);
492
492
  CREATE INDEX IF NOT EXISTS idx_webhook_hooks_enabled ON webhook_hooks(enabled);
493
493
  INSERT OR IGNORE INTO _migrations (id) VALUES (10);
494
- `
494
+ `,
495
+ `
496
+ CREATE TABLE IF NOT EXISTS session_memory_jobs (
497
+ id TEXT PRIMARY KEY,
498
+ session_id TEXT NOT NULL,
499
+ agent_id TEXT,
500
+ project_id TEXT,
501
+ source TEXT NOT NULL DEFAULT 'manual' CHECK(source IN ('claude-code','codex','manual','open-sessions')),
502
+ status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','processing','completed','failed')),
503
+ transcript TEXT NOT NULL,
504
+ chunk_count INTEGER NOT NULL DEFAULT 0,
505
+ memories_extracted INTEGER NOT NULL DEFAULT 0,
506
+ error TEXT,
507
+ metadata TEXT NOT NULL DEFAULT '{}',
508
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
509
+ started_at TEXT,
510
+ completed_at TEXT
511
+ );
512
+ CREATE INDEX IF NOT EXISTS idx_session_memory_jobs_status ON session_memory_jobs(status);
513
+ CREATE INDEX IF NOT EXISTS idx_session_memory_jobs_agent ON session_memory_jobs(agent_id);
514
+ CREATE INDEX IF NOT EXISTS idx_session_memory_jobs_project ON session_memory_jobs(project_id);
515
+ CREATE INDEX IF NOT EXISTS idx_session_memory_jobs_session ON session_memory_jobs(session_id);
516
+ INSERT OR IGNORE INTO _migrations (id) VALUES (13);
517
+ `
495
518
  ];
496
519
  });
497
520
 
@@ -8494,6 +8517,351 @@ function getSynthesisStatus(runId, projectId, db) {
8494
8517
 
8495
8518
  // src/mcp/index.ts
8496
8519
  init_synthesis();
8520
+
8521
+ // src/db/session-jobs.ts
8522
+ init_database();
8523
+ function parseJobRow(row) {
8524
+ return {
8525
+ id: row["id"],
8526
+ session_id: row["session_id"],
8527
+ agent_id: row["agent_id"] || null,
8528
+ project_id: row["project_id"] || null,
8529
+ source: row["source"],
8530
+ status: row["status"],
8531
+ transcript: row["transcript"],
8532
+ chunk_count: row["chunk_count"],
8533
+ memories_extracted: row["memories_extracted"],
8534
+ error: row["error"] || null,
8535
+ metadata: JSON.parse(row["metadata"] || "{}"),
8536
+ created_at: row["created_at"],
8537
+ started_at: row["started_at"] || null,
8538
+ completed_at: row["completed_at"] || null
8539
+ };
8540
+ }
8541
+ function createSessionJob(input, db) {
8542
+ const d = db || getDatabase();
8543
+ const id = uuid();
8544
+ const timestamp = now();
8545
+ const source = input.source ?? "manual";
8546
+ const metadata = JSON.stringify(input.metadata ?? {});
8547
+ d.run(`INSERT INTO session_memory_jobs
8548
+ (id, session_id, agent_id, project_id, source, status, transcript, chunk_count, memories_extracted, metadata, created_at)
8549
+ VALUES (?, ?, ?, ?, ?, 'pending', ?, 0, 0, ?, ?)`, [
8550
+ id,
8551
+ input.session_id,
8552
+ input.agent_id ?? null,
8553
+ input.project_id ?? null,
8554
+ source,
8555
+ input.transcript,
8556
+ metadata,
8557
+ timestamp
8558
+ ]);
8559
+ return getSessionJob(id, d);
8560
+ }
8561
+ function getSessionJob(id, db) {
8562
+ const d = db || getDatabase();
8563
+ const row = d.query("SELECT * FROM session_memory_jobs WHERE id = ?").get(id);
8564
+ if (!row)
8565
+ return null;
8566
+ return parseJobRow(row);
8567
+ }
8568
+ function listSessionJobs(filter, db) {
8569
+ const d = db || getDatabase();
8570
+ const conditions = [];
8571
+ const params = [];
8572
+ if (filter?.agent_id) {
8573
+ conditions.push("agent_id = ?");
8574
+ params.push(filter.agent_id);
8575
+ }
8576
+ if (filter?.project_id) {
8577
+ conditions.push("project_id = ?");
8578
+ params.push(filter.project_id);
8579
+ }
8580
+ if (filter?.status) {
8581
+ conditions.push("status = ?");
8582
+ params.push(filter.status);
8583
+ }
8584
+ if (filter?.session_id) {
8585
+ conditions.push("session_id = ?");
8586
+ params.push(filter.session_id);
8587
+ }
8588
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
8589
+ const limit = filter?.limit ?? 20;
8590
+ const offset = filter?.offset ?? 0;
8591
+ const rows = d.query(`SELECT * FROM session_memory_jobs ${where} ORDER BY created_at DESC LIMIT ? OFFSET ?`).all(...params, limit, offset);
8592
+ return rows.map(parseJobRow);
8593
+ }
8594
+ function updateSessionJob(id, updates, db) {
8595
+ const d = db || getDatabase();
8596
+ const setClauses = [];
8597
+ const params = [];
8598
+ if (updates.status !== undefined) {
8599
+ setClauses.push("status = ?");
8600
+ params.push(updates.status);
8601
+ }
8602
+ if (updates.chunk_count !== undefined) {
8603
+ setClauses.push("chunk_count = ?");
8604
+ params.push(updates.chunk_count);
8605
+ }
8606
+ if (updates.memories_extracted !== undefined) {
8607
+ setClauses.push("memories_extracted = ?");
8608
+ params.push(updates.memories_extracted);
8609
+ }
8610
+ if ("error" in updates) {
8611
+ setClauses.push("error = ?");
8612
+ params.push(updates.error ?? null);
8613
+ }
8614
+ if ("started_at" in updates) {
8615
+ setClauses.push("started_at = ?");
8616
+ params.push(updates.started_at ?? null);
8617
+ }
8618
+ if ("completed_at" in updates) {
8619
+ setClauses.push("completed_at = ?");
8620
+ params.push(updates.completed_at ?? null);
8621
+ }
8622
+ if (setClauses.length === 0)
8623
+ return getSessionJob(id, d);
8624
+ params.push(id);
8625
+ d.run(`UPDATE session_memory_jobs SET ${setClauses.join(", ")} WHERE id = ?`, params);
8626
+ return getSessionJob(id, d);
8627
+ }
8628
+ function getNextPendingJob(db) {
8629
+ const d = db || getDatabase();
8630
+ const row = d.query("SELECT * FROM session_memory_jobs WHERE status = 'pending' ORDER BY created_at ASC LIMIT 1").get();
8631
+ if (!row)
8632
+ return null;
8633
+ return parseJobRow(row);
8634
+ }
8635
+
8636
+ // src/lib/session-queue.ts
8637
+ init_database();
8638
+
8639
+ // src/lib/session-processor.ts
8640
+ init_memories();
8641
+ init_registry();
8642
+ var SESSION_EXTRACTION_USER_TEMPLATE = (chunk, sessionId) => `Extract memories from this session chunk (session: ${sessionId}):
8643
+
8644
+ ${chunk}
8645
+
8646
+ Return JSON array: [{"key": "...", "value": "...", "category": "knowledge|fact|preference|history", "importance": 1-10, "tags": [...]}]`;
8647
+ function chunkTranscript(transcript, chunkSize = 2000, overlap = 200) {
8648
+ if (!transcript || transcript.length === 0)
8649
+ return [];
8650
+ if (transcript.length <= chunkSize)
8651
+ return [transcript];
8652
+ const chunks = [];
8653
+ let start = 0;
8654
+ while (start < transcript.length) {
8655
+ const end = Math.min(start + chunkSize, transcript.length);
8656
+ chunks.push(transcript.slice(start, end));
8657
+ if (end === transcript.length)
8658
+ break;
8659
+ start += chunkSize - overlap;
8660
+ }
8661
+ return chunks;
8662
+ }
8663
+ async function extractMemoriesFromChunk(chunk, context, db) {
8664
+ const provider = providerRegistry.getAvailable();
8665
+ if (!provider)
8666
+ return 0;
8667
+ try {
8668
+ const extracted = await provider.extractMemories(SESSION_EXTRACTION_USER_TEMPLATE(chunk, context.sessionId), {
8669
+ sessionId: context.sessionId,
8670
+ agentId: context.agentId,
8671
+ projectId: context.projectId
8672
+ });
8673
+ let savedCount = 0;
8674
+ const sourceTag = context.source ? `source:${context.source}` : "source:manual";
8675
+ for (const memory of extracted) {
8676
+ if (!memory.content || !memory.content.trim())
8677
+ continue;
8678
+ try {
8679
+ createMemory({
8680
+ key: memory.content.slice(0, 120).replace(/\s+/g, "-").toLowerCase(),
8681
+ value: memory.content,
8682
+ category: memory.category,
8683
+ scope: memory.suggestedScope ?? "shared",
8684
+ importance: memory.importance,
8685
+ tags: [
8686
+ ...memory.tags,
8687
+ "session-extracted",
8688
+ sourceTag,
8689
+ `session:${context.sessionId}`
8690
+ ],
8691
+ source: "auto",
8692
+ agent_id: context.agentId,
8693
+ project_id: context.projectId,
8694
+ session_id: context.sessionId,
8695
+ metadata: {
8696
+ auto_extracted: true,
8697
+ session_source: context.source ?? "manual",
8698
+ extracted_at: new Date().toISOString(),
8699
+ reasoning: memory.reasoning
8700
+ }
8701
+ }, "merge", db);
8702
+ savedCount++;
8703
+ } catch {}
8704
+ }
8705
+ return savedCount;
8706
+ } catch {
8707
+ try {
8708
+ const fallbacks = providerRegistry.getFallbacks();
8709
+ for (const fallback of fallbacks) {
8710
+ try {
8711
+ const extracted = await fallback.extractMemories(SESSION_EXTRACTION_USER_TEMPLATE(chunk, context.sessionId), {
8712
+ sessionId: context.sessionId,
8713
+ agentId: context.agentId,
8714
+ projectId: context.projectId
8715
+ });
8716
+ let savedCount = 0;
8717
+ const sourceTag = context.source ? `source:${context.source}` : "source:manual";
8718
+ for (const memory of extracted) {
8719
+ if (!memory.content || !memory.content.trim())
8720
+ continue;
8721
+ try {
8722
+ createMemory({
8723
+ key: memory.content.slice(0, 120).replace(/\s+/g, "-").toLowerCase(),
8724
+ value: memory.content,
8725
+ category: memory.category,
8726
+ scope: memory.suggestedScope ?? "shared",
8727
+ importance: memory.importance,
8728
+ tags: [
8729
+ ...memory.tags,
8730
+ "session-extracted",
8731
+ sourceTag,
8732
+ `session:${context.sessionId}`
8733
+ ],
8734
+ source: "auto",
8735
+ agent_id: context.agentId,
8736
+ project_id: context.projectId,
8737
+ session_id: context.sessionId,
8738
+ metadata: {
8739
+ auto_extracted: true,
8740
+ session_source: context.source ?? "manual",
8741
+ extracted_at: new Date().toISOString(),
8742
+ reasoning: memory.reasoning
8743
+ }
8744
+ }, "merge", db);
8745
+ savedCount++;
8746
+ } catch {}
8747
+ }
8748
+ if (savedCount > 0)
8749
+ return savedCount;
8750
+ } catch {
8751
+ continue;
8752
+ }
8753
+ }
8754
+ } catch {}
8755
+ return 0;
8756
+ }
8757
+ }
8758
+ async function processSessionJob(jobId, db) {
8759
+ const result = {
8760
+ jobId,
8761
+ chunksProcessed: 0,
8762
+ memoriesExtracted: 0,
8763
+ errors: []
8764
+ };
8765
+ let job;
8766
+ try {
8767
+ job = getSessionJob(jobId, db);
8768
+ if (!job) {
8769
+ result.errors.push(`Job not found: ${jobId}`);
8770
+ return result;
8771
+ }
8772
+ } catch (e) {
8773
+ result.errors.push(`Failed to fetch job: ${String(e)}`);
8774
+ return result;
8775
+ }
8776
+ try {
8777
+ updateSessionJob(jobId, { status: "processing", started_at: new Date().toISOString() }, db);
8778
+ } catch (e) {
8779
+ result.errors.push(`Failed to mark job as processing: ${String(e)}`);
8780
+ return result;
8781
+ }
8782
+ const chunks = chunkTranscript(job.transcript);
8783
+ try {
8784
+ updateSessionJob(jobId, { chunk_count: chunks.length }, db);
8785
+ } catch {}
8786
+ let totalMemories = 0;
8787
+ for (let i = 0;i < chunks.length; i++) {
8788
+ const chunk = chunks[i];
8789
+ try {
8790
+ const count = await extractMemoriesFromChunk(chunk, {
8791
+ sessionId: job.session_id,
8792
+ agentId: job.agent_id ?? undefined,
8793
+ projectId: job.project_id ?? undefined,
8794
+ source: job.source
8795
+ }, db);
8796
+ totalMemories += count;
8797
+ result.chunksProcessed++;
8798
+ } catch (e) {
8799
+ result.errors.push(`Chunk ${i} failed: ${String(e)}`);
8800
+ }
8801
+ }
8802
+ result.memoriesExtracted = totalMemories;
8803
+ try {
8804
+ if (result.errors.length > 0 && result.chunksProcessed === 0) {
8805
+ updateSessionJob(jobId, {
8806
+ status: "failed",
8807
+ error: result.errors.join("; "),
8808
+ completed_at: new Date().toISOString(),
8809
+ memories_extracted: totalMemories,
8810
+ chunk_count: chunks.length
8811
+ }, db);
8812
+ } else {
8813
+ updateSessionJob(jobId, {
8814
+ status: "completed",
8815
+ completed_at: new Date().toISOString(),
8816
+ memories_extracted: totalMemories,
8817
+ chunk_count: chunks.length
8818
+ }, db);
8819
+ }
8820
+ } catch (e) {
8821
+ result.errors.push(`Failed to update job status: ${String(e)}`);
8822
+ }
8823
+ return result;
8824
+ }
8825
+
8826
+ // src/lib/session-queue.ts
8827
+ var _pendingQueue = new Set;
8828
+ var _isProcessing = false;
8829
+ function enqueueSessionJob(jobId) {
8830
+ _pendingQueue.add(jobId);
8831
+ if (!_isProcessing) {
8832
+ _processNext();
8833
+ }
8834
+ }
8835
+ async function _processNext() {
8836
+ if (_isProcessing)
8837
+ return;
8838
+ let jobId;
8839
+ if (_pendingQueue.size > 0) {
8840
+ jobId = [..._pendingQueue][0];
8841
+ _pendingQueue.delete(jobId);
8842
+ } else {
8843
+ try {
8844
+ const job = getNextPendingJob();
8845
+ if (job)
8846
+ jobId = job.id;
8847
+ } catch {
8848
+ return;
8849
+ }
8850
+ }
8851
+ if (!jobId)
8852
+ return;
8853
+ _isProcessing = true;
8854
+ try {
8855
+ await processSessionJob(jobId);
8856
+ } catch {} finally {
8857
+ _isProcessing = false;
8858
+ if (_pendingQueue.size > 0) {
8859
+ _processNext();
8860
+ }
8861
+ }
8862
+ }
8863
+
8864
+ // src/mcp/index.ts
8497
8865
  init_auto_memory();
8498
8866
  init_registry();
8499
8867
  import { createRequire } from "module";
@@ -10712,6 +11080,50 @@ server.tool("memory_auto_test", "Test memory extraction on text WITHOUT saving a
10712
11080
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
10713
11081
  }
10714
11082
  });
11083
+ server.tool("memory_ingest_session", "Submit a session transcript for async memory extraction. Returns job_id to track progress.", {
11084
+ transcript: exports_external.string(),
11085
+ session_id: exports_external.string(),
11086
+ agent_id: exports_external.string().optional(),
11087
+ project_id: exports_external.string().optional(),
11088
+ source: exports_external.enum(["claude-code", "codex", "manual", "open-sessions"]).optional()
11089
+ }, async (args) => {
11090
+ try {
11091
+ const job = createSessionJob({
11092
+ session_id: args.session_id,
11093
+ transcript: args.transcript,
11094
+ source: args.source ?? "manual",
11095
+ agent_id: args.agent_id,
11096
+ project_id: args.project_id
11097
+ });
11098
+ enqueueSessionJob(job.id);
11099
+ return { content: [{ type: "text", text: JSON.stringify({ job_id: job.id, status: "queued" }, null, 2) }] };
11100
+ } catch (e) {
11101
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
11102
+ }
11103
+ });
11104
+ server.tool("memory_session_status", "Get the status of a session memory extraction job.", { job_id: exports_external.string() }, async (args) => {
11105
+ try {
11106
+ const job = getSessionJob(args.job_id);
11107
+ if (!job)
11108
+ return { content: [{ type: "text", text: `Job not found: ${args.job_id}` }], isError: true };
11109
+ return { content: [{ type: "text", text: JSON.stringify(job, null, 2) }] };
11110
+ } catch (e) {
11111
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
11112
+ }
11113
+ });
11114
+ server.tool("memory_session_list", "List session memory extraction jobs.", {
11115
+ agent_id: exports_external.string().optional(),
11116
+ project_id: exports_external.string().optional(),
11117
+ status: exports_external.enum(["pending", "processing", "completed", "failed"]).optional(),
11118
+ limit: exports_external.coerce.number().optional()
11119
+ }, async (args) => {
11120
+ try {
11121
+ const jobs = listSessionJobs({ agent_id: args.agent_id, project_id: args.project_id, status: args.status, limit: args.limit ?? 20 });
11122
+ return { content: [{ type: "text", text: JSON.stringify(jobs, null, 2) }] };
11123
+ } catch (e) {
11124
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
11125
+ }
11126
+ });
10715
11127
  async function main() {
10716
11128
  loadWebhooksFromDb();
10717
11129
  const transport = new StdioServerTransport;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAs9CH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgI9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA6gDH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkI9C"}