signetai 0.199.0 → 0.199.2

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/mcp-stdio.js CHANGED
@@ -40896,6 +40896,29 @@ function up130(db) {
40896
40896
  END;
40897
40897
  `);
40898
40898
  }
40899
+ function up131(db) {
40900
+ db.exec(`
40901
+ CREATE TABLE IF NOT EXISTS dreaming_evidence_consumption (
40902
+ agent_id TEXT NOT NULL,
40903
+ source_kind TEXT NOT NULL CHECK (source_kind IN ('memory', 'artifact', 'transcript', 'summary')),
40904
+ source_id TEXT NOT NULL,
40905
+ source_captured_at TEXT NOT NULL,
40906
+ source_entry_id TEXT NOT NULL DEFAULT '',
40907
+ source_revision TEXT NOT NULL,
40908
+ delivered_offset INTEGER NOT NULL CHECK (delivered_offset >= 0),
40909
+ source_length INTEGER NOT NULL CHECK (source_length >= 0),
40910
+ pass_id TEXT NOT NULL,
40911
+ updated_at TEXT NOT NULL,
40912
+ PRIMARY KEY (agent_id, source_kind, source_id, source_captured_at, source_entry_id, source_revision)
40913
+ );
40914
+ CREATE INDEX IF NOT EXISTS idx_dreaming_evidence_consumption_source
40915
+ ON dreaming_evidence_consumption(agent_id, source_entry_id, source_kind, source_revision);
40916
+ CREATE INDEX IF NOT EXISTS idx_dreaming_evidence_consumption_pending
40917
+ ON dreaming_evidence_consumption(agent_id, source_kind, source_id, source_captured_at, source_revision, delivered_offset, source_length);
40918
+ CREATE INDEX IF NOT EXISTS idx_dreaming_evidence_consumption_continuation
40919
+ ON dreaming_evidence_consumption(agent_id, pass_id, delivered_offset, source_length);
40920
+ `);
40921
+ }
40899
40922
  var MIGRATIONS = [
40900
40923
  {
40901
40924
  version: 1,
@@ -41938,6 +41961,12 @@ var MIGRATIONS = [
41938
41961
  name: "embedding-repair-state",
41939
41962
  up: up130,
41940
41963
  artifacts: { tables: ["embedding_repair_budget", "embedding_repair_backoff"] }
41964
+ },
41965
+ {
41966
+ version: 131,
41967
+ name: "dreaming-evidence-consumption",
41968
+ up: up131,
41969
+ artifacts: { tables: ["dreaming_evidence_consumption"] }
41941
41970
  }
41942
41971
  ];
41943
41972
  var LATEST_SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1]?.version ?? 0;
@@ -43268,7 +43297,7 @@ function readEpisodicMemory(db, agentId, id) {
43268
43297
  function readEpisodicArtifact(db, agentId, id) {
43269
43298
  const ids = sourceIdCandidates(id);
43270
43299
  const placeholders = ids.map(() => "?").join(", ");
43271
- const row = db.prepare(`SELECT source_path, source_kind, source_id, source_node_id, session_id, session_key, session_token,
43300
+ const row = db.prepare(`SELECT source_path, source_sha256, source_kind, source_id, source_node_id, session_id, session_key, session_token,
43272
43301
  project, harness, content, captured_at, updated_at
43273
43302
  FROM memory_artifacts
43274
43303
  WHERE agent_id = ?
@@ -43294,6 +43323,7 @@ function readEpisodicArtifact(db, agentId, id) {
43294
43323
  sourceKind: row.source_kind,
43295
43324
  sourceId: row.source_node_id ?? row.session_key ?? row.session_id ?? row.session_token,
43296
43325
  sourceEntryId: readNonEmptyTrimmed(row.source_id),
43326
+ sourceRevision: readNonEmptyTrimmed(row.source_sha256) ?? row.captured_at ?? row.updated_at,
43297
43327
  sourcePath: row.source_path,
43298
43328
  project: row.project,
43299
43329
  harness: row.harness,
@@ -43463,6 +43493,15 @@ function searchEpisodicSources(db, params) {
43463
43493
  const like = `%${query}%`;
43464
43494
  const sinceArgs = params.since !== undefined ? [params.since, EPISODIC_CAPTURED_AT_FLOOR] : [];
43465
43495
  const beforeArgs = params.before !== undefined ? [params.before] : [];
43496
+ const deliveredFilterEnabled = params.excludeDelivered === true && db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'dreaming_evidence_consumption'").get() != null;
43497
+ const deliveredPredicate = (kind, id, capturedAt, sourceEntryId, sourceRevision) => deliveredFilterEnabled ? `AND NOT EXISTS (
43498
+ SELECT 1 FROM dreaming_evidence_consumption dec
43499
+ WHERE dec.agent_id = ? AND dec.source_kind = '${kind}' AND dec.source_id = ${id}
43500
+ AND dec.source_captured_at = ${capturedAt} AND dec.source_entry_id = ${sourceEntryId}
43501
+ AND dec.source_revision = ${sourceRevision}
43502
+ AND dec.delivered_offset >= dec.source_length
43503
+ )` : "";
43504
+ const deliveredArgs = deliveredFilterEnabled ? [params.agentId] : [];
43466
43505
  const transcriptSearchTime = tableHasColumn(db, "session_transcripts", "updated_at") ? "COALESCE(updated_at, created_at)" : "created_at";
43467
43506
  const transcriptCompleted = tableHasColumn(db, "session_transcripts", "completed_at") ? "completed_at IS NOT NULL" : "0";
43468
43507
  const branches = [];
@@ -43474,8 +43513,9 @@ function searchEpisodicSources(db, params) {
43474
43513
  AND COALESCE(is_deleted, 0) = 0 AND visibility != 'archived' AND scope IS NULL
43475
43514
  AND COALESCE(type, '') != 'session_summary' AND content LIKE ?
43476
43515
  ${params.since ? "AND (julianday(created_at) >= julianday(?) OR julianday(created_at) < julianday(?))" : ""}
43477
- ${params.before ? "AND julianday(created_at) <= julianday(?)" : ""}`,
43478
- args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
43516
+ ${params.before ? "AND julianday(created_at) <= julianday(?)" : ""}
43517
+ ${deliveredPredicate("memory", "id", "created_at", "''", "created_at")}`,
43518
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs, ...deliveredArgs]
43479
43519
  });
43480
43520
  }
43481
43521
  if (params.kind === undefined || params.kind === "artifact") {
@@ -43486,15 +43526,17 @@ function searchEpisodicSources(db, params) {
43486
43526
  AND length(ma.content) > 0 AND ma.content LIKE ?
43487
43527
  ${params.since ? "AND (julianday(ma.captured_at) >= julianday(?) OR julianday(ma.captured_at) < julianday(?))" : ""}
43488
43528
  ${params.before ? "AND julianday(ma.captured_at) <= julianday(?)" : ""}
43529
+ ${deliveredPredicate("artifact", "ma.source_path", "ma.captured_at", "COALESCE(ma.source_id, '')", "CASE WHEN ma.source_sha256 IS NULL OR ma.source_sha256 = '' THEN ma.captured_at ELSE ma.source_sha256 END")}
43489
43530
  AND (ma.source_sha256 IS NULL OR ma.source_sha256 = ''
43490
43531
  OR (ma.agent_id, ma.source_path) = (
43491
43532
  SELECT ma2.agent_id, ma2.source_path FROM memory_artifacts ma2
43492
43533
  WHERE ma2.agent_id = ma.agent_id AND COALESCE(ma2.is_deleted, 0) = 0
43493
43534
  AND ma2.source_sha256 = ma.source_sha256
43535
+ AND COALESCE(ma2.source_id, '') = COALESCE(ma.source_id, '')
43494
43536
  ORDER BY ma2.captured_at DESC, ma2.source_path ASC
43495
43537
  LIMIT 1
43496
43538
  ))`,
43497
- args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
43539
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs, ...deliveredArgs]
43498
43540
  });
43499
43541
  }
43500
43542
  if (params.kind === undefined || params.kind === "transcript") {
@@ -43503,8 +43545,9 @@ function searchEpisodicSources(db, params) {
43503
43545
  FROM session_transcripts
43504
43546
  WHERE agent_id = ? AND ${transcriptCompleted} AND content LIKE ?
43505
43547
  ${params.since ? `AND (julianday(${transcriptSearchTime}) >= julianday(?) OR julianday(${transcriptSearchTime}) < julianday(?))` : ""}
43506
- ${params.before ? `AND julianday(${transcriptSearchTime}) <= julianday(?)` : ""}`,
43507
- args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
43548
+ ${params.before ? `AND julianday(${transcriptSearchTime}) <= julianday(?)` : ""}
43549
+ ${deliveredPredicate("transcript", "session_key", transcriptSearchTime, "''", transcriptSearchTime)}`,
43550
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs, ...deliveredArgs]
43508
43551
  });
43509
43552
  }
43510
43553
  if (params.kind === "summary") {
@@ -43515,8 +43558,9 @@ function searchEpisodicSources(db, params) {
43515
43558
  AND COALESCE(source_type, 'summary') IN ('summary', 'compaction', 'checkpoint')
43516
43559
  AND content LIKE ?
43517
43560
  ${params.since ? "AND (julianday(latest_at) >= julianday(?) OR julianday(latest_at) < julianday(?))" : ""}
43518
- ${params.before ? "AND julianday(latest_at) <= julianday(?)" : ""}`,
43519
- args: [params.agentId, like, ...sinceArgs, ...beforeArgs]
43561
+ ${params.before ? "AND julianday(latest_at) <= julianday(?)" : ""}
43562
+ ${deliveredPredicate("summary", "id", "latest_at", "''", "latest_at")}`,
43563
+ args: [params.agentId, like, ...sinceArgs, ...beforeArgs, ...deliveredArgs]
43520
43564
  });
43521
43565
  }
43522
43566
  const union3 = branches.map((branch) => branch.sql).join(`
@@ -44100,6 +44144,91 @@ function createDreamingAgentEvidence(evidence) {
44100
44144
  });
44101
44145
  }
44102
44146
 
44147
+ // ../../platform/daemon/src/pipeline/dreaming-evidence-consumption.ts
44148
+ function tableExists6(db, table) {
44149
+ return db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(table) != null;
44150
+ }
44151
+ function tableHasColumn2(db, table, column) {
44152
+ try {
44153
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
44154
+ return rows.some((row) => row.name === column);
44155
+ } catch {
44156
+ return false;
44157
+ }
44158
+ }
44159
+ function sourceIdentity(source) {
44160
+ return source.sourceEntryId ?? "";
44161
+ }
44162
+ function sourceRevision(source) {
44163
+ return source.sourceRevision ?? source.capturedAt;
44164
+ }
44165
+ function deliveredOffsetForSource(db, agentId, source) {
44166
+ if (!tableExists6(db, "dreaming_evidence_consumption"))
44167
+ return 0;
44168
+ const row = db.prepare(`SELECT delivered_offset AS deliveredOffset FROM dreaming_evidence_consumption
44169
+ WHERE agent_id = ? AND source_kind = ? AND source_id = ? AND source_captured_at = ? AND source_entry_id = ? AND source_revision = ?`).get(agentId, source.kind, source.id, source.capturedAt, sourceIdentity(source), sourceRevision(source));
44170
+ return Math.max(0, row?.deliveredOffset ?? 0);
44171
+ }
44172
+ function pendingDreamingEvidenceContinuations(db, agentId, limit, kind) {
44173
+ if (!tableExists6(db, "dreaming_evidence_consumption"))
44174
+ return [];
44175
+ const boundedLimit = Math.min(Math.max(Math.floor(limit), 1), 50);
44176
+ const transcriptUpdatedAt = tableHasColumn2(db, "session_transcripts", "updated_at") ? "st.updated_at" : "NULL";
44177
+ const transcriptCompletedAt = tableHasColumn2(db, "session_transcripts", "completed_at") ? "st.completed_at" : "NULL";
44178
+ const transcriptRevision = `COALESCE(${transcriptCompletedAt}, ${transcriptUpdatedAt}, st.created_at)`;
44179
+ const rows = db.prepare(`SELECT dec.source_kind AS kind, dec.source_id AS id, dec.source_captured_at AS capturedAt,
44180
+ dec.source_entry_id AS sourceEntryId, dec.source_revision AS sourceRevision
44181
+ FROM dreaming_evidence_consumption dec
44182
+ INNER JOIN dreaming_passes pass ON pass.id = dec.pass_id AND pass.agent_id = dec.agent_id
44183
+ WHERE dec.agent_id = ?
44184
+ AND dec.delivered_offset > 0 AND dec.delivered_offset < dec.source_length
44185
+ AND (? IS NULL OR dec.source_kind = ?)
44186
+ AND (
44187
+ (dec.source_kind = 'memory' AND EXISTS (
44188
+ SELECT 1 FROM memories m
44189
+ WHERE m.agent_id = dec.agent_id AND m.id = dec.source_id
44190
+ AND m.memory_kind = 'episodic' AND COALESCE(m.is_deleted, 0) = 0
44191
+ AND m.visibility != 'archived' AND m.scope IS NULL
44192
+ AND COALESCE(m.type, '') != 'session_summary'
44193
+ AND dec.source_captured_at = m.created_at AND dec.source_entry_id = ''
44194
+ AND dec.source_revision = m.created_at
44195
+ ))
44196
+ OR (dec.source_kind = 'artifact' AND EXISTS (
44197
+ SELECT 1 FROM memory_artifacts ma
44198
+ WHERE ma.agent_id = dec.agent_id AND ma.source_path = dec.source_id
44199
+ AND COALESCE(ma.is_deleted, 0) = 0 AND length(ma.content) > 0
44200
+ AND dec.source_captured_at = ma.captured_at
44201
+ AND dec.source_entry_id = COALESCE(ma.source_id, '')
44202
+ AND dec.source_revision = CASE
44203
+ WHEN ma.source_sha256 IS NULL OR ma.source_sha256 = '' THEN ma.captured_at
44204
+ ELSE ma.source_sha256
44205
+ END
44206
+ ))
44207
+ OR (dec.source_kind = 'transcript' AND EXISTS (
44208
+ SELECT 1 FROM session_transcripts st
44209
+ WHERE st.agent_id = dec.agent_id AND st.session_key = dec.source_id
44210
+ AND dec.source_captured_at = ${transcriptRevision}
44211
+ AND dec.source_entry_id = '' AND dec.source_revision = ${transcriptRevision}
44212
+ ))
44213
+ OR (dec.source_kind = 'summary' AND EXISTS (
44214
+ SELECT 1 FROM session_summaries ss
44215
+ WHERE ss.agent_id = dec.agent_id AND ss.id = dec.source_id
44216
+ AND ss.depth = 0
44217
+ AND COALESCE(ss.source_type, 'summary') IN ('summary', 'compaction', 'checkpoint')
44218
+ AND dec.source_captured_at = ss.latest_at
44219
+ AND dec.source_entry_id = '' AND dec.source_revision = ss.latest_at
44220
+ ))
44221
+ )
44222
+ ORDER BY pass.rowid ASC, dec.source_kind ASC, dec.source_id ASC, dec.source_captured_at ASC
44223
+ LIMIT ?`).all(agentId, kind ?? null, kind ?? null, boundedLimit);
44224
+ return rows.flatMap((row) => {
44225
+ const source = readEpisodicSource(db, { agentId, from: `${row.kind}:${row.id}` });
44226
+ if (source === null || source.capturedAt !== row.capturedAt || sourceIdentity(source) !== row.sourceEntryId || sourceRevision(source) !== row.sourceRevision)
44227
+ return [];
44228
+ return [source];
44229
+ });
44230
+ }
44231
+
44103
44232
  // ../../node_modules/.bun/js-tiktoken@1.0.21/node_modules/js-tiktoken/dist/chunk-VL2OQCWN.js
44104
44233
  var import_base64_js = __toESM(require_base64_js(), 1);
44105
44234
  var __defProp3 = Object.defineProperty;
@@ -46021,11 +46150,22 @@ function requireStrictEpisodicSourceRefInTx(db, agentId, sourceRef) {
46021
46150
  }
46022
46151
  throw new OntologyProposalError(`Evidence source_ref was not found: ${resolved.sourceRef}`, 409);
46023
46152
  }
46153
+ function isDreamingAttentionEvidenceInTx(db, agentId, value) {
46154
+ const sourceRef = typeof value.source_ref === "string" ? value.source_ref.trim() : "";
46155
+ const sourceId = typeof value.source_id === "string" ? value.source_id.trim() : "";
46156
+ if (value.source_kind !== "attention" || value.source_root !== "dreaming_attention" || !/^attention:(?:\$\d+|[^:]+)$/.test(sourceRef) || sourceId.length === 0) {
46157
+ return false;
46158
+ }
46159
+ const row = db.prepare("SELECT id FROM dreaming_attention WHERE id = ? AND agent_id = ?").get(sourceId, agentId);
46160
+ return row !== undefined;
46161
+ }
46024
46162
  function validateProposalEvidenceSourcesInTx(db, agentId, evidence) {
46025
46163
  for (const value of evidence) {
46026
46164
  const ref3 = readOntologyEvidenceRef(value);
46027
46165
  if (ref3 === null || !isRecord3(ref3.reference) || !("source_ref" in ref3.reference))
46028
46166
  continue;
46167
+ if (isDreamingAttentionEvidenceInTx(db, agentId, ref3.reference))
46168
+ continue;
46029
46169
  requireStrictEpisodicSourceRefInTx(db, agentId, ref3.reference.source_ref);
46030
46170
  }
46031
46171
  }
@@ -46074,6 +46214,8 @@ function derivedMemorySourcesForProposalInTx(db, proposal) {
46074
46214
  const evidence = ref3.reference;
46075
46215
  if (!("source_ref" in evidence))
46076
46216
  continue;
46217
+ if (isDreamingAttentionEvidenceInTx(db, proposal.agent_id, evidence))
46218
+ continue;
46077
46219
  const source = requireStrictEpisodicSourceRefInTx(db, proposal.agent_id, evidence.source_ref);
46078
46220
  sources.push({
46079
46221
  sourceKind: source.kind,
@@ -47580,7 +47722,113 @@ var DREAMING_ONTOLOGY_OPERATION_SCHEMA = exports_external.discriminatedUnion("op
47580
47722
  operation("decline_attention")
47581
47723
  ]);
47582
47724
 
47725
+ // ../../platform/daemon/src/system-pressure.ts
47726
+ var CLEAR_COOLDOWN_MS = 5000;
47727
+ var currentLevel = "normal";
47728
+ var lastLagAt = 0;
47729
+ var startupGraceUntil = 0;
47730
+ var recoveryOutcome = "not_observed";
47731
+ var EVENT_LOOP_WEDGE_COOLDOWN_MS = 10 * 60 * 1000;
47732
+ function tickPressureState() {
47733
+ const now2 = Date.now();
47734
+ if (startupGraceUntil !== 0 && now2 >= startupGraceUntil) {
47735
+ startupGraceUntil = 0;
47736
+ }
47737
+ if (currentLevel !== "normal" && now2 >= startupGraceUntil && now2 - lastLagAt > CLEAR_COOLDOWN_MS) {
47738
+ currentLevel = "normal";
47739
+ recoveryOutcome = "recovered";
47740
+ }
47741
+ }
47742
+ function getSystemPressure() {
47743
+ return currentLevel;
47744
+ }
47745
+ function isSystemPressureHigh() {
47746
+ return currentLevel !== "normal";
47747
+ }
47748
+ async function awaitPressureClear(timeoutMs = 30000) {
47749
+ if (currentLevel === "normal")
47750
+ return true;
47751
+ const deadline = Date.now() + timeoutMs;
47752
+ while (Date.now() < deadline) {
47753
+ await new Promise((resolve) => setTimeout(resolve, 500));
47754
+ tickPressureState();
47755
+ if (getSystemPressure() === "normal")
47756
+ return true;
47757
+ }
47758
+ recoveryOutcome = "still_degraded";
47759
+ logger.warn("system-pressure", `Pressure did not clear within ${timeoutMs}ms — proceeding`);
47760
+ return false;
47761
+ }
47762
+
47763
+ // ../../platform/daemon/src/yielding-writes.ts
47764
+ var yieldToEventLoop = () => new Promise((resolve) => setTimeout(resolve, 0));
47765
+ async function writeBatch(accessor, processBatch) {
47766
+ if (accessor.withWriteTxAsync) {
47767
+ return accessor.withWriteTxAsync(processBatch);
47768
+ }
47769
+ return accessor.withWriteTx(processBatch);
47770
+ }
47771
+ async function runWriteBatches(accessor, items, processItem, options) {
47772
+ const maxPerTx = typeof options.maxPerTx === "number" && Number.isFinite(options.maxPerTx) ? Math.max(1, Math.floor(options.maxPerTx)) : 50;
47773
+ const maxTxDurationMs = typeof options.maxTxDurationMs === "number" && Number.isFinite(options.maxTxDurationMs) ? Math.max(1, options.maxTxDurationMs) : Number.POSITIVE_INFINITY;
47774
+ const yieldEvery = typeof options.yieldEvery === "number" && Number.isFinite(options.yieldEvery) ? Math.max(1, Math.floor(options.yieldEvery)) : 1;
47775
+ const maxTotal = Math.min(items.length, typeof options.maxTotal === "number" && Number.isFinite(options.maxTotal) ? Math.max(0, Math.floor(options.maxTotal)) : items.length);
47776
+ const results = [];
47777
+ let processed = 0;
47778
+ let batches = 0;
47779
+ let paused = 0;
47780
+ while (processed < maxTotal) {
47781
+ if (!options.skipPressure && isSystemPressureHigh()) {
47782
+ paused++;
47783
+ await awaitPressureClear();
47784
+ }
47785
+ let batch;
47786
+ try {
47787
+ batch = await writeBatch(accessor, (db) => {
47788
+ const startedAt = performance.now();
47789
+ const batchResults = [];
47790
+ for (const item of items.slice(processed, maxTotal)) {
47791
+ batchResults.push(processItem(db, item));
47792
+ if (batchResults.length >= maxPerTx)
47793
+ break;
47794
+ if (performance.now() - startedAt >= maxTxDurationMs)
47795
+ break;
47796
+ }
47797
+ return batchResults;
47798
+ });
47799
+ } catch (error51) {
47800
+ const message = error51 instanceof Error ? error51.message : String(error51);
47801
+ logger.warn("yielding-writes", `${options.label}: write batch failed after ${processed} committed items`, {
47802
+ processed,
47803
+ batches,
47804
+ error: message
47805
+ });
47806
+ return { items: results, processed, batches, paused, stopped: "failed", error: message };
47807
+ }
47808
+ if (batch.length === 0)
47809
+ throw new Error(`${options.label}: write batch made no progress`);
47810
+ results.push(...batch);
47811
+ processed += batch.length;
47812
+ batches++;
47813
+ if (batches % yieldEvery === 0)
47814
+ await yieldToEventLoop();
47815
+ }
47816
+ if (processed < items.length) {
47817
+ logger.debug("yielding-writes", `${options.label}: hit maxTotal cap (${maxTotal})`, { processed, batches });
47818
+ }
47819
+ return {
47820
+ items: results,
47821
+ processed,
47822
+ batches,
47823
+ paused,
47824
+ stopped: processed < items.length ? "capped" : "exhausted"
47825
+ };
47826
+ }
47827
+
47583
47828
  // ../../platform/daemon/src/pipeline/dreaming-operations.ts
47829
+ var DREAMING_MAX_OPERATIONS_PER_REQUEST = 100;
47830
+ var DREAMING_WRITE_MAX_OPERATIONS_PER_TX = 10;
47831
+ var DREAMING_WRITE_MAX_TX_DURATION_MS = 50;
47584
47832
  var FLAG_OP = "flag";
47585
47833
  var DECLINE_ATTENTION_OP = "decline_attention";
47586
47834
  var HYGIENE_ARCHIVE_OPS = new Set([
@@ -47648,30 +47896,30 @@ function asStringRecord(value) {
47648
47896
  }
47649
47897
  return Object.keys(record5).length > 0 ? record5 : undefined;
47650
47898
  }
47651
- function mintFlags(accessor, agentId, operations) {
47652
- const minted = new Map;
47653
- accessor.withWriteTx((db) => {
47654
- for (let index = 0;index < operations.length; index += 1) {
47655
- const operation2 = operations[index];
47656
- if (operation2.operation !== FLAG_OP)
47657
- continue;
47658
- const subjectRef = typeof operation2.payload.subjectRef === "string" ? operation2.payload.subjectRef.trim() : "";
47659
- if (!subjectRef)
47660
- continue;
47661
- const priority3 = typeof operation2.payload.priority === "number" ? operation2.payload.priority : undefined;
47662
- const attentionId = enqueueDreamingAttentionInTx(db, {
47663
- agentId,
47664
- kind: "hygiene",
47665
- subjectRef,
47666
- details: asStringRecord(operation2.payload.details),
47667
- priority: priority3
47668
- });
47669
- minted.set(index, attentionId);
47670
- }
47899
+ async function mintFlags(accessor, agentId, operations) {
47900
+ const flagged = operations.flatMap((operation2, index) => operation2.operation === FLAG_OP ? [{ index, operation: operation2 }] : []);
47901
+ const result = await runWriteBatches(accessor, flagged, (db, entry) => {
47902
+ const subjectRef = typeof entry.operation.payload.subjectRef === "string" ? entry.operation.payload.subjectRef.trim() : "";
47903
+ if (!subjectRef)
47904
+ return { index: entry.index, attentionId: null };
47905
+ const priority3 = typeof entry.operation.payload.priority === "number" ? entry.operation.payload.priority : undefined;
47906
+ const attentionId = enqueueDreamingAttentionInTx(db, {
47907
+ agentId,
47908
+ kind: "hygiene",
47909
+ subjectRef,
47910
+ details: asStringRecord(entry.operation.payload.details),
47911
+ priority: priority3
47912
+ });
47913
+ return { index: entry.index, attentionId };
47914
+ }, {
47915
+ label: "dreaming attention flags",
47916
+ maxPerTx: DREAMING_MAX_OPERATIONS_PER_REQUEST
47671
47917
  });
47672
- return minted;
47918
+ if (result.stopped === "failed")
47919
+ throw new Error(result.error ?? "Dreaming attention flag write failed");
47920
+ return new Map(result.items.flatMap((entry) => entry.attentionId === null ? [] : [[entry.index, entry.attentionId]]));
47673
47921
  }
47674
- function attentionProvenance(accessor, agentId, operation2, mintedById) {
47922
+ function attentionProvenance(accessor, agentId, operation2, mintedById, operations, operationIndex) {
47675
47923
  const reference = operation2.provenance?.trim();
47676
47924
  if (!reference?.startsWith("attention:"))
47677
47925
  return null;
@@ -47681,7 +47929,10 @@ function attentionProvenance(accessor, agentId, operation2, mintedById) {
47681
47929
  let attention = null;
47682
47930
  const sameBatch = reference.match(/^attention:\$(\d+)$/);
47683
47931
  if (sameBatch !== null) {
47684
- const attentionId = mintedById.get(Number.parseInt(sameBatch[1], 10));
47932
+ const flagIndex = sameBatchFlagIndex(accessor, agentId, operations, operationIndex, operation2);
47933
+ if (flagIndex === null)
47934
+ return null;
47935
+ const attentionId = mintedById.get(flagIndex);
47685
47936
  if (attentionId !== undefined)
47686
47937
  attention = getDreamingAttentionById(accessor, { agentId, id: attentionId });
47687
47938
  } else {
@@ -47691,28 +47942,7 @@ function attentionProvenance(accessor, agentId, operation2, mintedById) {
47691
47942
  }
47692
47943
  if (attention === null || attention.kind !== "hygiene")
47693
47944
  return null;
47694
- let expectedTarget = false;
47695
- if (operation2.operation === "archive_entity") {
47696
- expectedTarget = pinnedTarget(payload2, attention, "entity:", "entityId");
47697
- } else if (operation2.operation === "archive_aspect") {
47698
- expectedTarget = pinnedTarget(payload2, attention, "aspect:", "aspectId");
47699
- } else if (operation2.operation === "archive_claim_value") {
47700
- expectedTarget = pinnedTarget(payload2, attention, "attribute:", "attributeId");
47701
- } else if (operation2.operation === "archive_link") {
47702
- expectedTarget = pinnedTarget(payload2, attention, "link:", "linkId");
47703
- } else if (operation2.operation === "merge_entities") {
47704
- const targets = Array.isArray(payload2.targets) ? payload2.targets.filter((value) => typeof value === "string") : [];
47705
- const survivor = typeof payload2.survivor === "string" ? payload2.survivor : "";
47706
- const canonicalName = attention.details.canonicalName ?? pinnedBySubjectRef(attention.subjectRef, "duplicate:") ?? "";
47707
- const groupIds = semanticDuplicateIds(accessor, agentId, canonicalName);
47708
- expectedTarget = canonicalName.length > 0 && attention.subjectRef === `duplicate:${canonicalName}` && groupIds.size > 1 && groupIds.has(survivor) && targets.length >= 2 && targets.every((id) => groupIds.has(id)) && targets.includes(survivor) && targets.some((id) => id !== survivor);
47709
- } else if (operation2.operation === "merge_aspects") {
47710
- const sources = Array.isArray(payload2.sources) ? payload2.sources.filter((value) => typeof value === "string") : [];
47711
- const pinnedAspect = pinnedBySubjectRef(attention.subjectRef, "aspect:");
47712
- const detailAgrees = pinnedAspect !== null && (attention.details.aspectId === undefined || attention.details.aspectId === pinnedAspect);
47713
- expectedTarget = detailAgrees && typeof payload2.target === "string" && sources.length >= 1 && pinnedAspect !== null && sources.includes(pinnedAspect);
47714
- }
47715
- if (!expectedTarget)
47945
+ if (!hasExpectedAttentionTarget(accessor, agentId, operation2, attention))
47716
47946
  return null;
47717
47947
  return {
47718
47948
  provenance: {
@@ -47721,6 +47951,7 @@ function attentionProvenance(accessor, agentId, operation2, mintedById) {
47721
47951
  source_ref: reference,
47722
47952
  source_kind: "attention",
47723
47953
  source_id: attention.id,
47954
+ source_root: "dreaming_attention",
47724
47955
  subject_ref: attention.subjectRef,
47725
47956
  details: attention.details
47726
47957
  }
@@ -47739,6 +47970,81 @@ function pinnedBySubjectRef(subjectRef, prefix) {
47739
47970
  const id = subjectRef.slice(prefix.length);
47740
47971
  return id.length > 0 ? id : null;
47741
47972
  }
47973
+ function hasExpectedAttentionTarget(accessor, agentId, operation2, attention) {
47974
+ const payload2 = operation2.payload;
47975
+ if (operation2.operation === "archive_entity") {
47976
+ return pinnedTarget(payload2, attention, "entity:", "entityId");
47977
+ }
47978
+ if (operation2.operation === "archive_aspect") {
47979
+ return pinnedTarget(payload2, attention, "aspect:", "aspectId");
47980
+ }
47981
+ if (operation2.operation === "archive_claim_value") {
47982
+ return pinnedTarget(payload2, attention, "attribute:", "attributeId");
47983
+ }
47984
+ if (operation2.operation === "archive_link") {
47985
+ return pinnedTarget(payload2, attention, "link:", "linkId");
47986
+ }
47987
+ if (operation2.operation === "merge_entities") {
47988
+ const targets = Array.isArray(payload2.targets) ? payload2.targets.filter((value) => typeof value === "string") : [];
47989
+ const survivor = typeof payload2.survivor === "string" ? payload2.survivor : "";
47990
+ const canonicalName = attention.details.canonicalName ?? pinnedBySubjectRef(attention.subjectRef, "duplicate:") ?? "";
47991
+ const groupIds = semanticDuplicateIds(accessor, agentId, canonicalName);
47992
+ return canonicalName.length > 0 && attention.subjectRef === `duplicate:${canonicalName}` && groupIds.size > 1 && groupIds.has(survivor) && targets.length >= 2 && targets.every((id) => groupIds.has(id)) && targets.includes(survivor) && targets.some((id) => id !== survivor);
47993
+ }
47994
+ if (operation2.operation === "merge_aspects") {
47995
+ const sources = Array.isArray(payload2.sources) ? payload2.sources.filter((value) => typeof value === "string") : [];
47996
+ const pinnedAspect = pinnedBySubjectRef(attention.subjectRef, "aspect:");
47997
+ const detailAgrees = pinnedAspect !== null && (attention.details.aspectId === undefined || attention.details.aspectId === pinnedAspect);
47998
+ return detailAgrees && typeof payload2.target === "string" && sources.length >= 1 && pinnedAspect !== null && sources.includes(pinnedAspect);
47999
+ }
48000
+ return false;
48001
+ }
48002
+ function sameBatchFlagIndex(accessor, agentId, operations, operationIndex, operation2) {
48003
+ const reference = operation2.provenance?.trim();
48004
+ const sameBatch = reference?.match(/^attention:\$(\d+)$/);
48005
+ if (sameBatch === undefined || sameBatch === null)
48006
+ return null;
48007
+ const indexText = sameBatch[1];
48008
+ if (indexText === undefined)
48009
+ return null;
48010
+ const referencedIndex = Number.parseInt(indexText, 10);
48011
+ if (referencedIndex < 0 || referencedIndex >= operations.length)
48012
+ return null;
48013
+ const referenced = operations[referencedIndex];
48014
+ if (referencedIndex < operationIndex && referenced?.operation === FLAG_OP) {
48015
+ const subjectRef = stringField(referenced.payload, "subjectRef");
48016
+ if (subjectRef === null)
48017
+ return null;
48018
+ const attention = {
48019
+ id: `preflight:${referencedIndex}`,
48020
+ kind: "hygiene",
48021
+ subjectRef,
48022
+ details: asStringRecord(referenced.payload.details) ?? {},
48023
+ priority: 0,
48024
+ createdAt: ""
48025
+ };
48026
+ return hasExpectedAttentionTarget(accessor, agentId, operation2, attention) ? referencedIndex : null;
48027
+ }
48028
+ for (let index = operationIndex - 1;index >= 0; index -= 1) {
48029
+ const candidate = operations[index];
48030
+ if (candidate?.operation !== FLAG_OP)
48031
+ continue;
48032
+ const subjectRef = stringField(candidate.payload, "subjectRef");
48033
+ if (subjectRef === null)
48034
+ continue;
48035
+ const attention = {
48036
+ id: `continuation:${index}`,
48037
+ kind: "hygiene",
48038
+ subjectRef,
48039
+ details: asStringRecord(candidate.payload.details) ?? {},
48040
+ priority: 0,
48041
+ createdAt: ""
48042
+ };
48043
+ if (hasExpectedAttentionTarget(accessor, agentId, operation2, attention))
48044
+ return index;
48045
+ }
48046
+ return null;
48047
+ }
47742
48048
  function pinnedTarget(payload2, attention, prefix, detailKey) {
47743
48049
  const target2 = typeof payload2.target === "string" ? payload2.target : null;
47744
48050
  const pinned = target2 !== null ? pinnedBySubjectRef(attention.subjectRef, prefix) : null;
@@ -47920,6 +48226,47 @@ function toApplicatorPayload(accessor, agentId, operation2, payload2) {
47920
48226
  return payload2;
47921
48227
  }
47922
48228
  }
48229
+ function validateRequestBeforeWrites(params) {
48230
+ for (const [index, operation2] of params.operations.entries()) {
48231
+ if (operation2.operation === FLAG_OP) {
48232
+ if (stringField(operation2.payload, "subjectRef") === null)
48233
+ return "flag requires payload.subjectRef";
48234
+ continue;
48235
+ }
48236
+ if (operation2.operation === DECLINE_ATTENTION_OP) {
48237
+ const attentionId = stringField(operation2.payload, "attentionId");
48238
+ if (attentionId === null)
48239
+ return "decline_attention requires payload.attentionId";
48240
+ const pending = params.accessor.withReadDb((db) => db.prepare(`SELECT 1 FROM dreaming_attention
48241
+ WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).get(attentionId, params.agentId));
48242
+ if (pending == null)
48243
+ return "Attention record is not pending in this agent scope";
48244
+ continue;
48245
+ }
48246
+ if (toApplicatorPayload(params.accessor, params.agentId, operation2.operation, operation2.payload) === null) {
48247
+ return `Could not resolve operation target: ${operation2.operation}`;
48248
+ }
48249
+ if (HYGIENE_ARCHIVE_OPS.has(operation2.operation)) {
48250
+ const reference = operation2.provenance?.trim();
48251
+ const sameBatch = reference?.match(/^attention:\$(\d+)$/);
48252
+ if (sameBatch) {
48253
+ if (sameBatchFlagIndex(params.accessor, params.agentId, params.operations, index, operation2) === null) {
48254
+ return "Hygiene archives require attention provenance (attention:$<index> or attention:<uuid>)";
48255
+ }
48256
+ continue;
48257
+ }
48258
+ if (attentionProvenance(params.accessor, params.agentId, operation2, new Map, params.operations, index) === null) {
48259
+ return "Hygiene archives require attention provenance (attention:$<index> or attention:<uuid>)";
48260
+ }
48261
+ continue;
48262
+ }
48263
+ const evidenceResult = provenanceForEvidence(params.accessor, params.agentId, operation2);
48264
+ if (evidenceResult.provenance === null) {
48265
+ return evidenceResult.scopeMismatch ?? "Every operation must cite an exact quote from scoped episodic evidence";
48266
+ }
48267
+ }
48268
+ return null;
48269
+ }
47923
48270
  function existingReviewProposalId(db, params) {
47924
48271
  const row = db.prepare(`SELECT id FROM ontology_proposals
47925
48272
  WHERE agent_id = ? AND operation = ? AND status IN ('pending', 'applied', 'rejected')
@@ -47927,9 +48274,118 @@ function existingReviewProposalId(db, params) {
47927
48274
  ORDER BY updated_at DESC LIMIT 1`).get(params.agentId, params.operation, JSON.stringify(params.payload), JSON.stringify(params.evidence));
47928
48275
  return typeof row?.id === "string" ? row.id : null;
47929
48276
  }
47930
- function applyDreamingOperations(params) {
48277
+ function applyValidatedOperationBody(db, entry, params) {
48278
+ if (entry.input === null) {
48279
+ if (entry.decline === true && entry.attentionId !== null) {
48280
+ const pending = db.prepare(`SELECT 1 FROM dreaming_attention
48281
+ WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).get(entry.attentionId, params.agentId);
48282
+ if (pending == null) {
48283
+ return {
48284
+ index: entry.index,
48285
+ ok: false,
48286
+ error: "Attention record is not pending in this agent scope"
48287
+ };
48288
+ }
48289
+ db.prepare(`UPDATE dreaming_attention
48290
+ SET resolved_at = datetime('now'), resolved_by_pass_id = ?
48291
+ WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).run(params.passId ?? null, entry.attentionId, params.agentId);
48292
+ return { index: entry.index, ok: true, result: { attentionId: entry.attentionId } };
48293
+ }
48294
+ return { index: entry.index, ok: true, result: { attentionId: entry.attentionId } };
48295
+ }
48296
+ if (entry.reviewOnly) {
48297
+ const existingId = existingReviewProposalId(db, {
48298
+ agentId: params.agentId,
48299
+ operation: entry.input.operation,
48300
+ payload: entry.input.payload,
48301
+ evidence: entry.input.evidence ?? []
48302
+ });
48303
+ if (existingId !== null) {
48304
+ return {
48305
+ index: entry.index,
48306
+ ok: true,
48307
+ result: { reviewRequired: true, deduped: true, proposalId: existingId }
48308
+ };
48309
+ }
48310
+ const created = createOntologyProposalsInTx(db, [
48311
+ {
48312
+ agentId: params.agentId,
48313
+ operation: entry.input.operation,
48314
+ payload: entry.input.payload,
48315
+ confidence: entry.input.confidence,
48316
+ rationale: entry.input.reason,
48317
+ evidence: entry.input.evidence,
48318
+ risk: entry.input.risk,
48319
+ sourceKind: entry.input.sourceKind,
48320
+ sourceId: entry.input.sourceId,
48321
+ sourcePath: entry.input.sourcePath,
48322
+ sourceRoot: entry.input.sourceRoot,
48323
+ createdBy: params.actor
48324
+ }
48325
+ ]);
48326
+ return {
48327
+ index: entry.index,
48328
+ ok: true,
48329
+ proposal: created.items[0],
48330
+ result: { reviewRequired: true }
48331
+ };
48332
+ }
48333
+ if (entry.attentionId !== null) {
48334
+ const pending = db.prepare(`SELECT 1 FROM dreaming_attention
48335
+ WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).get(entry.attentionId, params.agentId);
48336
+ if (pending == null) {
48337
+ return {
48338
+ index: entry.index,
48339
+ ok: false,
48340
+ error: "Attention already consumed by an earlier operation in this batch"
48341
+ };
48342
+ }
48343
+ }
48344
+ const batch = applyOntologyOperationBatchInTx(db, {
48345
+ agentId: params.agentId,
48346
+ actor: params.actor,
48347
+ operations: [entry.input],
48348
+ writeCaps: params.writeCaps
48349
+ });
48350
+ if (entry.attentionId !== null) {
48351
+ db.prepare(`UPDATE dreaming_attention
48352
+ SET resolved_at = datetime('now'), resolved_by_pass_id = ?
48353
+ WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).run(params.passId ?? null, entry.attentionId, params.agentId);
48354
+ }
48355
+ return {
48356
+ index: entry.index,
48357
+ ok: true,
48358
+ proposal: batch.items[0]?.proposal,
48359
+ result: batch.items[0]?.result
48360
+ };
48361
+ }
48362
+ function applyValidatedOperationInTx(db, entry, params) {
48363
+ const savepoint = `signet_dream_op_${entry.index}`;
48364
+ db.exec(`SAVEPOINT ${savepoint}`);
48365
+ try {
48366
+ const result = applyValidatedOperationBody(db, entry, params);
48367
+ db.exec(`RELEASE SAVEPOINT ${savepoint}`);
48368
+ return result;
48369
+ } catch (error51) {
48370
+ db.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);
48371
+ db.exec(`RELEASE SAVEPOINT ${savepoint}`);
48372
+ return {
48373
+ index: entry.index,
48374
+ ok: false,
48375
+ error: error51 instanceof Error ? error51.message : String(error51)
48376
+ };
48377
+ }
48378
+ }
48379
+ async function applyDreamingOperations(params) {
47931
48380
  if (params.operations.length === 0)
47932
48381
  return { ok: false, items: [], error: "operations are required" };
48382
+ if (params.operations.length > DREAMING_MAX_OPERATIONS_PER_REQUEST) {
48383
+ return {
48384
+ ok: false,
48385
+ items: [],
48386
+ error: `operations cannot exceed ${DREAMING_MAX_OPERATIONS_PER_REQUEST} items`
48387
+ };
48388
+ }
47933
48389
  const allowedOperations = new Set(DREAMING_OPERATION_IDS);
47934
48390
  for (const operation2 of params.operations) {
47935
48391
  if (!allowedOperations.has(operation2.operation)) {
@@ -47939,13 +48395,15 @@ function applyDreamingOperations(params) {
47939
48395
  return { ok: false, items: [], error: "confidence must be a finite number between 0 and 1" };
47940
48396
  }
47941
48397
  }
47942
- const minted = mintFlags(params.accessor, params.agentId, params.operations);
48398
+ const validationError = validateRequestBeforeWrites(params);
48399
+ if (validationError !== null)
48400
+ return { ok: false, items: [], error: validationError };
48401
+ const minted = await mintFlags(params.accessor, params.agentId, params.operations);
47943
48402
  const validated = [];
47944
- for (let index = 0;index < params.operations.length; index += 1) {
47945
- const operation2 = params.operations[index];
48403
+ for (const [index, operation2] of params.operations.entries()) {
47946
48404
  if (operation2.operation === FLAG_OP) {
47947
48405
  const attentionId2 = minted.get(index) ?? null;
47948
- validated.push({ input: null, attentionId: attentionId2 });
48406
+ validated.push({ index, input: null, attentionId: attentionId2 });
47949
48407
  continue;
47950
48408
  }
47951
48409
  if (operation2.operation === DECLINE_ATTENTION_OP) {
@@ -47953,13 +48411,13 @@ function applyDreamingOperations(params) {
47953
48411
  if (attentionId2 === null) {
47954
48412
  return { ok: false, items: [], error: "decline_attention requires payload.attentionId" };
47955
48413
  }
47956
- validated.push({ input: null, attentionId: attentionId2, decline: true });
48414
+ validated.push({ index, input: null, attentionId: attentionId2, decline: true });
47957
48415
  continue;
47958
48416
  }
47959
48417
  let provenance = null;
47960
48418
  let attentionId = null;
47961
48419
  if (HYGIENE_ARCHIVE_OPS.has(operation2.operation)) {
47962
- const resolved = attentionProvenance(params.accessor, params.agentId, operation2, minted);
48420
+ const resolved = attentionProvenance(params.accessor, params.agentId, operation2, minted, params.operations, index);
47963
48421
  if (resolved !== null) {
47964
48422
  provenance = resolved.provenance;
47965
48423
  attentionId = resolved.attentionId;
@@ -47987,6 +48445,7 @@ function applyDreamingOperations(params) {
47987
48445
  return { ok: false, items: [], error: `Could not resolve operation target: ${operation2.operation}` };
47988
48446
  }
47989
48447
  validated.push({
48448
+ index,
47990
48449
  input: {
47991
48450
  operation: operation2.operation,
47992
48451
  payload: payload2,
@@ -48003,101 +48462,21 @@ function applyDreamingOperations(params) {
48003
48462
  reviewOnly: operation2.risk === "review_required" && !HYGIENE_ARCHIVE_OPS.has(operation2.operation)
48004
48463
  });
48005
48464
  }
48006
- const items = [];
48007
- params.accessor.withWriteTx((db) => {
48008
- for (let index = 0;index < validated.length; index += 1) {
48009
- const entry = validated[index];
48010
- if (entry.input === null) {
48011
- if (entry.decline === true && entry.attentionId !== null) {
48012
- const pending = db.prepare(`SELECT 1 FROM dreaming_attention
48013
- WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).get(entry.attentionId, params.agentId);
48014
- if (pending == null) {
48015
- items.push({
48016
- index,
48017
- ok: false,
48018
- error: "Attention record is not pending in this agent scope"
48019
- });
48020
- continue;
48021
- }
48022
- db.prepare(`UPDATE dreaming_attention
48023
- SET resolved_at = datetime('now'), resolved_by_pass_id = ?
48024
- WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).run(params.passId ?? null, entry.attentionId, params.agentId);
48025
- items.push({ index, ok: true, result: { attentionId: entry.attentionId } });
48026
- continue;
48027
- }
48028
- items.push({ index, ok: true, result: { attentionId: entry.attentionId } });
48029
- continue;
48030
- }
48031
- if (entry.reviewOnly) {
48032
- const existingId = existingReviewProposalId(db, {
48033
- agentId: params.agentId,
48034
- operation: entry.input.operation,
48035
- payload: entry.input.payload,
48036
- evidence: entry.input.evidence ?? []
48037
- });
48038
- if (existingId !== null) {
48039
- items.push({ index, ok: true, result: { reviewRequired: true, deduped: true, proposalId: existingId } });
48040
- continue;
48041
- }
48042
- const created = createOntologyProposalsInTx(db, [
48043
- {
48044
- agentId: params.agentId,
48045
- operation: entry.input.operation,
48046
- payload: entry.input.payload,
48047
- confidence: entry.input.confidence,
48048
- rationale: entry.input.reason,
48049
- evidence: entry.input.evidence,
48050
- risk: entry.input.risk,
48051
- sourceKind: entry.input.sourceKind,
48052
- sourceId: entry.input.sourceId,
48053
- sourcePath: entry.input.sourcePath,
48054
- sourceRoot: entry.input.sourceRoot,
48055
- createdBy: params.actor
48056
- }
48057
- ]);
48058
- items.push({
48059
- index,
48060
- ok: true,
48061
- proposal: created.items[0],
48062
- result: { reviewRequired: true }
48063
- });
48064
- continue;
48065
- }
48066
- if (entry.attentionId !== null) {
48067
- const pending = db.prepare(`SELECT 1 FROM dreaming_attention
48068
- WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).get(entry.attentionId, params.agentId);
48069
- if (pending == null) {
48070
- items.push({
48071
- index,
48072
- ok: false,
48073
- error: "Attention already consumed by an earlier operation in this batch"
48074
- });
48075
- continue;
48076
- }
48077
- }
48078
- const savepoint = `signet_dream_op_${index}`;
48079
- db.exec(`SAVEPOINT ${savepoint}`);
48080
- try {
48081
- const batch = applyOntologyOperationBatchInTx(db, {
48082
- agentId: params.agentId,
48083
- actor: params.actor,
48084
- operations: [entry.input],
48085
- writeCaps: params.writeCaps
48086
- });
48087
- db.exec(`RELEASE SAVEPOINT ${savepoint}`);
48088
- if (entry.attentionId !== null) {
48089
- db.prepare(`UPDATE dreaming_attention
48090
- SET resolved_at = datetime('now'), resolved_by_pass_id = ?
48091
- WHERE id = ? AND agent_id = ? AND resolved_at IS NULL`).run(params.passId ?? null, entry.attentionId, params.agentId);
48092
- }
48093
- items.push({ index, ok: true, proposal: batch.items[0]?.proposal, result: batch.items[0]?.result });
48094
- } catch (error51) {
48095
- db.exec(`ROLLBACK TO SAVEPOINT ${savepoint}`);
48096
- db.exec(`RELEASE SAVEPOINT ${savepoint}`);
48097
- items.push({ index, ok: false, error: error51 instanceof Error ? error51.message : String(error51) });
48098
- }
48099
- }
48465
+ const result = await runWriteBatches(params.accessor, validated, (db, entry) => applyValidatedOperationInTx(db, entry, params), {
48466
+ label: "dreaming ontology operations",
48467
+ maxPerTx: DREAMING_WRITE_MAX_OPERATIONS_PER_TX,
48468
+ maxTxDurationMs: DREAMING_WRITE_MAX_TX_DURATION_MS
48100
48469
  });
48470
+ const items = result.items;
48471
+ if (result.stopped === "failed") {
48472
+ return {
48473
+ ok: false,
48474
+ items,
48475
+ error: result.error ?? "Dreaming ontology write batch failed",
48476
+ retryFrom: result.processed,
48477
+ retryable: true
48478
+ };
48479
+ }
48101
48480
  const ok = items.some((item) => item.ok);
48102
48481
  return { ok, items, ...ok ? {} : { error: "No ontology operations applied" } };
48103
48482
  }
@@ -48116,6 +48495,24 @@ function parseRecord(value) {
48116
48495
  function parseTextList(value) {
48117
48496
  return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
48118
48497
  }
48498
+ function parseDeferredEvidenceList(value) {
48499
+ if (!Array.isArray(value))
48500
+ return [];
48501
+ const entries = [];
48502
+ for (const item of value) {
48503
+ if (typeof item === "string") {
48504
+ entries.push(item);
48505
+ continue;
48506
+ }
48507
+ if (typeof item !== "object" || item === null || Array.isArray(item))
48508
+ continue;
48509
+ const entry = item;
48510
+ if (typeof entry.agentId === "string" && typeof entry.sourceRef === "string") {
48511
+ entries.push({ agentId: entry.agentId, sourceRef: entry.sourceRef });
48512
+ }
48513
+ }
48514
+ return entries;
48515
+ }
48119
48516
  function parseRunbook(value) {
48120
48517
  const row = parseRecord(value);
48121
48518
  if (!row || typeof row.summary !== "string")
@@ -48123,7 +48520,8 @@ function parseRunbook(value) {
48123
48520
  return {
48124
48521
  summary: row.summary,
48125
48522
  openQuestions: parseTextList(row.openQuestions),
48126
- deferred: parseTextList(row.deferred)
48523
+ deferred: parseTextList(row.deferred),
48524
+ deferredEvidence: parseDeferredEvidenceList(row.deferredEvidence)
48127
48525
  };
48128
48526
  }
48129
48527
  function parseEvidenceWindow(value) {
@@ -48362,6 +48760,7 @@ function projectEvidenceItem(source, content, contentOffset, contentLength) {
48362
48760
  sourceId: source.sourceId,
48363
48761
  sourcePath: source.sourcePath,
48364
48762
  sourceEntryId: source.sourceEntryId,
48763
+ sourceRevision: source.sourceRevision ?? source.capturedAt,
48365
48764
  project: source.project,
48366
48765
  harness: source.harness,
48367
48766
  capturedAt: source.capturedAt
@@ -48570,7 +48969,7 @@ function createDreamingCapabilities(params) {
48570
48969
  }
48571
48970
  return { ok: true, result: getOntologyLinkEvidence(accessor, { agentId: scopeId, id: ref3.id }) };
48572
48971
  }),
48573
- capability("search_evidence", "Search episodic evidence", "Full-text search immutable episodic memories, artifacts, and transcripts in one agent scope. Historical summary records can be requested explicitly with kind=summary, but are not part of the default Dreaming delivery path. Results contain exact bounded excerpts of the rendered evidence with contentOffset/contentLength; use sourceRef for citations, which are validated against the complete canonical source. Each record carries completed: memory, artifact, and summary records are settled captures (true); a transcript is true only after the session-end machinery writes its completion marker, and false while the session is still running — do not file claims from a still-growing transcript, since its states may be contradicted by the session's end. If contentTruncated is true, page exact fragments with the same sourceRef and chunkSize: start at offset=0 when contentHasPrevious is true, then use offset=contentOffset+content.length from the fragment just returned until contentHasNext is false. Omit the query AND since to list the unprocessed window: the listing starts at the scope's evidence watermark (the last pass's surfaced frontier), so the newest unseen sources come first. Narrow with a query if the list is large; pass an explicit earlier since only when you need older history. Artifacts are deduped by content hash: content-identical files across vault paths collapse to one canonical entry.", true, exports_external.object({
48972
+ capability("search_evidence", "Search episodic evidence", "Full-text search immutable episodic memories, artifacts, and transcripts in one agent scope. Historical summary records can be requested explicitly with kind=summary, but are not part of the default Dreaming delivery path. Results contain exact bounded excerpts of the rendered evidence with contentOffset/contentLength; use sourceRef for citations, which are validated against the complete canonical source. Each record carries completed: memory, artifact, and summary records are settled captures (true); a transcript is true only after the session-end machinery writes its completion marker, and false while the session is still running — do not file claims from a still-growing transcript, since its states may be contradicted by the session's end. If contentTruncated is true, page exact fragments with the same sourceRef and chunkSize: start at offset=0 when contentHasPrevious is true, then use offset=contentOffset+content.length from the fragment just returned until contentHasNext is false. Omit query, since, and before to drain the durable delivery queue: it lists every incomplete source revision and resumes at its delivered offset, regardless of time watermark. Narrow with a query if the list is large; pass an explicit earlier since only when you need older history. Artifacts are deduped by content hash: content-identical files across vault paths collapse to one canonical entry.", true, exports_external.object({
48574
48973
  agentId: exports_external.string().min(1),
48575
48974
  query: exports_external.string().optional(),
48576
48975
  since: exports_external.string().optional(),
@@ -48591,16 +48990,23 @@ function createDreamingCapabilities(params) {
48591
48990
  const fragment = projectEvidenceFragment(source, Math.max(0, Math.floor(offset ?? 0)), Math.min(Math.max(Math.floor(chunkSize ?? MAX_EVIDENCE_EXCERPT_CHARS), 1), MAX_EVIDENCE_EXCERPT_CHARS));
48592
48991
  return fragment === null ? { ok: false, error: "Evidence fragment offset is outside the source" } : { ok: true, items: [fragment] };
48593
48992
  }
48594
- const effectiveSince = since ?? readEvidenceWatermark(db, scopeId);
48595
- const sources = searchEpisodicSources(db, {
48993
+ const scanFirst = query === undefined && since === undefined && before === undefined;
48994
+ const effectiveSince = scanFirst ? undefined : since ?? readEvidenceWatermark(db, scopeId) ?? undefined;
48995
+ const continuations = scanFirst ? pendingDreamingEvidenceContinuations(db, scopeId, limit ?? 20, kind) : [];
48996
+ const sources = continuations.length > 0 ? continuations : searchEpisodicSources(db, {
48596
48997
  agentId: scopeId,
48597
48998
  query: query ?? "",
48598
- since: effectiveSince ?? undefined,
48999
+ since: effectiveSince,
48599
49000
  before,
48600
49001
  kind,
49002
+ excludeDelivered: scanFirst,
48601
49003
  limit
48602
49004
  });
48603
- return { ok: true, items: projectEvidence(sources, query ?? "") };
49005
+ const items = scanFirst ? sources.flatMap((source) => {
49006
+ const fragment = projectEvidenceFragment(source, deliveredOffsetForSource(db, scopeId, source), MAX_EVIDENCE_EXCERPT_CHARS);
49007
+ return fragment === null ? [] : [fragment];
49008
+ }) : projectEvidence(sources, query ?? "");
49009
+ return { ok: true, items };
48604
49010
  })),
48605
49011
  capability("validate_proposal", "Validate proposal", "Run the daemon's deterministic pre-write guards in one pass for one agent scope: entity-label gate, duplicate-entity check, and/or contradiction check against active aspect values.", true, exports_external.object({
48606
49012
  agentId: exports_external.string().min(1),
@@ -48656,10 +49062,17 @@ function createDreamingCapabilities(params) {
48656
49062
  })
48657
49063
  })),
48658
49064
  capability("runbook_read", "Read Dreaming runbook", "Read recent scoped pass outcomes, evidence windows, quarantines, and structured runbook notes.", true, exports_external.object({ limit: exports_external.number().finite().optional() }), async ({ limit }) => ({ ok: true, items: readDreamingRunbook(accessor, agentId, bounded(limit, 5, 20)) })),
48659
- capability("runbook_write", "Write Dreaming runbook", "Before finishing a Dreaming pass, store one short structured note for future passes to review.", false, exports_external.object({
49065
+ capability("runbook_write", "Write Dreaming runbook", "Before finishing a Dreaming pass, store one short structured note for future passes to review. Deferred evidence in another scope must include its agentId.", false, exports_external.object({
48660
49066
  summary: exports_external.string().trim().min(1).max(2000),
48661
49067
  openQuestions: exports_external.array(exports_external.string().trim().min(1).max(500)).max(20).default([]),
48662
- deferred: exports_external.array(exports_external.string().trim().min(1).max(500)).max(20).default([])
49068
+ deferred: exports_external.array(exports_external.string().trim().min(1).max(500)).max(20).default([]),
49069
+ deferredEvidence: exports_external.array(exports_external.union([
49070
+ exports_external.string().regex(/^(memory|artifact|transcript|summary):.+$/),
49071
+ exports_external.object({
49072
+ agentId: exports_external.string().trim().min(1),
49073
+ sourceRef: exports_external.string().regex(/^(memory|artifact|transcript|summary):.+$/)
49074
+ })
49075
+ ])).max(20).default([])
48663
49076
  }), async (entry) => {
48664
49077
  if (!params.passId)
48665
49078
  return { ok: false, error: "Runbook writes require a live Dreaming pass" };
@@ -48717,12 +49130,12 @@ function createDreamingCapabilities(params) {
48717
49130
  })
48718
49131
  };
48719
49132
  }),
48720
- capability("apply_ontology_ops", "Apply ontology operations", 'Apply every semantic write through the daemon audit seam in one batch, in one agent scope (pass the agentId whose graph you are maintaining — hygiene attention records belong to the agent that flagged them). Ops are processed in array order. Hygiene ops (flag, archive_*, merge_entities) cite provenance: "attention:$<index>" for a flag earlier in the same batch, or "attention:<uuid>" from a prior batch. decline_attention closes a pending attention record you inspected and judged to keep. Content-bearing ops cite evidence with exact quotes from canonical episodic evidence in that scope.', false, exports_external.object({
49133
+ capability("apply_ontology_ops", "Apply ontology operations", 'Apply every semantic write through the daemon audit seam in one ordered request, in one agent scope (pass the agentId whose graph you are maintaining — hygiene attention records belong to the agent that flagged them). The daemon validates every input, citation, and resolvable target before creating flags or applying bounded, yielding writer transactions; each operation and its provenance resolution remains atomic, while an individual operation failure does not block later operations. If a writer transaction fails after earlier transactions committed, the result has `retryable: true` and `retryFrom`; retry only the uncommitted suffix. Do not replay returned items, and replace any earlier `attention:$<index>` references with `attention:<uuid>` built from the flag result `result.attentionId` before retrying. Hygiene ops (flag, archive_*, merge_entities) cite provenance: "attention:$<index>" for a flag earlier in the request, or "attention:<uuid>" from a prior request. decline_attention closes a pending attention record you inspected and judged to keep. Content-bearing ops cite evidence with exact quotes from canonical episodic evidence in that scope.', false, exports_external.object({
48721
49134
  agentId: exports_external.string().min(1),
48722
- operations: exports_external.array(DREAMING_ONTOLOGY_OPERATION_SCHEMA).min(1).max(100)
49135
+ operations: exports_external.array(DREAMING_ONTOLOGY_OPERATION_SCHEMA).min(1).max(DREAMING_MAX_OPERATIONS_PER_REQUEST)
48723
49136
  }), async ({ agentId: scopeId, operations }) => {
48724
49137
  params.onOperationsAboutToApply?.(operations, scopeId);
48725
- const result = applyDreamingOperations({
49138
+ const result = await applyDreamingOperations({
48726
49139
  accessor,
48727
49140
  agentId: scopeId,
48728
49141
  actor,
@@ -48731,7 +49144,13 @@ function createDreamingCapabilities(params) {
48731
49144
  writeCaps: params.writeCaps
48732
49145
  });
48733
49146
  params.onOperationsApplied?.(result, operations, scopeId);
48734
- return { ok: result.ok, ...result.error ? { error: result.error } : {}, items: result.items };
49147
+ return {
49148
+ ok: result.ok,
49149
+ ...result.error ? { error: result.error } : {},
49150
+ ...result.retryable === true ? { retryable: true } : {},
49151
+ ...result.retryFrom !== undefined ? { retryFrom: result.retryFrom } : {},
49152
+ items: result.items
49153
+ };
48735
49154
  })
48736
49155
  ];
48737
49156
  }
@@ -1,43 +1,43 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.199.0",
3
+ "version": "0.199.2",
4
4
  "assets": [
5
5
  {
6
6
  "name": "signet-darwin-arm64",
7
7
  "platform": "darwin-arm64",
8
- "sha256": "ea9e8905de74bf1be6877ca441e8f7052d56c08a466f047ddf2d4932cbc17214",
9
- "size": 125168800
8
+ "sha256": "13d1e9ed36079a4e88f09c9d485cecff247609c291206c848028625dbc21b062",
9
+ "size": 125234848
10
10
  },
11
11
  {
12
12
  "name": "signet-darwin-x64",
13
13
  "platform": "darwin-x64",
14
- "sha256": "cda89090977d67bd8185023b1bf02f819eef55fc2fd7c9a50c03968c00e8234f",
15
- "size": 130157120
14
+ "sha256": "4711bf757ae5e4c8a73d47da9a0473e3007239cdc75d4d23995f3517165c2bed",
15
+ "size": 130206272
16
16
  },
17
17
  {
18
18
  "name": "signet-linux-arm64",
19
19
  "platform": "linux-arm64",
20
- "sha256": "ce4fa4fdc2ab8acab17740274d017b2c29da61fb2ed14e42b6f7fc38945acc3f",
21
- "size": 169724031
20
+ "sha256": "fe2ea2d1c3e81f2d9ef3e865613190a7f7b3757ed0edc2b0033c49e968a4141f",
21
+ "size": 169782828
22
22
  },
23
23
  {
24
24
  "name": "signet-linux-x64",
25
25
  "platform": "linux-x64",
26
- "sha256": "4c90f6ec6eb4942d0d3db53dad4d99fdc6ef6e6940202532738e9371ffb4b95c",
27
- "size": 172098613
26
+ "sha256": "a5bd885fa4ae0635f41360d64a6303038fe61d2fc5e1925e6fd00741ea2a12ab",
27
+ "size": 172157410
28
28
  },
29
29
  {
30
30
  "name": "signet-win32-x64.exe",
31
31
  "platform": "win32-x64",
32
- "sha256": "adcd9a8585b78a2d5fe3451aadfcdc02ac9af2ff421eb049cc64da4b0cdf8352",
33
- "size": 180225024
32
+ "sha256": "ab57a2c94f49c13bef1e93e9e734a61cecfe32c4576c0c013203d6bc80258d5b",
33
+ "size": 180283392
34
34
  }
35
35
  ],
36
36
  "components": {
37
37
  "connectors": {
38
- "url": "signet-connectors-0.199.0.tar.gz",
39
- "sha256": "86d13eb45a80bf7e833583c87c43223391074199261c992e30de2762aff5e2ff",
40
- "size": 21667
38
+ "url": "signet-connectors-0.199.2.tar.gz",
39
+ "sha256": "72f74c5fdda2fb644ef55cc3e80a05a7ff365c0a3ab34953cecb3372c8c3c734",
40
+ "size": 21666
41
41
  }
42
42
  }
43
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signetai",
3
- "version": "0.199.0",
3
+ "version": "0.199.2",
4
4
  "description": "Signet native CLI installer wrapper",
5
5
  "type": "module",
6
6
  "bin": {
@@ -65,10 +65,10 @@
65
65
  "access": "public"
66
66
  },
67
67
  "optionalDependencies": {
68
- "signetai-darwin-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.0/signetai-darwin-arm64-0.199.0.tgz",
69
- "signetai-darwin-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.0/signetai-darwin-x64-0.199.0.tgz",
70
- "signetai-linux-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.0/signetai-linux-arm64-0.199.0.tgz",
71
- "signetai-linux-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.0/signetai-linux-x64-0.199.0.tgz",
72
- "signetai-win32-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.0/signetai-win32-x64-0.199.0.tgz"
68
+ "signetai-darwin-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.2/signetai-darwin-arm64-0.199.2.tgz",
69
+ "signetai-darwin-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.2/signetai-darwin-x64-0.199.2.tgz",
70
+ "signetai-linux-arm64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.2/signetai-linux-arm64-0.199.2.tgz",
71
+ "signetai-linux-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.2/signetai-linux-x64-0.199.2.tgz",
72
+ "signetai-win32-x64": "https://github.com/Signet-AI/signetai/releases/download/v0.199.2/signetai-win32-x64-0.199.2.tgz"
73
73
  }
74
74
  }