@rkat/web 0.5.2 → 0.6.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 (47) hide show
  1. package/dist/auth.d.ts +181 -0
  2. package/dist/auth.d.ts.map +1 -0
  3. package/dist/auth.js +134 -0
  4. package/dist/auth.js.map +1 -0
  5. package/dist/events.d.ts +1 -1
  6. package/dist/events.d.ts.map +1 -1
  7. package/dist/events.js +3 -0
  8. package/dist/events.js.map +1 -1
  9. package/dist/generated/auth.d.ts +247 -0
  10. package/dist/generated/auth.d.ts.map +1 -0
  11. package/dist/generated/auth.js +502 -0
  12. package/dist/generated/auth.js.map +1 -0
  13. package/dist/generated/events.d.ts +226 -54
  14. package/dist/generated/events.d.ts.map +1 -1
  15. package/dist/generated/events.js +5 -3
  16. package/dist/generated/events.js.map +1 -1
  17. package/dist/generated/mob.d.ts +50 -0
  18. package/dist/generated/mob.d.ts.map +1 -0
  19. package/dist/generated/mob.js +4 -0
  20. package/dist/generated/mob.js.map +1 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/mob.d.ts +23 -21
  26. package/dist/mob.d.ts.map +1 -1
  27. package/dist/mob.js +510 -47
  28. package/dist/mob.js.map +1 -1
  29. package/dist/runtime.d.ts +8 -8
  30. package/dist/runtime.d.ts.map +1 -1
  31. package/dist/runtime.js +29 -8
  32. package/dist/runtime.js.map +1 -1
  33. package/dist/session.d.ts +9 -6
  34. package/dist/session.d.ts.map +1 -1
  35. package/dist/session.js +44 -33
  36. package/dist/session.js.map +1 -1
  37. package/dist/types.d.ts +91 -45
  38. package/dist/types.d.ts.map +1 -1
  39. package/dist/types.js +67 -1
  40. package/dist/types.js.map +1 -1
  41. package/package.json +2 -2
  42. package/wasm/.meerkat-wasm-build.json +5 -0
  43. package/wasm/meerkat_web_runtime.d.ts +68 -34
  44. package/wasm/meerkat_web_runtime.js +132 -67
  45. package/wasm/meerkat_web_runtime_bg.wasm +0 -0
  46. package/wasm/meerkat_web_runtime_bg.wasm.d.ts +12 -8
  47. package/wasm/package.json +1 -1
package/dist/mob.js CHANGED
@@ -1,35 +1,444 @@
1
1
  import { EventSubscription } from './events.js';
2
+ function encodeBase64UrlJson(payload) {
3
+ const bytes = new TextEncoder().encode(JSON.stringify(payload));
4
+ let binary = '';
5
+ for (let i = 0; i < bytes.length; i += 1) {
6
+ binary += String.fromCharCode(bytes[i]);
7
+ }
8
+ const b64 = btoa(binary);
9
+ return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
10
+ }
11
+ function encodeMemberRef(mobId, agentIdentity) {
12
+ return encodeBase64UrlJson({ m: mobId, a: agentIdentity });
13
+ }
14
+ function spawnSpecPayload(spec) {
15
+ return {
16
+ profile: spec.profile,
17
+ agent_identity: spec.agent_identity,
18
+ runtime_mode: spec.runtime_mode,
19
+ initial_message: spec.initial_message,
20
+ labels: spec.labels,
21
+ context: spec.context,
22
+ additional_instructions: spec.additional_instructions,
23
+ };
24
+ }
25
+ function isRecord(value) {
26
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
27
+ }
28
+ function requireOnlyKeys(value, allowedKeys, message) {
29
+ const allowed = new Set(allowedKeys);
30
+ for (const key of Object.keys(value)) {
31
+ if (!allowed.has(key)) {
32
+ throw new Error(message);
33
+ }
34
+ }
35
+ }
36
+ function parseJsonPayload(json, context) {
37
+ try {
38
+ return JSON.parse(json);
39
+ }
40
+ catch (error) {
41
+ throw new Error(`${context}: invalid JSON`);
42
+ }
43
+ }
44
+ function requireRecord(value, message) {
45
+ if (!isRecord(value)) {
46
+ throw new Error(message);
47
+ }
48
+ return value;
49
+ }
50
+ function requireStringField(value, field, message) {
51
+ const raw = value[field];
52
+ if (typeof raw !== 'string' || raw.length === 0) {
53
+ throw new Error(message);
54
+ }
55
+ return raw;
56
+ }
57
+ function optionalStringField(value, field, message) {
58
+ const raw = value[field];
59
+ if (raw == null) {
60
+ return undefined;
61
+ }
62
+ if (typeof raw !== 'string') {
63
+ throw new Error(message);
64
+ }
65
+ return raw;
66
+ }
67
+ function optionalNonEmptyStringField(value, field, message) {
68
+ const raw = optionalStringField(value, field, message);
69
+ if (raw === undefined) {
70
+ return undefined;
71
+ }
72
+ if (raw.length === 0) {
73
+ throw new Error(message);
74
+ }
75
+ return raw;
76
+ }
77
+ function requireNumberField(value, field, message) {
78
+ const raw = value[field];
79
+ if (typeof raw !== 'number' || !Number.isFinite(raw)) {
80
+ throw new Error(message);
81
+ }
82
+ return raw;
83
+ }
84
+ function requireNonNegativeIntegerField(value, field, message) {
85
+ const raw = requireNumberField(value, field, message);
86
+ if (!Number.isInteger(raw) || raw < 0) {
87
+ throw new Error(message);
88
+ }
89
+ return raw;
90
+ }
91
+ function optionalNumberField(value, field, message) {
92
+ const raw = value[field];
93
+ if (raw == null) {
94
+ return undefined;
95
+ }
96
+ if (typeof raw !== 'number' || !Number.isFinite(raw)) {
97
+ throw new Error(message);
98
+ }
99
+ return raw;
100
+ }
101
+ function requireBooleanField(value, field, message) {
102
+ const raw = value[field];
103
+ if (typeof raw !== 'boolean') {
104
+ throw new Error(message);
105
+ }
106
+ return raw;
107
+ }
108
+ function optionalRecordField(value, field, message) {
109
+ const raw = value[field];
110
+ if (raw == null) {
111
+ return undefined;
112
+ }
113
+ return requireRecord(raw, message);
114
+ }
115
+ function optionalStringArrayField(value, field, message) {
116
+ const raw = value[field];
117
+ if (raw == null) {
118
+ return undefined;
119
+ }
120
+ if (!Array.isArray(raw) || raw.some((entry) => typeof entry !== 'string')) {
121
+ throw new Error(message);
122
+ }
123
+ return [...raw];
124
+ }
125
+ const WIRE_MOB_MEMBER_STATUSES = [
126
+ 'active',
127
+ 'retiring',
128
+ 'broken',
129
+ 'completed',
130
+ 'unknown',
131
+ ];
132
+ function parseWireMobMemberStatus(raw, message) {
133
+ if (typeof raw === 'string' &&
134
+ WIRE_MOB_MEMBER_STATUSES.includes(raw)) {
135
+ return raw;
136
+ }
137
+ throw new Error(message);
138
+ }
139
+ const WIRE_HANDLING_MODES = ['queue', 'steer'];
140
+ function parseWireHandlingMode(raw, message) {
141
+ if (typeof raw === 'string' && WIRE_HANDLING_MODES.includes(raw)) {
142
+ return raw;
143
+ }
144
+ throw new Error(message);
145
+ }
146
+ export function parseMobStatusResult(raw, context = 'Invalid mob/status response') {
147
+ const record = requireRecord(raw, `${context}: malformed envelope`);
148
+ const mobId = requireStringField(record, 'mob_id', `${context}: missing mob_id`);
149
+ const status = requireStringField(record, 'status', `${context}: missing status`);
150
+ return {
151
+ mob_id: mobId,
152
+ status,
153
+ state: status,
154
+ };
155
+ }
156
+ function parseMobAppendSystemContextResult(raw) {
157
+ const record = requireRecord(raw, 'Invalid mob append_system_context response: malformed envelope');
158
+ const status = requireStringField(record, 'status', 'Invalid mob append_system_context response: missing status');
159
+ if (status !== 'staged' && status !== 'duplicate') {
160
+ throw new Error('Invalid mob append_system_context response: invalid status');
161
+ }
162
+ return {
163
+ mob_id: requireStringField(record, 'mob_id', 'Invalid mob append_system_context response: missing mob_id'),
164
+ agent_identity: requireStringField(record, 'agent_identity', 'Invalid mob append_system_context response: missing agent_identity'),
165
+ status,
166
+ };
167
+ }
168
+ function normalizeSpawnManyEntry(raw, mobId) {
169
+ if (!isRecord(raw)) {
170
+ throw new Error('Invalid mob spawn response: malformed result entry');
171
+ }
172
+ if ('ok' in raw) {
173
+ throw new Error('Invalid mob spawn response: legacy ok result row');
174
+ }
175
+ requireOnlyKeys(raw, ['status', 'result'], 'Invalid mob spawn response: malformed result entry');
176
+ const status = raw.status;
177
+ if (status !== 'spawned' && status !== 'failed') {
178
+ throw new Error('Invalid mob spawn response: invalid result status');
179
+ }
180
+ if (!isRecord(raw.result)) {
181
+ throw new Error('Invalid mob spawn response: missing result payload');
182
+ }
183
+ if (status === 'failed') {
184
+ requireOnlyKeys(raw.result, ['message'], 'Invalid mob spawn response: malformed failed result payload');
185
+ const message = raw.result.message;
186
+ if (typeof message !== 'string' || message.length === 0) {
187
+ throw new Error('Invalid mob spawn response: failed result missing message');
188
+ }
189
+ throw new Error(`Mob spawn failed: ${message}`);
190
+ }
191
+ requireOnlyKeys(raw.result, ['agent_identity', 'member_ref'], 'Invalid mob spawn response: malformed spawned result payload');
192
+ const agentIdentity = raw.result.agent_identity;
193
+ const memberRef = raw.result.member_ref;
194
+ if (typeof agentIdentity !== 'string' || agentIdentity.length === 0) {
195
+ throw new Error('Invalid mob spawn response: spawned result missing agent_identity');
196
+ }
197
+ if (typeof memberRef !== 'string' || memberRef.length === 0) {
198
+ throw new Error('Invalid mob spawn response: spawned result missing member_ref');
199
+ }
200
+ return {
201
+ mob_id: mobId,
202
+ agent_identity: agentIdentity,
203
+ member_ref: memberRef,
204
+ };
205
+ }
206
+ function parseSubscriptionLaggedEvent(record, context) {
207
+ return {
208
+ type: 'lagged',
209
+ skipped: requireNumberField(record, 'skipped', `${context}: lagged skipped must be number`),
210
+ };
211
+ }
212
+ function normalizeEventSourceIdentity(raw, context) {
213
+ const source = requireRecord(raw, `${context}: missing source`);
214
+ const sourceType = requireStringField(source, 'type', `${context}: source missing type`);
215
+ switch (sourceType) {
216
+ case 'session': {
217
+ requireOnlyKeys(source, ['type', 'session_id', 'sessionId'], `${context}: malformed source`);
218
+ const sessionId = typeof source.session_id === 'string' ? source.session_id : source.sessionId;
219
+ if (typeof sessionId !== 'string' || sessionId.length === 0) {
220
+ throw new Error(`${context}: source missing session_id`);
221
+ }
222
+ return { type: 'session', session_id: sessionId };
223
+ }
224
+ case 'runtime': {
225
+ requireOnlyKeys(source, ['type', 'runtime_id', 'runtimeId'], `${context}: malformed source`);
226
+ const runtimeId = typeof source.runtime_id === 'string' ? source.runtime_id : source.runtimeId;
227
+ if (typeof runtimeId !== 'string' || runtimeId.length === 0) {
228
+ throw new Error(`${context}: source missing runtime_id`);
229
+ }
230
+ return { type: 'runtime', runtime_id: runtimeId };
231
+ }
232
+ case 'interaction': {
233
+ requireOnlyKeys(source, ['type', 'interaction_id', 'interactionId'], `${context}: malformed source`);
234
+ const interactionId = typeof source.interaction_id === 'string' ? source.interaction_id : source.interactionId;
235
+ if (typeof interactionId !== 'string' || interactionId.length === 0) {
236
+ throw new Error(`${context}: source missing interaction_id`);
237
+ }
238
+ return { type: 'interaction', interaction_id: interactionId };
239
+ }
240
+ case 'callback':
241
+ requireOnlyKeys(source, ['type'], `${context}: malformed source`);
242
+ return { type: 'callback' };
243
+ case 'external': {
244
+ requireOnlyKeys(source, ['type', 'source_id', 'sourceId'], `${context}: malformed source`);
245
+ const sourceId = typeof source.source_id === 'string' ? source.source_id : source.sourceId;
246
+ if (typeof sourceId !== 'string' || sourceId.length === 0) {
247
+ throw new Error(`${context}: source missing source_id`);
248
+ }
249
+ return { type: 'external', source_id: sourceId };
250
+ }
251
+ default:
252
+ throw new Error(`${context}: unsupported source type`);
253
+ }
254
+ }
255
+ function parseEventPayload(raw, context) {
256
+ const payload = requireRecord(raw, `${context}: missing payload`);
257
+ requireStringField(payload, 'type', `${context}: payload missing type`);
258
+ return payload;
259
+ }
260
+ function parseEventEnvelope(raw, context) {
261
+ const record = requireRecord(raw, `${context}: malformed envelope`);
262
+ const payload = parseEventPayload(record.payload, context);
263
+ const envelope = {
264
+ event_id: requireStringField(record, 'event_id', `${context}: missing event_id`),
265
+ source: normalizeEventSourceIdentity(record.source, context),
266
+ source_id: requireStringField(record, 'source_id', `${context}: missing source_id`),
267
+ seq: requireNumberField(record, 'seq', `${context}: missing seq`),
268
+ timestamp_ms: requireNumberField(record, 'timestamp_ms', `${context}: missing timestamp_ms`),
269
+ payload,
270
+ };
271
+ const mobId = optionalNonEmptyStringField(record, 'mob_id', `${context}: mob_id must be string`);
272
+ if (mobId !== undefined)
273
+ envelope.mob_id = mobId;
274
+ const agentIdentity = optionalNonEmptyStringField(record, 'agent_identity', `${context}: agent_identity must be string`);
275
+ if (agentIdentity !== undefined)
276
+ envelope.agent_identity = agentIdentity;
277
+ const memberRef = optionalNonEmptyStringField(record, 'member_ref', `${context}: member_ref must be string`);
278
+ if (memberRef !== undefined)
279
+ envelope.member_ref = memberRef;
280
+ const cursor = record.cursor;
281
+ if (cursor != null) {
282
+ if (typeof cursor !== 'string' && typeof cursor !== 'number') {
283
+ throw new Error(`${context}: cursor must be string or number`);
284
+ }
285
+ envelope.cursor = cursor;
286
+ }
287
+ return envelope;
288
+ }
289
+ function parseMemberEventItem(raw, context) {
290
+ const record = requireRecord(raw, `${context}: malformed event item`);
291
+ if (record.type === 'lagged') {
292
+ return parseSubscriptionLaggedEvent(record, context);
293
+ }
294
+ return parseEventEnvelope(record, context);
295
+ }
296
+ function parseAttributedSource(raw, context) {
297
+ const source = requireRecord(raw, `${context}: missing source`);
298
+ const identity = requireStringField(source, 'identity', `${context}: source missing identity`);
299
+ const generation = requireNonNegativeIntegerField(source, 'generation', `${context}: source generation must be a non-negative integer`);
300
+ return { identity, generation };
301
+ }
302
+ function parseAttributedEventItem(raw, context) {
303
+ const record = requireRecord(raw, `${context}: malformed attributed event`);
304
+ if (record.type === 'lagged') {
305
+ return parseSubscriptionLaggedEvent(record, context);
306
+ }
307
+ const source = parseAttributedSource(record.source, context);
308
+ const role = requireStringField(record, 'role', `${context}: missing role`);
309
+ const attributed = {
310
+ source,
311
+ role,
312
+ envelope: parseEventEnvelope(record.envelope, `${context}: envelope`),
313
+ };
314
+ const sourceFenceToken = optionalNumberField(record, 'source_fence_token', `${context}: source_fence_token must be number`);
315
+ return sourceFenceToken === undefined
316
+ ? attributed
317
+ : { ...attributed, source_fence_token: sourceFenceToken };
318
+ }
319
+ function parseEventItems(raw, context, parseItem) {
320
+ if (!Array.isArray(raw)) {
321
+ throw new Error(`${context}: events must be a list`);
322
+ }
323
+ return raw.map((item, index) => parseItem(item, `${context}[${index}]`));
324
+ }
325
+ function parseMobEvent(raw, context) {
326
+ const record = requireRecord(raw, `${context}: malformed mob event`);
327
+ return {
328
+ cursor: requireNumberField(record, 'cursor', `${context}: cursor must be number`),
329
+ timestamp: requireStringField(record, 'timestamp', `${context}: missing timestamp`),
330
+ mob_id: requireStringField(record, 'mob_id', `${context}: missing mob_id`),
331
+ kind: requireRecord(record.kind, `${context}: missing kind`),
332
+ };
333
+ }
334
+ function parseMobEvents(raw) {
335
+ return parseEventItems(raw, 'Invalid mob/events response', parseMobEvent);
336
+ }
337
+ function parseMobMemberSnapshot(raw, mobId, agentIdentity) {
338
+ const snapshot = requireRecord(raw, 'Invalid mob member_status response: malformed envelope');
339
+ const currentSessionId = optionalStringField(snapshot, 'current_session_id', 'Invalid mob member_status response: current_session_id must be string');
340
+ const realtimeAttachmentStatus = optionalStringField(snapshot, 'realtime_attachment_status', 'Invalid mob member_status response: realtime_attachment_status must be string');
341
+ const result = {
342
+ status: parseWireMobMemberStatus(snapshot.status, 'Invalid mob member_status response: missing status'),
343
+ member_ref: encodeMemberRef(mobId, agentIdentity),
344
+ output_preview: optionalStringField(snapshot, 'output_preview', 'Invalid mob member_status response: output_preview must be string'),
345
+ error: optionalStringField(snapshot, 'error', 'Invalid mob member_status response: error must be string'),
346
+ tokens_used: requireNonNegativeIntegerField(snapshot, 'tokens_used', 'Invalid mob member_status response: tokens_used must be number'),
347
+ is_final: requireBooleanField(snapshot, 'is_final', 'Invalid mob member_status response: is_final must be boolean'),
348
+ kickoff: optionalRecordField(snapshot, 'kickoff', 'Invalid mob member_status response: kickoff must be object'),
349
+ peer_connectivity: optionalRecordField(snapshot, 'peer_connectivity', 'Invalid mob member_status response: peer_connectivity must be object'),
350
+ };
351
+ if (currentSessionId !== undefined) {
352
+ result.current_session_id = currentSessionId;
353
+ }
354
+ if (realtimeAttachmentStatus !== undefined) {
355
+ result.realtime_attachment_status = realtimeAttachmentStatus;
356
+ }
357
+ if (Object.prototype.hasOwnProperty.call(snapshot, 'external_member')) {
358
+ result.external_member = snapshot.external_member;
359
+ }
360
+ return result;
361
+ }
362
+ function parseMobRespawnResult(raw) {
363
+ const result = requireRecord(raw, 'Invalid mob respawn response: malformed envelope');
364
+ const status = requireStringField(result, 'status', 'Invalid mob respawn response: missing status');
365
+ if (status !== 'completed' && status !== 'topology_restore_failed') {
366
+ throw new Error('Invalid mob respawn response: invalid status');
367
+ }
368
+ const receipt = requireRecord(result.receipt, 'Invalid mob respawn response: missing receipt');
369
+ const memberRef = requireStringField(receipt, 'member_ref', 'Invalid mob respawn response: receipt missing member_ref');
370
+ const identity = requireStringField(receipt, 'identity', 'Invalid mob respawn response: receipt missing identity');
371
+ return {
372
+ status,
373
+ receipt: {
374
+ agent_identity: identity,
375
+ member_ref: memberRef,
376
+ },
377
+ failed_peer_ids: optionalStringArrayField(result, 'failed_peer_ids', 'Invalid mob respawn response: failed_peer_ids must be string list'),
378
+ };
379
+ }
380
+ function parseMemberDeliveryReceipt(raw, expectedMobId, expectedAgentIdentity) {
381
+ const receipt = requireRecord(raw, 'Invalid mob member delivery response: malformed envelope');
382
+ const mobId = requireStringField(receipt, 'mob_id', 'Invalid mob member delivery response: missing mob_id');
383
+ if (mobId !== expectedMobId) {
384
+ throw new Error('Invalid mob member delivery response: mob_id mismatch');
385
+ }
386
+ const agentIdentity = requireStringField(receipt, 'agent_identity', 'Invalid mob member delivery response: missing agent_identity');
387
+ if (agentIdentity !== expectedAgentIdentity) {
388
+ throw new Error('Invalid mob member delivery response: agent_identity mismatch');
389
+ }
390
+ return {
391
+ agent_identity: agentIdentity,
392
+ member_ref: requireStringField(receipt, 'member_ref', 'Invalid mob member delivery response: missing member_ref'),
393
+ handling_mode: parseWireHandlingMode(receipt.handling_mode, 'Invalid mob member delivery response: missing handling_mode'),
394
+ };
395
+ }
396
+ function parseMobHelperResult(raw, context) {
397
+ const result = requireRecord(raw, `${context}: malformed envelope`);
398
+ return {
399
+ output: optionalStringField(result, 'output', `${context}: output must be string`),
400
+ tokens_used: requireNonNegativeIntegerField(result, 'tokens_used', `${context}: tokens_used must be number`),
401
+ agent_identity: requireStringField(result, 'agent_identity', `${context}: missing agent_identity`),
402
+ member_ref: requireStringField(result, 'member_ref', `${context}: missing member_ref`),
403
+ };
404
+ }
405
+ function parseMobFlowStatusResult(raw) {
406
+ const context = 'Invalid mob flow_status response';
407
+ const record = requireRecord(raw, `${context}: malformed envelope`);
408
+ if (!Object.prototype.hasOwnProperty.call(record, 'run')) {
409
+ throw new Error(`${context}: missing run`);
410
+ }
411
+ if (record.run == null) {
412
+ return null;
413
+ }
414
+ const run = requireRecord(record.run, `${context}: run must be object`);
415
+ return {
416
+ ...run,
417
+ run_id: requireStringField(run, 'run_id', `${context}: run missing run_id`),
418
+ status: requireStringField(run, 'status', `${context}: run missing status`),
419
+ };
420
+ }
2
421
  /** Capability-bearing handle for one mob member. */
3
422
  export class Member {
4
423
  mobId;
5
- meerkatId;
424
+ agentIdentity;
6
425
  bindings;
7
- constructor(mobId, meerkatId, bindings) {
426
+ constructor(mobId, agentIdentity, bindings) {
8
427
  this.mobId = mobId;
9
- this.meerkatId = meerkatId;
428
+ this.agentIdentity = agentIdentity;
10
429
  this.bindings = bindings;
11
430
  }
12
431
  async send(content, handlingMode = 'queue', renderMetadata) {
13
- const json = await this.bindings.mob_member_send(this.mobId, this.meerkatId, JSON.stringify({
432
+ const json = await this.bindings.mob_member_send(this.mobId, this.agentIdentity, JSON.stringify({
14
433
  content,
15
434
  handling_mode: handlingMode,
16
435
  render_metadata: renderMetadata,
17
436
  }));
18
- const receipt = JSON.parse(json);
19
- if (typeof receipt.session_id !== 'string' || receipt.session_id.length === 0) {
20
- throw new Error('Invalid mob member delivery response: missing session_id');
21
- }
22
- return {
23
- member_id: typeof receipt.member_id === 'string' && receipt.member_id.length > 0
24
- ? receipt.member_id
25
- : this.meerkatId,
26
- session_id: receipt.session_id,
27
- handling_mode: receipt.handling_mode ?? handlingMode,
28
- };
437
+ return parseMemberDeliveryReceipt(parseJsonPayload(json, 'Invalid mob member delivery response'), this.mobId, this.agentIdentity);
29
438
  }
30
439
  async subscribe() {
31
- const handle = await this.bindings.mob_member_subscribe(this.mobId, this.meerkatId);
32
- return new EventSubscription(() => this.bindings.poll_subscription(handle), (raw) => Array.isArray(raw) ? raw : [], () => this.bindings.close_subscription(handle));
440
+ const handle = await this.bindings.mob_member_subscribe(this.mobId, this.agentIdentity);
441
+ return new EventSubscription(() => this.bindings.poll_subscription(handle), (raw) => parseEventItems(raw, 'Invalid mob member subscription event', parseMemberEventItem), () => this.bindings.close_subscription(handle));
33
442
  }
34
443
  }
35
444
  /** A mob instance — a group of agents with shared orchestration. */
@@ -44,12 +453,16 @@ export class Mob {
44
453
  }
45
454
  /** Spawn one or more agents into the mob. */
46
455
  async spawn(specs) {
47
- const json = await this.bindings.mob_spawn(this.mobId, JSON.stringify(specs));
48
- return JSON.parse(json);
456
+ const json = await this.bindings.mob_spawn(this.mobId, JSON.stringify(specs.map(spawnSpecPayload)));
457
+ const parsed = parseJsonPayload(json, 'Invalid mob spawn response');
458
+ if (!Array.isArray(parsed)) {
459
+ throw new Error('Invalid mob spawn response: results must be a list');
460
+ }
461
+ return parsed.map((entry) => normalizeSpawnManyEntry(entry, this.mobId));
49
462
  }
50
463
  /** Retire an agent from the mob. */
51
- async retire(meerkatId) {
52
- await this.bindings.mob_retire(this.mobId, meerkatId);
464
+ async retire(agentIdentity) {
465
+ await this.bindings.mob_retire(this.mobId, agentIdentity);
53
466
  }
54
467
  /** Wire two agents for comms trust. */
55
468
  async wire(member, peer) {
@@ -78,69 +491,119 @@ export class Mob {
78
491
  /** List all members in the mob. */
79
492
  async listMembers() {
80
493
  const json = await this.bindings.mob_list_members(this.mobId);
81
- return JSON.parse(json);
494
+ const parsed = parseJsonPayload(json, 'Invalid mob list_members response');
495
+ if (!Array.isArray(parsed)) {
496
+ throw new Error('Invalid mob list_members response: members must be a list');
497
+ }
498
+ return parsed.map((rawMember, index) => {
499
+ const member = requireRecord(rawMember, `Invalid mob list_members entry ${index}: malformed member`);
500
+ if (typeof member.agent_identity !== 'string' || member.agent_identity.length === 0) {
501
+ throw new Error('Invalid mob list_members entry: missing agent_identity');
502
+ }
503
+ const agentIdentity = member.agent_identity;
504
+ const memberRef = typeof member.member_ref === 'string' && member.member_ref.length > 0
505
+ ? member.member_ref
506
+ : '';
507
+ if (!memberRef) {
508
+ throw new Error('Invalid mob list_members entry: missing member_ref');
509
+ }
510
+ const profile = typeof member.role === 'string' && member.role.length > 0
511
+ ? member.role
512
+ : typeof member.profile === 'string' && member.profile.length > 0
513
+ ? member.profile
514
+ : typeof member.profile_name === 'string' && member.profile_name.length > 0
515
+ ? member.profile_name
516
+ : undefined;
517
+ if (!profile) {
518
+ throw new Error('Invalid mob list_members entry: missing profile');
519
+ }
520
+ return {
521
+ agent_identity: agentIdentity,
522
+ member_ref: memberRef,
523
+ profile,
524
+ peer_id: member.peer_id != null ? String(member.peer_id) : undefined,
525
+ external_peer_specs: member.external_peer_specs && typeof member.external_peer_specs === 'object'
526
+ ? Object.fromEntries(Object.entries(member.external_peer_specs).map(([key, value]) => [key, (value ?? {})]))
527
+ : undefined,
528
+ runtime_mode: member.runtime_mode != null ? String(member.runtime_mode) : undefined,
529
+ state: member.state != null ? String(member.state) : undefined,
530
+ wired_to: Array.isArray(member.wired_to)
531
+ ? member.wired_to.map((peer) => String(peer))
532
+ : undefined,
533
+ labels: member.labels && typeof member.labels === 'object'
534
+ ? Object.fromEntries(Object.entries(member.labels).map(([key, value]) => [key, String(value)]))
535
+ : undefined,
536
+ status: member.status != null ? String(member.status) : undefined,
537
+ error: member.error != null ? String(member.error) : undefined,
538
+ is_final: member.is_final != null ? Boolean(member.is_final) : undefined,
539
+ kickoff: member.kickoff && typeof member.kickoff === 'object'
540
+ ? member.kickoff
541
+ : undefined,
542
+ };
543
+ });
82
544
  }
83
545
  /** Stage runtime system context for a specific member session. */
84
- async appendSystemContext(meerkatId, options) {
85
- const json = await this.bindings.mob_append_system_context(this.mobId, meerkatId, JSON.stringify({
546
+ async appendSystemContext(agentIdentity, options) {
547
+ const json = await this.bindings.mob_append_system_context(this.mobId, agentIdentity, JSON.stringify({
86
548
  text: options.text,
87
549
  source: options.source,
88
550
  idempotency_key: options.idempotencyKey,
89
551
  }));
90
- return JSON.parse(json);
552
+ return parseMobAppendSystemContextResult(parseJsonPayload(json, 'Invalid mob append_system_context response'));
91
553
  }
92
554
  /** Get a capability-bearing handle for one member. */
93
- member(meerkatId) {
94
- return new Member(this.mobId, meerkatId, this.bindings);
555
+ member(agentIdentity) {
556
+ return new Member(this.mobId, agentIdentity, this.bindings);
95
557
  }
96
- /**
97
558
  /** Retire and re-spawn an agent with the same profile. Returns a result envelope with receipt. */
98
- async respawn(meerkatId, initialMessage) {
559
+ async respawn(agentIdentity, initialMessage) {
99
560
  const payload = initialMessage != null
100
561
  ? typeof initialMessage === 'string'
101
562
  ? initialMessage
102
563
  : JSON.stringify(initialMessage)
103
564
  : undefined;
104
- const json = await this.bindings.mob_respawn(this.mobId, meerkatId, payload);
105
- return JSON.parse(json);
565
+ const json = await this.bindings.mob_respawn(this.mobId, agentIdentity, payload);
566
+ return parseMobRespawnResult(parseJsonPayload(json, 'Invalid mob respawn response'));
106
567
  }
107
568
  /** Force-cancel an active member turn. */
108
- async forceCancel(meerkatId) {
109
- await this.bindings.mob_force_cancel(this.mobId, meerkatId);
569
+ async forceCancel(agentIdentity) {
570
+ await this.bindings.mob_force_cancel(this.mobId, agentIdentity);
110
571
  }
111
572
  /** Read the current execution snapshot for a member. */
112
- async memberStatus(meerkatId) {
113
- const json = await this.bindings.mob_member_status(this.mobId, meerkatId);
114
- return JSON.parse(json);
573
+ async memberStatus(agentIdentity) {
574
+ const json = await this.bindings.mob_member_status(this.mobId, agentIdentity);
575
+ return parseMobMemberSnapshot(parseJsonPayload(json, 'Invalid mob member_status response'), this.mobId, agentIdentity);
115
576
  }
116
577
  /** Spawn a short-lived helper and return its terminal result. */
117
578
  async spawnHelper(prompt, options) {
118
579
  const json = await this.bindings.mob_spawn_helper(this.mobId, JSON.stringify({
119
580
  prompt,
120
- meerkat_id: options?.meerkatId,
581
+ agent_identity: options?.agentIdentity,
121
582
  profile_name: options?.profileName,
583
+ auth_binding: options?.authBinding,
122
584
  runtime_mode: options?.runtimeMode,
123
585
  backend: options?.backend,
124
586
  }));
125
- return JSON.parse(json);
587
+ return parseMobHelperResult(parseJsonPayload(json, 'Invalid mob spawn_helper response'), 'Invalid mob spawn_helper response');
126
588
  }
127
589
  /** Fork a helper from an existing member and return its terminal result. */
128
590
  async forkHelper(sourceMemberId, prompt, options) {
129
591
  const json = await this.bindings.mob_fork_helper(this.mobId, JSON.stringify({
130
592
  source_member_id: sourceMemberId,
131
593
  prompt,
132
- meerkat_id: options?.meerkatId,
594
+ agent_identity: options?.agentIdentity,
133
595
  profile_name: options?.profileName,
596
+ auth_binding: options?.authBinding,
134
597
  fork_context: options?.forkContext,
135
598
  runtime_mode: options?.runtimeMode,
136
599
  backend: options?.backend,
137
600
  }));
138
- return JSON.parse(json);
601
+ return parseMobHelperResult(parseJsonPayload(json, 'Invalid mob fork_helper response'), 'Invalid mob fork_helper response');
139
602
  }
140
603
  /** Get mob status. */
141
604
  async status() {
142
605
  const json = await this.bindings.mob_status(this.mobId);
143
- return JSON.parse(json);
606
+ return parseMobStatusResult(parseJsonPayload(json, 'Invalid mob/status response'));
144
607
  }
145
608
  /** Perform a lifecycle action (stop, resume, complete, destroy). */
146
609
  async lifecycle(action) {
@@ -150,7 +613,7 @@ export class Mob {
150
613
  async events(afterCursor = '', limit = 100) {
151
614
  const numericCursor = afterCursor === '' ? 0 : Number(afterCursor);
152
615
  const json = await this.bindings.mob_events(this.mobId, Number.isFinite(numericCursor) ? numericCursor : 0, limit);
153
- return JSON.parse(json);
616
+ return parseMobEvents(parseJsonPayload(json, 'Invalid mob/events response'));
154
617
  }
155
618
  /** Run a flow. Returns the run ID. */
156
619
  async runFlow(flowId, params = {}) {
@@ -159,21 +622,21 @@ export class Mob {
159
622
  /** Get flow status. */
160
623
  async flowStatus(runId) {
161
624
  const json = await this.bindings.mob_flow_status(this.mobId, runId);
162
- return JSON.parse(json);
625
+ return parseMobFlowStatusResult(parseJsonPayload(json, 'Invalid mob flow_status response'));
163
626
  }
164
627
  /** Cancel a running flow. */
165
628
  async cancelFlow(runId) {
166
629
  await this.bindings.mob_cancel_flow(this.mobId, runId);
167
630
  }
168
631
  /** Subscribe to events for a specific member. */
169
- async subscribeMemberEvents(meerkatId) {
170
- const handle = await this.bindings.mob_member_subscribe(this.mobId, meerkatId);
171
- return new EventSubscription(() => this.bindings.poll_subscription(handle), (raw) => Array.isArray(raw) ? raw : [], () => this.bindings.close_subscription(handle));
632
+ async subscribeMemberEvents(agentIdentity) {
633
+ const handle = await this.bindings.mob_member_subscribe(this.mobId, agentIdentity);
634
+ return new EventSubscription(() => this.bindings.poll_subscription(handle), (raw) => parseEventItems(raw, 'Invalid mob member subscription event', parseMemberEventItem), () => this.bindings.close_subscription(handle));
172
635
  }
173
636
  /** Subscribe to all mob-wide attributed events. */
174
637
  async subscribeEvents() {
175
638
  const handle = await this.bindings.mob_subscribe_events(this.mobId);
176
- return new EventSubscription(() => this.bindings.poll_subscription(handle), (raw) => Array.isArray(raw) ? raw : [], () => this.bindings.close_subscription(handle));
639
+ return new EventSubscription(() => this.bindings.poll_subscription(handle), (raw) => parseEventItems(raw, 'Invalid mob attributed subscription event', parseAttributedEventItem), () => this.bindings.close_subscription(handle));
177
640
  }
178
641
  }
179
642
  //# sourceMappingURL=mob.js.map