@signetai/connector-hermes-agent 0.185.4 → 0.185.5

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.
Files changed (2) hide show
  1. package/dist/index.js +487 -27
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
2
  import { spawnSync } from "node:child_process";
3
- import { createHash } from "node:crypto";
3
+ import { createHash as createHash3 } from "node:crypto";
4
4
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
5
5
  import { homedir } from "node:os";
6
6
  import { dirname as dirname6, join as join4 } from "node:path";
@@ -13,6 +13,7 @@ import { dirname as dirname5, isAbsolute, join as join3, relative, sep } from "n
13
13
  import { createRequire } from "node:module";
14
14
  import { dirname, join } from "node:path";
15
15
  import { fileURLToPath } from "node:url";
16
+ import { createHash } from "node:crypto";
16
17
  import { createRequire as createRequire2 } from "node:module";
17
18
  import { homedir as homedir4 } from "node:os";
18
19
  import { dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
@@ -10544,6 +10545,224 @@ function up116(db) {
10544
10545
  ON cross_agent_messages(delivery_path, delivery_state, delivery_lease_expires_at, delivery_updated_at);
10545
10546
  `);
10546
10547
  }
10548
+ function hasTable4(db, table) {
10549
+ return db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) != null;
10550
+ }
10551
+ function addColumnIfMissing25(db, table, column, definition) {
10552
+ const columns = db.prepare(`PRAGMA table_info(${table})`).all();
10553
+ if (columns.some((row) => row.name === column))
10554
+ return;
10555
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
10556
+ }
10557
+ function tableColumns(db, table) {
10558
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
10559
+ return new Set(rows.map((row) => typeof row.name === "string" ? row.name : ""));
10560
+ }
10561
+ function hashTranscript(content) {
10562
+ return createHash("sha256").update(content, "utf8").digest("hex");
10563
+ }
10564
+ function backfillTranscriptHashes(db) {
10565
+ const columns = tableColumns(db, "session_transcripts");
10566
+ if (!columns.has("content_hash") || !columns.has("content"))
10567
+ return;
10568
+ const rows = db.prepare("SELECT session_key, agent_id, content FROM session_transcripts WHERE content_hash IS NULL").all();
10569
+ const update = db.prepare("UPDATE session_transcripts SET content_hash = ? WHERE agent_id = ? AND session_key = ? AND content_hash IS NULL");
10570
+ for (const row of rows) {
10571
+ if (typeof row.content !== "string" || typeof row.session_key !== "string")
10572
+ continue;
10573
+ update.run(hashTranscript(row.content), typeof row.agent_id === "string" ? row.agent_id : "default", row.session_key);
10574
+ }
10575
+ }
10576
+ var COMPLETION_BOUNDARY_REASONS = new Set(["session_closed", "session_clear", "stale_session", "ttl_expired"]);
10577
+ function summaryJobTimestamp(job) {
10578
+ return job.completed_at ?? job.ended_at ?? job.captured_at ?? job.created_at ?? new Date(0).toISOString();
10579
+ }
10580
+ function laterTimestamp(current, candidate) {
10581
+ if (current === null)
10582
+ return candidate;
10583
+ if (candidate === null)
10584
+ return current;
10585
+ const currentMillis = Date.parse(current);
10586
+ const candidateMillis = Date.parse(candidate);
10587
+ if (Number.isFinite(currentMillis) && Number.isFinite(candidateMillis)) {
10588
+ return candidateMillis > currentMillis ? candidate : current;
10589
+ }
10590
+ return candidate > current ? candidate : current;
10591
+ }
10592
+ function isCompletionBoundary(job, columns) {
10593
+ return columns.has("trigger") && job.trigger === "session_end" || columns.has("boundary_reason") && COMPLETION_BOUNDARY_REASONS.has(job.boundary_reason ?? "");
10594
+ }
10595
+ function mergeTranscriptContent(current, next) {
10596
+ if (current.length === 0)
10597
+ return next;
10598
+ if (next.length === 0 || current === next || current.includes(next))
10599
+ return current;
10600
+ if (next.includes(current))
10601
+ return next;
10602
+ return `${current}
10603
+ ${next}`;
10604
+ }
10605
+ function backfillTranscriptsFromSummaryJobs(db) {
10606
+ if (!hasTable4(db, "summary_jobs"))
10607
+ return;
10608
+ const summaryColumns = tableColumns(db, "summary_jobs");
10609
+ if (!summaryColumns.has("transcript"))
10610
+ return;
10611
+ const select = (name) => summaryColumns.has(name) ? `"${name}" AS "${name}"` : `NULL AS "${name}"`;
10612
+ const jobs = db.prepare(`SELECT ${[
10613
+ "id",
10614
+ "session_key",
10615
+ "transcript",
10616
+ "harness",
10617
+ "project",
10618
+ "agent_id",
10619
+ "trigger",
10620
+ "boundary_reason",
10621
+ "captured_at",
10622
+ "ended_at",
10623
+ "completed_at",
10624
+ "created_at"
10625
+ ].map(select).join(", ")} FROM summary_jobs`).all();
10626
+ const candidates = new Map;
10627
+ for (const job of jobs) {
10628
+ if (typeof job.transcript !== "string" || job.transcript.trim().length === 0)
10629
+ continue;
10630
+ const agentId = typeof job.agent_id === "string" && job.agent_id.length > 0 ? job.agent_id : "default";
10631
+ const sessionKey = typeof job.session_key === "string" && job.session_key.trim().length > 0 ? job.session_key : `legacy-summary-job:${job.id ?? hashTranscript(`${summaryJobTimestamp(job)}\x00${job.transcript}`)}`;
10632
+ const key = `${agentId}\x00${sessionKey}`;
10633
+ const current = candidates.get(key);
10634
+ const timestamp = summaryJobTimestamp(job);
10635
+ const boundary = isCompletionBoundary(job, summaryColumns);
10636
+ const createdAt = job.captured_at ?? job.created_at ?? job.ended_at ?? timestamp;
10637
+ if (!current) {
10638
+ candidates.set(key, {
10639
+ sessionKey,
10640
+ job: { ...job, agent_id: agentId },
10641
+ content: job.transcript,
10642
+ createdAt,
10643
+ completedAt: boundary ? timestamp : null
10644
+ });
10645
+ continue;
10646
+ }
10647
+ const currentTimestamp = summaryJobTimestamp(current.job);
10648
+ const preferred = timestamp > currentTimestamp || timestamp === currentTimestamp && job.transcript.length > current.content.length ? { ...job, agent_id: agentId } : current.job;
10649
+ candidates.set(key, {
10650
+ sessionKey,
10651
+ job: preferred,
10652
+ content: mergeTranscriptContent(current.content, job.transcript),
10653
+ createdAt: current.createdAt < createdAt ? current.createdAt : createdAt,
10654
+ completedAt: laterTimestamp(current.completedAt, boundary ? timestamp : null)
10655
+ });
10656
+ }
10657
+ const transcriptColumns = tableColumns(db, "session_transcripts");
10658
+ const hasUpdated = transcriptColumns.has("updated_at");
10659
+ const hasCompleted = transcriptColumns.has("completed_at");
10660
+ const hasHash = transcriptColumns.has("content_hash");
10661
+ const insertColumns = ["session_key", "content", "harness", "project", "agent_id", "created_at"];
10662
+ if (hasUpdated)
10663
+ insertColumns.push("updated_at");
10664
+ if (hasCompleted)
10665
+ insertColumns.push("completed_at");
10666
+ if (hasHash)
10667
+ insertColumns.push("content_hash");
10668
+ const insert = db.prepare(`INSERT OR IGNORE INTO session_transcripts (${insertColumns.join(", ")}) VALUES (${insertColumns.map(() => "?").join(", ")})`);
10669
+ const existing = db.prepare("SELECT content, completed_at FROM session_transcripts WHERE agent_id = ? AND session_key = ?");
10670
+ for (const candidate of candidates.values()) {
10671
+ const job = candidate.job;
10672
+ const agentId = job.agent_id ?? "default";
10673
+ const existingRow = existing.get(agentId, candidate.sessionKey);
10674
+ if (existingRow != null) {
10675
+ const previousContent = typeof existingRow.content === "string" ? existingRow.content : "";
10676
+ const mergedContent = mergeTranscriptContent(previousContent, candidate.content);
10677
+ const completedAt = typeof existingRow.completed_at === "string" && existingRow.completed_at.length > 0 ? existingRow.completed_at : candidate.completedAt;
10678
+ const assignments = ["content = ?"];
10679
+ const values2 = [mergedContent];
10680
+ if (hasUpdated && mergedContent !== previousContent) {
10681
+ assignments.push("updated_at = ?");
10682
+ values2.push(candidate.createdAt);
10683
+ }
10684
+ if (hasCompleted && completedAt && !existingRow.completed_at) {
10685
+ assignments.push("completed_at = ?");
10686
+ values2.push(completedAt);
10687
+ }
10688
+ if (hasHash) {
10689
+ assignments.push("content_hash = ?");
10690
+ values2.push(hashTranscript(mergedContent));
10691
+ }
10692
+ values2.push(agentId, candidate.sessionKey);
10693
+ db.prepare(`UPDATE session_transcripts SET ${assignments.join(", ")} WHERE agent_id = ? AND session_key = ?`).run(...values2);
10694
+ continue;
10695
+ }
10696
+ const values = [
10697
+ candidate.sessionKey,
10698
+ candidate.content,
10699
+ job.harness ?? null,
10700
+ job.project ?? null,
10701
+ agentId,
10702
+ candidate.createdAt
10703
+ ];
10704
+ if (hasUpdated)
10705
+ values.push(candidate.createdAt);
10706
+ if (hasCompleted)
10707
+ values.push(candidate.completedAt);
10708
+ if (hasHash)
10709
+ values.push(hashTranscript(candidate.content));
10710
+ insert.run(...values);
10711
+ }
10712
+ }
10713
+ function up117(db) {
10714
+ if (!hasTable4(db, "session_transcripts"))
10715
+ return;
10716
+ addColumnIfMissing25(db, "session_transcripts", "completed_at", "TEXT");
10717
+ addColumnIfMissing25(db, "session_transcripts", "content_hash", "TEXT");
10718
+ backfillTranscriptHashes(db);
10719
+ if (hasTable4(db, "transcript_capture_jobs")) {
10720
+ const captureColumns = db.prepare("PRAGMA table_info(transcript_capture_jobs)").all();
10721
+ if (captureColumns.some((row) => row.name === "summary_status")) {
10722
+ db.exec("UPDATE transcript_capture_jobs SET summary_status = 'not_requested' WHERE summary_status IN ('pending', 'failed', 'skipped')");
10723
+ }
10724
+ }
10725
+ if (hasTable4(db, "summary_jobs")) {
10726
+ backfillTranscriptsFromSummaryJobs(db);
10727
+ backfillTranscriptHashes(db);
10728
+ const summaryColumns = tableColumns(db, "summary_jobs");
10729
+ const timestampParts = ["completed_at", "ended_at", "captured_at", "created_at"].filter((column) => summaryColumns.has(column)).map((column) => `sj.${column}`);
10730
+ const timestampValue = timestampParts.length === 1 ? timestampParts[0] : `COALESCE(${timestampParts.join(", ")})`;
10731
+ const completionTimestamp = timestampValue ? `MAX(${timestampValue})` : "NULL";
10732
+ const boundaryParts = [
10733
+ summaryColumns.has("trigger") ? "sj.trigger = 'session_end'" : null,
10734
+ summaryColumns.has("boundary_reason") ? "sj.boundary_reason IN ('session_closed', 'session_clear', 'stale_session', 'ttl_expired')" : null
10735
+ ].filter((part) => part !== null);
10736
+ const boundaryPredicate = boundaryParts.length > 0 ? `(${boundaryParts.join(" OR ")})` : "1=1";
10737
+ const agentPredicate = summaryColumns.has("agent_id") ? "sj.agent_id = session_transcripts.agent_id" : "session_transcripts.agent_id = 'default'";
10738
+ if (completionTimestamp !== "NULL") {
10739
+ db.exec(`
10740
+ UPDATE session_transcripts
10741
+ SET completed_at = COALESCE(
10742
+ completed_at,
10743
+ (
10744
+ SELECT ${completionTimestamp}
10745
+ FROM summary_jobs AS sj
10746
+ WHERE ${agentPredicate}
10747
+ AND sj.session_key = session_transcripts.session_key
10748
+ AND ${boundaryPredicate}
10749
+ )
10750
+ )
10751
+ WHERE completed_at IS NULL;
10752
+ `);
10753
+ }
10754
+ db.exec("DELETE FROM summary_jobs");
10755
+ }
10756
+ const completionIndexColumns = ["agent_id", "completed_at"];
10757
+ if (tableColumns(db, "session_transcripts").has("updated_at"))
10758
+ completionIndexColumns.push("updated_at");
10759
+ db.exec(`
10760
+ CREATE INDEX IF NOT EXISTS idx_st_agent_completed
10761
+ ON session_transcripts(${completionIndexColumns.join(", ")});
10762
+ CREATE INDEX IF NOT EXISTS idx_st_agent_hash
10763
+ ON session_transcripts(agent_id, content_hash);
10764
+ `);
10765
+ }
10547
10766
  var MIGRATIONS = [
10548
10767
  {
10549
10768
  version: 1,
@@ -11483,6 +11702,17 @@ var MIGRATIONS = [
11483
11702
  { table: "cross_agent_messages", column: "acp_target_agent_name" }
11484
11703
  ]
11485
11704
  }
11705
+ },
11706
+ {
11707
+ version: 117,
11708
+ name: "retire-summary-worker",
11709
+ up: up117,
11710
+ artifacts: {
11711
+ columns: [
11712
+ { table: "session_transcripts", column: "completed_at" },
11713
+ { table: "session_transcripts", column: "content_hash" }
11714
+ ]
11715
+ }
11486
11716
  }
11487
11717
  ];
11488
11718
  var LATEST_SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
@@ -11791,6 +12021,7 @@ function resolveSignetApiKey() {
11791
12021
  import { createRequire as createRequire3 } from "node:module";
11792
12022
  import { dirname as dirname2, join as join2 } from "node:path";
11793
12023
  import { fileURLToPath as fileURLToPath2 } from "node:url";
12024
+ import { createHash as createHash2 } from "node:crypto";
11794
12025
  import { homedir as homedir2 } from "os";
11795
12026
  import { join as join22 } from "path";
11796
12027
  import { createRequire as createRequire22 } from "node:module";
@@ -18750,7 +18981,7 @@ function memoriesFtsNeedsTokenizerRepair2(sql) {
18750
18981
  return true;
18751
18982
  return !normalized.includes(`tokenize='${MEMORIES_FTS_TOKENIZER2}'`);
18752
18983
  }
18753
- function up117(db) {
18984
+ function up118(db) {
18754
18985
  db.exec(`
18755
18986
  CREATE TABLE IF NOT EXISTS schema_migrations (
18756
18987
  version INTEGER PRIMARY KEY,
@@ -18843,27 +19074,27 @@ function hasColumn22(db, table, column) {
18843
19074
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
18844
19075
  return rows.some((r) => r.name === column);
18845
19076
  }
18846
- function addColumnIfMissing25(db, table, column, definition) {
19077
+ function addColumnIfMissing26(db, table, column, definition) {
18847
19078
  if (!hasColumn22(db, table, column)) {
18848
19079
  db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
18849
19080
  }
18850
19081
  }
18851
19082
  function up210(db) {
18852
- addColumnIfMissing25(db, "memories", "content_hash", "TEXT");
18853
- addColumnIfMissing25(db, "memories", "normalized_content", "TEXT");
18854
- addColumnIfMissing25(db, "memories", "is_deleted", "INTEGER DEFAULT 0");
18855
- addColumnIfMissing25(db, "memories", "deleted_at", "TEXT");
18856
- addColumnIfMissing25(db, "memories", "extraction_status", "TEXT DEFAULT 'none'");
18857
- addColumnIfMissing25(db, "memories", "embedding_model", "TEXT");
18858
- addColumnIfMissing25(db, "memories", "extraction_model", "TEXT");
18859
- addColumnIfMissing25(db, "memories", "update_count", "INTEGER DEFAULT 0");
18860
- addColumnIfMissing25(db, "memories", "who", "TEXT");
18861
- addColumnIfMissing25(db, "memories", "why", "TEXT");
18862
- addColumnIfMissing25(db, "memories", "project", "TEXT");
18863
- addColumnIfMissing25(db, "memories", "pinned", "INTEGER DEFAULT 0");
18864
- addColumnIfMissing25(db, "memories", "importance", "REAL DEFAULT 0.5");
18865
- addColumnIfMissing25(db, "memories", "last_accessed", "TEXT");
18866
- addColumnIfMissing25(db, "memories", "access_count", "INTEGER DEFAULT 0");
19083
+ addColumnIfMissing26(db, "memories", "content_hash", "TEXT");
19084
+ addColumnIfMissing26(db, "memories", "normalized_content", "TEXT");
19085
+ addColumnIfMissing26(db, "memories", "is_deleted", "INTEGER DEFAULT 0");
19086
+ addColumnIfMissing26(db, "memories", "deleted_at", "TEXT");
19087
+ addColumnIfMissing26(db, "memories", "extraction_status", "TEXT DEFAULT 'none'");
19088
+ addColumnIfMissing26(db, "memories", "embedding_model", "TEXT");
19089
+ addColumnIfMissing26(db, "memories", "extraction_model", "TEXT");
19090
+ addColumnIfMissing26(db, "memories", "update_count", "INTEGER DEFAULT 0");
19091
+ addColumnIfMissing26(db, "memories", "who", "TEXT");
19092
+ addColumnIfMissing26(db, "memories", "why", "TEXT");
19093
+ addColumnIfMissing26(db, "memories", "project", "TEXT");
19094
+ addColumnIfMissing26(db, "memories", "pinned", "INTEGER DEFAULT 0");
19095
+ addColumnIfMissing26(db, "memories", "importance", "REAL DEFAULT 0.5");
19096
+ addColumnIfMissing26(db, "memories", "last_accessed", "TEXT");
19097
+ addColumnIfMissing26(db, "memories", "access_count", "INTEGER DEFAULT 0");
18867
19098
  db.exec(`
18868
19099
  CREATE TABLE IF NOT EXISTS memory_history (
18869
19100
  id TEXT PRIMARY KEY,
@@ -18959,7 +19190,7 @@ function up210(db) {
18959
19190
  ON memory_entity_mentions(entity_id);
18960
19191
  `);
18961
19192
  }
18962
- function addColumnIfMissing26(db, table, column, definition) {
19193
+ function addColumnIfMissing27(db, table, column, definition) {
18963
19194
  const rows = db.prepare(`PRAGMA table_info(${table})`).all();
18964
19195
  if (rows.some((r) => r.name === column))
18965
19196
  return false;
@@ -18967,8 +19198,8 @@ function addColumnIfMissing26(db, table, column, definition) {
18967
19198
  return true;
18968
19199
  }
18969
19200
  function up310(db) {
18970
- addColumnIfMissing26(db, "memories", "why", "TEXT");
18971
- addColumnIfMissing26(db, "memories", "project", "TEXT");
19201
+ addColumnIfMissing27(db, "memories", "why", "TEXT");
19202
+ addColumnIfMissing27(db, "memories", "project", "TEXT");
18972
19203
  db.exec(`DROP INDEX IF EXISTS idx_memories_content_hash`);
18973
19204
  db.exec(`
18974
19205
  UPDATE memories
@@ -19173,7 +19404,7 @@ function up1010(db) {
19173
19404
  )
19174
19405
  `);
19175
19406
  }
19176
- function up118(db) {
19407
+ function up119(db) {
19177
19408
  db.exec(`
19178
19409
  CREATE TABLE IF NOT EXISTS session_scores (
19179
19410
  id TEXT PRIMARY KEY,
@@ -20394,7 +20625,7 @@ function up492(db) {
20394
20625
  );
20395
20626
  `);
20396
20627
  }
20397
- function hasTable4(db, name) {
20628
+ function hasTable5(db, name) {
20398
20629
  return db.prepare(`SELECT name
20399
20630
  FROM sqlite_master
20400
20631
  WHERE type = 'table' AND name = ?
@@ -20424,7 +20655,7 @@ function up502(db) {
20424
20655
  CREATE INDEX IF NOT EXISTS idx_entity_dependency_history_created
20425
20656
  ON entity_dependency_history(created_at DESC);
20426
20657
  `);
20427
- if (!hasTable4(db, "entity_dependencies"))
20658
+ if (!hasTable5(db, "entity_dependencies"))
20428
20659
  return;
20429
20660
  db.exec("DROP TRIGGER IF EXISTS trg_entity_dependencies_related_to_reason_insert");
20430
20661
  db.exec("DROP TRIGGER IF EXISTS trg_entity_dependencies_related_to_reason_update");
@@ -22326,11 +22557,229 @@ function up1162(db) {
22326
22557
  ON cross_agent_messages(delivery_path, delivery_state, delivery_lease_expires_at, delivery_updated_at);
22327
22558
  `);
22328
22559
  }
22560
+ function hasTable42(db, table) {
22561
+ return db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) != null;
22562
+ }
22563
+ function addColumnIfMissing252(db, table, column, definition) {
22564
+ const columns = db.prepare(`PRAGMA table_info(${table})`).all();
22565
+ if (columns.some((row) => row.name === column))
22566
+ return;
22567
+ db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
22568
+ }
22569
+ function tableColumns2(db, table) {
22570
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
22571
+ return new Set(rows.map((row) => typeof row.name === "string" ? row.name : ""));
22572
+ }
22573
+ function hashTranscript2(content) {
22574
+ return createHash2("sha256").update(content, "utf8").digest("hex");
22575
+ }
22576
+ function backfillTranscriptHashes2(db) {
22577
+ const columns = tableColumns2(db, "session_transcripts");
22578
+ if (!columns.has("content_hash") || !columns.has("content"))
22579
+ return;
22580
+ const rows = db.prepare("SELECT session_key, agent_id, content FROM session_transcripts WHERE content_hash IS NULL").all();
22581
+ const update = db.prepare("UPDATE session_transcripts SET content_hash = ? WHERE agent_id = ? AND session_key = ? AND content_hash IS NULL");
22582
+ for (const row of rows) {
22583
+ if (typeof row.content !== "string" || typeof row.session_key !== "string")
22584
+ continue;
22585
+ update.run(hashTranscript2(row.content), typeof row.agent_id === "string" ? row.agent_id : "default", row.session_key);
22586
+ }
22587
+ }
22588
+ var COMPLETION_BOUNDARY_REASONS2 = new Set(["session_closed", "session_clear", "stale_session", "ttl_expired"]);
22589
+ function summaryJobTimestamp2(job) {
22590
+ return job.completed_at ?? job.ended_at ?? job.captured_at ?? job.created_at ?? new Date(0).toISOString();
22591
+ }
22592
+ function laterTimestamp2(current, candidate) {
22593
+ if (current === null)
22594
+ return candidate;
22595
+ if (candidate === null)
22596
+ return current;
22597
+ const currentMillis = Date.parse(current);
22598
+ const candidateMillis = Date.parse(candidate);
22599
+ if (Number.isFinite(currentMillis) && Number.isFinite(candidateMillis)) {
22600
+ return candidateMillis > currentMillis ? candidate : current;
22601
+ }
22602
+ return candidate > current ? candidate : current;
22603
+ }
22604
+ function isCompletionBoundary2(job, columns) {
22605
+ return columns.has("trigger") && job.trigger === "session_end" || columns.has("boundary_reason") && COMPLETION_BOUNDARY_REASONS2.has(job.boundary_reason ?? "");
22606
+ }
22607
+ function mergeTranscriptContent2(current, next) {
22608
+ if (current.length === 0)
22609
+ return next;
22610
+ if (next.length === 0 || current === next || current.includes(next))
22611
+ return current;
22612
+ if (next.includes(current))
22613
+ return next;
22614
+ return `${current}
22615
+ ${next}`;
22616
+ }
22617
+ function backfillTranscriptsFromSummaryJobs2(db) {
22618
+ if (!hasTable42(db, "summary_jobs"))
22619
+ return;
22620
+ const summaryColumns = tableColumns2(db, "summary_jobs");
22621
+ if (!summaryColumns.has("transcript"))
22622
+ return;
22623
+ const select = (name) => summaryColumns.has(name) ? `"${name}" AS "${name}"` : `NULL AS "${name}"`;
22624
+ const jobs = db.prepare(`SELECT ${[
22625
+ "id",
22626
+ "session_key",
22627
+ "transcript",
22628
+ "harness",
22629
+ "project",
22630
+ "agent_id",
22631
+ "trigger",
22632
+ "boundary_reason",
22633
+ "captured_at",
22634
+ "ended_at",
22635
+ "completed_at",
22636
+ "created_at"
22637
+ ].map(select).join(", ")} FROM summary_jobs`).all();
22638
+ const candidates = new Map;
22639
+ for (const job of jobs) {
22640
+ if (typeof job.transcript !== "string" || job.transcript.trim().length === 0)
22641
+ continue;
22642
+ const agentId = typeof job.agent_id === "string" && job.agent_id.length > 0 ? job.agent_id : "default";
22643
+ const sessionKey = typeof job.session_key === "string" && job.session_key.trim().length > 0 ? job.session_key : `legacy-summary-job:${job.id ?? hashTranscript2(`${summaryJobTimestamp2(job)}\x00${job.transcript}`)}`;
22644
+ const key = `${agentId}\x00${sessionKey}`;
22645
+ const current = candidates.get(key);
22646
+ const timestamp = summaryJobTimestamp2(job);
22647
+ const boundary = isCompletionBoundary2(job, summaryColumns);
22648
+ const createdAt = job.captured_at ?? job.created_at ?? job.ended_at ?? timestamp;
22649
+ if (!current) {
22650
+ candidates.set(key, {
22651
+ sessionKey,
22652
+ job: { ...job, agent_id: agentId },
22653
+ content: job.transcript,
22654
+ createdAt,
22655
+ completedAt: boundary ? timestamp : null
22656
+ });
22657
+ continue;
22658
+ }
22659
+ const currentTimestamp = summaryJobTimestamp2(current.job);
22660
+ const preferred = timestamp > currentTimestamp || timestamp === currentTimestamp && job.transcript.length > current.content.length ? { ...job, agent_id: agentId } : current.job;
22661
+ candidates.set(key, {
22662
+ sessionKey,
22663
+ job: preferred,
22664
+ content: mergeTranscriptContent2(current.content, job.transcript),
22665
+ createdAt: current.createdAt < createdAt ? current.createdAt : createdAt,
22666
+ completedAt: laterTimestamp2(current.completedAt, boundary ? timestamp : null)
22667
+ });
22668
+ }
22669
+ const transcriptColumns = tableColumns2(db, "session_transcripts");
22670
+ const hasUpdated = transcriptColumns.has("updated_at");
22671
+ const hasCompleted = transcriptColumns.has("completed_at");
22672
+ const hasHash = transcriptColumns.has("content_hash");
22673
+ const insertColumns = ["session_key", "content", "harness", "project", "agent_id", "created_at"];
22674
+ if (hasUpdated)
22675
+ insertColumns.push("updated_at");
22676
+ if (hasCompleted)
22677
+ insertColumns.push("completed_at");
22678
+ if (hasHash)
22679
+ insertColumns.push("content_hash");
22680
+ const insert = db.prepare(`INSERT OR IGNORE INTO session_transcripts (${insertColumns.join(", ")}) VALUES (${insertColumns.map(() => "?").join(", ")})`);
22681
+ const existing = db.prepare("SELECT content, completed_at FROM session_transcripts WHERE agent_id = ? AND session_key = ?");
22682
+ for (const candidate of candidates.values()) {
22683
+ const job = candidate.job;
22684
+ const agentId = job.agent_id ?? "default";
22685
+ const existingRow = existing.get(agentId, candidate.sessionKey);
22686
+ if (existingRow != null) {
22687
+ const previousContent = typeof existingRow.content === "string" ? existingRow.content : "";
22688
+ const mergedContent = mergeTranscriptContent2(previousContent, candidate.content);
22689
+ const completedAt = typeof existingRow.completed_at === "string" && existingRow.completed_at.length > 0 ? existingRow.completed_at : candidate.completedAt;
22690
+ const assignments = ["content = ?"];
22691
+ const values2 = [mergedContent];
22692
+ if (hasUpdated && mergedContent !== previousContent) {
22693
+ assignments.push("updated_at = ?");
22694
+ values2.push(candidate.createdAt);
22695
+ }
22696
+ if (hasCompleted && completedAt && !existingRow.completed_at) {
22697
+ assignments.push("completed_at = ?");
22698
+ values2.push(completedAt);
22699
+ }
22700
+ if (hasHash) {
22701
+ assignments.push("content_hash = ?");
22702
+ values2.push(hashTranscript2(mergedContent));
22703
+ }
22704
+ values2.push(agentId, candidate.sessionKey);
22705
+ db.prepare(`UPDATE session_transcripts SET ${assignments.join(", ")} WHERE agent_id = ? AND session_key = ?`).run(...values2);
22706
+ continue;
22707
+ }
22708
+ const values = [
22709
+ candidate.sessionKey,
22710
+ candidate.content,
22711
+ job.harness ?? null,
22712
+ job.project ?? null,
22713
+ agentId,
22714
+ candidate.createdAt
22715
+ ];
22716
+ if (hasUpdated)
22717
+ values.push(candidate.createdAt);
22718
+ if (hasCompleted)
22719
+ values.push(candidate.completedAt);
22720
+ if (hasHash)
22721
+ values.push(hashTranscript2(candidate.content));
22722
+ insert.run(...values);
22723
+ }
22724
+ }
22725
+ function up1172(db) {
22726
+ if (!hasTable42(db, "session_transcripts"))
22727
+ return;
22728
+ addColumnIfMissing252(db, "session_transcripts", "completed_at", "TEXT");
22729
+ addColumnIfMissing252(db, "session_transcripts", "content_hash", "TEXT");
22730
+ backfillTranscriptHashes2(db);
22731
+ if (hasTable42(db, "transcript_capture_jobs")) {
22732
+ const captureColumns = db.prepare("PRAGMA table_info(transcript_capture_jobs)").all();
22733
+ if (captureColumns.some((row) => row.name === "summary_status")) {
22734
+ db.exec("UPDATE transcript_capture_jobs SET summary_status = 'not_requested' WHERE summary_status IN ('pending', 'failed', 'skipped')");
22735
+ }
22736
+ }
22737
+ if (hasTable42(db, "summary_jobs")) {
22738
+ backfillTranscriptsFromSummaryJobs2(db);
22739
+ backfillTranscriptHashes2(db);
22740
+ const summaryColumns = tableColumns2(db, "summary_jobs");
22741
+ const timestampParts = ["completed_at", "ended_at", "captured_at", "created_at"].filter((column) => summaryColumns.has(column)).map((column) => `sj.${column}`);
22742
+ const timestampValue = timestampParts.length === 1 ? timestampParts[0] : `COALESCE(${timestampParts.join(", ")})`;
22743
+ const completionTimestamp = timestampValue ? `MAX(${timestampValue})` : "NULL";
22744
+ const boundaryParts = [
22745
+ summaryColumns.has("trigger") ? "sj.trigger = 'session_end'" : null,
22746
+ summaryColumns.has("boundary_reason") ? "sj.boundary_reason IN ('session_closed', 'session_clear', 'stale_session', 'ttl_expired')" : null
22747
+ ].filter((part) => part !== null);
22748
+ const boundaryPredicate = boundaryParts.length > 0 ? `(${boundaryParts.join(" OR ")})` : "1=1";
22749
+ const agentPredicate = summaryColumns.has("agent_id") ? "sj.agent_id = session_transcripts.agent_id" : "session_transcripts.agent_id = 'default'";
22750
+ if (completionTimestamp !== "NULL") {
22751
+ db.exec(`
22752
+ UPDATE session_transcripts
22753
+ SET completed_at = COALESCE(
22754
+ completed_at,
22755
+ (
22756
+ SELECT ${completionTimestamp}
22757
+ FROM summary_jobs AS sj
22758
+ WHERE ${agentPredicate}
22759
+ AND sj.session_key = session_transcripts.session_key
22760
+ AND ${boundaryPredicate}
22761
+ )
22762
+ )
22763
+ WHERE completed_at IS NULL;
22764
+ `);
22765
+ }
22766
+ db.exec("DELETE FROM summary_jobs");
22767
+ }
22768
+ const completionIndexColumns = ["agent_id", "completed_at"];
22769
+ if (tableColumns2(db, "session_transcripts").has("updated_at"))
22770
+ completionIndexColumns.push("updated_at");
22771
+ db.exec(`
22772
+ CREATE INDEX IF NOT EXISTS idx_st_agent_completed
22773
+ ON session_transcripts(${completionIndexColumns.join(", ")});
22774
+ CREATE INDEX IF NOT EXISTS idx_st_agent_hash
22775
+ ON session_transcripts(agent_id, content_hash);
22776
+ `);
22777
+ }
22329
22778
  var MIGRATIONS2 = [
22330
22779
  {
22331
22780
  version: 1,
22332
22781
  name: "baseline",
22333
- up: up117,
22782
+ up: up118,
22334
22783
  artifacts: { tables: ["memories", "conversations", "embeddings"] }
22335
22784
  },
22336
22785
  {
@@ -22396,7 +22845,7 @@ var MIGRATIONS2 = [
22396
22845
  {
22397
22846
  version: 11,
22398
22847
  name: "session-scores",
22399
- up: up118,
22848
+ up: up119,
22400
22849
  artifacts: { tables: ["session_scores"] }
22401
22850
  },
22402
22851
  {
@@ -23265,6 +23714,17 @@ var MIGRATIONS2 = [
23265
23714
  { table: "cross_agent_messages", column: "acp_target_agent_name" }
23266
23715
  ]
23267
23716
  }
23717
+ },
23718
+ {
23719
+ version: 117,
23720
+ name: "retire-summary-worker",
23721
+ up: up1172,
23722
+ artifacts: {
23723
+ columns: [
23724
+ { table: "session_transcripts", column: "completed_at" },
23725
+ { table: "session_transcripts", column: "content_hash" }
23726
+ ]
23727
+ }
23268
23728
  }
23269
23729
  ];
23270
23730
  var LATEST_SCHEMA_VERSION2 = MIGRATIONS2[MIGRATIONS2.length - 1]?.version ?? 0;
@@ -23838,7 +24298,7 @@ function getConnectorVersion() {
23838
24298
  }
23839
24299
  function computePluginSourceHash() {
23840
24300
  const sourceDir = getPluginSourceDir();
23841
- const hash = createHash("sha256");
24301
+ const hash = createHash3("sha256");
23842
24302
  for (const file of PLUGIN_FILES) {
23843
24303
  const path = join4(sourceDir, file);
23844
24304
  hash.update(file);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signetai/connector-hermes-agent",
3
- "version": "0.185.4",
3
+ "version": "0.185.5",
4
4
  "description": "Signet connector for Hermes Agent — installs Signet as a pluggable memory provider",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,8 +25,8 @@
25
25
  "typecheck": "tsc --noEmit"
26
26
  },
27
27
  "dependencies": {
28
- "@signetai/connector-base": "0.185.4",
29
- "@signetai/core": "0.185.4"
28
+ "@signetai/connector-base": "0.185.5",
29
+ "@signetai/core": "0.185.5"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/node": "^22.0.0",