hebbrix 2.3.0 → 2.3.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/CHANGELOG.md +7 -0
- package/README.md +23 -1
- package/dist/index.d.mts +59 -4
- package/dist/index.d.ts +59 -4
- package/dist/index.js +290 -25
- package/dist/index.mjs +287 -25
- package/package.json +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.3.1 — 2026-08-27
|
|
4
|
+
|
|
5
|
+
- Make single-memory `wait_for_index` a client-enforced readiness contract:
|
|
6
|
+
submit exactly one write, poll the durable receipt to searchable completion,
|
|
7
|
+
preserve receipt and idempotency context on timeout or cancellation, and
|
|
8
|
+
reject terminal indexing states.
|
|
9
|
+
|
|
3
10
|
## 2.3.0 — 2026-08-27
|
|
4
11
|
|
|
5
12
|
- Reconcile every exported advanced method with the canonical public OpenAPI,
|
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ outcome-learning APIs.
|
|
|
6
6
|
## Install
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
npm install hebbrix@2.3.
|
|
9
|
+
npm install hebbrix@2.3.1
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Node.js 16+ and modern browsers are supported.
|
|
@@ -43,6 +43,28 @@ it throws `IndexingTimeoutError`; the error retains the receipt, durable memory
|
|
|
43
43
|
IDs, and status URL. Reuse the same idempotency key with the same body to recover
|
|
44
44
|
the same logical resources.
|
|
45
45
|
|
|
46
|
+
Single writes and batch writes use the same one-write readiness rule. The
|
|
47
|
+
client sends exactly one mutation, then uses read-only status requests. Set
|
|
48
|
+
`index_timeout_ms` and `index_poll_interval_ms` on `memories.create()` to tune
|
|
49
|
+
that client-side wait. A signal can cancel the initial request; once a receipt
|
|
50
|
+
is available, cancellation stops only the read-only polling.
|
|
51
|
+
`IndexingAbortedError` then preserves the durable receipt and IDs so
|
|
52
|
+
cancellation cannot be mistaken for a failed write. Terminal `failed`,
|
|
53
|
+
`cancelled`, or `canceled` states raise `IndexingTerminalError` with the same
|
|
54
|
+
receipt context.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
const ready = await client.memories.create({
|
|
59
|
+
content: "Customer prefers concise replies",
|
|
60
|
+
wait_for_index: true,
|
|
61
|
+
index_timeout_ms: 30_000,
|
|
62
|
+
index_poll_interval_ms: 250,
|
|
63
|
+
signal: controller.signal,
|
|
64
|
+
idempotency_key: "customer-42-preference-v1",
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
46
68
|
```typescript
|
|
47
69
|
const receipt = await client.memories.createBatch({
|
|
48
70
|
memories: [{ content: "First fact" }, { content: "Second fact" }],
|
package/dist/index.d.mts
CHANGED
|
@@ -38,6 +38,12 @@ interface Memory {
|
|
|
38
38
|
source_reference?: string;
|
|
39
39
|
access_count: number;
|
|
40
40
|
last_accessed_at?: string;
|
|
41
|
+
/** Authoritative indexing state returned by GET /v1/memories/{id}. */
|
|
42
|
+
processing_status?: string;
|
|
43
|
+
/** True only when the memory is available to search. */
|
|
44
|
+
searchable?: boolean;
|
|
45
|
+
outbox_event_id?: string;
|
|
46
|
+
status_url?: string;
|
|
41
47
|
created_at: string;
|
|
42
48
|
updated_at: string;
|
|
43
49
|
}
|
|
@@ -155,6 +161,12 @@ interface CreateMemoryParams {
|
|
|
155
161
|
source?: string;
|
|
156
162
|
/** Stable retry key sent as the Idempotency-Key transport header. */
|
|
157
163
|
idempotency_key?: string;
|
|
164
|
+
/** Optional caller cancellation signal; it is never serialized. */
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
/** Client-side readiness deadline used only when wait_for_index=true. */
|
|
167
|
+
index_timeout_ms?: number;
|
|
168
|
+
/** Poll interval for a durable pending receipt. */
|
|
169
|
+
index_poll_interval_ms?: number;
|
|
158
170
|
}
|
|
159
171
|
interface MemoryAddResult {
|
|
160
172
|
id: string;
|
|
@@ -162,6 +174,7 @@ interface MemoryAddResult {
|
|
|
162
174
|
event: "ADD" | "UPDATE" | "NOOP" | string;
|
|
163
175
|
memory?: string;
|
|
164
176
|
reason?: string;
|
|
177
|
+
processing_status?: string;
|
|
165
178
|
}
|
|
166
179
|
interface MemoryAddResponse {
|
|
167
180
|
results: MemoryAddResult[];
|
|
@@ -170,6 +183,9 @@ interface MemoryAddResponse {
|
|
|
170
183
|
searchable: boolean;
|
|
171
184
|
outbox_event_id?: string;
|
|
172
185
|
status_url?: string;
|
|
186
|
+
idempotency_replay?: boolean;
|
|
187
|
+
request_id?: string;
|
|
188
|
+
retry_after?: string;
|
|
173
189
|
job_id?: string;
|
|
174
190
|
created_count: number;
|
|
175
191
|
updated_count: number;
|
|
@@ -370,9 +386,23 @@ declare class CollectionsResource extends BaseResource {
|
|
|
370
386
|
}
|
|
371
387
|
declare class MemoriesResource extends BaseResource {
|
|
372
388
|
/**
|
|
373
|
-
* Create
|
|
389
|
+
* Create one logical memory write. When `wait_for_index=true`, a durable
|
|
390
|
+
* pending receipt is polled without issuing a second create request.
|
|
374
391
|
*/
|
|
375
392
|
create(params: CreateMemoryParams): Promise<MemoryAddResponse>;
|
|
393
|
+
/** Poll a single-write durable receipt until every accepted memory is searchable. */
|
|
394
|
+
waitForSearchable(receipt: MemoryAddResponse, options?: {
|
|
395
|
+
timeoutMs?: number;
|
|
396
|
+
pollIntervalMs?: number;
|
|
397
|
+
signal?: AbortSignal;
|
|
398
|
+
idempotencyKey?: string;
|
|
399
|
+
}): Promise<MemoryAddResponse>;
|
|
400
|
+
private memoryIds;
|
|
401
|
+
private isSearchableCompletion;
|
|
402
|
+
private isTerminalStatus;
|
|
403
|
+
private readinessPath;
|
|
404
|
+
private throwIfPollingAborted;
|
|
405
|
+
private pollingDelay;
|
|
376
406
|
/**
|
|
377
407
|
* Create up to 100 memories with one unambiguous readiness contract.
|
|
378
408
|
* `wait_for_index=true` resolves only for a fully searchable batch. A durable
|
|
@@ -689,11 +719,36 @@ declare class EntitlementError extends HebbrixError {
|
|
|
689
719
|
details?: Record<string, any>;
|
|
690
720
|
});
|
|
691
721
|
}
|
|
692
|
-
|
|
722
|
+
interface IndexingWaitErrorOptions {
|
|
723
|
+
idempotencyKey?: string;
|
|
724
|
+
cause?: unknown;
|
|
725
|
+
}
|
|
726
|
+
/** Base class for readiness failures after the API has accepted a durable write. */
|
|
727
|
+
declare class IndexingWaitError extends Error {
|
|
693
728
|
receipt: Record<string, any>;
|
|
694
729
|
memoryIds: string[];
|
|
730
|
+
jobId?: string;
|
|
695
731
|
statusUrl?: string;
|
|
696
|
-
|
|
732
|
+
requestId?: string;
|
|
733
|
+
outboxEventId?: string;
|
|
734
|
+
indexingEventId?: string;
|
|
735
|
+
eventId?: string;
|
|
736
|
+
idempotencyReplay?: boolean;
|
|
737
|
+
idempotencyKey?: string;
|
|
738
|
+
retryAfter?: string;
|
|
739
|
+
recovery: Record<string, unknown>;
|
|
740
|
+
cause?: unknown;
|
|
741
|
+
constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
|
|
742
|
+
}
|
|
743
|
+
declare class IndexingTimeoutError extends IndexingWaitError {
|
|
744
|
+
constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
|
|
745
|
+
}
|
|
746
|
+
declare class IndexingAbortedError extends IndexingWaitError {
|
|
747
|
+
constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
|
|
748
|
+
}
|
|
749
|
+
declare class IndexingTerminalError extends IndexingWaitError {
|
|
750
|
+
processingStatus: string;
|
|
751
|
+
constructor(message: string, receipt: Record<string, any>, processingStatus: string, options?: IndexingWaitErrorOptions);
|
|
697
752
|
}
|
|
698
753
|
declare class AuthenticationError extends HebbrixError {
|
|
699
754
|
constructor(message?: string, options?: {
|
|
@@ -752,4 +807,4 @@ interface SafetyEnvelope {
|
|
|
752
807
|
*/
|
|
753
808
|
declare function enforceSearchSafety<T extends object>(response: T, rowsKey?: "results" | "sources"): T & SafetyEnvelope;
|
|
754
809
|
|
|
755
|
-
export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingTimeoutError, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
|
|
810
|
+
export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingAbortedError, IndexingTerminalError, IndexingTimeoutError, IndexingWaitError, type IndexingWaitErrorOptions, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,12 @@ interface Memory {
|
|
|
38
38
|
source_reference?: string;
|
|
39
39
|
access_count: number;
|
|
40
40
|
last_accessed_at?: string;
|
|
41
|
+
/** Authoritative indexing state returned by GET /v1/memories/{id}. */
|
|
42
|
+
processing_status?: string;
|
|
43
|
+
/** True only when the memory is available to search. */
|
|
44
|
+
searchable?: boolean;
|
|
45
|
+
outbox_event_id?: string;
|
|
46
|
+
status_url?: string;
|
|
41
47
|
created_at: string;
|
|
42
48
|
updated_at: string;
|
|
43
49
|
}
|
|
@@ -155,6 +161,12 @@ interface CreateMemoryParams {
|
|
|
155
161
|
source?: string;
|
|
156
162
|
/** Stable retry key sent as the Idempotency-Key transport header. */
|
|
157
163
|
idempotency_key?: string;
|
|
164
|
+
/** Optional caller cancellation signal; it is never serialized. */
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
/** Client-side readiness deadline used only when wait_for_index=true. */
|
|
167
|
+
index_timeout_ms?: number;
|
|
168
|
+
/** Poll interval for a durable pending receipt. */
|
|
169
|
+
index_poll_interval_ms?: number;
|
|
158
170
|
}
|
|
159
171
|
interface MemoryAddResult {
|
|
160
172
|
id: string;
|
|
@@ -162,6 +174,7 @@ interface MemoryAddResult {
|
|
|
162
174
|
event: "ADD" | "UPDATE" | "NOOP" | string;
|
|
163
175
|
memory?: string;
|
|
164
176
|
reason?: string;
|
|
177
|
+
processing_status?: string;
|
|
165
178
|
}
|
|
166
179
|
interface MemoryAddResponse {
|
|
167
180
|
results: MemoryAddResult[];
|
|
@@ -170,6 +183,9 @@ interface MemoryAddResponse {
|
|
|
170
183
|
searchable: boolean;
|
|
171
184
|
outbox_event_id?: string;
|
|
172
185
|
status_url?: string;
|
|
186
|
+
idempotency_replay?: boolean;
|
|
187
|
+
request_id?: string;
|
|
188
|
+
retry_after?: string;
|
|
173
189
|
job_id?: string;
|
|
174
190
|
created_count: number;
|
|
175
191
|
updated_count: number;
|
|
@@ -370,9 +386,23 @@ declare class CollectionsResource extends BaseResource {
|
|
|
370
386
|
}
|
|
371
387
|
declare class MemoriesResource extends BaseResource {
|
|
372
388
|
/**
|
|
373
|
-
* Create
|
|
389
|
+
* Create one logical memory write. When `wait_for_index=true`, a durable
|
|
390
|
+
* pending receipt is polled without issuing a second create request.
|
|
374
391
|
*/
|
|
375
392
|
create(params: CreateMemoryParams): Promise<MemoryAddResponse>;
|
|
393
|
+
/** Poll a single-write durable receipt until every accepted memory is searchable. */
|
|
394
|
+
waitForSearchable(receipt: MemoryAddResponse, options?: {
|
|
395
|
+
timeoutMs?: number;
|
|
396
|
+
pollIntervalMs?: number;
|
|
397
|
+
signal?: AbortSignal;
|
|
398
|
+
idempotencyKey?: string;
|
|
399
|
+
}): Promise<MemoryAddResponse>;
|
|
400
|
+
private memoryIds;
|
|
401
|
+
private isSearchableCompletion;
|
|
402
|
+
private isTerminalStatus;
|
|
403
|
+
private readinessPath;
|
|
404
|
+
private throwIfPollingAborted;
|
|
405
|
+
private pollingDelay;
|
|
376
406
|
/**
|
|
377
407
|
* Create up to 100 memories with one unambiguous readiness contract.
|
|
378
408
|
* `wait_for_index=true` resolves only for a fully searchable batch. A durable
|
|
@@ -689,11 +719,36 @@ declare class EntitlementError extends HebbrixError {
|
|
|
689
719
|
details?: Record<string, any>;
|
|
690
720
|
});
|
|
691
721
|
}
|
|
692
|
-
|
|
722
|
+
interface IndexingWaitErrorOptions {
|
|
723
|
+
idempotencyKey?: string;
|
|
724
|
+
cause?: unknown;
|
|
725
|
+
}
|
|
726
|
+
/** Base class for readiness failures after the API has accepted a durable write. */
|
|
727
|
+
declare class IndexingWaitError extends Error {
|
|
693
728
|
receipt: Record<string, any>;
|
|
694
729
|
memoryIds: string[];
|
|
730
|
+
jobId?: string;
|
|
695
731
|
statusUrl?: string;
|
|
696
|
-
|
|
732
|
+
requestId?: string;
|
|
733
|
+
outboxEventId?: string;
|
|
734
|
+
indexingEventId?: string;
|
|
735
|
+
eventId?: string;
|
|
736
|
+
idempotencyReplay?: boolean;
|
|
737
|
+
idempotencyKey?: string;
|
|
738
|
+
retryAfter?: string;
|
|
739
|
+
recovery: Record<string, unknown>;
|
|
740
|
+
cause?: unknown;
|
|
741
|
+
constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
|
|
742
|
+
}
|
|
743
|
+
declare class IndexingTimeoutError extends IndexingWaitError {
|
|
744
|
+
constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
|
|
745
|
+
}
|
|
746
|
+
declare class IndexingAbortedError extends IndexingWaitError {
|
|
747
|
+
constructor(message: string, receipt: Record<string, any>, options?: IndexingWaitErrorOptions);
|
|
748
|
+
}
|
|
749
|
+
declare class IndexingTerminalError extends IndexingWaitError {
|
|
750
|
+
processingStatus: string;
|
|
751
|
+
constructor(message: string, receipt: Record<string, any>, processingStatus: string, options?: IndexingWaitErrorOptions);
|
|
697
752
|
}
|
|
698
753
|
declare class AuthenticationError extends HebbrixError {
|
|
699
754
|
constructor(message?: string, options?: {
|
|
@@ -752,4 +807,4 @@ interface SafetyEnvelope {
|
|
|
752
807
|
*/
|
|
753
808
|
declare function enforceSearchSafety<T extends object>(response: T, rowsKey?: "results" | "sources"): T & SafetyEnvelope;
|
|
754
809
|
|
|
755
|
-
export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingTimeoutError, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
|
|
810
|
+
export { type APIKeyResponse, AuthResource, type AuthResponse, AuthenticationError, type BatchMemoryCreateParams, type BatchMemoryItemParams, type BatchMemoryResponse, type ClientConfig, type Collection, CollectionsResource, ConsolidationResource, type CorrectionCreateParams, type CorrectionSearchParams, CorrectionsResource, type CreateCollectionParams, type CreateMemoryParams, type CursorPage, EntitlementError, type EvidenceClaim, type GroundingReceipt, HebbrixError, IndexingAbortedError, IndexingTerminalError, IndexingTimeoutError, IndexingWaitError, type IndexingWaitErrorOptions, type ListParams, MemoriesResource, type Memory, type MemoryAddResponse, type MemoryAddResult, MemoryClient, type MemoryJobReceipt, MemoryJobsResource, type MemoryListParams, MemoryToolsResource, type MemoryWithMetadata, NotFoundError, ProceduralResource, type ProofContext, type ProofLoopCandidate, type ProofLoopDecisionParams, type ProofLoopMetricParams, ProofLoopResource, RLResource, RateLimitError, type ReasonParams, type ReasoningResponse, type ReasoningSource, type SafetyEnvelope, type SearchParams, SearchResource, type SearchResponse, type SearchResult, ServerError, TemporalResource, type UpdateCollectionParams, type UpdateMemoryParams, type User, ValidationError, WorkingMemoryResource, enforceSearchSafety };
|
package/dist/index.js
CHANGED
|
@@ -27,7 +27,10 @@ __export(index_exports, {
|
|
|
27
27
|
CorrectionsResource: () => CorrectionsResource,
|
|
28
28
|
EntitlementError: () => EntitlementError,
|
|
29
29
|
HebbrixError: () => HebbrixError,
|
|
30
|
+
IndexingAbortedError: () => IndexingAbortedError,
|
|
31
|
+
IndexingTerminalError: () => IndexingTerminalError,
|
|
30
32
|
IndexingTimeoutError: () => IndexingTimeoutError,
|
|
33
|
+
IndexingWaitError: () => IndexingWaitError,
|
|
31
34
|
MemoriesResource: () => MemoriesResource,
|
|
32
35
|
MemoryClient: () => MemoryClient,
|
|
33
36
|
MemoryJobsResource: () => MemoryJobsResource,
|
|
@@ -119,16 +122,72 @@ var EntitlementError = class _EntitlementError extends HebbrixError {
|
|
|
119
122
|
Object.setPrototypeOf(this, _EntitlementError.prototype);
|
|
120
123
|
}
|
|
121
124
|
};
|
|
122
|
-
var
|
|
123
|
-
constructor(message, receipt) {
|
|
125
|
+
var IndexingWaitError = class _IndexingWaitError extends Error {
|
|
126
|
+
constructor(message, receipt, options = {}) {
|
|
124
127
|
super(message);
|
|
125
|
-
this.name = "
|
|
128
|
+
this.name = "IndexingWaitError";
|
|
126
129
|
this.receipt = { ...receipt };
|
|
127
|
-
this.memoryIds = [
|
|
128
|
-
|
|
130
|
+
this.memoryIds = [
|
|
131
|
+
...new Set(
|
|
132
|
+
[
|
|
133
|
+
...receipt.memory_ids || [],
|
|
134
|
+
receipt.memory_id,
|
|
135
|
+
receipt.id,
|
|
136
|
+
...(receipt.results || []).map(
|
|
137
|
+
(row) => row.memory_id || row.id
|
|
138
|
+
)
|
|
139
|
+
].filter(Boolean)
|
|
140
|
+
)
|
|
141
|
+
];
|
|
142
|
+
this.jobId = receipt.job_id;
|
|
143
|
+
this.statusUrl = receipt.status_url || (this.memoryIds.length === 1 ? `/v1/memories/${encodeURIComponent(this.memoryIds[0])}` : this.jobId ? `/v1/memory-jobs/${encodeURIComponent(this.jobId)}` : void 0);
|
|
144
|
+
this.requestId = receipt.request_id;
|
|
145
|
+
this.outboxEventId = receipt.outbox_event_id;
|
|
146
|
+
this.indexingEventId = receipt.indexing_event_id || this.outboxEventId;
|
|
147
|
+
this.eventId = receipt.event_id || this.indexingEventId;
|
|
148
|
+
this.idempotencyReplay = receipt.idempotency_replay;
|
|
149
|
+
this.idempotencyKey = options.idempotencyKey || receipt.idempotency_key;
|
|
150
|
+
this.retryAfter = receipt.retry_after;
|
|
151
|
+
this.recovery = Object.fromEntries(
|
|
152
|
+
Object.entries({
|
|
153
|
+
memory_ids: this.memoryIds,
|
|
154
|
+
job_id: this.jobId,
|
|
155
|
+
status_url: this.statusUrl,
|
|
156
|
+
request_id: this.requestId,
|
|
157
|
+
outbox_event_id: this.outboxEventId,
|
|
158
|
+
indexing_event_id: this.indexingEventId,
|
|
159
|
+
event_id: this.eventId,
|
|
160
|
+
idempotency_key: this.idempotencyKey,
|
|
161
|
+
idempotency_replay: this.idempotencyReplay,
|
|
162
|
+
retry_after: this.retryAfter
|
|
163
|
+
}).filter(([, value]) => value !== void 0 && value !== null)
|
|
164
|
+
);
|
|
165
|
+
this.cause = options.cause;
|
|
166
|
+
Object.setPrototypeOf(this, _IndexingWaitError.prototype);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var IndexingTimeoutError = class _IndexingTimeoutError extends IndexingWaitError {
|
|
170
|
+
constructor(message, receipt, options = {}) {
|
|
171
|
+
super(message, receipt, options);
|
|
172
|
+
this.name = "IndexingTimeoutError";
|
|
129
173
|
Object.setPrototypeOf(this, _IndexingTimeoutError.prototype);
|
|
130
174
|
}
|
|
131
175
|
};
|
|
176
|
+
var IndexingAbortedError = class _IndexingAbortedError extends IndexingWaitError {
|
|
177
|
+
constructor(message, receipt, options = {}) {
|
|
178
|
+
super(message, receipt, options);
|
|
179
|
+
this.name = "IndexingAbortedError";
|
|
180
|
+
Object.setPrototypeOf(this, _IndexingAbortedError.prototype);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var IndexingTerminalError = class _IndexingTerminalError extends IndexingWaitError {
|
|
184
|
+
constructor(message, receipt, processingStatus, options = {}) {
|
|
185
|
+
super(message, receipt, options);
|
|
186
|
+
this.name = "IndexingTerminalError";
|
|
187
|
+
this.processingStatus = processingStatus;
|
|
188
|
+
Object.setPrototypeOf(this, _IndexingTerminalError.prototype);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
132
191
|
var AuthenticationError = class _AuthenticationError extends HebbrixError {
|
|
133
192
|
constructor(message = "Authentication failed", options = {}) {
|
|
134
193
|
super(message, 401, options);
|
|
@@ -242,22 +301,195 @@ var CollectionsResource = class extends BaseResource {
|
|
|
242
301
|
};
|
|
243
302
|
var MemoriesResource = class extends BaseResource {
|
|
244
303
|
/**
|
|
245
|
-
* Create
|
|
304
|
+
* Create one logical memory write. When `wait_for_index=true`, a durable
|
|
305
|
+
* pending receipt is polled without issuing a second create request.
|
|
246
306
|
*/
|
|
247
307
|
async create(params) {
|
|
248
308
|
if (!params.content?.trim() && !params.messages?.length) {
|
|
249
309
|
throw new TypeError("content or messages must be provided");
|
|
250
310
|
}
|
|
251
|
-
const {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
311
|
+
const {
|
|
312
|
+
idempotency_key,
|
|
313
|
+
signal,
|
|
314
|
+
index_timeout_ms,
|
|
315
|
+
index_poll_interval_ms,
|
|
316
|
+
...input
|
|
317
|
+
} = params;
|
|
318
|
+
const receipt = await this.client.request(
|
|
319
|
+
"POST",
|
|
320
|
+
"/v1/memories",
|
|
321
|
+
{
|
|
322
|
+
headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
|
|
323
|
+
body: JSON.stringify({
|
|
324
|
+
source_type: "text",
|
|
325
|
+
metadata: {},
|
|
326
|
+
infer: false,
|
|
327
|
+
wait_for_index: false,
|
|
328
|
+
...input
|
|
329
|
+
}),
|
|
330
|
+
signal
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
if (params.wait_for_index && !this.isSearchableCompletion(receipt)) {
|
|
334
|
+
return this.waitForSearchable(receipt, {
|
|
335
|
+
timeoutMs: index_timeout_ms,
|
|
336
|
+
pollIntervalMs: index_poll_interval_ms,
|
|
337
|
+
signal,
|
|
338
|
+
idempotencyKey: idempotency_key
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return receipt;
|
|
342
|
+
}
|
|
343
|
+
/** Poll a single-write durable receipt until every accepted memory is searchable. */
|
|
344
|
+
async waitForSearchable(receipt, options = {}) {
|
|
345
|
+
if (this.isSearchableCompletion(receipt)) {
|
|
346
|
+
return receipt;
|
|
347
|
+
}
|
|
348
|
+
if (this.isTerminalStatus(receipt.processing_status)) {
|
|
349
|
+
const status = String(receipt.processing_status).toLowerCase();
|
|
350
|
+
throw new IndexingTerminalError(
|
|
351
|
+
`memory indexing reached terminal state ${status}`,
|
|
352
|
+
receipt,
|
|
353
|
+
status,
|
|
354
|
+
{ idempotencyKey: options.idempotencyKey }
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
const ids = this.memoryIds(receipt);
|
|
358
|
+
if (!ids.length) {
|
|
359
|
+
throw new Error("memory receipt does not contain a durable memory id");
|
|
360
|
+
}
|
|
361
|
+
const timeoutMs = Math.max(0, options.timeoutMs ?? 6e4);
|
|
362
|
+
const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 500);
|
|
363
|
+
const deadline = Date.now() + timeoutMs;
|
|
364
|
+
const paths = ids.map(
|
|
365
|
+
(id, index) => index === 0 && receipt.status_url ? this.readinessPath(receipt.status_url, id) : `/v1/memories/${encodeURIComponent(id)}`
|
|
366
|
+
);
|
|
367
|
+
while (true) {
|
|
368
|
+
this.throwIfPollingAborted(receipt, options);
|
|
369
|
+
if (Date.now() >= deadline) {
|
|
370
|
+
throw new IndexingTimeoutError(
|
|
371
|
+
`memory was not searchable within ${timeoutMs}ms; the write is durable`,
|
|
372
|
+
receipt,
|
|
373
|
+
{ idempotencyKey: options.idempotencyKey }
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
let rows;
|
|
377
|
+
try {
|
|
378
|
+
rows = await Promise.all(
|
|
379
|
+
paths.map(
|
|
380
|
+
(path) => this.client.request("GET", path, {
|
|
381
|
+
signal: options.signal
|
|
382
|
+
})
|
|
383
|
+
)
|
|
384
|
+
);
|
|
385
|
+
} catch (error) {
|
|
386
|
+
if (options.signal?.aborted) {
|
|
387
|
+
throw new IndexingAbortedError(
|
|
388
|
+
"memory readiness polling was aborted after the write became durable",
|
|
389
|
+
receipt,
|
|
390
|
+
{ idempotencyKey: options.idempotencyKey, cause: error }
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
const terminal = rows.find(
|
|
396
|
+
(row) => this.isTerminalStatus(row.processing_status)
|
|
397
|
+
);
|
|
398
|
+
if (terminal) {
|
|
399
|
+
const status = String(terminal.processing_status).toLowerCase();
|
|
400
|
+
throw new IndexingTerminalError(
|
|
401
|
+
`memory ${terminal.id} indexing reached terminal state ${status}`,
|
|
402
|
+
receipt,
|
|
403
|
+
status,
|
|
404
|
+
{ idempotencyKey: options.idempotencyKey }
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
if (rows.every(
|
|
408
|
+
(row) => row.searchable === true && String(row.processing_status || "").toLowerCase() === "completed"
|
|
409
|
+
)) {
|
|
410
|
+
return {
|
|
411
|
+
...receipt,
|
|
412
|
+
processing_status: "completed",
|
|
413
|
+
searchable: true,
|
|
414
|
+
results: receipt.results.map((result) => ({
|
|
415
|
+
...result,
|
|
416
|
+
processing_status: "completed"
|
|
417
|
+
}))
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
const remainingMs = deadline - Date.now();
|
|
421
|
+
if (remainingMs <= 0) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
await this.pollingDelay(
|
|
425
|
+
Math.min(pollIntervalMs, remainingMs),
|
|
426
|
+
receipt,
|
|
427
|
+
options
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
memoryIds(receipt) {
|
|
432
|
+
return [
|
|
433
|
+
...new Set(
|
|
434
|
+
(receipt.results || []).map((row) => row.memory_id || row.id).filter((id) => Boolean(id))
|
|
435
|
+
)
|
|
436
|
+
];
|
|
437
|
+
}
|
|
438
|
+
isSearchableCompletion(receipt) {
|
|
439
|
+
return receipt.searchable === true && String(receipt.processing_status || "").toLowerCase() === "completed";
|
|
440
|
+
}
|
|
441
|
+
isTerminalStatus(status) {
|
|
442
|
+
return ["failed", "cancelled", "canceled"].includes(
|
|
443
|
+
String(status || "").toLowerCase()
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
readinessPath(statusUrl, memoryId) {
|
|
447
|
+
try {
|
|
448
|
+
const parsed = new URL(statusUrl, "https://status.hebbrix.invalid");
|
|
449
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
450
|
+
return `/v1/memories/${encodeURIComponent(memoryId)}`;
|
|
451
|
+
}
|
|
452
|
+
return `${parsed.pathname}${parsed.search}`;
|
|
453
|
+
} catch {
|
|
454
|
+
return `/v1/memories/${encodeURIComponent(memoryId)}`;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
throwIfPollingAborted(receipt, options) {
|
|
458
|
+
if (options.signal?.aborted) {
|
|
459
|
+
throw new IndexingAbortedError(
|
|
460
|
+
"memory readiness polling was aborted after the write became durable",
|
|
461
|
+
receipt,
|
|
462
|
+
{
|
|
463
|
+
idempotencyKey: options.idempotencyKey,
|
|
464
|
+
cause: options.signal.reason
|
|
465
|
+
}
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
async pollingDelay(delayMs, receipt, options) {
|
|
470
|
+
await new Promise((resolve, reject) => {
|
|
471
|
+
const onAbort = () => {
|
|
472
|
+
clearTimeout(timer);
|
|
473
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
474
|
+
reject(
|
|
475
|
+
new IndexingAbortedError(
|
|
476
|
+
"memory readiness polling was aborted after the write became durable",
|
|
477
|
+
receipt,
|
|
478
|
+
{
|
|
479
|
+
idempotencyKey: options.idempotencyKey,
|
|
480
|
+
cause: options.signal?.reason
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
};
|
|
485
|
+
const timer = setTimeout(() => {
|
|
486
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
487
|
+
resolve();
|
|
488
|
+
}, delayMs);
|
|
489
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
490
|
+
if (options.signal?.aborted) {
|
|
491
|
+
onAbort();
|
|
492
|
+
}
|
|
261
493
|
});
|
|
262
494
|
}
|
|
263
495
|
/**
|
|
@@ -608,9 +840,12 @@ var ProceduralResource = class extends BaseResource {
|
|
|
608
840
|
* Execute a procedure
|
|
609
841
|
*/
|
|
610
842
|
async execute(procedureId, context) {
|
|
611
|
-
const response = await this.client.post(
|
|
612
|
-
|
|
613
|
-
|
|
843
|
+
const response = await this.client.post(
|
|
844
|
+
`/v1/procedures/${procedureId}/execute`,
|
|
845
|
+
{
|
|
846
|
+
input_state: context || {}
|
|
847
|
+
}
|
|
848
|
+
);
|
|
614
849
|
return response?.execution_result || response;
|
|
615
850
|
}
|
|
616
851
|
/**
|
|
@@ -627,7 +862,10 @@ var ProceduralResource = class extends BaseResource {
|
|
|
627
862
|
body.action = { steps: params.action_sequence };
|
|
628
863
|
}
|
|
629
864
|
if (params.metadata !== void 0) body.parameters = params.metadata;
|
|
630
|
-
const response = await this.client.patch(
|
|
865
|
+
const response = await this.client.patch(
|
|
866
|
+
`/v1/procedures/${procedureId}`,
|
|
867
|
+
body
|
|
868
|
+
);
|
|
631
869
|
return this.unwrapProcedure(response);
|
|
632
870
|
}
|
|
633
871
|
/**
|
|
@@ -710,7 +948,9 @@ var TemporalResource = class extends BaseResource {
|
|
|
710
948
|
*/
|
|
711
949
|
async pointInTime(timestamp, entity) {
|
|
712
950
|
if (!entity) {
|
|
713
|
-
throw new TypeError(
|
|
951
|
+
throw new TypeError(
|
|
952
|
+
"entity is required and maps to the canonical subject"
|
|
953
|
+
);
|
|
714
954
|
}
|
|
715
955
|
return this.queryAtTime({
|
|
716
956
|
timestamp,
|
|
@@ -794,7 +1034,8 @@ var MemoryToolsResource = class extends BaseResource {
|
|
|
794
1034
|
*/
|
|
795
1035
|
async insert(params) {
|
|
796
1036
|
const metadata = { ...params.metadata || {} };
|
|
797
|
-
if (params.position !== void 0)
|
|
1037
|
+
if (params.position !== void 0)
|
|
1038
|
+
metadata.requested_position = params.position;
|
|
798
1039
|
if (params.reason !== void 0) metadata.reason = params.reason;
|
|
799
1040
|
return this.client.post("/v1/memory-tools/insert", {
|
|
800
1041
|
collection_id: params.collection_id,
|
|
@@ -838,7 +1079,7 @@ var MemoryClient = class {
|
|
|
838
1079
|
getHeaders() {
|
|
839
1080
|
const headers = {
|
|
840
1081
|
"Content-Type": "application/json",
|
|
841
|
-
"User-Agent": "hebbrix-typescript/2.3.
|
|
1082
|
+
"User-Agent": "hebbrix-typescript/2.3.1"
|
|
842
1083
|
};
|
|
843
1084
|
if (this.apiKey) {
|
|
844
1085
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
@@ -864,7 +1105,9 @@ var MemoryClient = class {
|
|
|
864
1105
|
throw new RateLimitError(message, { code, requestId, details });
|
|
865
1106
|
} else if (statusCode >= 500) {
|
|
866
1107
|
throw new ServerError(message, { code, requestId, details });
|
|
867
|
-
} else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(
|
|
1108
|
+
} else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(
|
|
1109
|
+
details?.error
|
|
1110
|
+
))) {
|
|
868
1111
|
throw new EntitlementError(message, statusCode, {
|
|
869
1112
|
code,
|
|
870
1113
|
requestId,
|
|
@@ -876,7 +1119,11 @@ var MemoryClient = class {
|
|
|
876
1119
|
}
|
|
877
1120
|
async request(method, path, options = {}) {
|
|
878
1121
|
const url = `${this.baseUrl}${path}`;
|
|
879
|
-
const {
|
|
1122
|
+
const {
|
|
1123
|
+
headers: requestHeaders,
|
|
1124
|
+
signal: requestSignal,
|
|
1125
|
+
...requestOptions
|
|
1126
|
+
} = options;
|
|
880
1127
|
const response = await fetch(url, {
|
|
881
1128
|
...requestOptions,
|
|
882
1129
|
method,
|
|
@@ -903,6 +1150,21 @@ var MemoryClient = class {
|
|
|
903
1150
|
if (!response.ok) {
|
|
904
1151
|
this.handleError(response, data);
|
|
905
1152
|
}
|
|
1153
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
1154
|
+
const requestId = response.headers.get("X-Request-ID");
|
|
1155
|
+
const statusUrl = response.headers.get("Location");
|
|
1156
|
+
const outboxEventId = response.headers.get("X-Hebbrix-Index-Event");
|
|
1157
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
1158
|
+
const idempotencyReplay = response.headers.get("X-Idempotent-Replay");
|
|
1159
|
+
data = {
|
|
1160
|
+
...data,
|
|
1161
|
+
...data.request_id === void 0 && requestId ? { request_id: requestId } : {},
|
|
1162
|
+
...data.status_url === void 0 && statusUrl ? { status_url: statusUrl } : {},
|
|
1163
|
+
...data.outbox_event_id === void 0 && outboxEventId ? { outbox_event_id: outboxEventId } : {},
|
|
1164
|
+
...data.retry_after === void 0 && retryAfter ? { retry_after: retryAfter } : {},
|
|
1165
|
+
...data.idempotency_replay === void 0 && idempotencyReplay ? { idempotency_replay: idempotencyReplay.toLowerCase() === "true" } : {}
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
906
1168
|
return data;
|
|
907
1169
|
}
|
|
908
1170
|
async get(path, params) {
|
|
@@ -955,7 +1217,10 @@ var MemoryClient = class {
|
|
|
955
1217
|
CorrectionsResource,
|
|
956
1218
|
EntitlementError,
|
|
957
1219
|
HebbrixError,
|
|
1220
|
+
IndexingAbortedError,
|
|
1221
|
+
IndexingTerminalError,
|
|
958
1222
|
IndexingTimeoutError,
|
|
1223
|
+
IndexingWaitError,
|
|
959
1224
|
MemoriesResource,
|
|
960
1225
|
MemoryClient,
|
|
961
1226
|
MemoryJobsResource,
|
package/dist/index.mjs
CHANGED
|
@@ -71,16 +71,72 @@ var EntitlementError = class _EntitlementError extends HebbrixError {
|
|
|
71
71
|
Object.setPrototypeOf(this, _EntitlementError.prototype);
|
|
72
72
|
}
|
|
73
73
|
};
|
|
74
|
-
var
|
|
75
|
-
constructor(message, receipt) {
|
|
74
|
+
var IndexingWaitError = class _IndexingWaitError extends Error {
|
|
75
|
+
constructor(message, receipt, options = {}) {
|
|
76
76
|
super(message);
|
|
77
|
-
this.name = "
|
|
77
|
+
this.name = "IndexingWaitError";
|
|
78
78
|
this.receipt = { ...receipt };
|
|
79
|
-
this.memoryIds = [
|
|
80
|
-
|
|
79
|
+
this.memoryIds = [
|
|
80
|
+
...new Set(
|
|
81
|
+
[
|
|
82
|
+
...receipt.memory_ids || [],
|
|
83
|
+
receipt.memory_id,
|
|
84
|
+
receipt.id,
|
|
85
|
+
...(receipt.results || []).map(
|
|
86
|
+
(row) => row.memory_id || row.id
|
|
87
|
+
)
|
|
88
|
+
].filter(Boolean)
|
|
89
|
+
)
|
|
90
|
+
];
|
|
91
|
+
this.jobId = receipt.job_id;
|
|
92
|
+
this.statusUrl = receipt.status_url || (this.memoryIds.length === 1 ? `/v1/memories/${encodeURIComponent(this.memoryIds[0])}` : this.jobId ? `/v1/memory-jobs/${encodeURIComponent(this.jobId)}` : void 0);
|
|
93
|
+
this.requestId = receipt.request_id;
|
|
94
|
+
this.outboxEventId = receipt.outbox_event_id;
|
|
95
|
+
this.indexingEventId = receipt.indexing_event_id || this.outboxEventId;
|
|
96
|
+
this.eventId = receipt.event_id || this.indexingEventId;
|
|
97
|
+
this.idempotencyReplay = receipt.idempotency_replay;
|
|
98
|
+
this.idempotencyKey = options.idempotencyKey || receipt.idempotency_key;
|
|
99
|
+
this.retryAfter = receipt.retry_after;
|
|
100
|
+
this.recovery = Object.fromEntries(
|
|
101
|
+
Object.entries({
|
|
102
|
+
memory_ids: this.memoryIds,
|
|
103
|
+
job_id: this.jobId,
|
|
104
|
+
status_url: this.statusUrl,
|
|
105
|
+
request_id: this.requestId,
|
|
106
|
+
outbox_event_id: this.outboxEventId,
|
|
107
|
+
indexing_event_id: this.indexingEventId,
|
|
108
|
+
event_id: this.eventId,
|
|
109
|
+
idempotency_key: this.idempotencyKey,
|
|
110
|
+
idempotency_replay: this.idempotencyReplay,
|
|
111
|
+
retry_after: this.retryAfter
|
|
112
|
+
}).filter(([, value]) => value !== void 0 && value !== null)
|
|
113
|
+
);
|
|
114
|
+
this.cause = options.cause;
|
|
115
|
+
Object.setPrototypeOf(this, _IndexingWaitError.prototype);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
var IndexingTimeoutError = class _IndexingTimeoutError extends IndexingWaitError {
|
|
119
|
+
constructor(message, receipt, options = {}) {
|
|
120
|
+
super(message, receipt, options);
|
|
121
|
+
this.name = "IndexingTimeoutError";
|
|
81
122
|
Object.setPrototypeOf(this, _IndexingTimeoutError.prototype);
|
|
82
123
|
}
|
|
83
124
|
};
|
|
125
|
+
var IndexingAbortedError = class _IndexingAbortedError extends IndexingWaitError {
|
|
126
|
+
constructor(message, receipt, options = {}) {
|
|
127
|
+
super(message, receipt, options);
|
|
128
|
+
this.name = "IndexingAbortedError";
|
|
129
|
+
Object.setPrototypeOf(this, _IndexingAbortedError.prototype);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var IndexingTerminalError = class _IndexingTerminalError extends IndexingWaitError {
|
|
133
|
+
constructor(message, receipt, processingStatus, options = {}) {
|
|
134
|
+
super(message, receipt, options);
|
|
135
|
+
this.name = "IndexingTerminalError";
|
|
136
|
+
this.processingStatus = processingStatus;
|
|
137
|
+
Object.setPrototypeOf(this, _IndexingTerminalError.prototype);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
84
140
|
var AuthenticationError = class _AuthenticationError extends HebbrixError {
|
|
85
141
|
constructor(message = "Authentication failed", options = {}) {
|
|
86
142
|
super(message, 401, options);
|
|
@@ -194,22 +250,195 @@ var CollectionsResource = class extends BaseResource {
|
|
|
194
250
|
};
|
|
195
251
|
var MemoriesResource = class extends BaseResource {
|
|
196
252
|
/**
|
|
197
|
-
* Create
|
|
253
|
+
* Create one logical memory write. When `wait_for_index=true`, a durable
|
|
254
|
+
* pending receipt is polled without issuing a second create request.
|
|
198
255
|
*/
|
|
199
256
|
async create(params) {
|
|
200
257
|
if (!params.content?.trim() && !params.messages?.length) {
|
|
201
258
|
throw new TypeError("content or messages must be provided");
|
|
202
259
|
}
|
|
203
|
-
const {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
260
|
+
const {
|
|
261
|
+
idempotency_key,
|
|
262
|
+
signal,
|
|
263
|
+
index_timeout_ms,
|
|
264
|
+
index_poll_interval_ms,
|
|
265
|
+
...input
|
|
266
|
+
} = params;
|
|
267
|
+
const receipt = await this.client.request(
|
|
268
|
+
"POST",
|
|
269
|
+
"/v1/memories",
|
|
270
|
+
{
|
|
271
|
+
headers: idempotency_key ? { "Idempotency-Key": idempotency_key } : void 0,
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
source_type: "text",
|
|
274
|
+
metadata: {},
|
|
275
|
+
infer: false,
|
|
276
|
+
wait_for_index: false,
|
|
277
|
+
...input
|
|
278
|
+
}),
|
|
279
|
+
signal
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
if (params.wait_for_index && !this.isSearchableCompletion(receipt)) {
|
|
283
|
+
return this.waitForSearchable(receipt, {
|
|
284
|
+
timeoutMs: index_timeout_ms,
|
|
285
|
+
pollIntervalMs: index_poll_interval_ms,
|
|
286
|
+
signal,
|
|
287
|
+
idempotencyKey: idempotency_key
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
return receipt;
|
|
291
|
+
}
|
|
292
|
+
/** Poll a single-write durable receipt until every accepted memory is searchable. */
|
|
293
|
+
async waitForSearchable(receipt, options = {}) {
|
|
294
|
+
if (this.isSearchableCompletion(receipt)) {
|
|
295
|
+
return receipt;
|
|
296
|
+
}
|
|
297
|
+
if (this.isTerminalStatus(receipt.processing_status)) {
|
|
298
|
+
const status = String(receipt.processing_status).toLowerCase();
|
|
299
|
+
throw new IndexingTerminalError(
|
|
300
|
+
`memory indexing reached terminal state ${status}`,
|
|
301
|
+
receipt,
|
|
302
|
+
status,
|
|
303
|
+
{ idempotencyKey: options.idempotencyKey }
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
const ids = this.memoryIds(receipt);
|
|
307
|
+
if (!ids.length) {
|
|
308
|
+
throw new Error("memory receipt does not contain a durable memory id");
|
|
309
|
+
}
|
|
310
|
+
const timeoutMs = Math.max(0, options.timeoutMs ?? 6e4);
|
|
311
|
+
const pollIntervalMs = Math.max(50, options.pollIntervalMs ?? 500);
|
|
312
|
+
const deadline = Date.now() + timeoutMs;
|
|
313
|
+
const paths = ids.map(
|
|
314
|
+
(id, index) => index === 0 && receipt.status_url ? this.readinessPath(receipt.status_url, id) : `/v1/memories/${encodeURIComponent(id)}`
|
|
315
|
+
);
|
|
316
|
+
while (true) {
|
|
317
|
+
this.throwIfPollingAborted(receipt, options);
|
|
318
|
+
if (Date.now() >= deadline) {
|
|
319
|
+
throw new IndexingTimeoutError(
|
|
320
|
+
`memory was not searchable within ${timeoutMs}ms; the write is durable`,
|
|
321
|
+
receipt,
|
|
322
|
+
{ idempotencyKey: options.idempotencyKey }
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
let rows;
|
|
326
|
+
try {
|
|
327
|
+
rows = await Promise.all(
|
|
328
|
+
paths.map(
|
|
329
|
+
(path) => this.client.request("GET", path, {
|
|
330
|
+
signal: options.signal
|
|
331
|
+
})
|
|
332
|
+
)
|
|
333
|
+
);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if (options.signal?.aborted) {
|
|
336
|
+
throw new IndexingAbortedError(
|
|
337
|
+
"memory readiness polling was aborted after the write became durable",
|
|
338
|
+
receipt,
|
|
339
|
+
{ idempotencyKey: options.idempotencyKey, cause: error }
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
const terminal = rows.find(
|
|
345
|
+
(row) => this.isTerminalStatus(row.processing_status)
|
|
346
|
+
);
|
|
347
|
+
if (terminal) {
|
|
348
|
+
const status = String(terminal.processing_status).toLowerCase();
|
|
349
|
+
throw new IndexingTerminalError(
|
|
350
|
+
`memory ${terminal.id} indexing reached terminal state ${status}`,
|
|
351
|
+
receipt,
|
|
352
|
+
status,
|
|
353
|
+
{ idempotencyKey: options.idempotencyKey }
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
if (rows.every(
|
|
357
|
+
(row) => row.searchable === true && String(row.processing_status || "").toLowerCase() === "completed"
|
|
358
|
+
)) {
|
|
359
|
+
return {
|
|
360
|
+
...receipt,
|
|
361
|
+
processing_status: "completed",
|
|
362
|
+
searchable: true,
|
|
363
|
+
results: receipt.results.map((result) => ({
|
|
364
|
+
...result,
|
|
365
|
+
processing_status: "completed"
|
|
366
|
+
}))
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const remainingMs = deadline - Date.now();
|
|
370
|
+
if (remainingMs <= 0) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
await this.pollingDelay(
|
|
374
|
+
Math.min(pollIntervalMs, remainingMs),
|
|
375
|
+
receipt,
|
|
376
|
+
options
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
memoryIds(receipt) {
|
|
381
|
+
return [
|
|
382
|
+
...new Set(
|
|
383
|
+
(receipt.results || []).map((row) => row.memory_id || row.id).filter((id) => Boolean(id))
|
|
384
|
+
)
|
|
385
|
+
];
|
|
386
|
+
}
|
|
387
|
+
isSearchableCompletion(receipt) {
|
|
388
|
+
return receipt.searchable === true && String(receipt.processing_status || "").toLowerCase() === "completed";
|
|
389
|
+
}
|
|
390
|
+
isTerminalStatus(status) {
|
|
391
|
+
return ["failed", "cancelled", "canceled"].includes(
|
|
392
|
+
String(status || "").toLowerCase()
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
readinessPath(statusUrl, memoryId) {
|
|
396
|
+
try {
|
|
397
|
+
const parsed = new URL(statusUrl, "https://status.hebbrix.invalid");
|
|
398
|
+
if (!["http:", "https:"].includes(parsed.protocol)) {
|
|
399
|
+
return `/v1/memories/${encodeURIComponent(memoryId)}`;
|
|
400
|
+
}
|
|
401
|
+
return `${parsed.pathname}${parsed.search}`;
|
|
402
|
+
} catch {
|
|
403
|
+
return `/v1/memories/${encodeURIComponent(memoryId)}`;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
throwIfPollingAborted(receipt, options) {
|
|
407
|
+
if (options.signal?.aborted) {
|
|
408
|
+
throw new IndexingAbortedError(
|
|
409
|
+
"memory readiness polling was aborted after the write became durable",
|
|
410
|
+
receipt,
|
|
411
|
+
{
|
|
412
|
+
idempotencyKey: options.idempotencyKey,
|
|
413
|
+
cause: options.signal.reason
|
|
414
|
+
}
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async pollingDelay(delayMs, receipt, options) {
|
|
419
|
+
await new Promise((resolve, reject) => {
|
|
420
|
+
const onAbort = () => {
|
|
421
|
+
clearTimeout(timer);
|
|
422
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
423
|
+
reject(
|
|
424
|
+
new IndexingAbortedError(
|
|
425
|
+
"memory readiness polling was aborted after the write became durable",
|
|
426
|
+
receipt,
|
|
427
|
+
{
|
|
428
|
+
idempotencyKey: options.idempotencyKey,
|
|
429
|
+
cause: options.signal?.reason
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
);
|
|
433
|
+
};
|
|
434
|
+
const timer = setTimeout(() => {
|
|
435
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
436
|
+
resolve();
|
|
437
|
+
}, delayMs);
|
|
438
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
439
|
+
if (options.signal?.aborted) {
|
|
440
|
+
onAbort();
|
|
441
|
+
}
|
|
213
442
|
});
|
|
214
443
|
}
|
|
215
444
|
/**
|
|
@@ -560,9 +789,12 @@ var ProceduralResource = class extends BaseResource {
|
|
|
560
789
|
* Execute a procedure
|
|
561
790
|
*/
|
|
562
791
|
async execute(procedureId, context) {
|
|
563
|
-
const response = await this.client.post(
|
|
564
|
-
|
|
565
|
-
|
|
792
|
+
const response = await this.client.post(
|
|
793
|
+
`/v1/procedures/${procedureId}/execute`,
|
|
794
|
+
{
|
|
795
|
+
input_state: context || {}
|
|
796
|
+
}
|
|
797
|
+
);
|
|
566
798
|
return response?.execution_result || response;
|
|
567
799
|
}
|
|
568
800
|
/**
|
|
@@ -579,7 +811,10 @@ var ProceduralResource = class extends BaseResource {
|
|
|
579
811
|
body.action = { steps: params.action_sequence };
|
|
580
812
|
}
|
|
581
813
|
if (params.metadata !== void 0) body.parameters = params.metadata;
|
|
582
|
-
const response = await this.client.patch(
|
|
814
|
+
const response = await this.client.patch(
|
|
815
|
+
`/v1/procedures/${procedureId}`,
|
|
816
|
+
body
|
|
817
|
+
);
|
|
583
818
|
return this.unwrapProcedure(response);
|
|
584
819
|
}
|
|
585
820
|
/**
|
|
@@ -662,7 +897,9 @@ var TemporalResource = class extends BaseResource {
|
|
|
662
897
|
*/
|
|
663
898
|
async pointInTime(timestamp, entity) {
|
|
664
899
|
if (!entity) {
|
|
665
|
-
throw new TypeError(
|
|
900
|
+
throw new TypeError(
|
|
901
|
+
"entity is required and maps to the canonical subject"
|
|
902
|
+
);
|
|
666
903
|
}
|
|
667
904
|
return this.queryAtTime({
|
|
668
905
|
timestamp,
|
|
@@ -746,7 +983,8 @@ var MemoryToolsResource = class extends BaseResource {
|
|
|
746
983
|
*/
|
|
747
984
|
async insert(params) {
|
|
748
985
|
const metadata = { ...params.metadata || {} };
|
|
749
|
-
if (params.position !== void 0)
|
|
986
|
+
if (params.position !== void 0)
|
|
987
|
+
metadata.requested_position = params.position;
|
|
750
988
|
if (params.reason !== void 0) metadata.reason = params.reason;
|
|
751
989
|
return this.client.post("/v1/memory-tools/insert", {
|
|
752
990
|
collection_id: params.collection_id,
|
|
@@ -790,7 +1028,7 @@ var MemoryClient = class {
|
|
|
790
1028
|
getHeaders() {
|
|
791
1029
|
const headers = {
|
|
792
1030
|
"Content-Type": "application/json",
|
|
793
|
-
"User-Agent": "hebbrix-typescript/2.3.
|
|
1031
|
+
"User-Agent": "hebbrix-typescript/2.3.1"
|
|
794
1032
|
};
|
|
795
1033
|
if (this.apiKey) {
|
|
796
1034
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
@@ -816,7 +1054,9 @@ var MemoryClient = class {
|
|
|
816
1054
|
throw new RateLimitError(message, { code, requestId, details });
|
|
817
1055
|
} else if (statusCode >= 500) {
|
|
818
1056
|
throw new ServerError(message, { code, requestId, details });
|
|
819
|
-
} else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(
|
|
1057
|
+
} else if ((statusCode === 402 || statusCode === 403) && (String(code || "").includes("ENTITLEMENT") || ["feature_not_available", "tier_upgrade_required"].includes(
|
|
1058
|
+
details?.error
|
|
1059
|
+
))) {
|
|
820
1060
|
throw new EntitlementError(message, statusCode, {
|
|
821
1061
|
code,
|
|
822
1062
|
requestId,
|
|
@@ -828,7 +1068,11 @@ var MemoryClient = class {
|
|
|
828
1068
|
}
|
|
829
1069
|
async request(method, path, options = {}) {
|
|
830
1070
|
const url = `${this.baseUrl}${path}`;
|
|
831
|
-
const {
|
|
1071
|
+
const {
|
|
1072
|
+
headers: requestHeaders,
|
|
1073
|
+
signal: requestSignal,
|
|
1074
|
+
...requestOptions
|
|
1075
|
+
} = options;
|
|
832
1076
|
const response = await fetch(url, {
|
|
833
1077
|
...requestOptions,
|
|
834
1078
|
method,
|
|
@@ -855,6 +1099,21 @@ var MemoryClient = class {
|
|
|
855
1099
|
if (!response.ok) {
|
|
856
1100
|
this.handleError(response, data);
|
|
857
1101
|
}
|
|
1102
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
1103
|
+
const requestId = response.headers.get("X-Request-ID");
|
|
1104
|
+
const statusUrl = response.headers.get("Location");
|
|
1105
|
+
const outboxEventId = response.headers.get("X-Hebbrix-Index-Event");
|
|
1106
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
1107
|
+
const idempotencyReplay = response.headers.get("X-Idempotent-Replay");
|
|
1108
|
+
data = {
|
|
1109
|
+
...data,
|
|
1110
|
+
...data.request_id === void 0 && requestId ? { request_id: requestId } : {},
|
|
1111
|
+
...data.status_url === void 0 && statusUrl ? { status_url: statusUrl } : {},
|
|
1112
|
+
...data.outbox_event_id === void 0 && outboxEventId ? { outbox_event_id: outboxEventId } : {},
|
|
1113
|
+
...data.retry_after === void 0 && retryAfter ? { retry_after: retryAfter } : {},
|
|
1114
|
+
...data.idempotency_replay === void 0 && idempotencyReplay ? { idempotency_replay: idempotencyReplay.toLowerCase() === "true" } : {}
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
858
1117
|
return data;
|
|
859
1118
|
}
|
|
860
1119
|
async get(path, params) {
|
|
@@ -906,7 +1165,10 @@ export {
|
|
|
906
1165
|
CorrectionsResource,
|
|
907
1166
|
EntitlementError,
|
|
908
1167
|
HebbrixError,
|
|
1168
|
+
IndexingAbortedError,
|
|
1169
|
+
IndexingTerminalError,
|
|
909
1170
|
IndexingTimeoutError,
|
|
1171
|
+
IndexingWaitError,
|
|
910
1172
|
MemoriesResource,
|
|
911
1173
|
MemoryClient,
|
|
912
1174
|
MemoryJobsResource,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hebbrix",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Typed TypeScript client for Hebbrix memory, retrieval, and outcome-learning APIs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -46,10 +46,14 @@
|
|
|
46
46
|
],
|
|
47
47
|
"author": "Hebbrix Team <support@hebbrix.com>",
|
|
48
48
|
"license": "MIT",
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/Hebbrix/hebbrix-typescript.git"
|
|
52
|
+
},
|
|
49
53
|
"bugs": {
|
|
50
|
-
"url": "https://
|
|
54
|
+
"url": "https://github.com/Hebbrix/hebbrix-typescript/issues"
|
|
51
55
|
},
|
|
52
|
-
"homepage": "https://hebbrix.com",
|
|
56
|
+
"homepage": "https://docs.hebbrix.com",
|
|
53
57
|
"publishConfig": {
|
|
54
58
|
"access": "public"
|
|
55
59
|
},
|