@onesi/genesis 0.1.13 → 0.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/README.md +1 -1
- package/dist/auto.d.ts +1010 -0
- package/dist/auto.js +125 -0
- package/dist/beacons.d.ts +42 -0
- package/dist/beacons.js +71 -0
- package/dist/blinds-owner-enrollment.d.ts +121 -0
- package/dist/blinds-owner-enrollment.js +23 -2
- package/dist/boxes.d.ts +1074 -0
- package/dist/boxes.js +338 -0
- package/dist/client.d.ts +3 -19947
- package/dist/client.js +127 -18
- package/dist/errors.d.ts +6 -0
- package/dist/errors.js +38 -3
- package/dist/flares.d.ts +32 -0
- package/dist/flares.js +5 -0
- package/dist/fleets.d.ts +32 -0
- package/dist/fleets.js +59 -6
- package/dist/flocks.d.ts +334 -1
- package/dist/flocks.js +85 -0
- package/dist/foundry.d.ts +429 -0
- package/dist/foundry.js +135 -0
- package/dist/garden.d.ts +754 -0
- package/dist/garden.js +76 -0
- package/dist/gateway.d.ts +365 -0
- package/dist/gateway.js +82 -0
- package/dist/gears.d.ts +121 -2
- package/dist/gears.js +24 -2
- package/dist/generated/operations.d.ts +3 -19948
- package/dist/generated/operations.js +64214 -13423
- package/dist/generated/schema.d.ts +85708 -17364
- package/dist/genesis.d.ts +9041 -1250
- package/dist/genesis.js +92 -25
- package/dist/genesis.openapi.json +133172 -31267
- package/dist/henry.d.ts +202 -1
- package/dist/henry.js +223 -0
- package/dist/hives-cells.d.ts +8 -3
- package/dist/hives-cells.js +17 -4
- package/dist/hives-environment.d.ts +9 -0
- package/dist/hives-environment.js +22 -0
- package/dist/hives-node.js +4 -1
- package/dist/hives-operations.d.ts +121 -3
- package/dist/hives-operations.js +2 -0
- package/dist/hives-platform.d.ts +149 -0
- package/dist/hives-platform.js +183 -0
- package/dist/hives-resources-transport.d.ts +7 -1
- package/dist/hives-resources-transport.js +10 -2
- package/dist/hives-sse.d.ts +24 -0
- package/dist/hives-sse.js +111 -0
- package/dist/hives-topics.d.ts +4 -3
- package/dist/hives-topics.js +9 -4
- package/dist/iam-directory.d.ts +8 -0
- package/dist/iam-directory.js +23 -0
- package/dist/iam.d.ts +397 -0
- package/dist/iam.js +92 -0
- package/dist/idempotency.d.ts +3 -0
- package/dist/idempotency.js +27 -0
- package/dist/index.d.ts +22 -6
- package/dist/index.js +19 -5
- package/dist/instances.d.ts +177 -2
- package/dist/instances.js +37 -5
- package/dist/minds-agent.d.ts +28 -0
- package/dist/minds-agent.js +53 -10
- package/dist/minds-engine.d.ts +394 -0
- package/dist/minds-engine.js +555 -0
- package/dist/minds.d.ts +109 -1
- package/dist/minds.js +49 -14
- package/dist/orgs.d.ts +405 -0
- package/dist/orgs.js +63 -0
- package/dist/redact.d.ts +37 -0
- package/dist/redact.js +330 -0
- package/dist/runner.d.ts +4 -0
- package/dist/runner.js +1 -0
- package/dist/scopes.d.ts +316 -0
- package/dist/scopes.js +40 -0
- package/dist/taps.d.ts +118 -0
- package/dist/taps.js +45 -0
- package/dist/traces.d.ts +574 -0
- package/dist/traces.js +97 -0
- package/dist/types.d.ts +12 -1
- package/package.json +1 -1
package/dist/henry.d.ts
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
import type { GenesisClient } from './client.js';
|
|
2
2
|
import type { OperationInput } from './types.js';
|
|
3
|
+
import type { components } from './generated/schema.js';
|
|
4
|
+
export type HenryRun = components['schemas']['Henry.Run'];
|
|
5
|
+
export type HenryRunEvent = components['schemas']['Henry.RunEvent'];
|
|
6
|
+
export type HenryRunEventMessage = components['schemas']['Henry.RunEventMessage'];
|
|
7
|
+
export type HenryRunStreamStatus = components['schemas']['Henry.RunStreamStatus'];
|
|
8
|
+
export type HenryMessageDelivery = components['schemas']['Henry.RunMessageDelivery'];
|
|
9
|
+
/** One event of a live run stream. `end` comes once the run is completed, failed or cancelled. */
|
|
10
|
+
export type HenryStreamEvent = {
|
|
11
|
+
event: 'activity';
|
|
12
|
+
data: HenryRunEvent;
|
|
13
|
+
} | {
|
|
14
|
+
event: 'status' | 'end';
|
|
15
|
+
data: HenryRunStreamStatus;
|
|
16
|
+
} | {
|
|
17
|
+
event: 'error';
|
|
18
|
+
data: {
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export interface HenryStreamOptions {
|
|
23
|
+
/** Start after this activity seq (default 0: from the first event). */
|
|
24
|
+
afterSeq?: number;
|
|
25
|
+
/** Stops the stream; the iterator then returns without an error. */
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
/** Reconnects allowed after a stream closes without `end` (1-1000, default 100). Henry closes each stream within 120 s. */
|
|
28
|
+
maxReconnects?: number;
|
|
29
|
+
/** Reconnect when no byte (event or 15 s keepalive) arrives for this long (default 45000 ms). */
|
|
30
|
+
idleMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/** A turn: the inputs that led to one model answer, and that answer. Its number is the `turn` to fork from to re-run it. */
|
|
33
|
+
export interface HenryTurn {
|
|
34
|
+
turn: number;
|
|
35
|
+
inputs: HenryRunEventMessage[];
|
|
36
|
+
events: Pick<HenryRunEvent, 'seq' | 'at' | 'type' | 'detail'>[];
|
|
37
|
+
answer: HenryRunEventMessage;
|
|
38
|
+
}
|
|
39
|
+
export interface HenryReplay {
|
|
40
|
+
run_id: string;
|
|
41
|
+
status?: string;
|
|
42
|
+
turns: HenryTurn[];
|
|
43
|
+
pending: Omit<HenryTurn, 'answer'>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Fold a run's events into turns. Turn N holds the inputs that led to the run's (N+1)th model answer and that answer, so
|
|
47
|
+
* forking from turn N re-runs that answer. Events after the last answer are returned as `pending`.
|
|
48
|
+
*/
|
|
49
|
+
export declare function foldHenryTurns(events: HenryRunEvent[]): {
|
|
50
|
+
turns: HenryTurn[];
|
|
51
|
+
pending: Omit<HenryTurn, 'answer'>;
|
|
52
|
+
};
|
|
3
53
|
/** Henry always derives its organization from the gateway's verified caller. */
|
|
4
54
|
export declare function henryModule(client: GenesisClient): {
|
|
5
55
|
config: () => Promise<{
|
|
@@ -27,9 +77,20 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
27
77
|
publicKeyBase64: string;
|
|
28
78
|
}>;
|
|
29
79
|
};
|
|
80
|
+
blinds: {
|
|
81
|
+
/** HTTPS request through the organization's bound Blinds machine. */
|
|
82
|
+
proxy: (body: NonNullable<OperationInput<"henry_proxyBlinds">["body"]>) => Promise<{
|
|
83
|
+
request_id?: string;
|
|
84
|
+
status: number;
|
|
85
|
+
headers: {
|
|
86
|
+
[key: string]: string;
|
|
87
|
+
};
|
|
88
|
+
body: string;
|
|
89
|
+
}>;
|
|
90
|
+
};
|
|
30
91
|
runs: {
|
|
31
92
|
list: (page_token?: string) => Promise<{
|
|
32
|
-
runs:
|
|
93
|
+
runs: components["schemas"]["Henry.Run"][];
|
|
33
94
|
next_page_token?: string | null;
|
|
34
95
|
}>;
|
|
35
96
|
create: (body: NonNullable<OperationInput<"henry_createRun">["body"]>) => Promise<{
|
|
@@ -44,6 +105,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
44
105
|
at: string;
|
|
45
106
|
type: string;
|
|
46
107
|
detail: string;
|
|
108
|
+
message_index?: number;
|
|
109
|
+
message_id?: string;
|
|
47
110
|
}[];
|
|
48
111
|
approvals: {
|
|
49
112
|
id: string;
|
|
@@ -57,6 +120,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
57
120
|
code?: number;
|
|
58
121
|
receipt?: Record<string, never>;
|
|
59
122
|
usage?: Record<string, never> | null;
|
|
123
|
+
started_at?: string;
|
|
124
|
+
ended_at?: string;
|
|
60
125
|
}[];
|
|
61
126
|
messages: ({
|
|
62
127
|
role: string;
|
|
@@ -64,6 +129,16 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
64
129
|
} & {
|
|
65
130
|
[key: string]: unknown;
|
|
66
131
|
})[];
|
|
132
|
+
trace_id?: string;
|
|
133
|
+
forked_from?: {
|
|
134
|
+
run_id: string;
|
|
135
|
+
turn: number;
|
|
136
|
+
text_sha256?: string;
|
|
137
|
+
};
|
|
138
|
+
inbox?: components["schemas"]["Henry.RunInboxMessage"][];
|
|
139
|
+
interrupt_execution?: string;
|
|
140
|
+
observatory_version?: number;
|
|
141
|
+
telemetry?: components["schemas"]["Henry.RunTelemetry"];
|
|
67
142
|
}>;
|
|
68
143
|
get: (run_id: string) => Promise<{
|
|
69
144
|
id: string;
|
|
@@ -77,6 +152,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
77
152
|
at: string;
|
|
78
153
|
type: string;
|
|
79
154
|
detail: string;
|
|
155
|
+
message_index?: number;
|
|
156
|
+
message_id?: string;
|
|
80
157
|
}[];
|
|
81
158
|
approvals: {
|
|
82
159
|
id: string;
|
|
@@ -90,6 +167,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
90
167
|
code?: number;
|
|
91
168
|
receipt?: Record<string, never>;
|
|
92
169
|
usage?: Record<string, never> | null;
|
|
170
|
+
started_at?: string;
|
|
171
|
+
ended_at?: string;
|
|
93
172
|
}[];
|
|
94
173
|
messages: ({
|
|
95
174
|
role: string;
|
|
@@ -97,6 +176,32 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
97
176
|
} & {
|
|
98
177
|
[key: string]: unknown;
|
|
99
178
|
})[];
|
|
179
|
+
trace_id?: string;
|
|
180
|
+
forked_from?: {
|
|
181
|
+
run_id: string;
|
|
182
|
+
turn: number;
|
|
183
|
+
text_sha256?: string;
|
|
184
|
+
};
|
|
185
|
+
inbox?: components["schemas"]["Henry.RunInboxMessage"][];
|
|
186
|
+
interrupt_execution?: string;
|
|
187
|
+
observatory_version?: number;
|
|
188
|
+
telemetry?: components["schemas"]["Henry.RunTelemetry"];
|
|
189
|
+
}>;
|
|
190
|
+
/** Page activity events: pass the previous page's next_after_seq as after_seq. */
|
|
191
|
+
events: (run_id: string, query?: {
|
|
192
|
+
after_seq?: number;
|
|
193
|
+
limit?: number;
|
|
194
|
+
}) => Promise<{
|
|
195
|
+
run_id: string;
|
|
196
|
+
status?: string;
|
|
197
|
+
events: components["schemas"]["Henry.RunEvent"][];
|
|
198
|
+
next_after_seq: number;
|
|
199
|
+
has_more: boolean;
|
|
200
|
+
}>;
|
|
201
|
+
/** Delete a finished run; active runs must be cancelled first (409). */
|
|
202
|
+
delete: (run_id: string) => Promise<{
|
|
203
|
+
run_id: string;
|
|
204
|
+
deleted: boolean;
|
|
100
205
|
}>;
|
|
101
206
|
command: (run_id: string, action: "pause" | "resume" | "cancel" | "input", text?: string) => Promise<{
|
|
102
207
|
id: string;
|
|
@@ -110,6 +215,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
110
215
|
at: string;
|
|
111
216
|
type: string;
|
|
112
217
|
detail: string;
|
|
218
|
+
message_index?: number;
|
|
219
|
+
message_id?: string;
|
|
113
220
|
}[];
|
|
114
221
|
approvals: {
|
|
115
222
|
id: string;
|
|
@@ -123,6 +230,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
123
230
|
code?: number;
|
|
124
231
|
receipt?: Record<string, never>;
|
|
125
232
|
usage?: Record<string, never> | null;
|
|
233
|
+
started_at?: string;
|
|
234
|
+
ended_at?: string;
|
|
126
235
|
}[];
|
|
127
236
|
messages: ({
|
|
128
237
|
role: string;
|
|
@@ -130,6 +239,16 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
130
239
|
} & {
|
|
131
240
|
[key: string]: unknown;
|
|
132
241
|
})[];
|
|
242
|
+
trace_id?: string;
|
|
243
|
+
forked_from?: {
|
|
244
|
+
run_id: string;
|
|
245
|
+
turn: number;
|
|
246
|
+
text_sha256?: string;
|
|
247
|
+
};
|
|
248
|
+
inbox?: components["schemas"]["Henry.RunInboxMessage"][];
|
|
249
|
+
interrupt_execution?: string;
|
|
250
|
+
observatory_version?: number;
|
|
251
|
+
telemetry?: components["schemas"]["Henry.RunTelemetry"];
|
|
133
252
|
}>;
|
|
134
253
|
approval: (run_id: string, approval_id: string, decision: "approve" | "reject") => Promise<{
|
|
135
254
|
id: string;
|
|
@@ -143,6 +262,70 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
143
262
|
at: string;
|
|
144
263
|
type: string;
|
|
145
264
|
detail: string;
|
|
265
|
+
message_index?: number;
|
|
266
|
+
message_id?: string;
|
|
267
|
+
}[];
|
|
268
|
+
approvals: {
|
|
269
|
+
id: string;
|
|
270
|
+
action: string;
|
|
271
|
+
url: string;
|
|
272
|
+
status: string;
|
|
273
|
+
requested_at: string;
|
|
274
|
+
}[];
|
|
275
|
+
phases: {
|
|
276
|
+
id?: string;
|
|
277
|
+
code?: number;
|
|
278
|
+
receipt?: Record<string, never>;
|
|
279
|
+
usage?: Record<string, never> | null;
|
|
280
|
+
started_at?: string;
|
|
281
|
+
ended_at?: string;
|
|
282
|
+
}[];
|
|
283
|
+
messages: ({
|
|
284
|
+
role: string;
|
|
285
|
+
content?: string | null;
|
|
286
|
+
} & {
|
|
287
|
+
[key: string]: unknown;
|
|
288
|
+
})[];
|
|
289
|
+
trace_id?: string;
|
|
290
|
+
forked_from?: {
|
|
291
|
+
run_id: string;
|
|
292
|
+
turn: number;
|
|
293
|
+
text_sha256?: string;
|
|
294
|
+
};
|
|
295
|
+
inbox?: components["schemas"]["Henry.RunInboxMessage"][];
|
|
296
|
+
interrupt_execution?: string;
|
|
297
|
+
observatory_version?: number;
|
|
298
|
+
telemetry?: components["schemas"]["Henry.RunTelemetry"];
|
|
299
|
+
}>;
|
|
300
|
+
/**
|
|
301
|
+
* Send a message into a run: `steer` lands before the next model call, `queue` (default) after the current turn,
|
|
302
|
+
* `interrupt` cancels the turn in flight. A completed run takes it at once and runs the next turn in this request.
|
|
303
|
+
*/
|
|
304
|
+
message: (run_id: string, body: {
|
|
305
|
+
text: string;
|
|
306
|
+
delivery?: HenryMessageDelivery;
|
|
307
|
+
}) => Promise<{
|
|
308
|
+
message: components["schemas"]["Henry.RunMessageReceipt"];
|
|
309
|
+
run: components["schemas"]["Henry.Run"];
|
|
310
|
+
}>;
|
|
311
|
+
/**
|
|
312
|
+
* Start a new run from turn N of this one (0 = the original task; default the latest, which needs text). run_id is
|
|
313
|
+
* the new run's idempotency key: one is generated unless supplied, and a retry with it returns the same run.
|
|
314
|
+
*/
|
|
315
|
+
fork: (run_id: string, body?: NonNullable<OperationInput<"henry_forkRun">["body"]>) => Promise<{
|
|
316
|
+
id: string;
|
|
317
|
+
task: string;
|
|
318
|
+
model: string;
|
|
319
|
+
status: "ready" | "running" | "acting" | "paused" | "awaiting_approval" | "completed" | "cancelled" | "failed" | "waiting_input";
|
|
320
|
+
created_at: string;
|
|
321
|
+
updated_at: string;
|
|
322
|
+
activity: {
|
|
323
|
+
id: string;
|
|
324
|
+
at: string;
|
|
325
|
+
type: string;
|
|
326
|
+
detail: string;
|
|
327
|
+
message_index?: number;
|
|
328
|
+
message_id?: string;
|
|
146
329
|
}[];
|
|
147
330
|
approvals: {
|
|
148
331
|
id: string;
|
|
@@ -156,6 +339,8 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
156
339
|
code?: number;
|
|
157
340
|
receipt?: Record<string, never>;
|
|
158
341
|
usage?: Record<string, never> | null;
|
|
342
|
+
started_at?: string;
|
|
343
|
+
ended_at?: string;
|
|
159
344
|
}[];
|
|
160
345
|
messages: ({
|
|
161
346
|
role: string;
|
|
@@ -163,6 +348,22 @@ export declare function henryModule(client: GenesisClient): {
|
|
|
163
348
|
} & {
|
|
164
349
|
[key: string]: unknown;
|
|
165
350
|
})[];
|
|
351
|
+
trace_id?: string;
|
|
352
|
+
forked_from?: {
|
|
353
|
+
run_id: string;
|
|
354
|
+
turn: number;
|
|
355
|
+
text_sha256?: string;
|
|
356
|
+
};
|
|
357
|
+
inbox?: components["schemas"]["Henry.RunInboxMessage"][];
|
|
358
|
+
interrupt_execution?: string;
|
|
359
|
+
observatory_version?: number;
|
|
360
|
+
telemetry?: components["schemas"]["Henry.RunTelemetry"];
|
|
166
361
|
}>;
|
|
362
|
+
/** Follow a run live: an async iterator over its stream, reconnecting with Last-Event-ID until `end`. */
|
|
363
|
+
streamEvents: (run_id: string, options?: HenryStreamOptions) => AsyncGenerator<HenryStreamEvent, any, any>;
|
|
364
|
+
/** Read every event of a run and fold them into turns (see foldHenryTurns). */
|
|
365
|
+
replay: (run_id: string, options?: {
|
|
366
|
+
signal?: AbortSignal;
|
|
367
|
+
}) => Promise<HenryReplay>;
|
|
167
368
|
};
|
|
168
369
|
};
|
package/dist/henry.js
CHANGED
|
@@ -1,4 +1,183 @@
|
|
|
1
1
|
import { GenesisError } from './errors.js';
|
|
2
|
+
const MAX_SSE_EVENT_CHARS = 4 * 1024 * 1024;
|
|
3
|
+
const REPLAY_PAGE = 500;
|
|
4
|
+
const MAX_REPLAY_PAGES = 2000;
|
|
5
|
+
/**
|
|
6
|
+
* Fold a run's events into turns. Turn N holds the inputs that led to the run's (N+1)th model answer and that answer, so
|
|
7
|
+
* forking from turn N re-runs that answer. Events after the last answer are returned as `pending`.
|
|
8
|
+
*/
|
|
9
|
+
export function foldHenryTurns(events) {
|
|
10
|
+
const turns = [];
|
|
11
|
+
let current = { turn: 0, inputs: [], events: [] };
|
|
12
|
+
for (const event of events) {
|
|
13
|
+
current.events.push({ seq: event.seq, at: event.at, type: event.type, ...(event.detail === undefined ? {} : { detail: event.detail }) });
|
|
14
|
+
const message = event.message;
|
|
15
|
+
if (message?.role === 'assistant') {
|
|
16
|
+
turns.push({ ...current, answer: message });
|
|
17
|
+
current = { turn: turns.length, inputs: [], events: [] };
|
|
18
|
+
}
|
|
19
|
+
else if (message)
|
|
20
|
+
current.inputs.push(message);
|
|
21
|
+
}
|
|
22
|
+
return { turns, pending: current };
|
|
23
|
+
}
|
|
24
|
+
const invalid = (operationId, message) => new GenesisError({ status: 0, type: 'invalid_request', operationId, message });
|
|
25
|
+
const STREAM_EVENTS = new Set(['activity', 'status', 'end', 'error']);
|
|
26
|
+
/** Parse one SSE frame's lines into { event, id, data }; undefined for comments, keepalives and data-less frames. */
|
|
27
|
+
function frame(lines) {
|
|
28
|
+
let event = 'message';
|
|
29
|
+
let id;
|
|
30
|
+
const data = [];
|
|
31
|
+
for (const line of lines) {
|
|
32
|
+
if (line.startsWith(':'))
|
|
33
|
+
continue;
|
|
34
|
+
const colon = line.indexOf(':');
|
|
35
|
+
const field = colon < 0 ? line : line.slice(0, colon);
|
|
36
|
+
let value = colon < 0 ? '' : line.slice(colon + 1);
|
|
37
|
+
if (value.startsWith(' '))
|
|
38
|
+
value = value.slice(1);
|
|
39
|
+
if (field === 'event')
|
|
40
|
+
event = value;
|
|
41
|
+
else if (field === 'id')
|
|
42
|
+
id = value;
|
|
43
|
+
else if (field === 'data')
|
|
44
|
+
data.push(value);
|
|
45
|
+
}
|
|
46
|
+
return data.length ? { event, ...(id === undefined ? {} : { id }), data: data.join('\n') } : undefined;
|
|
47
|
+
}
|
|
48
|
+
const wait = (ms, signal) => new Promise(resolve => {
|
|
49
|
+
const done = () => { clearTimeout(timer); signal?.removeEventListener('abort', done); resolve(); };
|
|
50
|
+
const timer = setTimeout(done, ms);
|
|
51
|
+
signal?.addEventListener('abort', done, { once: true });
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Follow a run over SSE, reconnecting with Last-Event-ID after each stream closes (Henry closes one within 120 s) until
|
|
55
|
+
* `end`, the signal aborts or maxReconnects is used up. Never buffers a whole stream.
|
|
56
|
+
*/
|
|
57
|
+
async function* streamRunEvents(client, run_id, options = {}) {
|
|
58
|
+
const operationId = 'henry_listRunEvents';
|
|
59
|
+
const { signal } = options;
|
|
60
|
+
let last = options.afterSeq ?? 0;
|
|
61
|
+
let lastStatus;
|
|
62
|
+
if (!Number.isSafeInteger(last) || last < 0 || last > 9_999_999)
|
|
63
|
+
throw invalid(operationId, 'afterSeq must be an integer from 0 to 9999999.');
|
|
64
|
+
const maxReconnects = options.maxReconnects ?? 100;
|
|
65
|
+
if (!Number.isInteger(maxReconnects) || maxReconnects < 1 || maxReconnects > 1000)
|
|
66
|
+
throw invalid(operationId, 'maxReconnects must be an integer from 1 to 1000.');
|
|
67
|
+
const idleMs = options.idleMs ?? 45_000;
|
|
68
|
+
if (!Number.isInteger(idleMs) || idleMs < 1000 || idleMs > 300_000)
|
|
69
|
+
throw invalid(operationId, 'idleMs must be an integer from 1000 to 300000.');
|
|
70
|
+
for (let attempt = 0; attempt <= maxReconnects && !signal?.aborted; attempt++) {
|
|
71
|
+
// One connection: aborted by the caller's signal, or when the stream goes quiet for idleMs.
|
|
72
|
+
const connection = new AbortController();
|
|
73
|
+
const abort = () => connection.abort();
|
|
74
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
75
|
+
let idle;
|
|
76
|
+
const touch = () => { clearTimeout(idle); idle = setTimeout(abort, idleMs); };
|
|
77
|
+
let progressed = false;
|
|
78
|
+
try {
|
|
79
|
+
touch();
|
|
80
|
+
let response;
|
|
81
|
+
try {
|
|
82
|
+
// Exactly text/event-stream: an Accept that also allows JSON gets the paged read instead of a stream.
|
|
83
|
+
response = await client.raw(operationId, { run_id }, { signal: connection.signal, headers: { accept: 'text/event-stream', 'last-event-id': String(last) } });
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
if (signal?.aborted)
|
|
87
|
+
return;
|
|
88
|
+
// An HTTP answer (404, 403, 429 streams_busy...) is raised, not retried in a loop. A dropped or quiet connection is retried.
|
|
89
|
+
if (error instanceof GenesisError && error.status !== 0 && ![502, 503, 504].includes(error.status))
|
|
90
|
+
throw error;
|
|
91
|
+
await wait(1000, signal);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const reader = response.body?.getReader();
|
|
95
|
+
if (!reader) {
|
|
96
|
+
await wait(1000, signal);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const decoder = new TextDecoder();
|
|
100
|
+
let buffer = '';
|
|
101
|
+
let lines = [];
|
|
102
|
+
let size = 0;
|
|
103
|
+
try {
|
|
104
|
+
for (;;) {
|
|
105
|
+
let chunk;
|
|
106
|
+
try {
|
|
107
|
+
chunk = await reader.read();
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
if (chunk.done)
|
|
113
|
+
break;
|
|
114
|
+
touch();
|
|
115
|
+
buffer += decoder.decode(chunk.value, { stream: true });
|
|
116
|
+
let index;
|
|
117
|
+
while ((index = buffer.search(/\r\n|\r|\n/)) >= 0) {
|
|
118
|
+
const line = buffer.slice(0, index);
|
|
119
|
+
buffer = buffer.slice(index + (buffer.startsWith('\r\n', index) ? 2 : 1));
|
|
120
|
+
if (line !== '') {
|
|
121
|
+
size += line.length;
|
|
122
|
+
if (size > MAX_SSE_EVENT_CHARS)
|
|
123
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId, message: 'Henry stream event exceeds 4 MiB.' });
|
|
124
|
+
lines.push(line);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const parsed = frame(lines);
|
|
128
|
+
lines = [];
|
|
129
|
+
size = 0;
|
|
130
|
+
if (!parsed || !STREAM_EVENTS.has(parsed.event))
|
|
131
|
+
continue;
|
|
132
|
+
let data;
|
|
133
|
+
try {
|
|
134
|
+
data = JSON.parse(parsed.data);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId, message: 'Henry stream sent invalid JSON.' });
|
|
138
|
+
}
|
|
139
|
+
if (parsed.event === 'status') {
|
|
140
|
+
// Each connection opens with the current status: report a change only.
|
|
141
|
+
const status = data?.status;
|
|
142
|
+
if (status === lastStatus)
|
|
143
|
+
continue;
|
|
144
|
+
lastStatus = status;
|
|
145
|
+
}
|
|
146
|
+
if (parsed.event === 'activity') {
|
|
147
|
+
const seq = data?.seq;
|
|
148
|
+
if (typeof seq !== 'number' || !Number.isSafeInteger(seq))
|
|
149
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId, message: 'Henry stream activity has no seq.' });
|
|
150
|
+
if (seq <= last)
|
|
151
|
+
continue; // already yielded before a reconnect
|
|
152
|
+
last = seq;
|
|
153
|
+
progressed = true;
|
|
154
|
+
}
|
|
155
|
+
yield { event: parsed.event, data };
|
|
156
|
+
if (parsed.event === 'end')
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (buffer.length > MAX_SSE_EVENT_CHARS)
|
|
160
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId, message: 'Henry stream event exceeds 4 MiB.' });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
void reader.cancel().catch(() => { });
|
|
165
|
+
}
|
|
166
|
+
if (signal?.aborted)
|
|
167
|
+
return;
|
|
168
|
+
// A stream that closed with nothing new waits before reconnecting, so a failing upstream is never hammered.
|
|
169
|
+
if (!progressed)
|
|
170
|
+
await wait(1000, signal);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
clearTimeout(idle);
|
|
174
|
+
signal?.removeEventListener('abort', abort);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (!signal?.aborted)
|
|
178
|
+
throw new GenesisError({ status: 0, type: 'stream_incomplete', operationId,
|
|
179
|
+
message: `Henry run ${run_id} did not end within ${maxReconnects} reconnects; resume with afterSeq ${last}.` });
|
|
180
|
+
}
|
|
2
181
|
function receiptVerificationKey(value) {
|
|
3
182
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
4
183
|
throw new Error('Henry returned an invalid receipt verification key.');
|
|
@@ -34,12 +213,56 @@ export function henryModule(client) {
|
|
|
34
213
|
}
|
|
35
214
|
},
|
|
36
215
|
},
|
|
216
|
+
blinds: {
|
|
217
|
+
/** HTTPS request through the organization's bound Blinds machine. */
|
|
218
|
+
proxy: (body) => client.request('henry_proxyBlinds', { body }),
|
|
219
|
+
},
|
|
37
220
|
runs: {
|
|
38
221
|
list: (page_token) => client.request('henry_listRuns', page_token ? { page_token } : {}),
|
|
39
222
|
create: (body) => client.request('henry_createRun', { body: { ...body, run_id: body.run_id ?? globalThis.crypto.randomUUID() } }),
|
|
40
223
|
get: (run_id) => client.request('henry_getRun', { run_id }),
|
|
224
|
+
/** Page activity events: pass the previous page's next_after_seq as after_seq. */
|
|
225
|
+
events: (run_id, query = {}) => client.request('henry_listRunEvents', { run_id, ...query }),
|
|
226
|
+
/** Delete a finished run; active runs must be cancelled first (409). */
|
|
227
|
+
delete: (run_id) => client.request('henry_deleteRun', { run_id }),
|
|
41
228
|
command: (run_id, action, text) => client.request('henry_commandRun', { run_id, body: { action, ...(text === undefined ? {} : { text }) } }),
|
|
42
229
|
approval: (run_id, approval_id, decision) => client.request('henry_decideApproval', { run_id, approval_id, body: { decision } }),
|
|
230
|
+
/**
|
|
231
|
+
* Send a message into a run: `steer` lands before the next model call, `queue` (default) after the current turn,
|
|
232
|
+
* `interrupt` cancels the turn in flight. A completed run takes it at once and runs the next turn in this request.
|
|
233
|
+
*/
|
|
234
|
+
message: (run_id, body) => {
|
|
235
|
+
if (typeof body?.text !== 'string' || !body.text.trim() || body.text.length > 16000)
|
|
236
|
+
throw invalid('henry_sendRunMessage', 'Message text must contain 1-16000 characters.');
|
|
237
|
+
return client.request('henry_sendRunMessage', { run_id, body: { text: body.text, ...(body.delivery === undefined ? {} : { delivery: body.delivery }) } });
|
|
238
|
+
},
|
|
239
|
+
/**
|
|
240
|
+
* Start a new run from turn N of this one (0 = the original task; default the latest, which needs text). run_id is
|
|
241
|
+
* the new run's idempotency key: one is generated unless supplied, and a retry with it returns the same run.
|
|
242
|
+
*/
|
|
243
|
+
fork: (run_id, body = {}) => {
|
|
244
|
+
if (body.turn !== undefined && (!Number.isSafeInteger(body.turn) || body.turn < 0))
|
|
245
|
+
throw invalid('henry_forkRun', 'turn must be a non-negative integer.');
|
|
246
|
+
return client.request('henry_forkRun', { run_id, body: { ...body, run_id: body.run_id ?? globalThis.crypto.randomUUID() } });
|
|
247
|
+
},
|
|
248
|
+
/** Follow a run live: an async iterator over its stream, reconnecting with Last-Event-ID until `end`. */
|
|
249
|
+
streamEvents: (run_id, options = {}) => streamRunEvents(client, run_id, options),
|
|
250
|
+
/** Read every event of a run and fold them into turns (see foldHenryTurns). */
|
|
251
|
+
replay: async (run_id, options = {}) => {
|
|
252
|
+
const events = [];
|
|
253
|
+
let after = 0;
|
|
254
|
+
for (let pages = 0; pages < MAX_REPLAY_PAGES; pages++) {
|
|
255
|
+
const page = await client.request('henry_listRunEvents', { run_id, after_seq: after, limit: REPLAY_PAGE }, { signal: options.signal });
|
|
256
|
+
events.push(...page.events);
|
|
257
|
+
if (!page.has_more)
|
|
258
|
+
return { run_id: page.run_id, ...(page.status === undefined ? {} : { status: page.status }), ...foldHenryTurns(events) };
|
|
259
|
+
if (!Number.isSafeInteger(page.next_after_seq) || page.next_after_seq <= after) {
|
|
260
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId: 'henry_listRunEvents', message: 'Henry events did not advance.' });
|
|
261
|
+
}
|
|
262
|
+
after = page.next_after_seq;
|
|
263
|
+
}
|
|
264
|
+
throw new GenesisError({ status: 0, type: 'invalid_response', operationId: 'henry_listRunEvents', message: 'Henry run has too many events to replay.' });
|
|
265
|
+
},
|
|
43
266
|
},
|
|
44
267
|
};
|
|
45
268
|
}
|
package/dist/hives-cells.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { GenesisClient } from './client.js';
|
|
2
|
-
import { type HivesResourceOptions } from './hives-resources-transport.js';
|
|
2
|
+
import { type HivesFundedWriteOptions, type HivesResourceOptions } from './hives-resources-transport.js';
|
|
3
3
|
export interface HivesCorsRule {
|
|
4
4
|
allowed_origins: string[];
|
|
5
5
|
allowed_methods: string[];
|
|
@@ -112,16 +112,21 @@ export declare function hivesCells(client: GenesisClient): {
|
|
|
112
112
|
continuation_token?: string;
|
|
113
113
|
max_keys?: number;
|
|
114
114
|
}, options?: HivesResourceOptions): Promise<HivesObjectList>;
|
|
115
|
-
put(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?:
|
|
115
|
+
put(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: HivesFundedWriteOptions & {
|
|
116
116
|
content_type?: string;
|
|
117
117
|
}): Promise<HivesObjectAcknowledgement>;
|
|
118
118
|
remove: (project: string, id: string, key: string, options?: HivesResourceOptions) => Promise<void>;
|
|
119
119
|
download: (project: string, id: string, key: string, options?: HivesResourceOptions) => Promise<Response>;
|
|
120
120
|
/** Existing flat-key path compatibility; nested keys use canonical collection methods above. */
|
|
121
|
-
putFlat(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?:
|
|
121
|
+
putFlat(project: string, id: string, key: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: HivesFundedWriteOptions & {
|
|
122
122
|
content_type?: string;
|
|
123
123
|
}): Promise<HivesObjectAcknowledgement>;
|
|
124
124
|
removeFlat: (project: string, id: string, key: string, options?: HivesResourceOptions) => Promise<void>;
|
|
125
|
+
/** The flat key "download" on its own static route, which shadows /objects/{key} for that key. */
|
|
126
|
+
putDownload(project: string, id: string, bytes: Blob | ArrayBuffer | ArrayBufferView, options?: HivesFundedWriteOptions & {
|
|
127
|
+
content_type?: string;
|
|
128
|
+
}): Promise<HivesObjectAcknowledgement>;
|
|
129
|
+
removeDownload: (project: string, id: string, options?: HivesResourceOptions) => Promise<void>;
|
|
125
130
|
};
|
|
126
131
|
presign(project: string, id: string, body: HivesPresign, options?: HivesResourceOptions): Promise<HivesPresignedUrl>;
|
|
127
132
|
};
|
package/dist/hives-cells.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HIVES_OBJECT_BYTES, hivesResourceCall, hivesResourceId, hivesObjectBody, hivesContentType, resourceError } from './hives-resources-transport.js';
|
|
1
|
+
import { HIVES_OBJECT_BYTES, hivesFundedWriteHeaders, hivesResourceCall, hivesResourceId, hivesObjectBody, hivesContentType, resourceError } from './hives-resources-transport.js';
|
|
2
2
|
export function hivesObjectKey(key) {
|
|
3
3
|
const bytes = new TextEncoder().encode(key);
|
|
4
4
|
if (typeof key !== 'string' || !key || bytes.length > 1024 || new TextDecoder('utf-8', { fatal: true }).decode(bytes) !== key
|
|
@@ -59,7 +59,12 @@ function object(value, id) {
|
|
|
59
59
|
hivesObjectKey(value.key);
|
|
60
60
|
return Object.fromEntries(['key', 'bucket_id', 'size_bytes', 'etag', 'last_modified', 'generation', 'content_type', 'metadata', 'metadata_scope'].map(k => [k, value[k]]));
|
|
61
61
|
}
|
|
62
|
-
function acknowledgement(
|
|
62
|
+
function acknowledgement(answer, key, id, size) {
|
|
63
|
+
// A funded write answers with its settled storage operation receipt; the acknowledgement is its result.
|
|
64
|
+
const receipt = answer;
|
|
65
|
+
if (receipt && receipt.object !== undefined && (receipt.object !== 'storage_write_operation' || receipt.state !== 'settled'))
|
|
66
|
+
throw resourceError(0);
|
|
67
|
+
const value = (receipt?.object === undefined ? answer : receipt.result);
|
|
63
68
|
if (!value || value.bucket_id !== id || value.key !== key || value.size_bytes !== size || !Number.isSafeInteger(value.size_bytes) || value.size_bytes < 0 || typeof value.etag !== 'string' || typeof value.generation !== 'string' || value.content_type !== null && typeof value.content_type !== 'string')
|
|
64
69
|
throw resourceError(0);
|
|
65
70
|
return { key: value.key, bucket_id: value.bucket_id, size_bytes: value.size_bytes, etag: value.etag, generation: value.generation, content_type: value.content_type };
|
|
@@ -67,6 +72,8 @@ function acknowledgement(value, key, id, size) {
|
|
|
67
72
|
export function hivesCells(client) {
|
|
68
73
|
const ids = (project_id, bucket_id) => ({ project_id: hivesResourceId(project_id), ...(bucket_id === undefined ? {} : { bucket_id: hivesResourceId(bucket_id) }) });
|
|
69
74
|
const call = (id, input, options, mode = 'json', limit = 2 * 1024 * 1024) => hivesResourceCall(client, id, input, options, mode, limit, 100_000);
|
|
75
|
+
// Object writes are funded: each carries one Idempotency-Key (the caller's, or a fresh one).
|
|
76
|
+
const write = (id, input, options) => hivesResourceCall(client, id, input, options, 'json', 2 * 1024 * 1024, 100_000, undefined, { headers: hivesFundedWriteHeaders(options, id) });
|
|
70
77
|
return {
|
|
71
78
|
async list(project, query = {}, options) {
|
|
72
79
|
if (Object.keys(query).some(k => !['page', 'per_page'].includes(k)) || query.page !== undefined && (!Number.isInteger(query.page) || query.page < 1 || query.page > 10000) || query.per_page !== undefined && (!Number.isInteger(query.per_page) || query.per_page < 1 || query.per_page > 100))
|
|
@@ -113,7 +120,7 @@ export function hivesCells(client) {
|
|
|
113
120
|
async put(project, id, key, bytes, options = {}) {
|
|
114
121
|
const body = await hivesObjectBody(bytes);
|
|
115
122
|
const content_type = hivesContentType(options.content_type);
|
|
116
|
-
return acknowledgement(await
|
|
123
|
+
return acknowledgement(await write('hives_upload_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key), body, content_type }, options), key, id, body.byteLength);
|
|
117
124
|
},
|
|
118
125
|
remove: (project, id, key, options) => call('hives_delete_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key) }, options, 'empty'),
|
|
119
126
|
download: (project, id, key, options) => call('hives_download_object_by_key', { ...ids(project, id), key_base64url: hivesObjectKey(key) }, options, 'binary', HIVES_OBJECT_BYTES),
|
|
@@ -123,10 +130,16 @@ export function hivesCells(client) {
|
|
|
123
130
|
if (!/^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*$/.test(key))
|
|
124
131
|
throw resourceError(0);
|
|
125
132
|
const body = await hivesObjectBody(bytes);
|
|
126
|
-
return acknowledgement(await
|
|
133
|
+
return acknowledgement(await write('hives_upload_object', { ...ids(project, id), key, body, content_type: hivesContentType(options.content_type) }, options), key, id, body.byteLength);
|
|
127
134
|
},
|
|
128
135
|
removeFlat: (project, id, key, options) => { hivesObjectKey(key); if (!/^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)*$/.test(key))
|
|
129
136
|
throw resourceError(0); return call('hives_delete_object', { ...ids(project, id), key }, options, 'empty'); },
|
|
137
|
+
/** The flat key "download" on its own static route, which shadows /objects/{key} for that key. */
|
|
138
|
+
async putDownload(project, id, bytes, options = {}) {
|
|
139
|
+
const body = await hivesObjectBody(bytes);
|
|
140
|
+
return acknowledgement(await write('hives_upload_object_named_download', { ...ids(project, id), body, content_type: hivesContentType(options.content_type) }, options), 'download', id, body.byteLength);
|
|
141
|
+
},
|
|
142
|
+
removeDownload: (project, id, options) => call('hives_delete_object_named_download', ids(project, id), options, 'empty'),
|
|
130
143
|
},
|
|
131
144
|
async presign(project, id, body, options) {
|
|
132
145
|
hivesObjectKey(body.key);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Environment metadata never carries stored values. Reveals are explicit. */
|
|
2
2
|
export declare function validateHivesEnvironment(input: unknown): Record<string, string>;
|
|
3
|
+
/** Names for DELETE /env: 1–100 distinct valid environment names. */
|
|
4
|
+
export declare function validateHivesEnvironmentNames(input: unknown): string[];
|
|
3
5
|
export declare function hivesEnvironmentMetadata(value: unknown, project: unknown, updated: boolean): {
|
|
4
6
|
project_id: string;
|
|
5
7
|
updated: {
|
|
@@ -26,3 +28,10 @@ export declare function hivesEnvironmentReveal(value: unknown, key: unknown): {
|
|
|
26
28
|
name: string;
|
|
27
29
|
value: string;
|
|
28
30
|
};
|
|
31
|
+
/** PUT /env answers the whole decrypted map. Keep only the submitted names it confirms; never a value. */
|
|
32
|
+
export declare function hivesEnvironmentSetNames(value: unknown, project: unknown, submitted: unknown): {
|
|
33
|
+
project_id: string;
|
|
34
|
+
updated: {
|
|
35
|
+
name: string;
|
|
36
|
+
}[];
|
|
37
|
+
};
|