@onesi/genesis 0.1.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/dist/auto.d.ts +1010 -0
  3. package/dist/auto.js +125 -0
  4. package/dist/beacons.d.ts +42 -0
  5. package/dist/beacons.js +71 -0
  6. package/dist/blinds-owner-enrollment.d.ts +109 -0
  7. package/dist/blinds-owner-enrollment.js +21 -2
  8. package/dist/client.d.ts +3 -19947
  9. package/dist/client.js +124 -17
  10. package/dist/errors.js +1 -1
  11. package/dist/flares.d.ts +32 -0
  12. package/dist/flares.js +5 -0
  13. package/dist/fleets.d.ts +32 -0
  14. package/dist/fleets.js +59 -6
  15. package/dist/flocks.d.ts +285 -1
  16. package/dist/flocks.js +59 -0
  17. package/dist/foundry.d.ts +424 -0
  18. package/dist/foundry.js +133 -0
  19. package/dist/garden.d.ts +754 -0
  20. package/dist/garden.js +76 -0
  21. package/dist/gateway.d.ts +365 -0
  22. package/dist/gateway.js +82 -0
  23. package/dist/gears.d.ts +121 -2
  24. package/dist/gears.js +24 -2
  25. package/dist/generated/operations.d.ts +3 -19948
  26. package/dist/generated/operations.js +54590 -13302
  27. package/dist/generated/schema.d.ts +69793 -17548
  28. package/dist/genesis.d.ts +7908 -1260
  29. package/dist/genesis.js +90 -25
  30. package/dist/genesis.openapi.json +109121 -29920
  31. package/dist/henry.d.ts +202 -1
  32. package/dist/henry.js +223 -0
  33. package/dist/hives-environment.d.ts +9 -0
  34. package/dist/hives-environment.js +22 -0
  35. package/dist/hives-node.js +3 -0
  36. package/dist/hives-operations.d.ts +114 -0
  37. package/dist/hives-operations.js +2 -0
  38. package/dist/hives-platform.d.ts +149 -0
  39. package/dist/hives-platform.js +183 -0
  40. package/dist/hives-sse.d.ts +24 -0
  41. package/dist/hives-sse.js +111 -0
  42. package/dist/iam-directory.d.ts +8 -0
  43. package/dist/iam-directory.js +23 -0
  44. package/dist/iam.d.ts +391 -0
  45. package/dist/iam.js +92 -0
  46. package/dist/idempotency.d.ts +3 -0
  47. package/dist/idempotency.js +22 -0
  48. package/dist/index.d.ts +18 -4
  49. package/dist/index.js +16 -4
  50. package/dist/instances.d.ts +177 -2
  51. package/dist/instances.js +37 -5
  52. package/dist/minds-agent.d.ts +28 -0
  53. package/dist/minds-agent.js +53 -10
  54. package/dist/minds-engine.d.ts +394 -0
  55. package/dist/minds-engine.js +555 -0
  56. package/dist/minds.d.ts +109 -1
  57. package/dist/minds.js +49 -14
  58. package/dist/orgs.d.ts +405 -0
  59. package/dist/orgs.js +63 -0
  60. package/dist/runner.d.ts +4 -0
  61. package/dist/runner.js +1 -0
  62. package/dist/scopes.d.ts +310 -0
  63. package/dist/scopes.js +40 -0
  64. package/dist/taps.d.ts +118 -0
  65. package/dist/taps.js +45 -0
  66. package/dist/traces.d.ts +574 -0
  67. package/dist/traces.js +97 -0
  68. package/dist/types.d.ts +12 -1
  69. 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: import("./index.js").components["schemas"]["Henry.Run"][];
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
  }
@@ -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
+ };
@@ -17,6 +17,18 @@ export function validateHivesEnvironment(input) {
17
17
  throw new Error('Environment input exceeds 2 MiB. Split it into smaller batches.');
18
18
  return result;
19
19
  }
20
+ /** Names for DELETE /env: 1–100 distinct valid environment names. */
21
+ export function validateHivesEnvironmentNames(input) {
22
+ if (!Array.isArray(input) || input.length < 1 || input.length > 100)
23
+ throw new Error('Environment deletion requires a JSON array of 1–100 names.');
24
+ for (const name of input) {
25
+ if (typeof name !== 'string' || name.length > 255 || !/^[A-Za-z][A-Za-z0-9_]*$/.test(name))
26
+ throw new Error('Environment names must start with a letter and contain only letters, numbers and underscores (up to 255 characters).');
27
+ }
28
+ if (new Set(input).size !== input.length)
29
+ throw new Error('Environment deletion names must be distinct.');
30
+ return [...input];
31
+ }
20
32
  function record(value) {
21
33
  if (!value || typeof value !== 'object' || Array.isArray(value))
22
34
  throw new Error('Hives returned invalid environment metadata.');
@@ -56,3 +68,13 @@ export function hivesEnvironmentReveal(value, key) {
56
68
  throw new Error('Hives returned invalid environment reveal data.');
57
69
  return { name: data.name, value: data.value };
58
70
  }
71
+ /** PUT /env answers the whole decrypted map. Keep only the submitted names it confirms; never a value. */
72
+ export function hivesEnvironmentSetNames(value, project, submitted) {
73
+ const data = record(value);
74
+ if (typeof project !== 'string' || !submitted || typeof submitted !== 'object')
75
+ throw new Error('Hives returned invalid environment data.');
76
+ const updated = Object.keys(submitted);
77
+ if (updated.some((name) => typeof data[name] !== 'string'))
78
+ throw new Error('Hives did not confirm every submitted environment name. Read the names before retrying.');
79
+ return { project_id: project, updated: updated.map((name) => ({ name })) };
80
+ }
@@ -16,6 +16,9 @@ export function hivesOperationBudget(id) {
16
16
  return 100_000;
17
17
  if (id === 'hives_cancel_deployment' || id === 'hives_delete_deployment' || id === 'hives_stop_deployment')
18
18
  return 330_000;
19
+ // A live SSE subscription is bounded by its caller's window or --follow limit (at most 300 s).
20
+ if (id === 'hives_stream_logs')
21
+ return 330_000;
19
22
  if (['hives_create_deployment', 'hives_upload_deployment', 'hives_invoke_deployment', 'hives_invoke_function', 'hives_invoke_function_async'].includes(id))
20
23
  return 40_000;
21
24
  if (['hives_create_function', 'hives_update_function', 'hives_delete_function'].includes(id))