iranti 0.2.51 → 0.3.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.
Files changed (163) hide show
  1. package/README.md +30 -17
  2. package/dist/scripts/api-key-create.js +1 -1
  3. package/dist/scripts/api-key-list.js +1 -1
  4. package/dist/scripts/api-key-revoke.js +1 -1
  5. package/dist/scripts/claude-code-memory-hook.js +116 -30
  6. package/dist/scripts/codex-setup.js +86 -4
  7. package/dist/scripts/iranti-cli.js +1359 -57
  8. package/dist/scripts/iranti-mcp.js +578 -75
  9. package/dist/scripts/seed.js +11 -6
  10. package/dist/scripts/setup.js +1 -1
  11. package/dist/src/api/healthChecks.d.ts +29 -0
  12. package/dist/src/api/healthChecks.d.ts.map +1 -0
  13. package/dist/src/api/healthChecks.js +72 -0
  14. package/dist/src/api/healthChecks.js.map +1 -0
  15. package/dist/src/api/middleware/validation.d.ts +22 -0
  16. package/dist/src/api/middleware/validation.d.ts.map +1 -1
  17. package/dist/src/api/middleware/validation.js +93 -3
  18. package/dist/src/api/middleware/validation.js.map +1 -1
  19. package/dist/src/api/routes/knowledge.d.ts.map +1 -1
  20. package/dist/src/api/routes/knowledge.js +53 -0
  21. package/dist/src/api/routes/knowledge.js.map +1 -1
  22. package/dist/src/api/routes/memory.d.ts.map +1 -1
  23. package/dist/src/api/routes/memory.js +73 -9
  24. package/dist/src/api/routes/memory.js.map +1 -1
  25. package/dist/src/api/server.js +38 -43
  26. package/dist/src/api/server.js.map +1 -1
  27. package/dist/src/attendant/AttendantInstance.d.ts +135 -2
  28. package/dist/src/attendant/AttendantInstance.d.ts.map +1 -1
  29. package/dist/src/attendant/AttendantInstance.js +1836 -93
  30. package/dist/src/attendant/AttendantInstance.js.map +1 -1
  31. package/dist/src/attendant/index.d.ts +1 -1
  32. package/dist/src/attendant/index.d.ts.map +1 -1
  33. package/dist/src/attendant/index.js +1 -1
  34. package/dist/src/attendant/index.js.map +1 -1
  35. package/dist/src/attendant/registry.d.ts.map +1 -1
  36. package/dist/src/attendant/registry.js +2 -0
  37. package/dist/src/attendant/registry.js.map +1 -1
  38. package/dist/src/chat/index.d.ts +23 -0
  39. package/dist/src/chat/index.d.ts.map +1 -1
  40. package/dist/src/chat/index.js +111 -22
  41. package/dist/src/chat/index.js.map +1 -1
  42. package/dist/src/generated/prisma/browser.d.ts +5 -0
  43. package/dist/src/generated/prisma/browser.d.ts.map +1 -1
  44. package/dist/src/generated/prisma/client.d.ts +5 -0
  45. package/dist/src/generated/prisma/client.d.ts.map +1 -1
  46. package/dist/src/generated/prisma/commonInputTypes.d.ts +48 -0
  47. package/dist/src/generated/prisma/commonInputTypes.d.ts.map +1 -1
  48. package/dist/src/generated/prisma/internal/class.d.ts +11 -0
  49. package/dist/src/generated/prisma/internal/class.d.ts.map +1 -1
  50. package/dist/src/generated/prisma/internal/class.js +4 -4
  51. package/dist/src/generated/prisma/internal/class.js.map +1 -1
  52. package/dist/src/generated/prisma/internal/prismaNamespace.d.ts +92 -1
  53. package/dist/src/generated/prisma/internal/prismaNamespace.d.ts.map +1 -1
  54. package/dist/src/generated/prisma/internal/prismaNamespace.js +17 -2
  55. package/dist/src/generated/prisma/internal/prismaNamespace.js.map +1 -1
  56. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts +16 -0
  57. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.d.ts.map +1 -1
  58. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js +17 -2
  59. package/dist/src/generated/prisma/internal/prismaNamespaceBrowser.js.map +1 -1
  60. package/dist/src/generated/prisma/models/StaffEvent.d.ts +1184 -0
  61. package/dist/src/generated/prisma/models/StaffEvent.d.ts.map +1 -0
  62. package/dist/src/generated/prisma/models/StaffEvent.js +3 -0
  63. package/dist/src/generated/prisma/models/StaffEvent.js.map +1 -0
  64. package/dist/src/generated/prisma/models.d.ts +1 -0
  65. package/dist/src/generated/prisma/models.d.ts.map +1 -1
  66. package/dist/src/lib/assistantCheckpoint.d.ts +21 -0
  67. package/dist/src/lib/assistantCheckpoint.d.ts.map +1 -0
  68. package/dist/src/lib/assistantCheckpoint.js +143 -0
  69. package/dist/src/lib/assistantCheckpoint.js.map +1 -0
  70. package/dist/src/lib/autoRemember.d.ts +15 -0
  71. package/dist/src/lib/autoRemember.d.ts.map +1 -1
  72. package/dist/src/lib/autoRemember.js +433 -71
  73. package/dist/src/lib/autoRemember.js.map +1 -1
  74. package/dist/src/lib/cliHelpCatalog.d.ts.map +1 -1
  75. package/dist/src/lib/cliHelpCatalog.js +23 -11
  76. package/dist/src/lib/cliHelpCatalog.js.map +1 -1
  77. package/dist/src/lib/cliHelpRenderer.d.ts +1 -0
  78. package/dist/src/lib/cliHelpRenderer.d.ts.map +1 -1
  79. package/dist/src/lib/cliHelpRenderer.js +4 -0
  80. package/dist/src/lib/cliHelpRenderer.js.map +1 -1
  81. package/dist/src/lib/commandErrors.d.ts +5 -1
  82. package/dist/src/lib/commandErrors.d.ts.map +1 -1
  83. package/dist/src/lib/commandErrors.js +250 -17
  84. package/dist/src/lib/commandErrors.js.map +1 -1
  85. package/dist/src/lib/createFirstPartyIranti.d.ts.map +1 -1
  86. package/dist/src/lib/createFirstPartyIranti.js +1 -0
  87. package/dist/src/lib/createFirstPartyIranti.js.map +1 -1
  88. package/dist/src/lib/dbStaffEventEmitter.d.ts +2 -0
  89. package/dist/src/lib/dbStaffEventEmitter.d.ts.map +1 -1
  90. package/dist/src/lib/dbStaffEventEmitter.js +15 -0
  91. package/dist/src/lib/dbStaffEventEmitter.js.map +1 -1
  92. package/dist/src/lib/hostMemoryFormatting.d.ts +25 -0
  93. package/dist/src/lib/hostMemoryFormatting.d.ts.map +1 -0
  94. package/dist/src/lib/hostMemoryFormatting.js +55 -0
  95. package/dist/src/lib/hostMemoryFormatting.js.map +1 -0
  96. package/dist/src/lib/issueFacts.d.ts +37 -0
  97. package/dist/src/lib/issueFacts.d.ts.map +1 -0
  98. package/dist/src/lib/issueFacts.js +72 -0
  99. package/dist/src/lib/issueFacts.js.map +1 -0
  100. package/dist/src/lib/llm.d.ts +8 -0
  101. package/dist/src/lib/llm.d.ts.map +1 -1
  102. package/dist/src/lib/llm.js +33 -0
  103. package/dist/src/lib/llm.js.map +1 -1
  104. package/dist/src/lib/packageRoot.d.ts +2 -0
  105. package/dist/src/lib/packageRoot.d.ts.map +1 -0
  106. package/dist/src/lib/packageRoot.js +22 -0
  107. package/dist/src/lib/packageRoot.js.map +1 -0
  108. package/dist/src/lib/projectLearning.d.ts +21 -0
  109. package/dist/src/lib/projectLearning.d.ts.map +1 -0
  110. package/dist/src/lib/projectLearning.js +357 -0
  111. package/dist/src/lib/projectLearning.js.map +1 -0
  112. package/dist/src/lib/protocolEnforcement.d.ts +29 -0
  113. package/dist/src/lib/protocolEnforcement.d.ts.map +1 -0
  114. package/dist/src/lib/protocolEnforcement.js +124 -0
  115. package/dist/src/lib/protocolEnforcement.js.map +1 -0
  116. package/dist/src/lib/providers/claude.js +1 -1
  117. package/dist/src/lib/providers/claude.js.map +1 -1
  118. package/dist/src/lib/router.js +1 -1
  119. package/dist/src/lib/router.js.map +1 -1
  120. package/dist/src/lib/runtimeEnv.d.ts.map +1 -1
  121. package/dist/src/lib/runtimeEnv.js +8 -3
  122. package/dist/src/lib/runtimeEnv.js.map +1 -1
  123. package/dist/src/lib/scaffoldCloseout.d.ts +27 -0
  124. package/dist/src/lib/scaffoldCloseout.d.ts.map +1 -0
  125. package/dist/src/lib/scaffoldCloseout.js +139 -0
  126. package/dist/src/lib/scaffoldCloseout.js.map +1 -0
  127. package/dist/src/lib/semanticFactTags.d.ts +10 -0
  128. package/dist/src/lib/semanticFactTags.d.ts.map +1 -0
  129. package/dist/src/lib/semanticFactTags.js +166 -0
  130. package/dist/src/lib/semanticFactTags.js.map +1 -0
  131. package/dist/src/lib/sessionLedger.d.ts +94 -0
  132. package/dist/src/lib/sessionLedger.d.ts.map +1 -0
  133. package/dist/src/lib/sessionLedger.js +997 -0
  134. package/dist/src/lib/sessionLedger.js.map +1 -0
  135. package/dist/src/lib/sharedStateInvalidation.d.ts +10 -0
  136. package/dist/src/lib/sharedStateInvalidation.d.ts.map +1 -0
  137. package/dist/src/lib/sharedStateInvalidation.js +184 -0
  138. package/dist/src/lib/sharedStateInvalidation.js.map +1 -0
  139. package/dist/src/lib/staffEventsTable.d.ts +3 -0
  140. package/dist/src/lib/staffEventsTable.d.ts.map +1 -0
  141. package/dist/src/lib/staffEventsTable.js +58 -0
  142. package/dist/src/lib/staffEventsTable.js.map +1 -0
  143. package/dist/src/librarian/index.d.ts.map +1 -1
  144. package/dist/src/librarian/index.js +113 -2
  145. package/dist/src/librarian/index.js.map +1 -1
  146. package/dist/src/library/client.d.ts +6 -1
  147. package/dist/src/library/client.d.ts.map +1 -1
  148. package/dist/src/library/client.js +21 -7
  149. package/dist/src/library/client.js.map +1 -1
  150. package/dist/src/library/embeddings.d.ts +9 -1
  151. package/dist/src/library/embeddings.d.ts.map +1 -1
  152. package/dist/src/library/embeddings.js +28 -3
  153. package/dist/src/library/embeddings.js.map +1 -1
  154. package/dist/src/library/queries.d.ts.map +1 -1
  155. package/dist/src/library/queries.js +263 -46
  156. package/dist/src/library/queries.js.map +1 -1
  157. package/dist/src/sdk/index.d.ts +52 -1
  158. package/dist/src/sdk/index.d.ts.map +1 -1
  159. package/dist/src/sdk/index.js +546 -98
  160. package/dist/src/sdk/index.js.map +1 -1
  161. package/package.json +24 -3
  162. package/prisma/migrations/20260331101500_add_staff_events_ledger/migration.sql +24 -0
  163. package/prisma/schema.prisma +22 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resetStaffEventEmitter = exports.getStaffEventEmitter = exports.setStaffEventEmitter = exports.buildStaffEvent = exports.NoopEventEmitter = exports.Iranti = void 0;
3
+ exports.resetStaffEventEmitter = exports.getStaffEventEmitter = exports.setStaffEventEmitter = exports.buildStaffEvent = exports.NoopEventEmitter = exports.Iranti = exports.ProtocolViolationError = void 0;
4
4
  require("dotenv/config");
5
5
  const client_1 = require("../library/client");
6
6
  const staffEventEmitter_1 = require("../lib/staffEventEmitter");
@@ -19,8 +19,37 @@ const relationships_1 = require("../library/relationships");
19
19
  const agent_registry_1 = require("../library/agent-registry");
20
20
  const entity_resolution_1 = require("../library/entity-resolution");
21
21
  const autoRemember_1 = require("../lib/autoRemember");
22
+ const issueFacts_1 = require("../lib/issueFacts");
22
23
  const mock_1 = require("../lib/providers/mock");
24
+ const protocolEnforcement_1 = require("../lib/protocolEnforcement");
25
+ Object.defineProperty(exports, "ProtocolViolationError", { enumerable: true, get: function () { return protocolEnforcement_1.ProtocolViolationError; } });
23
26
  const client_2 = require("../generated/prisma/client");
27
+ const sessionLedger_1 = require("../lib/sessionLedger");
28
+ function normalizeDbApplicationToken(value) {
29
+ const trimmed = value?.trim();
30
+ if (!trimmed)
31
+ return undefined;
32
+ const normalized = trimmed
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9:_-]+/g, '_')
35
+ .replace(/_+/g, '_')
36
+ .replace(/^_+|_+$/g, '');
37
+ return normalized || undefined;
38
+ }
39
+ function deriveDbApplicationName(config) {
40
+ const explicit = normalizeDbApplicationToken(config.dbApplicationName);
41
+ if (explicit) {
42
+ return explicit.slice(0, 63);
43
+ }
44
+ const source = normalizeDbApplicationToken(config.sessionLedgerSource);
45
+ const host = normalizeDbApplicationToken(config.sessionLedgerHost);
46
+ const agentId = normalizeDbApplicationToken(config.sessionLedgerAgentId);
47
+ const parts = ['iranti', source, host ?? agentId].filter((part) => Boolean(part));
48
+ if (parts.length === 1) {
49
+ return undefined;
50
+ }
51
+ return parts.join(':').slice(0, 63);
52
+ }
24
53
  // ─── Entity Parsing ──────────────────────────────────────────────────────────
25
54
  function parseEntity(entity) {
26
55
  if (!entity || typeof entity !== 'string') {
@@ -143,11 +172,22 @@ function mapArchiveResult(result) {
143
172
  class Iranti {
144
173
  constructor(config = {}) {
145
174
  this.config = config;
175
+ this.protocolTracker = new protocolEnforcement_1.AgentProtocolTracker();
176
+ this.sessionLedgerContext = {
177
+ source: config.sessionLedgerSource?.trim() || undefined,
178
+ host: typeof config.sessionLedgerHost === 'string'
179
+ ? (config.sessionLedgerHost.trim() || null)
180
+ : (config.sessionLedgerHost ?? null),
181
+ agentId: config.sessionLedgerAgentId?.trim() || undefined,
182
+ };
146
183
  const connectionString = config.connectionString ?? process.env.DATABASE_URL;
147
184
  if (!connectionString) {
148
185
  throw new Error('connectionString is required. Provide it in config or set DATABASE_URL environment variable.');
149
186
  }
150
- (0, client_1.initDb)(connectionString);
187
+ (0, client_1.initDb)(connectionString, {
188
+ applicationName: deriveDbApplicationName(config),
189
+ max: config.dbPoolMax,
190
+ });
151
191
  if (config.llmProvider) {
152
192
  process.env.LLM_PROVIDER = config.llmProvider;
153
193
  }
@@ -159,6 +199,107 @@ class Iranti {
159
199
  (0, staffEventRegistry_1.setStaffEventEmitter)(config.staffEventEmitter);
160
200
  }
161
201
  }
202
+ protocolMode() {
203
+ return this.config.protocolEnforcement ?? 'off';
204
+ }
205
+ protocolAgentId() {
206
+ return this.sessionLedgerContext.agentId?.trim() || undefined;
207
+ }
208
+ checkProtocol(operation, requirements) {
209
+ const mode = this.protocolMode();
210
+ if (mode === 'off')
211
+ return;
212
+ const agentId = this.protocolAgentId();
213
+ if (!agentId)
214
+ return;
215
+ const violation = this.protocolTracker.check(agentId, operation, requirements);
216
+ if (!violation)
217
+ return;
218
+ if (mode === 'warn') {
219
+ this.emitLedgerEvent({
220
+ staffComponent: 'Attendant',
221
+ actionType: 'host_failure',
222
+ agentId,
223
+ source: 'sdk',
224
+ reason: violation.code,
225
+ level: 'audit',
226
+ metadata: {
227
+ operation,
228
+ protocolViolation: violation,
229
+ },
230
+ });
231
+ return;
232
+ }
233
+ throw new protocolEnforcement_1.ProtocolViolationError(violation);
234
+ }
235
+ syncMemoryUseCompliance(agentId, compliance) {
236
+ const ignoredMemoryIssue = compliance?.issues.find((issue) => issue.code === 'ignored_injected_memory');
237
+ if (ignoredMemoryIssue?.severity === 'error') {
238
+ this.protocolTracker.markMemoryUseAcknowledgementRequired(agentId);
239
+ return;
240
+ }
241
+ this.protocolTracker.clearMemoryUseAcknowledgementRequired(agentId);
242
+ }
243
+ consumeDiscoveryBudget(operation) {
244
+ if (this.protocolMode() === 'off')
245
+ return;
246
+ const agentId = this.protocolAgentId();
247
+ if (!agentId)
248
+ return;
249
+ if (['query', 'history', 'queryAll', 'search', 'related', 'related_deep', 'who_knows'].includes(operation)) {
250
+ this.protocolTracker.notifyDiscoveryConsumed(agentId);
251
+ }
252
+ }
253
+ setSessionLedgerContext(context) {
254
+ if ('source' in context) {
255
+ this.sessionLedgerContext.source = typeof context.source === 'string'
256
+ ? (context.source.trim() || undefined)
257
+ : undefined;
258
+ }
259
+ if ('host' in context) {
260
+ this.sessionLedgerContext.host = typeof context.host === 'string'
261
+ ? (context.host.trim() || null)
262
+ : (context.host ?? null);
263
+ }
264
+ if ('agentId' in context) {
265
+ this.sessionLedgerContext.agentId = typeof context.agentId === 'string'
266
+ ? (context.agentId.trim() || undefined)
267
+ : undefined;
268
+ }
269
+ }
270
+ buildSessionLedgerContext() {
271
+ if (!this.sessionLedgerContext.source && !this.sessionLedgerContext.host && !this.sessionLedgerContext.agentId) {
272
+ return undefined;
273
+ }
274
+ return {
275
+ source: this.sessionLedgerContext.source,
276
+ host: this.sessionLedgerContext.host ?? null,
277
+ agentId: this.sessionLedgerContext.agentId,
278
+ };
279
+ }
280
+ emitLedgerEvent(event) {
281
+ const context = this.buildSessionLedgerContext();
282
+ const metadata = event.metadata && typeof event.metadata === 'object'
283
+ ? { ...event.metadata }
284
+ : {};
285
+ if (context?.host) {
286
+ metadata.host = context.host;
287
+ }
288
+ (0, staffEventRegistry_1.getStaffEventEmitter)().emit({
289
+ ...event,
290
+ agentId: context?.agentId && (!event.agentId || event.agentId === 'sdk')
291
+ ? context.agentId
292
+ : event.agentId,
293
+ source: context?.source ?? event.source,
294
+ metadata,
295
+ });
296
+ }
297
+ async noteRediscoveryEvidence() {
298
+ const agentId = this.protocolAgentId();
299
+ if (!agentId)
300
+ return;
301
+ await (0, registry_1.getAttendant)(agentId).noteDiscoveryOccurred();
302
+ }
162
303
  // ── Write ───────────────────────────────────────────────────────────────
163
304
  async write(input) {
164
305
  if (input.confidence < 0 || input.confidence > 100) {
@@ -186,7 +327,10 @@ class Iranti {
186
327
  validFrom: input.validFrom,
187
328
  validUntil: input.validUntil ?? undefined,
188
329
  requestId: input.requestId,
330
+ properties: input.properties,
189
331
  });
332
+ await (0, registry_1.getAttendant)(input.agent).notifyWriteOccurred();
333
+ this.protocolTracker.clearMemoryUseAcknowledgementRequired(input.agent);
190
334
  return {
191
335
  action: result.action,
192
336
  key: input.key,
@@ -195,6 +339,9 @@ class Iranti {
195
339
  inputEntity: input.entity,
196
340
  };
197
341
  }
342
+ async writeIssue(input) {
343
+ return this.write((0, issueFacts_1.buildIssueFactWrite)(input));
344
+ }
198
345
  // ── Ingest ──────────────────────────────────────────────────────────────
199
346
  async ingest(input) {
200
347
  const { entityType, entityId } = parseEntity(input.entity);
@@ -206,6 +353,8 @@ class Iranti {
206
353
  confidence: input.confidence,
207
354
  createdBy: input.agent,
208
355
  });
356
+ await (0, registry_1.getAttendant)(input.agent).notifyWriteOccurred();
357
+ this.protocolTracker.clearMemoryUseAcknowledgementRequired(input.agent);
209
358
  return {
210
359
  extractedCandidates: result.extractedCandidates,
211
360
  written: result.written,
@@ -222,11 +371,16 @@ class Iranti {
222
371
  }
223
372
  // ── Handshake ───────────────────────────────────────────────────────────
224
373
  async handshake(input) {
225
- const attendant = (0, registry_1.getAttendant)(resolveAgentId(input, 'handshake'));
226
- return attendant.handshake({
374
+ const agentId = resolveAgentId(input, 'handshake');
375
+ const attendant = (0, registry_1.getAttendant)(agentId);
376
+ const result = await attendant.handshake({
227
377
  task: input.task,
228
378
  recentMessages: input.recentMessages,
379
+ ledgerContext: this.buildSessionLedgerContext(),
229
380
  });
381
+ this.protocolTracker.markHandshake(agentId);
382
+ this.syncMemoryUseCompliance(agentId, result.compliance);
383
+ return result;
230
384
  }
231
385
  // ── Reconvene ───────────────────────────────────────────────────────────
232
386
  async reconvene(agentId, input) {
@@ -234,34 +388,42 @@ class Iranti {
234
388
  return attendant.reconvene({
235
389
  task: input.task,
236
390
  recentMessages: input.recentMessages,
391
+ ledgerContext: this.buildSessionLedgerContext(),
237
392
  });
238
393
  }
239
394
  async checkpoint(input) {
240
- const attendant = (0, registry_1.getAttendant)(resolveAgentId(input, 'checkpoint'));
241
- return attendant.checkpoint({
395
+ const agentId = resolveAgentId(input, 'checkpoint');
396
+ const attendant = (0, registry_1.getAttendant)(agentId);
397
+ const result = await attendant.checkpoint({
242
398
  task: input.task,
243
399
  recentMessages: input.recentMessages,
244
400
  checkpoint: input.checkpoint,
245
401
  sessionId: input.sessionId,
246
402
  heartbeatAt: input.heartbeatAt,
403
+ ledgerContext: this.buildSessionLedgerContext(),
247
404
  });
405
+ this.protocolTracker.clearMemoryUseAcknowledgementRequired(agentId);
406
+ return result;
248
407
  }
249
408
  async resumeSession(input) {
250
409
  const attendant = (0, registry_1.getAttendant)(resolveAgentId(input, 'resumeSession'));
251
410
  return attendant.resumeSession({
252
411
  sessionId: input.sessionId,
412
+ ledgerContext: this.buildSessionLedgerContext(),
253
413
  });
254
414
  }
255
415
  async completeSession(input) {
256
416
  const attendant = (0, registry_1.getAttendant)(resolveAgentId(input, 'completeSession'));
257
417
  return attendant.completeSession({
258
418
  sessionId: input.sessionId,
419
+ ledgerContext: this.buildSessionLedgerContext(),
259
420
  });
260
421
  }
261
422
  async abandonSession(input) {
262
423
  const attendant = (0, registry_1.getAttendant)(resolveAgentId(input, 'abandonSession'));
263
424
  return attendant.abandonSession({
264
425
  sessionId: input.sessionId,
426
+ ledgerContext: this.buildSessionLedgerContext(),
265
427
  });
266
428
  }
267
429
  async inspectSession(input) {
@@ -269,6 +431,7 @@ class Iranti {
269
431
  return attendant.inspectSession({
270
432
  task: input.task,
271
433
  recentMessages: input.recentMessages,
434
+ ledgerContext: this.buildSessionLedgerContext(),
272
435
  });
273
436
  }
274
437
  async listSessions(input = {}) {
@@ -279,7 +442,7 @@ class Iranti {
279
442
  const checkpoint = raw?.sessionCheckpoint ?? null;
280
443
  if (!checkpoint)
281
444
  return null;
282
- return (0, AttendantInstance_1.summarizeSessionState)(entry.entityId, checkpoint, typeof raw?.briefGeneratedAt === 'string' ? raw.briefGeneratedAt : undefined);
445
+ return (0, AttendantInstance_1.summarizeSessionState)(entry.entityId, checkpoint, typeof raw?.briefGeneratedAt === 'string' ? raw.briefGeneratedAt : undefined, raw?.compliance ?? null);
283
446
  })
284
447
  .filter((entry) => Boolean(entry));
285
448
  if (input.operatorState) {
@@ -294,88 +457,203 @@ class Iranti {
294
457
  }
295
458
  return sessions;
296
459
  }
460
+ async listSessionLedger(input = {}) {
461
+ return (0, sessionLedger_1.querySessionLedger)(input);
462
+ }
297
463
  getAttendant(agentId) {
298
464
  return (0, registry_1.getAttendant)(agentId);
299
465
  }
300
466
  // ── Query ───────────────────────────────────────────────────────────────
301
467
  async query(entity, key, options = {}) {
468
+ this.checkProtocol('query', { handshake: true, attend: true });
302
469
  const resolved = await resolveQueryEntity(entity);
303
470
  const personalRecallCandidates = (isPersonalEntityString(entity) && (0, autoRemember_1.isPersonalMemoryKey)(key)
304
471
  ? (0, autoRemember_1.getPersonalRecallEntities)(entity)
305
472
  : [])
306
473
  .filter((candidate) => candidate !== resolved.canonicalEntity);
307
- if (options.asOf) {
308
- const current = await (0, queries_1.findEntry)({ entityType: resolved.entityType, entityId: resolved.entityId, key });
309
- const currentMatches = current && !current.isProtected && current.validFrom <= options.asOf;
310
- if (currentMatches) {
311
- await (0, queries_1.recordKnowledgeEntryAccess)([current.id]);
312
- return {
313
- found: true,
314
- value: current.valueRaw,
315
- summary: current.valueSummary,
316
- confidence: current.confidence,
317
- source: current.source,
318
- validFrom: current.validFrom,
319
- validUntil: current.validUntil,
320
- contested: false,
321
- fromArchive: false,
322
- archivedReason: null,
323
- resolutionState: null,
324
- resolutionOutcome: null,
325
- resolvedEntity: resolved.canonicalEntity,
326
- inputEntity: entity,
327
- };
328
- }
329
- const historical = await (0, queries_1.findArchiveAsOf)({ entityType: resolved.entityType, entityId: resolved.entityId, key }, options.asOf, {
330
- includeExpired: options.includeExpired,
331
- includeContested: options.includeContested,
332
- });
333
- if (historical) {
334
- return {
335
- found: true,
336
- ...mapArchiveResult(historical),
337
- resolvedEntity: resolved.canonicalEntity,
338
- inputEntity: entity,
339
- };
474
+ try {
475
+ if (options.asOf) {
476
+ const current = await (0, queries_1.findEntry)({ entityType: resolved.entityType, entityId: resolved.entityId, key });
477
+ const currentMatches = current && !current.isProtected && current.validFrom <= options.asOf;
478
+ if (currentMatches) {
479
+ this.consumeDiscoveryBudget('query');
480
+ await (0, queries_1.recordKnowledgeEntryAccess)([current.id]);
481
+ this.emitLedgerEvent({
482
+ staffComponent: 'Attendant',
483
+ actionType: 'query_executed',
484
+ agentId: 'sdk',
485
+ source: 'sdk',
486
+ entityType: resolved.entityType,
487
+ entityId: resolved.entityId,
488
+ key,
489
+ reason: 'query_exact_current',
490
+ level: 'audit',
491
+ metadata: {
492
+ found: true,
493
+ fromArchive: false,
494
+ asOf: options.asOf.toISOString(),
495
+ },
496
+ });
497
+ await this.noteRediscoveryEvidence();
498
+ return {
499
+ found: true,
500
+ value: current.valueRaw,
501
+ summary: current.valueSummary,
502
+ confidence: current.confidence,
503
+ source: current.source,
504
+ validFrom: current.validFrom,
505
+ validUntil: current.validUntil,
506
+ contested: false,
507
+ fromArchive: false,
508
+ archivedReason: null,
509
+ resolutionState: null,
510
+ resolutionOutcome: null,
511
+ resolvedEntity: resolved.canonicalEntity,
512
+ inputEntity: entity,
513
+ };
514
+ }
515
+ const historical = await (0, queries_1.findArchiveAsOf)({ entityType: resolved.entityType, entityId: resolved.entityId, key }, options.asOf, {
516
+ includeExpired: options.includeExpired,
517
+ includeContested: options.includeContested,
518
+ });
519
+ if (historical) {
520
+ this.consumeDiscoveryBudget('query');
521
+ this.emitLedgerEvent({
522
+ staffComponent: 'Attendant',
523
+ actionType: 'query_executed',
524
+ agentId: 'sdk',
525
+ source: 'sdk',
526
+ entityType: resolved.entityType,
527
+ entityId: resolved.entityId,
528
+ key,
529
+ reason: 'query_historical_match',
530
+ level: 'audit',
531
+ metadata: {
532
+ found: true,
533
+ fromArchive: true,
534
+ asOf: options.asOf.toISOString(),
535
+ },
536
+ });
537
+ await this.noteRediscoveryEvidence();
538
+ return {
539
+ found: true,
540
+ ...mapArchiveResult(historical),
541
+ resolvedEntity: resolved.canonicalEntity,
542
+ inputEntity: entity,
543
+ };
544
+ }
545
+ this.emitLedgerEvent({
546
+ staffComponent: 'Attendant',
547
+ actionType: 'query_executed',
548
+ agentId: 'sdk',
549
+ source: 'sdk',
550
+ entityType: resolved.entityType,
551
+ entityId: resolved.entityId,
552
+ key,
553
+ reason: 'query_historical_miss',
554
+ level: 'audit',
555
+ metadata: {
556
+ found: false,
557
+ fromArchive: true,
558
+ asOf: options.asOf.toISOString(),
559
+ },
560
+ });
561
+ await this.noteRediscoveryEvidence();
562
+ return { found: false, resolvedEntity: resolved.canonicalEntity, inputEntity: entity };
340
563
  }
341
- return { found: false, resolvedEntity: resolved.canonicalEntity, inputEntity: entity };
342
- }
343
- const primaryEntry = await (0, queries_1.findEntry)({ entityType: resolved.entityType, entityId: resolved.entityId, key });
344
- let entry = primaryEntry;
345
- let resolvedEntity = resolved.canonicalEntity;
346
- if ((!entry || entry.isProtected) && personalRecallCandidates.length > 0) {
347
- for (const candidate of personalRecallCandidates) {
348
- const fallback = await resolveQueryEntity(candidate);
349
- const fallbackEntry = await (0, queries_1.findEntry)({ entityType: fallback.entityType, entityId: fallback.entityId, key });
350
- if (fallbackEntry && !fallbackEntry.isProtected) {
351
- entry = fallbackEntry;
352
- resolvedEntity = fallback.canonicalEntity;
353
- break;
564
+ const primaryEntry = await (0, queries_1.findEntry)({ entityType: resolved.entityType, entityId: resolved.entityId, key });
565
+ let entry = primaryEntry;
566
+ const resolvedEntity = resolved.canonicalEntity;
567
+ let usedFallback = false;
568
+ if ((!entry || entry.isProtected) && personalRecallCandidates.length > 0) {
569
+ for (const candidate of personalRecallCandidates) {
570
+ const fallback = await resolveQueryEntity(candidate);
571
+ const fallbackEntry = await (0, queries_1.findEntry)({ entityType: fallback.entityType, entityId: fallback.entityId, key });
572
+ if (fallbackEntry && !fallbackEntry.isProtected) {
573
+ entry = fallbackEntry;
574
+ usedFallback = true;
575
+ break;
576
+ }
354
577
  }
355
578
  }
579
+ if (!entry || entry.isProtected) {
580
+ this.emitLedgerEvent({
581
+ staffComponent: 'Attendant',
582
+ actionType: 'query_executed',
583
+ agentId: 'sdk',
584
+ source: 'sdk',
585
+ entityType: resolved.entityType,
586
+ entityId: resolved.entityId,
587
+ key,
588
+ reason: personalRecallCandidates.length > 0 ? 'query_personal_fallback_miss' : 'query_exact_miss',
589
+ level: 'audit',
590
+ metadata: {
591
+ found: false,
592
+ resolvedEntity,
593
+ inputEntity: entity,
594
+ },
595
+ });
596
+ await this.noteRediscoveryEvidence();
597
+ return { found: false, resolvedEntity, inputEntity: entity };
598
+ }
599
+ await (0, queries_1.recordKnowledgeEntryAccess)([entry.id]);
600
+ this.consumeDiscoveryBudget('query');
601
+ this.emitLedgerEvent({
602
+ staffComponent: 'Attendant',
603
+ actionType: 'query_executed',
604
+ agentId: 'sdk',
605
+ source: 'sdk',
606
+ entityType: entry.entityType,
607
+ entityId: entry.entityId,
608
+ key,
609
+ reason: usedFallback ? 'query_personal_fallback_match' : 'query_exact_match',
610
+ level: 'audit',
611
+ metadata: {
612
+ found: true,
613
+ resolvedEntity,
614
+ inputEntity: entity,
615
+ },
616
+ });
617
+ await this.noteRediscoveryEvidence();
618
+ return {
619
+ found: true,
620
+ value: entry.valueRaw,
621
+ summary: entry.valueSummary,
622
+ confidence: entry.confidence,
623
+ source: entry.source,
624
+ validFrom: entry.validFrom,
625
+ validUntil: entry.validUntil,
626
+ contested: false,
627
+ fromArchive: false,
628
+ archivedReason: null,
629
+ resolutionState: null,
630
+ resolutionOutcome: null,
631
+ resolvedEntity,
632
+ inputEntity: entity,
633
+ };
356
634
  }
357
- if (!entry || entry.isProtected) {
358
- return { found: false, resolvedEntity, inputEntity: entity };
635
+ catch (error) {
636
+ this.emitLedgerEvent({
637
+ staffComponent: 'Attendant',
638
+ actionType: 'host_failure',
639
+ agentId: 'sdk',
640
+ source: 'sdk',
641
+ entityType: resolved.entityType,
642
+ entityId: resolved.entityId,
643
+ key,
644
+ reason: 'query_failed',
645
+ level: 'audit',
646
+ metadata: {
647
+ operation: 'query',
648
+ inputEntity: entity,
649
+ error: error instanceof Error ? error.message : String(error),
650
+ },
651
+ });
652
+ throw error;
359
653
  }
360
- await (0, queries_1.recordKnowledgeEntryAccess)([entry.id]);
361
- return {
362
- found: true,
363
- value: entry.valueRaw,
364
- summary: entry.valueSummary,
365
- confidence: entry.confidence,
366
- source: entry.source,
367
- validFrom: entry.validFrom,
368
- validUntil: entry.validUntil,
369
- contested: false,
370
- fromArchive: false,
371
- archivedReason: null,
372
- resolutionState: null,
373
- resolutionOutcome: null,
374
- resolvedEntity,
375
- inputEntity: entity,
376
- };
377
654
  }
378
655
  async history(entity, key, options = {}) {
656
+ this.checkProtocol('history', { handshake: true, attend: true });
379
657
  const resolved = await resolveQueryEntity(entity);
380
658
  const [archiveRows, current] = await Promise.all([
381
659
  (0, queries_1.findArchiveHistory)({ entityType: resolved.entityType, entityId: resolved.entityId, key }, {
@@ -412,14 +690,18 @@ class Iranti {
412
690
  resolutionOutcome: null,
413
691
  });
414
692
  }
693
+ this.consumeDiscoveryBudget('history');
415
694
  return history.sort((a, b) => a.validFrom.getTime() - b.validFrom.getTime());
416
695
  }
417
696
  // ── Query All ───────────────────────────────────────────────────────────
418
697
  async queryAll(entity) {
698
+ this.checkProtocol('queryAll', { handshake: true, attend: true });
419
699
  const resolved = await resolveQueryEntity(entity);
420
700
  const entries = await (0, queries_1.findEntriesByEntity)(resolved.entityType, resolved.entityId);
421
701
  const visibleEntries = entries.filter((e) => !e.isProtected);
422
702
  await (0, queries_1.recordKnowledgeEntryAccess)(visibleEntries.map((entry) => entry.id));
703
+ this.consumeDiscoveryBudget('queryAll');
704
+ await this.noteRediscoveryEvidence();
423
705
  return visibleEntries
424
706
  .map((e) => ({
425
707
  key: e.key,
@@ -431,31 +713,69 @@ class Iranti {
431
713
  }
432
714
  // ── Maintenance ─────────────────────────────────────────────────────────
433
715
  async search(input) {
716
+ this.checkProtocol('search', { handshake: true, attend: true });
434
717
  if (!input.query || typeof input.query !== 'string' || input.query.trim().length === 0) {
435
718
  throw new Error('query is required for search().');
436
719
  }
437
- const rows = await (0, queries_1.searchEntriesHybrid)({
438
- query: input.query.trim(),
439
- limit: input.limit,
440
- entityType: input.entityType,
441
- entityId: input.entityId,
442
- lexicalWeight: input.lexicalWeight,
443
- vectorWeight: input.vectorWeight,
444
- minScore: input.minScore,
445
- });
446
- return rows.map((row) => ({
447
- id: row.id,
448
- entity: `${row.entityType}/${row.entityId}`,
449
- key: row.key,
450
- value: row.valueRaw,
451
- summary: row.valueSummary,
452
- confidence: row.confidence,
453
- source: row.source,
454
- validUntil: row.validUntil,
455
- lexicalScore: row.lexicalScore,
456
- vectorScore: row.vectorScore,
457
- score: row.score,
458
- }));
720
+ try {
721
+ const rows = await (0, queries_1.searchEntriesHybrid)({
722
+ query: input.query.trim(),
723
+ limit: input.limit,
724
+ entityType: input.entityType,
725
+ entityId: input.entityId,
726
+ lexicalWeight: input.lexicalWeight,
727
+ vectorWeight: input.vectorWeight,
728
+ minScore: input.minScore,
729
+ });
730
+ this.emitLedgerEvent({
731
+ staffComponent: 'Attendant',
732
+ actionType: 'search_executed',
733
+ agentId: 'sdk',
734
+ source: 'sdk',
735
+ entityType: input.entityType,
736
+ entityId: input.entityId,
737
+ reason: 'hybrid_search',
738
+ level: 'audit',
739
+ metadata: {
740
+ queryPreview: input.query.trim().slice(0, 120),
741
+ resultCount: rows.length,
742
+ minScore: input.minScore ?? null,
743
+ },
744
+ });
745
+ this.consumeDiscoveryBudget('search');
746
+ await this.noteRediscoveryEvidence();
747
+ return rows.map((row) => ({
748
+ id: row.id,
749
+ entity: `${row.entityType}/${row.entityId}`,
750
+ key: row.key,
751
+ value: row.valueRaw,
752
+ summary: row.valueSummary,
753
+ confidence: row.confidence,
754
+ source: row.source,
755
+ validUntil: row.validUntil,
756
+ lexicalScore: row.lexicalScore,
757
+ vectorScore: row.vectorScore,
758
+ score: row.score,
759
+ }));
760
+ }
761
+ catch (error) {
762
+ this.emitLedgerEvent({
763
+ staffComponent: 'Attendant',
764
+ actionType: 'host_failure',
765
+ agentId: 'sdk',
766
+ source: 'sdk',
767
+ entityType: input.entityType,
768
+ entityId: input.entityId,
769
+ reason: 'search_failed',
770
+ level: 'audit',
771
+ metadata: {
772
+ operation: 'search',
773
+ queryPreview: input.query.trim().slice(0, 120),
774
+ error: error instanceof Error ? error.message : String(error),
775
+ },
776
+ });
777
+ throw error;
778
+ }
459
779
  }
460
780
  async runMaintenance() {
461
781
  return (0, archivist_1.runArchivist)();
@@ -473,14 +793,90 @@ class Iranti {
473
793
  createdBy: options.createdBy,
474
794
  properties: options.properties,
475
795
  });
796
+ await (0, registry_1.getAttendant)(options.createdBy).notifyWriteOccurred();
797
+ this.protocolTracker.clearMemoryUseAcknowledgementRequired(options.createdBy);
476
798
  }
477
799
  async getRelated(entity) {
800
+ this.checkProtocol('related', { handshake: true, attend: true });
478
801
  const { entityType, entityId } = parseEntity(entity);
479
- return (0, relationships_1.getRelated)(entityType, entityId);
802
+ try {
803
+ const result = await (0, relationships_1.getRelated)(entityType, entityId);
804
+ this.consumeDiscoveryBudget('related');
805
+ this.emitLedgerEvent({
806
+ staffComponent: 'Attendant',
807
+ actionType: 'related_executed',
808
+ agentId: 'sdk',
809
+ source: 'sdk',
810
+ entityType,
811
+ entityId,
812
+ reason: 'relationship_lookup',
813
+ level: 'audit',
814
+ metadata: {
815
+ resultCount: result.length,
816
+ },
817
+ });
818
+ await this.noteRediscoveryEvidence();
819
+ return result;
820
+ }
821
+ catch (error) {
822
+ this.emitLedgerEvent({
823
+ staffComponent: 'Attendant',
824
+ actionType: 'host_failure',
825
+ agentId: 'sdk',
826
+ source: 'sdk',
827
+ entityType,
828
+ entityId,
829
+ reason: 'related_failed',
830
+ level: 'audit',
831
+ metadata: {
832
+ operation: 'related',
833
+ error: error instanceof Error ? error.message : String(error),
834
+ },
835
+ });
836
+ throw error;
837
+ }
480
838
  }
481
839
  async getRelatedDeep(entity, depth = 2) {
840
+ this.checkProtocol('related_deep', { handshake: true, attend: true });
482
841
  const { entityType, entityId } = parseEntity(entity);
483
- return (0, relationships_1.getRelatedDeep)(entityType, entityId, depth);
842
+ try {
843
+ const result = await (0, relationships_1.getRelatedDeep)(entityType, entityId, depth);
844
+ this.consumeDiscoveryBudget('related_deep');
845
+ this.emitLedgerEvent({
846
+ staffComponent: 'Attendant',
847
+ actionType: 'related_deep_executed',
848
+ agentId: 'sdk',
849
+ source: 'sdk',
850
+ entityType,
851
+ entityId,
852
+ reason: 'relationship_lookup_deep',
853
+ level: 'audit',
854
+ metadata: {
855
+ resultCount: result.length,
856
+ depth,
857
+ },
858
+ });
859
+ await this.noteRediscoveryEvidence();
860
+ return result;
861
+ }
862
+ catch (error) {
863
+ this.emitLedgerEvent({
864
+ staffComponent: 'Attendant',
865
+ actionType: 'host_failure',
866
+ agentId: 'sdk',
867
+ source: 'sdk',
868
+ entityType,
869
+ entityId,
870
+ reason: 'related_deep_failed',
871
+ level: 'audit',
872
+ metadata: {
873
+ operation: 'related_deep',
874
+ depth,
875
+ error: error instanceof Error ? error.message : String(error),
876
+ },
877
+ });
878
+ throw error;
879
+ }
484
880
  }
485
881
  // ── Agent Registry ──────────────────────────────────────────────────────
486
882
  async registerAgent(profile) {
@@ -490,8 +886,44 @@ class Iranti {
490
886
  return (0, agent_registry_1.getAgent)(agentId);
491
887
  }
492
888
  async whoKnows(entity) {
889
+ this.checkProtocol('who_knows', { handshake: true, attend: true });
493
890
  const { entityType, entityId } = parseEntity(entity);
494
- return (0, agent_registry_1.whoKnows)(entityType, entityId);
891
+ try {
892
+ const result = await (0, agent_registry_1.whoKnows)(entityType, entityId);
893
+ this.consumeDiscoveryBudget('who_knows');
894
+ this.emitLedgerEvent({
895
+ staffComponent: 'Attendant',
896
+ actionType: 'whoknows_executed',
897
+ agentId: 'sdk',
898
+ source: 'sdk',
899
+ entityType,
900
+ entityId,
901
+ reason: 'agent_contribution_lookup',
902
+ level: 'audit',
903
+ metadata: {
904
+ resultCount: result.length,
905
+ },
906
+ });
907
+ await this.noteRediscoveryEvidence();
908
+ return result;
909
+ }
910
+ catch (error) {
911
+ this.emitLedgerEvent({
912
+ staffComponent: 'Attendant',
913
+ actionType: 'host_failure',
914
+ agentId: 'sdk',
915
+ source: 'sdk',
916
+ entityType,
917
+ entityId,
918
+ reason: 'whoknows_failed',
919
+ level: 'audit',
920
+ metadata: {
921
+ operation: 'whoknows',
922
+ error: error instanceof Error ? error.message : String(error),
923
+ },
924
+ });
925
+ throw error;
926
+ }
495
927
  }
496
928
  async listAgents() {
497
929
  return (0, agent_registry_1.listAgents)();
@@ -502,6 +934,7 @@ class Iranti {
502
934
  // ── Context Window Observation ────────────────────────────────────────────
503
935
  async observe(input) {
504
936
  const agentId = resolveAgentId(input, 'observe');
937
+ this.checkProtocol('observe', { handshake: true });
505
938
  if (input.entityHints !== undefined) {
506
939
  if (!Array.isArray(input.entityHints)) {
507
940
  throw new Error('entityHints must be an array of "entityType/entityId" strings.');
@@ -518,10 +951,14 @@ class Iranti {
518
951
  currentContext: input.currentContext,
519
952
  maxFacts: input.maxFacts,
520
953
  entityHints: input.entityHints,
954
+ ledgerContext: this.buildSessionLedgerContext(),
521
955
  });
522
956
  }
523
957
  async attend(input) {
524
958
  const agentId = resolveAgentId(input, 'attend');
959
+ if (input.phase === 'pre-response') {
960
+ this.checkProtocol('attend', { postResponse: true });
961
+ }
525
962
  if (input.entityHints !== undefined) {
526
963
  if (!Array.isArray(input.entityHints)) {
527
964
  throw new Error('entityHints must be an array of "entityType/entityId" strings.');
@@ -534,13 +971,24 @@ class Iranti {
534
971
  }
535
972
  }
536
973
  const attendant = (0, registry_1.getAttendant)(agentId);
537
- return attendant.attend({
974
+ const result = await attendant.attend({
538
975
  currentContext: input.currentContext,
539
976
  maxFacts: input.maxFacts,
540
977
  entityHints: input.entityHints,
541
978
  latestMessage: input.latestMessage,
542
979
  forceInject: input.forceInject,
980
+ suppressEvents: input.suppressEvents,
981
+ phase: input.phase,
982
+ ledgerContext: this.buildSessionLedgerContext(),
543
983
  });
984
+ if (result.bootstrap?.handshakePerformed) {
985
+ this.protocolTracker.markHandshake(agentId);
986
+ }
987
+ this.protocolTracker.markAttend(agentId, input.phase);
988
+ if (input.phase === 'post-response') {
989
+ this.syncMemoryUseCompliance(agentId, result.compliance);
990
+ }
991
+ return result;
544
992
  }
545
993
  // ── Mock Configuration (dev/test only) ──────────────────────────────────
546
994
  configureMock(config) {