hebbrix 2.1.0 → 2.2.1

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/index.js CHANGED
@@ -24,9 +24,11 @@ __export(index_exports, {
24
24
  AuthenticationError: () => AuthenticationError,
25
25
  CollectionsResource: () => CollectionsResource,
26
26
  ConsolidationResource: () => ConsolidationResource,
27
+ CorrectionsResource: () => CorrectionsResource,
27
28
  HebbrixError: () => HebbrixError,
28
29
  MemoriesResource: () => MemoriesResource,
29
30
  MemoryClient: () => MemoryClient,
31
+ MemoryJobsResource: () => MemoryJobsResource,
30
32
  MemoryToolsResource: () => MemoryToolsResource,
31
33
  NotFoundError: () => NotFoundError,
32
34
  ProceduralResource: () => ProceduralResource,
@@ -38,10 +40,65 @@ __export(index_exports, {
38
40
  TemporalResource: () => TemporalResource,
39
41
  ValidationError: () => ValidationError,
40
42
  WorkingMemoryResource: () => WorkingMemoryResource,
41
- WorldModelResource: () => WorldModelResource
43
+ WorldModelResource: () => WorldModelResource,
44
+ enforceSearchSafety: () => enforceSearchSafety
42
45
  });
43
46
  module.exports = __toCommonJS(index_exports);
44
47
 
48
+ // src/safety.ts
49
+ var REQUIRED_FIELDS = [
50
+ "no_match",
51
+ "abstain_recommended",
52
+ "query_confidence",
53
+ "grounding",
54
+ "evidence_ids",
55
+ "safety_contract_version"
56
+ ];
57
+ function enforceSearchSafety(response, rowsKey = "results") {
58
+ const data = { ...response };
59
+ const rawRows = data[rowsKey];
60
+ const rows = Array.isArray(rawRows) ? rawRows.filter((row) => typeof row === "object" && row !== null) : [];
61
+ const missing = REQUIRED_FIELDS.filter(
62
+ (field) => !Object.prototype.hasOwnProperty.call(data, field)
63
+ );
64
+ let reason;
65
+ if (missing.length > 0) {
66
+ reason = `missing_safety_fields:${missing.join(",")}`;
67
+ } else if (typeof data.no_match !== "boolean" || typeof data.abstain_recommended !== "boolean") {
68
+ reason = "invalid_abstention_fields";
69
+ } else if (typeof data.query_confidence !== "number" || !Number.isFinite(data.query_confidence) || data.query_confidence < 0 || data.query_confidence > 1) {
70
+ reason = "invalid_query_confidence";
71
+ } else if (typeof data.grounding !== "object" || data.grounding === null || Array.isArray(data.grounding)) {
72
+ reason = "invalid_grounding_receipt";
73
+ } else if (!Array.isArray(data.evidence_ids)) {
74
+ reason = "invalid_evidence_ids";
75
+ } else {
76
+ const evidenceIds = new Set(data.evidence_ids.map(String));
77
+ const rowIds = rows.map((row) => row.memory_id ?? row.id).filter((value) => typeof value === "string" && value.length > 0);
78
+ if (rowIds.some((value) => !evidenceIds.has(value))) {
79
+ reason = "rows_not_bound_to_evidence_ids";
80
+ } else if (data.no_match && (rowIds.length > 0 || evidenceIds.size > 0)) {
81
+ reason = "no_match_contains_evidence";
82
+ }
83
+ }
84
+ if (reason || data.no_match === true) {
85
+ data[rowsKey] = [];
86
+ if (rowsKey === "results") data.total = 0;
87
+ data.no_match = true;
88
+ data.abstain_recommended = true;
89
+ data.query_confidence = 0;
90
+ data.evidence_ids = [];
91
+ data.evidence_claims = [];
92
+ if (reason) {
93
+ data.sdk_safety_reason = reason;
94
+ data.grounding = { status: "no_grounded_match", reason };
95
+ }
96
+ } else if (data.degraded === true || data.abstain_recommended === true) {
97
+ data.sdk_safety_reason = "degraded_evidence_preserved";
98
+ }
99
+ return data;
100
+ }
101
+
45
102
  // src/resources.ts
46
103
  var BaseResource = class {
47
104
  constructor(client) {
@@ -121,14 +178,104 @@ var MemoriesResource = class extends BaseResource {
121
178
  * Create a new memory
122
179
  */
123
180
  async create(params) {
124
- return this.client.post("/v1/memories", params);
181
+ if (!params.content?.trim() && !params.messages?.length) {
182
+ throw new TypeError("content or messages must be provided");
183
+ }
184
+ const { idempotency_key, ...input } = params;
185
+ return this.client.request("POST", "/v1/memories", {
186
+ headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
187
+ body: JSON.stringify({
188
+ source_type: "text",
189
+ metadata: {},
190
+ infer: false,
191
+ wait_for_index: false,
192
+ ...input
193
+ })
194
+ });
195
+ }
196
+ /**
197
+ * Create up to 100 memories with one unambiguous readiness contract.
198
+ * `wait_for_index=true` resolves only for a fully searchable batch; a server
199
+ * deadline or indexing failure rejects the request instead of returning a
200
+ * successful processing receipt.
201
+ */
202
+ async createBatch(params) {
203
+ if (!params.memories?.length || params.memories.length > 100) {
204
+ throw new TypeError("memories must contain between 1 and 100 items");
205
+ }
206
+ if (params.memories.some((item) => !item.content?.trim())) {
207
+ throw new TypeError("every batch memory must contain non-empty content");
208
+ }
209
+ const { idempotency_key, signal, ...body } = params;
210
+ const receipt = await this.client.request(
211
+ "POST",
212
+ "/v1/memories/batch",
213
+ {
214
+ headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
215
+ body: JSON.stringify({ wait_for_index: false, ...body }),
216
+ signal
217
+ }
218
+ );
219
+ if (params.wait_for_index && !(receipt.searchable === true && receipt.processing_status === "completed")) {
220
+ throw new Error(
221
+ "wait_for_index batch response was not fully searchable; retry with the same Idempotency-Key"
222
+ );
223
+ }
224
+ return receipt;
225
+ }
226
+ /** Poll every item in an asynchronous batch receipt until it is searchable. */
227
+ async waitForBatchSearchable(receipt, options = {}) {
228
+ const ids = [...new Set(receipt.memory_ids || [])];
229
+ if (!ids.length) {
230
+ throw new Error("batch receipt does not contain memory_ids");
231
+ }
232
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 6e4);
233
+ const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 500);
234
+ const deadline = Date.now() + timeoutMs;
235
+ while (true) {
236
+ if (options.signal?.aborted) {
237
+ throw options.signal.reason || new Error("batch readiness polling was aborted");
238
+ }
239
+ const rows = await Promise.all(ids.map((id) => this.get(id)));
240
+ const terminal = rows.find(
241
+ (row) => ["failed", "cancelled", "canceled"].includes(
242
+ String(row.processing_status || "").toLowerCase()
243
+ )
244
+ );
245
+ if (terminal) {
246
+ throw new Error(
247
+ `memory ${terminal.id} indexing reached terminal state ${terminal.processing_status}`
248
+ );
249
+ }
250
+ if (rows.every((row) => row.searchable === true)) {
251
+ return {
252
+ ...receipt,
253
+ processing_status: "completed",
254
+ searchable: true,
255
+ results: ids.map((id) => ({
256
+ id,
257
+ memory_id: id,
258
+ processing_status: "completed"
259
+ }))
260
+ };
261
+ }
262
+ if (Date.now() >= deadline) {
263
+ throw new Error(`batch was not searchable within ${timeoutMs}ms`);
264
+ }
265
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
266
+ }
125
267
  }
126
268
  /**
127
269
  * List memories
128
270
  */
129
- async list(params = {}) {
271
+ async listPage(params = {}) {
130
272
  return this.client.get("/v1/memories", params);
131
273
  }
274
+ /** Back-compatible one-page convenience; use listPage for cursor metadata. */
275
+ async list(params = {}) {
276
+ const page = await this.listPage(params);
277
+ return page.items;
278
+ }
132
279
  /**
133
280
  * Get a specific memory
134
281
  */
@@ -148,30 +295,79 @@ var MemoriesResource = class extends BaseResource {
148
295
  await this.client.delete(`/v1/memories/${memoryId}`);
149
296
  }
150
297
  };
298
+ var MemoryJobsResource = class extends BaseResource {
299
+ async get(jobId) {
300
+ return this.client.get(`/v1/memory-jobs/${jobId}`);
301
+ }
302
+ async wait(jobId, options = {}) {
303
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 6e4);
304
+ const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 500);
305
+ const deadline = Date.now() + timeoutMs;
306
+ while (true) {
307
+ const receipt = await this.get(jobId);
308
+ const status = String(receipt.status || "").toLowerCase();
309
+ if (["completed", "failed", "cancelled", "canceled"].includes(status)) {
310
+ return receipt;
311
+ }
312
+ if (Date.now() >= deadline) {
313
+ throw new Error(`memory job ${jobId} did not finish in ${timeoutMs}ms`);
314
+ }
315
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
316
+ }
317
+ }
318
+ };
319
+ var CorrectionsResource = class extends BaseResource {
320
+ async create(params) {
321
+ const { idempotency_key, ...body } = params;
322
+ return this.client.request("POST", "/v1/corrections", {
323
+ headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
324
+ body: JSON.stringify({
325
+ correction_type: "preference",
326
+ confidence: 1,
327
+ ...body
328
+ })
329
+ });
330
+ }
331
+ async relevant(params) {
332
+ return this.client.get("/v1/corrections/relevant", {
333
+ include_global: false,
334
+ limit: 10,
335
+ ...params
336
+ });
337
+ }
338
+ async get(correctionId) {
339
+ return this.client.get(`/v1/corrections/${correctionId}`);
340
+ }
341
+ async delete(correctionId) {
342
+ return this.client.delete(`/v1/corrections/${correctionId}`);
343
+ }
344
+ };
151
345
  var SearchResource = class extends BaseResource {
152
346
  /**
153
347
  * Search memories
154
348
  */
155
349
  async search(params) {
156
- const response = await this.client.post("/v1/search", {
157
- query: params.query,
158
- collection_id: params.collection_id,
159
- limit: params.limit || 10,
160
- search_type: params.search_type || "hybrid",
161
- filters: params.filters || {}
162
- });
350
+ const response = await this.searchWithProof(params);
163
351
  return response.results;
164
352
  }
165
353
  /** Search while preserving the automatic ProofLoop evidence context. */
166
354
  async searchWithProof(params) {
167
- return this.client.post("/v1/search", {
355
+ const response = await this.client.post("/v1/search", {
168
356
  query: params.query,
169
357
  collection_id: params.collection_id,
170
358
  user_id: params.user_id,
359
+ agent_id: params.agent_id,
360
+ run_id: params.run_id,
171
361
  limit: params.limit || 10,
172
362
  search_type: params.search_type || "hybrid",
173
- filters: params.filters || {}
363
+ filters: params.filters || {},
364
+ fast: params.fast,
365
+ threshold: params.threshold,
366
+ include_low_confidence: params.include_low_confidence ?? false,
367
+ group_by_source: params.group_by_source ?? true,
368
+ debug: params.debug ?? false
174
369
  });
370
+ return enforceSearchSafety(response);
175
371
  }
176
372
  /**
177
373
  * Find similar memories
@@ -187,12 +383,20 @@ var SearchResource = class extends BaseResource {
187
383
  * Perform reasoning over memories
188
384
  */
189
385
  async reason(params) {
190
- return this.client.post("/v1/search/reason", {
191
- query: params.query,
192
- collection_id: params.collection_id,
193
- provider: params.provider,
194
- include_steps: params.include_steps || false
195
- });
386
+ const response = await this.client.post(
387
+ "/v1/search/reason",
388
+ {
389
+ query: params.query,
390
+ collection_id: params.collection_id,
391
+ provider: params.provider,
392
+ include_steps: params.include_steps ?? false,
393
+ user_id: params.user_id,
394
+ agent_id: params.agent_id,
395
+ run_id: params.run_id,
396
+ facets: params.facets ?? []
397
+ }
398
+ );
399
+ return enforceSearchSafety(response, "sources");
196
400
  }
197
401
  };
198
402
  var ProofLoopResource = class extends BaseResource {
@@ -212,11 +416,37 @@ var ProofLoopResource = class extends BaseResource {
212
416
  ...body
213
417
  });
214
418
  }
419
+ async getDecision(decisionId) {
420
+ return this.client.get(`/v1/learning/decisions/${decisionId}`);
421
+ }
422
+ async defineMetric(params) {
423
+ return this.client.post("/v1/learning/metrics", params);
424
+ }
425
+ async listMetrics(params = {}) {
426
+ return this.client.get("/v1/learning/metrics", params);
427
+ }
428
+ async policyInsights(policyKey, params = {}) {
429
+ return this.client.get(`/v1/learning/policies/${policyKey}/insights`, {
430
+ collection_id: params.collection_id,
431
+ user_id: params.user_id,
432
+ action_key: params.action_keys,
433
+ context: params.context ? JSON.stringify(params.context) : void 0
434
+ });
435
+ }
436
+ async evaluatePolicy(policyKey, params = {}) {
437
+ return this.client.post(`/v1/learning/policies/${policyKey}/evaluate`, {
438
+ collection_id: params.collection_id,
439
+ user_id: params.user_id,
440
+ limit: params.limit ?? 500
441
+ });
442
+ }
215
443
  async proof(decisionId) {
216
444
  return this.client.get(`/v1/learning/decisions/${decisionId}/proof`);
217
445
  }
218
- async publicKey() {
219
- return this.client.get("/v1/learning/proof-key");
446
+ async publicKey(keyId) {
447
+ return this.client.get("/v1/learning/proof-key", {
448
+ key_id: keyId
449
+ });
220
450
  }
221
451
  };
222
452
  var RLResource = class extends BaseResource {
@@ -257,56 +487,78 @@ var RLResource = class extends BaseResource {
257
487
  }
258
488
  };
259
489
  var ProceduralResource = class extends BaseResource {
490
+ unwrapProcedure(response) {
491
+ if (response?.procedure) return response.procedure;
492
+ if (response?.procedure_id && !response?.id) {
493
+ return { ...response, id: response.procedure_id };
494
+ }
495
+ return response;
496
+ }
260
497
  /**
261
498
  * Create a new procedure
262
499
  */
263
500
  async create(params) {
264
- return this.client.post("/procedural", {
501
+ const response = await this.client.post("/v1/procedures", {
265
502
  name: params.name,
266
503
  description: params.description,
267
- trigger_condition: params.trigger_condition,
268
- action_sequence: params.action_sequence,
504
+ condition: { expression: params.trigger_condition },
505
+ action: { steps: params.action_sequence },
269
506
  collection_id: params.collection_id,
270
507
  category: params.category,
271
- metadata: params.metadata || {}
508
+ parameters: params.metadata || {}
272
509
  });
510
+ return this.unwrapProcedure(response);
273
511
  }
274
512
  /**
275
513
  * List procedures
276
514
  */
277
515
  async list(params) {
278
- return this.client.get("/procedural", {
516
+ const response = await this.client.get("/v1/procedures", {
279
517
  collection_id: params?.collection_id,
280
518
  category: params?.category,
281
519
  skip: params?.skip || 0,
282
520
  limit: params?.limit || 100
283
521
  });
522
+ return Array.isArray(response) ? response : response?.procedures || [];
284
523
  }
285
524
  /**
286
525
  * Get a specific procedure
287
526
  */
288
527
  async get(procedureId) {
289
- return this.client.get(`/procedural/${procedureId}`);
528
+ const response = await this.client.get(`/v1/procedures/${procedureId}`);
529
+ return this.unwrapProcedure(response);
290
530
  }
291
531
  /**
292
532
  * Execute a procedure
293
533
  */
294
534
  async execute(procedureId, context) {
295
- return this.client.post(`/procedural/${procedureId}/execute`, {
296
- context: context || {}
535
+ const response = await this.client.post(`/v1/procedures/${procedureId}/execute`, {
536
+ input_state: context || {}
297
537
  });
538
+ return response?.execution_result || response;
298
539
  }
299
540
  /**
300
541
  * Update a procedure
301
542
  */
302
543
  async update(procedureId, params) {
303
- return this.client.patch(`/procedural/${procedureId}`, params);
544
+ const body = {};
545
+ if (params.name !== void 0) body.name = params.name;
546
+ if (params.description !== void 0) body.description = params.description;
547
+ if (params.trigger_condition !== void 0) {
548
+ body.condition = { expression: params.trigger_condition };
549
+ }
550
+ if (params.action_sequence !== void 0) {
551
+ body.action = { steps: params.action_sequence };
552
+ }
553
+ if (params.metadata !== void 0) body.parameters = params.metadata;
554
+ const response = await this.client.patch(`/v1/procedures/${procedureId}`, body);
555
+ return this.unwrapProcedure(response);
304
556
  }
305
557
  /**
306
558
  * Delete a procedure
307
559
  */
308
560
  async delete(procedureId) {
309
- await this.client.delete(`/procedural/${procedureId}`);
561
+ await this.client.delete(`/v1/procedures/${procedureId}`);
310
562
  }
311
563
  };
312
564
  var TemporalResource = class extends BaseResource {
@@ -345,6 +597,10 @@ var TemporalResource = class extends BaseResource {
345
597
  entity
346
598
  });
347
599
  }
600
+ /** Permanently delete a tenant-scoped temporal fact by stable ID. */
601
+ async deleteFact(factId) {
602
+ return this.client.delete(`/temporal/facts/${factId}`);
603
+ }
348
604
  };
349
605
  var WorkingMemoryResource = class extends BaseResource {
350
606
  /**
@@ -513,6 +769,8 @@ var MemoryClient = class {
513
769
  this.auth = new AuthResource(this);
514
770
  this.collections = new CollectionsResource(this);
515
771
  this.memories = new MemoriesResource(this);
772
+ this.memoryJobs = new MemoryJobsResource(this);
773
+ this.corrections = new CorrectionsResource(this);
516
774
  this.searchResource = new SearchResource(this);
517
775
  this.rl = new RLResource(this);
518
776
  this.procedural = new ProceduralResource(this);
@@ -526,7 +784,7 @@ var MemoryClient = class {
526
784
  getHeaders() {
527
785
  const headers = {
528
786
  "Content-Type": "application/json",
529
- "User-Agent": "hebbrix-typescript/2.1.0"
787
+ "User-Agent": "hebbrix-typescript/2.2.1"
530
788
  };
531
789
  if (this.apiKey) {
532
790
  headers["Authorization"] = `Bearer ${this.apiKey}`;
@@ -535,7 +793,8 @@ var MemoryClient = class {
535
793
  }
536
794
  handleError(response, data) {
537
795
  const statusCode = response.status;
538
- const message = data?.error?.message || data?.detail || response.statusText;
796
+ const detail = data?.detail;
797
+ const message = data?.error?.message || (typeof detail === "string" ? detail : detail?.message) || response.statusText;
539
798
  if (statusCode === 401) {
540
799
  throw new AuthenticationError(message);
541
800
  } else if (statusCode === 404) {
@@ -553,21 +812,29 @@ var MemoryClient = class {
553
812
  }
554
813
  async request(method, path, options = {}) {
555
814
  const url = `${this.baseUrl}${path}`;
815
+ const { headers: requestHeaders, signal: requestSignal, ...requestOptions } = options;
556
816
  const response = await fetch(url, {
817
+ ...requestOptions,
557
818
  method,
558
819
  headers: {
559
820
  ...this.getHeaders(),
560
- ...options.headers || {}
821
+ ...requestHeaders || {}
561
822
  },
562
- ...options,
563
- signal: AbortSignal.timeout(this.timeout)
823
+ signal: requestSignal || AbortSignal.timeout(this.timeout)
564
824
  });
565
- let data;
825
+ let data = void 0;
566
826
  const contentType = response.headers.get("content-type");
567
- if (contentType?.includes("application/json")) {
568
- data = await response.json();
569
- } else {
570
- data = await response.text();
827
+ const responseText = await response.text();
828
+ if (responseText) {
829
+ if (contentType?.includes("application/json")) {
830
+ try {
831
+ data = JSON.parse(responseText);
832
+ } catch {
833
+ data = { detail: responseText };
834
+ }
835
+ } else {
836
+ data = responseText;
837
+ }
571
838
  }
572
839
  if (!response.ok) {
573
840
  this.handleError(response, data);
@@ -580,7 +847,11 @@ var MemoryClient = class {
580
847
  const searchParams = new URLSearchParams();
581
848
  Object.entries(params).forEach(([key, value]) => {
582
849
  if (value !== void 0 && value !== null) {
583
- searchParams.append(key, String(value));
850
+ if (Array.isArray(value)) {
851
+ value.forEach((item) => searchParams.append(key, String(item)));
852
+ } else {
853
+ searchParams.append(key, String(value));
854
+ }
584
855
  }
585
856
  });
586
857
  url += `?${searchParams.toString()}`;
@@ -617,9 +888,11 @@ var MemoryClient = class {
617
888
  AuthenticationError,
618
889
  CollectionsResource,
619
890
  ConsolidationResource,
891
+ CorrectionsResource,
620
892
  HebbrixError,
621
893
  MemoriesResource,
622
894
  MemoryClient,
895
+ MemoryJobsResource,
623
896
  MemoryToolsResource,
624
897
  NotFoundError,
625
898
  ProceduralResource,
@@ -631,5 +904,6 @@ var MemoryClient = class {
631
904
  TemporalResource,
632
905
  ValidationError,
633
906
  WorkingMemoryResource,
634
- WorldModelResource
907
+ WorldModelResource,
908
+ enforceSearchSafety
635
909
  });