@rkat/sdk 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.
- package/README.md +4 -4
- package/dist/client.d.ts +186 -34
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +865 -184
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +162 -32
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +571 -97
- package/dist/events.js.map +1 -1
- package/dist/generated/types.d.ts +1778 -59
- package/dist/generated/types.d.ts.map +1 -1
- package/dist/generated/types.js +2 -2
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mob.d.ts +30 -23
- package/dist/mob.d.ts.map +1 -1
- package/dist/mob.js +22 -19
- package/dist/mob.js.map +1 -1
- package/dist/realtime.d.ts +45 -0
- package/dist/realtime.d.ts.map +1 -0
- package/dist/realtime.js +166 -0
- package/dist/realtime.js.map +1 -0
- package/dist/session.d.ts +10 -3
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +19 -2
- package/dist/session.js.map +1 -1
- package/dist/types.d.ts +175 -57
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
package/dist/client.js
CHANGED
|
@@ -25,9 +25,11 @@
|
|
|
25
25
|
* ```
|
|
26
26
|
*/
|
|
27
27
|
import { spawn } from "node:child_process";
|
|
28
|
+
import { once } from "node:events";
|
|
28
29
|
import { chmodSync, existsSync, mkdirSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
29
30
|
import os from "node:os";
|
|
30
31
|
import path from "node:path";
|
|
32
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
31
33
|
import { createInterface } from "node:readline";
|
|
32
34
|
import { Buffer } from "node:buffer";
|
|
33
35
|
import { MeerkatError, CapabilityUnavailableError } from "./generated/errors.js";
|
|
@@ -40,31 +42,143 @@ import { EventSubscription } from "./subscription.js";
|
|
|
40
42
|
const MEERKAT_REPO = "lukacf/meerkat";
|
|
41
43
|
const MEERKAT_RELEASE_BINARY = "rkat-rpc";
|
|
42
44
|
const MEERKAT_BINARY_CACHE_ROOT = path.join(os.homedir(), ".cache", "meerkat", "bin", MEERKAT_RELEASE_BINARY);
|
|
45
|
+
const MOB_SPAWN_MANY_FAILURE_CAUSES = new Set([
|
|
46
|
+
"profile_not_found",
|
|
47
|
+
"member_not_found",
|
|
48
|
+
"member_already_exists",
|
|
49
|
+
"not_externally_addressable",
|
|
50
|
+
"invalid_transition",
|
|
51
|
+
"wiring_error",
|
|
52
|
+
"bridge_command_rejected",
|
|
53
|
+
"member_restore_failed",
|
|
54
|
+
"kickoff_wait_timed_out",
|
|
55
|
+
"ready_wait_timed_out",
|
|
56
|
+
"definition_error",
|
|
57
|
+
"flow_not_found",
|
|
58
|
+
"flow_failed",
|
|
59
|
+
"run_not_found",
|
|
60
|
+
"run_canceled",
|
|
61
|
+
"flow_turn_timed_out",
|
|
62
|
+
"frame_depth_limit_exceeded",
|
|
63
|
+
"frame_atomic_persistence_unavailable",
|
|
64
|
+
"spec_revision_conflict",
|
|
65
|
+
"schema_validation",
|
|
66
|
+
"insufficient_targets",
|
|
67
|
+
"topology_violation",
|
|
68
|
+
"bridge_delivery_rejected",
|
|
69
|
+
"supervisor_escalation",
|
|
70
|
+
"unsupported_for_mode",
|
|
71
|
+
"reset_barrier",
|
|
72
|
+
"storage_error",
|
|
73
|
+
"session_error",
|
|
74
|
+
"comms_error",
|
|
75
|
+
"callback_pending",
|
|
76
|
+
"stale_fence_token",
|
|
77
|
+
"stale_event_cursor",
|
|
78
|
+
"work_not_found",
|
|
79
|
+
"internal",
|
|
80
|
+
]);
|
|
81
|
+
function isMobSpawnManyFailureCause(value) {
|
|
82
|
+
return typeof value === "string" && MOB_SPAWN_MANY_FAILURE_CAUSES.has(value);
|
|
83
|
+
}
|
|
43
84
|
/**
|
|
44
|
-
* Normalize a SkillRef to the wire format
|
|
45
|
-
*
|
|
46
|
-
* SkillKey objects are converted from camelCase to snake_case.
|
|
47
|
-
* Legacy strings are parsed and emit a console warning.
|
|
85
|
+
* Normalize a structured SkillRef to the bare SkillKey wire format.
|
|
48
86
|
*/
|
|
49
|
-
function
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
console.warn(`[meerkat-sdk] legacy skill reference '${ref}' is deprecated; pass { sourceUuid, skillName } instead.`);
|
|
59
|
-
return { source_uuid: sourceUuid, skill_name: rest.join("/") };
|
|
87
|
+
function normalizeSkillKey(ref) {
|
|
88
|
+
if (ref === null ||
|
|
89
|
+
typeof ref !== "object" ||
|
|
90
|
+
typeof ref.sourceUuid !== "string" ||
|
|
91
|
+
typeof ref.skillName !== "string") {
|
|
92
|
+
throw new Error("Skill references must be SkillKey objects");
|
|
93
|
+
}
|
|
94
|
+
return { source_uuid: ref.sourceUuid, skill_name: ref.skillName };
|
|
60
95
|
}
|
|
61
|
-
function
|
|
96
|
+
function skillKeysToWire(refs) {
|
|
62
97
|
if (!refs)
|
|
63
98
|
return undefined;
|
|
64
|
-
return refs.map(
|
|
99
|
+
return refs.map(normalizeSkillKey);
|
|
100
|
+
}
|
|
101
|
+
function skillRefsToWire(refs) {
|
|
102
|
+
const keys = skillKeysToWire(refs);
|
|
103
|
+
return keys?.map((key) => ({ kind: "structured", ...key }));
|
|
104
|
+
}
|
|
105
|
+
function setIfDefined(payload, key, value) {
|
|
106
|
+
if (value !== undefined) {
|
|
107
|
+
payload[key] = value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function mobSpawnPayload(mobId, spec) {
|
|
111
|
+
const payload = {
|
|
112
|
+
mob_id: mobId,
|
|
113
|
+
profile: spec.profile,
|
|
114
|
+
agent_identity: spec.agentIdentity,
|
|
115
|
+
};
|
|
116
|
+
setIfDefined(payload, "initial_message", spec.initialMessage);
|
|
117
|
+
setIfDefined(payload, "runtime_mode", spec.runtimeMode);
|
|
118
|
+
setIfDefined(payload, "backend", spec.backend);
|
|
119
|
+
setIfDefined(payload, "labels", spec.labels);
|
|
120
|
+
setIfDefined(payload, "context", spec.context);
|
|
121
|
+
setIfDefined(payload, "additional_instructions", spec.additionalInstructions);
|
|
122
|
+
setIfDefined(payload, "binding", spec.binding);
|
|
123
|
+
setIfDefined(payload, "shell_env", spec.shellEnv);
|
|
124
|
+
setIfDefined(payload, "auto_wire_parent", spec.autoWireParent);
|
|
125
|
+
setIfDefined(payload, "launch_mode", spec.launchMode);
|
|
126
|
+
setIfDefined(payload, "tool_access_policy", spec.toolAccessPolicy);
|
|
127
|
+
setIfDefined(payload, "budget_split_policy", spec.budgetSplitPolicy);
|
|
128
|
+
setIfDefined(payload, "inherited_tool_filter", spec.inheritedToolFilter);
|
|
129
|
+
setIfDefined(payload, "override_profile", spec.overrideProfile);
|
|
130
|
+
setIfDefined(payload, "auth_binding", spec.authBinding);
|
|
131
|
+
return payload;
|
|
132
|
+
}
|
|
133
|
+
function mobSpawnManySpecPayload(spec) {
|
|
134
|
+
const payload = {
|
|
135
|
+
profile: spec.profile,
|
|
136
|
+
agent_identity: spec.agentIdentity,
|
|
137
|
+
};
|
|
138
|
+
setIfDefined(payload, "initial_message", spec.initialMessage);
|
|
139
|
+
setIfDefined(payload, "runtime_mode", spec.runtimeMode);
|
|
140
|
+
setIfDefined(payload, "backend", spec.backend);
|
|
141
|
+
setIfDefined(payload, "labels", spec.labels);
|
|
142
|
+
setIfDefined(payload, "context", spec.context);
|
|
143
|
+
setIfDefined(payload, "additional_instructions", spec.additionalInstructions);
|
|
144
|
+
setIfDefined(payload, "auth_binding", spec.authBinding);
|
|
145
|
+
return payload;
|
|
146
|
+
}
|
|
147
|
+
function mobTurnStartPayload(mobId, agentIdentity, prompt, options) {
|
|
148
|
+
const payload = {
|
|
149
|
+
mob_id: mobId,
|
|
150
|
+
agent_identity: agentIdentity,
|
|
151
|
+
prompt: typeof prompt === "string"
|
|
152
|
+
? prompt
|
|
153
|
+
: prompt.map((block) => ({ ...block })),
|
|
154
|
+
};
|
|
155
|
+
const wireRefs = skillRefsToWire(options?.skillRefs);
|
|
156
|
+
if (wireRefs) {
|
|
157
|
+
payload.skill_refs = wireRefs;
|
|
158
|
+
}
|
|
159
|
+
if (options?.flowToolOverlay) {
|
|
160
|
+
payload.flow_tool_overlay = {
|
|
161
|
+
allowed_tools: options.flowToolOverlay.allowedTools,
|
|
162
|
+
blocked_tools: options.flowToolOverlay.blockedTools,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
setIfDefined(payload, "additional_instructions", options?.additionalInstructions);
|
|
166
|
+
setIfDefined(payload, "keep_alive", options?.keepAlive);
|
|
167
|
+
setIfDefined(payload, "model", options?.model);
|
|
168
|
+
setIfDefined(payload, "provider", options?.provider);
|
|
169
|
+
setIfDefined(payload, "max_tokens", options?.maxTokens);
|
|
170
|
+
setIfDefined(payload, "system_prompt", options?.systemPrompt);
|
|
171
|
+
setIfDefined(payload, "output_schema", options?.outputSchema);
|
|
172
|
+
setIfDefined(payload, "structured_output_retries", options?.structuredOutputRetries);
|
|
173
|
+
setIfDefined(payload, "provider_params", options?.providerParams);
|
|
174
|
+
setIfDefined(payload, "clear_provider_params", options?.clearProviderParams);
|
|
175
|
+
setIfDefined(payload, "auth_binding", options?.authBinding);
|
|
176
|
+
setIfDefined(payload, "clear_auth_binding", options?.clearAuthBinding);
|
|
177
|
+
return payload;
|
|
65
178
|
}
|
|
66
179
|
export class MeerkatClient {
|
|
67
180
|
process = null;
|
|
181
|
+
processStderr = "";
|
|
68
182
|
requestId = 0;
|
|
69
183
|
_capabilities = [];
|
|
70
184
|
_methods = new Set();
|
|
@@ -118,6 +232,31 @@ export class MeerkatClient {
|
|
|
118
232
|
this.process = spawn(this.rkatPath, args, {
|
|
119
233
|
stdio: ["pipe", "pipe", "pipe"],
|
|
120
234
|
});
|
|
235
|
+
const child = this.process;
|
|
236
|
+
this.processStderr = "";
|
|
237
|
+
child.stderr?.on("data", (chunk) => {
|
|
238
|
+
this.processStderr = (this.processStderr + String(chunk)).slice(-8192);
|
|
239
|
+
});
|
|
240
|
+
child.once("error", (error) => {
|
|
241
|
+
if (this.process === child) {
|
|
242
|
+
this.process = null;
|
|
243
|
+
this.rejectPendingRequests(new MeerkatError("PROCESS_ERROR", `Failed to start ${this.rkatPath}: ${error.message}`));
|
|
244
|
+
this.closeQueues();
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
child.once("close", (code, signal) => {
|
|
248
|
+
const expectedClose = this.process !== child;
|
|
249
|
+
if (this.process === child) {
|
|
250
|
+
this.process = null;
|
|
251
|
+
this.rl?.close();
|
|
252
|
+
this.rl = null;
|
|
253
|
+
}
|
|
254
|
+
if (!expectedClose) {
|
|
255
|
+
const suffix = this.processStderr.trim() ? `: ${this.processStderr.trim()}` : "";
|
|
256
|
+
this.rejectPendingRequests(new MeerkatError("PROCESS_EXITED", `${this.rkatPath} exited before replying (code ${code ?? "null"}, signal ${signal ?? "null"})${suffix}`));
|
|
257
|
+
this.closeQueues();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
121
260
|
this.rl = createInterface({ input: this.process.stdout });
|
|
122
261
|
this.rl.on("line", (line) => this.handleLine(line));
|
|
123
262
|
// Handshake
|
|
@@ -153,14 +292,32 @@ export class MeerkatClient {
|
|
|
153
292
|
this.rl.close();
|
|
154
293
|
this.rl = null;
|
|
155
294
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
295
|
+
const process = this.process;
|
|
296
|
+
this.process = null;
|
|
297
|
+
if (process) {
|
|
298
|
+
process.stdin?.end();
|
|
299
|
+
const closed = once(process, "close").catch(() => []);
|
|
300
|
+
process.kill();
|
|
301
|
+
const timeout = delay(5000).then(() => "timeout");
|
|
302
|
+
const outcome = await Promise.race([closed, timeout]);
|
|
303
|
+
if (outcome === "timeout" && process.exitCode == null && process.signalCode == null) {
|
|
304
|
+
process.kill("SIGKILL");
|
|
305
|
+
await closed.catch(() => { });
|
|
306
|
+
}
|
|
307
|
+
process.stdin?.destroy();
|
|
308
|
+
process.stdout?.destroy();
|
|
309
|
+
process.stderr?.destroy();
|
|
159
310
|
}
|
|
311
|
+
this.rejectPendingRequests(new MeerkatError("CLIENT_CLOSED", "Client closed"));
|
|
312
|
+
this.closeQueues();
|
|
313
|
+
}
|
|
314
|
+
rejectPendingRequests(reason) {
|
|
160
315
|
for (const [, pending] of this.pendingRequests) {
|
|
161
|
-
pending.reject(
|
|
316
|
+
pending.reject(reason);
|
|
162
317
|
}
|
|
163
318
|
this.pendingRequests.clear();
|
|
319
|
+
}
|
|
320
|
+
closeQueues() {
|
|
164
321
|
for (const [, queue] of this.eventQueues) {
|
|
165
322
|
queue.put(null);
|
|
166
323
|
}
|
|
@@ -251,6 +408,22 @@ export class MeerkatClient {
|
|
|
251
408
|
const raw = await this.request("session/create", params);
|
|
252
409
|
return new DeferredSession(this, String(raw.session_id ?? ""), raw.session_ref != null ? String(raw.session_ref) : undefined);
|
|
253
410
|
}
|
|
411
|
+
async askHelp(question, options) {
|
|
412
|
+
const params = { question };
|
|
413
|
+
if (options?.prompt !== undefined)
|
|
414
|
+
params.prompt = options.prompt;
|
|
415
|
+
if (options?.executionMode !== undefined) {
|
|
416
|
+
params.execution_mode = options.executionMode;
|
|
417
|
+
}
|
|
418
|
+
if (options?.model !== undefined)
|
|
419
|
+
params.model = options.model;
|
|
420
|
+
if (options?.provider !== undefined)
|
|
421
|
+
params.provider = options.provider;
|
|
422
|
+
if (options?.maxTokens !== undefined)
|
|
423
|
+
params.max_tokens = options.maxTokens;
|
|
424
|
+
const raw = await this.request("help/ask", params);
|
|
425
|
+
return MeerkatClient.parseRunResult(raw);
|
|
426
|
+
}
|
|
254
427
|
// -- Session queries ----------------------------------------------------
|
|
255
428
|
async listSessions(options) {
|
|
256
429
|
const params = {};
|
|
@@ -268,13 +441,31 @@ export class MeerkatClient {
|
|
|
268
441
|
const raw = await this.request("session/read", { session_id: sessionId });
|
|
269
442
|
return MeerkatClient.parseSessionInfo(raw);
|
|
270
443
|
}
|
|
271
|
-
async sendExternalEvent(sessionId, payload, options) {
|
|
272
|
-
const params = {
|
|
273
|
-
|
|
274
|
-
|
|
444
|
+
async sendExternalEvent(sessionId, eventType, payload, options) {
|
|
445
|
+
const params = {
|
|
446
|
+
session_id: sessionId,
|
|
447
|
+
kind: "generic_json",
|
|
448
|
+
event_type: eventType,
|
|
449
|
+
payload,
|
|
450
|
+
};
|
|
451
|
+
if (options?.blocks !== undefined) {
|
|
452
|
+
params.blocks = options.blocks;
|
|
275
453
|
}
|
|
276
454
|
return this.request("session/external_event", params);
|
|
277
455
|
}
|
|
456
|
+
async sendPeerResponseTerminal(sessionId, peerId, requestId, status, result, options) {
|
|
457
|
+
const params = {
|
|
458
|
+
session_id: sessionId,
|
|
459
|
+
peer_id: peerId,
|
|
460
|
+
request_id: requestId,
|
|
461
|
+
status,
|
|
462
|
+
result,
|
|
463
|
+
};
|
|
464
|
+
if (options?.displayName !== undefined) {
|
|
465
|
+
params.display_name = options.displayName;
|
|
466
|
+
}
|
|
467
|
+
return this.request("session/peer_response_terminal", params);
|
|
468
|
+
}
|
|
278
469
|
async injectContext(sessionId, text, options) {
|
|
279
470
|
const params = { session_id: sessionId, text };
|
|
280
471
|
if (options?.source !== undefined) {
|
|
@@ -361,13 +552,6 @@ export class MeerkatClient {
|
|
|
361
552
|
const result = await this.request("skills/list", {});
|
|
362
553
|
return result.skills ?? [];
|
|
363
554
|
}
|
|
364
|
-
async inspectSkill(id, options) {
|
|
365
|
-
const params = { id };
|
|
366
|
-
if (options?.source !== undefined) {
|
|
367
|
-
params.source = options.source;
|
|
368
|
-
}
|
|
369
|
-
return this.request("skills/inspect", params);
|
|
370
|
-
}
|
|
371
555
|
async getBlob(blobId) {
|
|
372
556
|
const result = await this.request("blob/get", { blob_id: blobId });
|
|
373
557
|
return {
|
|
@@ -376,6 +560,45 @@ export class MeerkatClient {
|
|
|
376
560
|
dataBase64: String(result.data ?? ""),
|
|
377
561
|
};
|
|
378
562
|
}
|
|
563
|
+
async getRuntimeHostInfo() {
|
|
564
|
+
return this.request("runtime/host_info", {});
|
|
565
|
+
}
|
|
566
|
+
async getRuntimeHostCapabilities() {
|
|
567
|
+
return this.request("runtime/capabilities", {});
|
|
568
|
+
}
|
|
569
|
+
async getRuntimeHostHealth() {
|
|
570
|
+
return this.request("runtime/health", {});
|
|
571
|
+
}
|
|
572
|
+
async requestApproval(params) {
|
|
573
|
+
return this.request("approval/request", params);
|
|
574
|
+
}
|
|
575
|
+
async listApprovals(params = {}) {
|
|
576
|
+
return this.request("approval/list", params);
|
|
577
|
+
}
|
|
578
|
+
async getApproval(params) {
|
|
579
|
+
return this.request("approval/get", params);
|
|
580
|
+
}
|
|
581
|
+
async decideApproval(params) {
|
|
582
|
+
return this.request("approval/decide", params);
|
|
583
|
+
}
|
|
584
|
+
async listArtifacts(params = {}) {
|
|
585
|
+
return this.request("artifact/list", params);
|
|
586
|
+
}
|
|
587
|
+
async getArtifact(params) {
|
|
588
|
+
return this.request("artifact/get", params);
|
|
589
|
+
}
|
|
590
|
+
async downloadArtifact(params) {
|
|
591
|
+
return this.request("artifact/download", params);
|
|
592
|
+
}
|
|
593
|
+
async latestEventCursor(params) {
|
|
594
|
+
return this.request("events/latest_cursor", params);
|
|
595
|
+
}
|
|
596
|
+
async listEventsSince(params) {
|
|
597
|
+
return this.request("events/list_since", params);
|
|
598
|
+
}
|
|
599
|
+
async eventSnapshot(params) {
|
|
600
|
+
return this.request("events/snapshot", params);
|
|
601
|
+
}
|
|
379
602
|
async getModelsCatalog() {
|
|
380
603
|
const result = await this.request("models/catalog", {});
|
|
381
604
|
return MeerkatClient.parseModelsCatalog(result);
|
|
@@ -472,110 +695,167 @@ export class MeerkatClient {
|
|
|
472
695
|
const status = typeof rawStatus === "string"
|
|
473
696
|
? rawStatus
|
|
474
697
|
: (typeof rawStatus === "object" && rawStatus !== null
|
|
475
|
-
?
|
|
476
|
-
:
|
|
698
|
+
? Object.keys(rawStatus)[0]
|
|
699
|
+
: undefined);
|
|
700
|
+
if (!status) {
|
|
701
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/status response: missing status");
|
|
702
|
+
}
|
|
477
703
|
return { mobId: String(result.mob_id ?? mobId), status };
|
|
478
704
|
}
|
|
479
705
|
async listMobMembers(mobId) {
|
|
480
706
|
const result = await this.request("mob/members", { mob_id: mobId });
|
|
481
707
|
const members = result.members ?? [];
|
|
482
|
-
return members.map((member) =>
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
: undefined,
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
?
|
|
505
|
-
: undefined
|
|
506
|
-
: undefined,
|
|
507
|
-
|
|
708
|
+
return members.map((member) => {
|
|
709
|
+
const agentIdentity = String(member.agent_identity ?? "");
|
|
710
|
+
const memberRef = typeof member.member_ref === "string" && member.member_ref.length > 0
|
|
711
|
+
? member.member_ref
|
|
712
|
+
: undefined;
|
|
713
|
+
if (!agentIdentity || !memberRef) {
|
|
714
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/members response: missing identity-native member fields");
|
|
715
|
+
}
|
|
716
|
+
return {
|
|
717
|
+
agentIdentity,
|
|
718
|
+
memberRef,
|
|
719
|
+
profile: String(member.profile_name ?? member.profile ?? member.role ?? ""),
|
|
720
|
+
peerId: member.peer_id != null ? String(member.peer_id) : undefined,
|
|
721
|
+
externalPeerSpecs: member.external_peer_specs && typeof member.external_peer_specs === "object"
|
|
722
|
+
? Object.fromEntries(Object.entries(member.external_peer_specs).map(([key, value]) => [key, (value ?? {})]))
|
|
723
|
+
: undefined,
|
|
724
|
+
runtimeMode: member.runtime_mode != null ? String(member.runtime_mode) : undefined,
|
|
725
|
+
state: member.state != null ? String(member.state) : undefined,
|
|
726
|
+
wiredTo: Array.isArray(member.wired_to)
|
|
727
|
+
? member.wired_to.map((peer) => String(peer))
|
|
728
|
+
: undefined,
|
|
729
|
+
labels: member.labels && typeof member.labels === "object"
|
|
730
|
+
? Object.fromEntries(Object.entries(member.labels).map(([key, value]) => [key, String(value)]))
|
|
731
|
+
: undefined,
|
|
732
|
+
status: member.status != null ? String(member.status) : undefined,
|
|
733
|
+
error: member.error != null ? String(member.error) : undefined,
|
|
734
|
+
isFinal: member.is_final != null ? Boolean(member.is_final) : undefined,
|
|
735
|
+
};
|
|
736
|
+
});
|
|
508
737
|
}
|
|
509
|
-
async sendMobMemberContent(mobId,
|
|
738
|
+
async sendMobMemberContent(mobId, agentIdentity, content, options) {
|
|
510
739
|
const result = await this.request("mob/member_send", {
|
|
511
740
|
mob_id: mobId,
|
|
512
|
-
|
|
741
|
+
agent_identity: agentIdentity,
|
|
513
742
|
content,
|
|
514
743
|
handling_mode: options?.handlingMode,
|
|
515
744
|
render_metadata: options?.renderMetadata,
|
|
516
745
|
});
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
746
|
+
const memberRef = typeof result.member_ref === "string" && result.member_ref.length > 0
|
|
747
|
+
? result.member_ref
|
|
748
|
+
: undefined;
|
|
749
|
+
if (!memberRef) {
|
|
750
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/member_send response: missing member_ref");
|
|
520
751
|
}
|
|
521
752
|
return {
|
|
522
|
-
|
|
523
|
-
? result.
|
|
524
|
-
:
|
|
525
|
-
|
|
753
|
+
agentIdentity: typeof result.agent_identity === "string" && result.agent_identity.length > 0
|
|
754
|
+
? result.agent_identity
|
|
755
|
+
: agentIdentity,
|
|
756
|
+
memberRef,
|
|
526
757
|
handlingMode: result.handling_mode === "steer" || result.handling_mode === "queue"
|
|
527
758
|
? result.handling_mode
|
|
528
759
|
: (options?.handlingMode ?? "queue"),
|
|
529
760
|
};
|
|
530
761
|
}
|
|
531
762
|
async spawnMobMember(mobId, options) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
763
|
+
const result = await this.request("mob/spawn", mobSpawnPayload(mobId, options));
|
|
764
|
+
const memberRef = typeof result.member_ref === "string" && result.member_ref.length > 0
|
|
765
|
+
? result.member_ref
|
|
766
|
+
: undefined;
|
|
767
|
+
if (!memberRef) {
|
|
768
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn response: missing member_ref");
|
|
769
|
+
}
|
|
770
|
+
return {
|
|
771
|
+
mobId: String(result.mob_id ?? mobId),
|
|
772
|
+
agentIdentity: typeof result.agent_identity === "string" && result.agent_identity.length > 0
|
|
773
|
+
? result.agent_identity
|
|
774
|
+
: options.agentIdentity,
|
|
775
|
+
memberRef,
|
|
776
|
+
};
|
|
544
777
|
}
|
|
545
778
|
async spawnMobMembers(mobId, specs) {
|
|
546
779
|
const result = await this.request("mob/spawn_many", {
|
|
547
780
|
mob_id: mobId,
|
|
548
|
-
specs: specs.map(
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
781
|
+
specs: specs.map(mobSpawnManySpecPayload),
|
|
782
|
+
});
|
|
783
|
+
if (!Array.isArray(result.results)) {
|
|
784
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: results must be a list");
|
|
785
|
+
}
|
|
786
|
+
const entries = result.results;
|
|
787
|
+
return entries.map((entry) => {
|
|
788
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
789
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: malformed result entry");
|
|
790
|
+
}
|
|
791
|
+
const record = entry;
|
|
792
|
+
const entryKeys = Object.keys(record);
|
|
793
|
+
if (entryKeys.some((key) => key !== "status" && key !== "result") ||
|
|
794
|
+
"ok" in record ||
|
|
795
|
+
"error" in record ||
|
|
796
|
+
"agent_identity" in record ||
|
|
797
|
+
"member_ref" in record) {
|
|
798
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: legacy result carrier fields are not allowed");
|
|
799
|
+
}
|
|
800
|
+
const status = record.status;
|
|
801
|
+
const rawResult = record.result;
|
|
802
|
+
if (status !== "spawned" && status !== "failed") {
|
|
803
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: invalid result status");
|
|
804
|
+
}
|
|
805
|
+
if (!rawResult || typeof rawResult !== "object" || Array.isArray(rawResult)) {
|
|
806
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: missing result payload");
|
|
807
|
+
}
|
|
808
|
+
const resultRecord = rawResult;
|
|
809
|
+
if (status === "spawned") {
|
|
810
|
+
if (Object.keys(resultRecord).some((key) => key !== "agent_identity" && key !== "member_ref")) {
|
|
811
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: spawned result has unknown fields");
|
|
812
|
+
}
|
|
813
|
+
const agentIdentity = resultRecord.agent_identity;
|
|
814
|
+
const memberRef = resultRecord.member_ref;
|
|
815
|
+
if (typeof agentIdentity !== "string" || agentIdentity.length === 0) {
|
|
816
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: spawned result missing agent_identity");
|
|
817
|
+
}
|
|
818
|
+
if (typeof memberRef !== "string" || memberRef.length === 0) {
|
|
819
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: spawned result missing member_ref");
|
|
820
|
+
}
|
|
821
|
+
return {
|
|
822
|
+
status,
|
|
823
|
+
result: {
|
|
824
|
+
agent_identity: agentIdentity,
|
|
825
|
+
member_ref: memberRef,
|
|
826
|
+
},
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
if (Object.keys(resultRecord).some((key) => key !== "cause" && key !== "message")) {
|
|
830
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: failed result has unknown fields");
|
|
831
|
+
}
|
|
832
|
+
const cause = resultRecord.cause;
|
|
833
|
+
if (!isMobSpawnManyFailureCause(cause)) {
|
|
834
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: failed result has invalid cause");
|
|
835
|
+
}
|
|
836
|
+
const message = resultRecord.message;
|
|
837
|
+
if (typeof message !== "string" || message.length === 0) {
|
|
838
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_many response: failed result missing message");
|
|
839
|
+
}
|
|
840
|
+
return {
|
|
841
|
+
status,
|
|
842
|
+
result: {
|
|
843
|
+
cause,
|
|
844
|
+
message,
|
|
845
|
+
},
|
|
846
|
+
};
|
|
559
847
|
});
|
|
560
|
-
const entries = Array.isArray(result.results)
|
|
561
|
-
? result.results
|
|
562
|
-
: [];
|
|
563
|
-
return entries.map((entry) => ({
|
|
564
|
-
ok: Boolean(entry.ok),
|
|
565
|
-
memberRef: entry.member_ref && typeof entry.member_ref === "object"
|
|
566
|
-
? entry.member_ref
|
|
567
|
-
: undefined,
|
|
568
|
-
sessionId: entry.session_id != null ? String(entry.session_id) : undefined,
|
|
569
|
-
error: entry.error != null ? String(entry.error) : undefined,
|
|
570
|
-
}));
|
|
571
848
|
}
|
|
572
|
-
async retireMobMember(mobId,
|
|
573
|
-
await this.request("mob/retire", {
|
|
849
|
+
async retireMobMember(mobId, agentIdentity) {
|
|
850
|
+
await this.request("mob/retire", {
|
|
851
|
+
mob_id: mobId,
|
|
852
|
+
agent_identity: agentIdentity,
|
|
853
|
+
});
|
|
574
854
|
}
|
|
575
|
-
async respawnMobMember(mobId,
|
|
855
|
+
async respawnMobMember(mobId, agentIdentity, initialMessage) {
|
|
576
856
|
const result = await this.request("mob/respawn", {
|
|
577
857
|
mob_id: mobId,
|
|
578
|
-
|
|
858
|
+
agent_identity: agentIdentity,
|
|
579
859
|
initial_message: initialMessage,
|
|
580
860
|
});
|
|
581
861
|
const status = String(result.status ?? "completed");
|
|
@@ -586,21 +866,35 @@ export class MeerkatClient {
|
|
|
586
866
|
if (!receipt || typeof receipt !== "object") {
|
|
587
867
|
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/respawn response: missing receipt");
|
|
588
868
|
}
|
|
869
|
+
const memberRef = typeof receipt.member_ref === "string" && receipt.member_ref.length > 0
|
|
870
|
+
? receipt.member_ref
|
|
871
|
+
: undefined;
|
|
872
|
+
if (!memberRef) {
|
|
873
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/respawn response: receipt missing member_ref");
|
|
874
|
+
}
|
|
589
875
|
return {
|
|
590
876
|
status: status === "topology_restore_failed" ? "topology_restore_failed" : "completed",
|
|
591
877
|
receipt: {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
newSessionId: receipt.new_session_id != null ? String(receipt.new_session_id) : undefined,
|
|
878
|
+
agentIdentity: receipt.identity != null ? String(receipt.identity) : agentIdentity,
|
|
879
|
+
memberRef,
|
|
595
880
|
},
|
|
596
881
|
failedPeerIds: rawFailed.map((peerId) => String(peerId)),
|
|
597
882
|
};
|
|
598
883
|
}
|
|
599
|
-
async forceCancelMobMember(mobId,
|
|
600
|
-
await this.request("mob/force_cancel", {
|
|
884
|
+
async forceCancelMobMember(mobId, agentIdentity) {
|
|
885
|
+
await this.request("mob/force_cancel", {
|
|
886
|
+
mob_id: mobId,
|
|
887
|
+
agent_identity: agentIdentity,
|
|
888
|
+
});
|
|
601
889
|
}
|
|
602
|
-
async
|
|
603
|
-
|
|
890
|
+
async mobTurnStart(mobId, agentIdentity, prompt, options) {
|
|
891
|
+
return await this.request("mob/turn_start", mobTurnStartPayload(mobId, agentIdentity, prompt, options));
|
|
892
|
+
}
|
|
893
|
+
async mobMemberStatus(mobId, agentIdentity) {
|
|
894
|
+
const result = await this.request("mob/member_status", {
|
|
895
|
+
mob_id: mobId,
|
|
896
|
+
agent_identity: agentIdentity,
|
|
897
|
+
});
|
|
604
898
|
const rawConnectivity = result.peer_connectivity && typeof result.peer_connectivity === "object"
|
|
605
899
|
? result.peer_connectivity
|
|
606
900
|
: undefined;
|
|
@@ -610,7 +904,9 @@ export class MeerkatClient {
|
|
|
610
904
|
error: result.error != null ? String(result.error) : undefined,
|
|
611
905
|
tokensUsed: Number(result.tokens_used ?? 0),
|
|
612
906
|
isFinal: Boolean(result.is_final),
|
|
613
|
-
|
|
907
|
+
liveAttachmentStatus: typeof result.realtime_attachment_status === "string"
|
|
908
|
+
? result.realtime_attachment_status
|
|
909
|
+
: undefined,
|
|
614
910
|
peerConnectivity: rawConnectivity
|
|
615
911
|
? {
|
|
616
912
|
reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
|
|
@@ -626,8 +922,94 @@ export class MeerkatClient {
|
|
|
626
922
|
: [],
|
|
627
923
|
}
|
|
628
924
|
: undefined,
|
|
925
|
+
currentSessionId: typeof result.current_session_id === "string" && result.current_session_id.length > 0
|
|
926
|
+
? result.current_session_id
|
|
927
|
+
: undefined,
|
|
928
|
+
};
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Point-in-time aggregate of a mob's status plus its member list.
|
|
932
|
+
* Wraps the `mob/snapshot` RPC (DELETE_ME C2).
|
|
933
|
+
*/
|
|
934
|
+
async mobSnapshot(mobId) {
|
|
935
|
+
const result = await this.request("mob/snapshot", { mob_id: mobId });
|
|
936
|
+
return {
|
|
937
|
+
mobId: String(result.mob_id ?? mobId),
|
|
938
|
+
status: String(result.status ?? "unknown"),
|
|
939
|
+
members: Array.isArray(result.members) ? result.members : [],
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Destroy a mob and surface the structured `MobDestroyReport`.
|
|
944
|
+
* Wraps the `mob/destroy` RPC (DELETE_ME C3). Unlike `mob/lifecycle`
|
|
945
|
+
* with `action: "destroy"`, this dedicated endpoint has a predictable
|
|
946
|
+
* response shape that does not require branching on an action string.
|
|
947
|
+
*/
|
|
948
|
+
async mobDestroy(mobId) {
|
|
949
|
+
const result = await this.request("mob/destroy", { mob_id: mobId });
|
|
950
|
+
const report = result.destroy_report && typeof result.destroy_report === "object"
|
|
951
|
+
? result.destroy_report
|
|
952
|
+
: {};
|
|
953
|
+
return {
|
|
954
|
+
mobId: String(result.mob_id ?? mobId),
|
|
955
|
+
ok: Boolean(result.ok ?? false),
|
|
956
|
+
destroyReport: report,
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Rotate the supervisor bridge for all members of a mob.
|
|
961
|
+
* Wraps the `mob/rotate_supervisor` RPC (DELETE_ME C10). Returns the
|
|
962
|
+
* full `SupervisorRotationReport` so operators can inspect per-member
|
|
963
|
+
* rotation outcomes instead of getting a bare `ok: true`.
|
|
964
|
+
*/
|
|
965
|
+
async mobRotateSupervisor(mobId) {
|
|
966
|
+
const result = await this.request("mob/rotate_supervisor", { mob_id: mobId });
|
|
967
|
+
return result;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Submit a unit of work to a mob member through the work lane.
|
|
971
|
+
* Wraps the `mob/submit_work` RPC (DELETE_ME C4). Work lane was
|
|
972
|
+
* Rust-only prior to this; `origin` is `"external"` for
|
|
973
|
+
* user-originated turns and `"internal"` for mob-orchestration work.
|
|
974
|
+
* When `workRef` is omitted the server generates a fresh UUID.
|
|
975
|
+
*/
|
|
976
|
+
async mobSubmitWork(args) {
|
|
977
|
+
const params = {
|
|
978
|
+
member_ref: args.memberRef,
|
|
979
|
+
content: args.content,
|
|
980
|
+
origin: args.origin ?? "external",
|
|
981
|
+
};
|
|
982
|
+
if (args.workRef !== undefined) {
|
|
983
|
+
params.work_ref = args.workRef;
|
|
984
|
+
}
|
|
985
|
+
const result = await this.request("mob/submit_work", params);
|
|
986
|
+
return {
|
|
987
|
+
mobId: String(result.mob_id ?? ""),
|
|
988
|
+
workRef: String(result.work_ref ?? ""),
|
|
989
|
+
memberRef: String(result.member_ref ?? args.memberRef),
|
|
629
990
|
};
|
|
630
991
|
}
|
|
992
|
+
/**
|
|
993
|
+
* Cancel a previously submitted unit of work.
|
|
994
|
+
* Wraps the `mob/cancel_work` RPC (DELETE_ME C4).
|
|
995
|
+
*/
|
|
996
|
+
async mobCancelWork(mobId, workRef) {
|
|
997
|
+
const result = await this.request("mob/cancel_work", {
|
|
998
|
+
mob_id: mobId,
|
|
999
|
+
work_ref: workRef,
|
|
1000
|
+
});
|
|
1001
|
+
return { ok: Boolean(result.ok ?? false) };
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Cancel all in-flight work for a specific mob member.
|
|
1005
|
+
* Wraps the `mob/cancel_all_work` RPC (DELETE_ME C4).
|
|
1006
|
+
*/
|
|
1007
|
+
async mobCancelAllWork(args) {
|
|
1008
|
+
const result = await this.request("mob/cancel_all_work", {
|
|
1009
|
+
member_ref: args.memberRef,
|
|
1010
|
+
});
|
|
1011
|
+
return { ok: Boolean(result.ok ?? false) };
|
|
1012
|
+
}
|
|
631
1013
|
async waitMobKickoff(mobId, options) {
|
|
632
1014
|
const params = { mob_id: mobId };
|
|
633
1015
|
if (options?.memberIds !== undefined) {
|
|
@@ -640,17 +1022,70 @@ export class MeerkatClient {
|
|
|
640
1022
|
const members = Array.isArray(result.members) ? result.members : [];
|
|
641
1023
|
return members.map((entry) => {
|
|
642
1024
|
const member = entry && typeof entry === "object" ? entry : {};
|
|
1025
|
+
const agentIdentity = String(member.agent_identity ?? "");
|
|
1026
|
+
if (!agentIdentity) {
|
|
1027
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/wait_kickoff response: member missing agent_identity");
|
|
1028
|
+
}
|
|
1029
|
+
const status = MeerkatClient.requireStringField(member, "status", "Invalid mob/wait_kickoff response");
|
|
1030
|
+
const tokensUsed = MeerkatClient.requireNumberField(member, "tokens_used", "Invalid mob/wait_kickoff response");
|
|
1031
|
+
const isFinal = MeerkatClient.requireBooleanField(member, "is_final", "Invalid mob/wait_kickoff response");
|
|
1032
|
+
const rawConnectivity = member.peer_connectivity && typeof member.peer_connectivity === "object"
|
|
1033
|
+
? member.peer_connectivity
|
|
1034
|
+
: undefined;
|
|
1035
|
+
return {
|
|
1036
|
+
agentIdentity,
|
|
1037
|
+
status,
|
|
1038
|
+
outputPreview: member.output_preview != null ? String(member.output_preview) : undefined,
|
|
1039
|
+
error: member.error != null ? String(member.error) : undefined,
|
|
1040
|
+
tokensUsed,
|
|
1041
|
+
isFinal,
|
|
1042
|
+
peerConnectivity: rawConnectivity
|
|
1043
|
+
? {
|
|
1044
|
+
reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
|
|
1045
|
+
unknownPeerCount: Number(rawConnectivity.unknown_peer_count ?? 0),
|
|
1046
|
+
unreachablePeers: Array.isArray(rawConnectivity.unreachable_peers)
|
|
1047
|
+
? rawConnectivity.unreachable_peers.map((peer) => {
|
|
1048
|
+
const rawPeer = peer && typeof peer === "object" ? peer : {};
|
|
1049
|
+
return {
|
|
1050
|
+
peer: String(rawPeer.peer ?? ""),
|
|
1051
|
+
reason: rawPeer.reason != null ? String(rawPeer.reason) : undefined,
|
|
1052
|
+
};
|
|
1053
|
+
})
|
|
1054
|
+
: [],
|
|
1055
|
+
}
|
|
1056
|
+
: undefined,
|
|
1057
|
+
};
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
async waitMobReady(mobId, options) {
|
|
1061
|
+
const params = { mob_id: mobId };
|
|
1062
|
+
if (options?.memberIds !== undefined) {
|
|
1063
|
+
params.member_ids = options.memberIds;
|
|
1064
|
+
}
|
|
1065
|
+
if (options?.timeoutMs !== undefined) {
|
|
1066
|
+
params.timeout_ms = options.timeoutMs;
|
|
1067
|
+
}
|
|
1068
|
+
const result = await this.request("mob/wait_ready", params);
|
|
1069
|
+
const members = Array.isArray(result.members) ? result.members : [];
|
|
1070
|
+
return members.map((entry) => {
|
|
1071
|
+
const member = entry && typeof entry === "object" ? entry : {};
|
|
1072
|
+
const agentIdentity = String(member.agent_identity ?? "");
|
|
1073
|
+
if (!agentIdentity) {
|
|
1074
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/wait_ready response: member missing agent_identity");
|
|
1075
|
+
}
|
|
1076
|
+
const status = MeerkatClient.requireStringField(member, "status", "Invalid mob/wait_ready response");
|
|
1077
|
+
const tokensUsed = MeerkatClient.requireNumberField(member, "tokens_used", "Invalid mob/wait_ready response");
|
|
1078
|
+
const isFinal = MeerkatClient.requireBooleanField(member, "is_final", "Invalid mob/wait_ready response");
|
|
643
1079
|
const rawConnectivity = member.peer_connectivity && typeof member.peer_connectivity === "object"
|
|
644
1080
|
? member.peer_connectivity
|
|
645
1081
|
: undefined;
|
|
646
1082
|
return {
|
|
647
|
-
|
|
648
|
-
status
|
|
1083
|
+
agentIdentity,
|
|
1084
|
+
status,
|
|
649
1085
|
outputPreview: member.output_preview != null ? String(member.output_preview) : undefined,
|
|
650
1086
|
error: member.error != null ? String(member.error) : undefined,
|
|
651
|
-
tokensUsed
|
|
652
|
-
isFinal
|
|
653
|
-
currentSessionId: member.current_session_id != null ? String(member.current_session_id) : undefined,
|
|
1087
|
+
tokensUsed,
|
|
1088
|
+
isFinal,
|
|
654
1089
|
peerConnectivity: rawConnectivity
|
|
655
1090
|
? {
|
|
656
1091
|
reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
|
|
@@ -672,20 +1107,36 @@ export class MeerkatClient {
|
|
|
672
1107
|
async wait_mob_kickoff(mobId, options) {
|
|
673
1108
|
return this.waitMobKickoff(mobId, options);
|
|
674
1109
|
}
|
|
1110
|
+
async wait_mob_ready(mobId, options) {
|
|
1111
|
+
return this.waitMobReady(mobId, options);
|
|
1112
|
+
}
|
|
675
1113
|
async spawnMobHelper(mobId, prompt, options) {
|
|
676
1114
|
const roleName = options?.roleName ?? options?.profileName;
|
|
677
1115
|
const result = await this.request("mob/spawn_helper", {
|
|
678
1116
|
mob_id: mobId,
|
|
679
1117
|
prompt,
|
|
680
|
-
|
|
1118
|
+
agent_identity: options?.agentIdentity,
|
|
681
1119
|
role_name: roleName,
|
|
682
1120
|
runtime_mode: options?.runtimeMode,
|
|
683
1121
|
backend: options?.backend,
|
|
684
1122
|
});
|
|
1123
|
+
const resultIdentity = typeof result.agent_identity === "string" && result.agent_identity.length > 0
|
|
1124
|
+
? result.agent_identity
|
|
1125
|
+
: options?.agentIdentity;
|
|
1126
|
+
if (!resultIdentity) {
|
|
1127
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_helper response: missing agent identity");
|
|
1128
|
+
}
|
|
1129
|
+
const memberRef = typeof result.member_ref === "string" && result.member_ref.length > 0
|
|
1130
|
+
? result.member_ref
|
|
1131
|
+
: undefined;
|
|
1132
|
+
if (!memberRef) {
|
|
1133
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/spawn_helper response: missing member_ref");
|
|
1134
|
+
}
|
|
685
1135
|
return {
|
|
686
1136
|
output: result.output != null ? String(result.output) : undefined,
|
|
687
1137
|
tokensUsed: Number(result.tokens_used ?? 0),
|
|
688
|
-
|
|
1138
|
+
agentIdentity: resultIdentity,
|
|
1139
|
+
memberRef,
|
|
689
1140
|
};
|
|
690
1141
|
}
|
|
691
1142
|
async forkMobHelper(mobId, sourceMemberId, prompt, options) {
|
|
@@ -694,16 +1145,29 @@ export class MeerkatClient {
|
|
|
694
1145
|
mob_id: mobId,
|
|
695
1146
|
source_member_id: sourceMemberId,
|
|
696
1147
|
prompt,
|
|
697
|
-
|
|
1148
|
+
agent_identity: options?.agentIdentity,
|
|
698
1149
|
role_name: roleName,
|
|
699
1150
|
fork_context: options?.forkContext,
|
|
700
1151
|
runtime_mode: options?.runtimeMode,
|
|
701
1152
|
backend: options?.backend,
|
|
702
1153
|
});
|
|
1154
|
+
const resultIdentity = typeof result.agent_identity === "string" && result.agent_identity.length > 0
|
|
1155
|
+
? result.agent_identity
|
|
1156
|
+
: options?.agentIdentity;
|
|
1157
|
+
if (!resultIdentity) {
|
|
1158
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/fork_helper response: missing agent identity");
|
|
1159
|
+
}
|
|
1160
|
+
const memberRef = typeof result.member_ref === "string" && result.member_ref.length > 0
|
|
1161
|
+
? result.member_ref
|
|
1162
|
+
: undefined;
|
|
1163
|
+
if (!memberRef) {
|
|
1164
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/fork_helper response: missing member_ref");
|
|
1165
|
+
}
|
|
703
1166
|
return {
|
|
704
1167
|
output: result.output != null ? String(result.output) : undefined,
|
|
705
1168
|
tokensUsed: Number(result.tokens_used ?? 0),
|
|
706
|
-
|
|
1169
|
+
agentIdentity: resultIdentity,
|
|
1170
|
+
memberRef,
|
|
707
1171
|
};
|
|
708
1172
|
}
|
|
709
1173
|
async wireMobMembers(mobId, member, peer) {
|
|
@@ -721,10 +1185,10 @@ export class MeerkatClient {
|
|
|
721
1185
|
async mobLifecycle(mobId, action) {
|
|
722
1186
|
await this.request("mob/lifecycle", { mob_id: mobId, action });
|
|
723
1187
|
}
|
|
724
|
-
async appendMobSystemContext(mobId,
|
|
1188
|
+
async appendMobSystemContext(mobId, agentIdentity, text, options) {
|
|
725
1189
|
return this.request("mob/append_system_context", {
|
|
726
1190
|
mob_id: mobId,
|
|
727
|
-
|
|
1191
|
+
agent_identity: agentIdentity,
|
|
728
1192
|
text,
|
|
729
1193
|
source: options?.source,
|
|
730
1194
|
idempotency_key: options?.idempotencyKey,
|
|
@@ -744,6 +1208,9 @@ export class MeerkatClient {
|
|
|
744
1208
|
: [];
|
|
745
1209
|
return { events };
|
|
746
1210
|
}
|
|
1211
|
+
async mobIngressInteraction(params) {
|
|
1212
|
+
return this.request("mob/ingress_interaction", params);
|
|
1213
|
+
}
|
|
747
1214
|
async createMobProfile(name, profile) {
|
|
748
1215
|
const raw = await this.request("mob/profile/create", {
|
|
749
1216
|
name,
|
|
@@ -798,8 +1265,8 @@ export class MeerkatClient {
|
|
|
798
1265
|
async subscribeMobEvents(mobId) {
|
|
799
1266
|
return this.openEventSubscription("mob/stream_open", { mob_id: mobId }, "mob/stream_close", MeerkatClient.parseAttributedMobEvent);
|
|
800
1267
|
}
|
|
801
|
-
async subscribeMobMemberEvents(mobId,
|
|
802
|
-
return this.openEventSubscription("mob/stream_open", { mob_id: mobId,
|
|
1268
|
+
async subscribeMobMemberEvents(mobId, agentIdentity) {
|
|
1269
|
+
return this.openEventSubscription("mob/stream_open", { mob_id: mobId, agent_identity: agentIdentity }, "mob/stream_close", MeerkatClient.parseAgentEventEnvelope);
|
|
803
1270
|
}
|
|
804
1271
|
async openEventSubscription(openMethod, params, closeMethod, parse) {
|
|
805
1272
|
const result = this.process?.stdin
|
|
@@ -838,14 +1305,59 @@ export class MeerkatClient {
|
|
|
838
1305
|
});
|
|
839
1306
|
}
|
|
840
1307
|
static parseAgentEventEnvelope(raw) {
|
|
1308
|
+
const eventId = MeerkatClient.parseOptionalString(raw.event_id ?? raw.eventId);
|
|
1309
|
+
const source = MeerkatClient.parseEventSourceIdentity(raw.source);
|
|
1310
|
+
const sourceId = MeerkatClient.parseOptionalString(raw.source_id ?? raw.sourceId);
|
|
1311
|
+
const seq = MeerkatClient.parseOptionalNumber(raw.seq);
|
|
1312
|
+
const timestampMs = MeerkatClient.parseOptionalNumber(raw.timestamp_ms ?? raw.timestampMs);
|
|
1313
|
+
const payloadRaw = raw.payload;
|
|
1314
|
+
const payload = payloadRaw && typeof payloadRaw === "object"
|
|
1315
|
+
? parseCoreEvent(payloadRaw)
|
|
1316
|
+
: undefined;
|
|
841
1317
|
return {
|
|
842
|
-
eventId
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
1318
|
+
...(eventId != null ? { eventId } : {}),
|
|
1319
|
+
...(source != null ? { source } : {}),
|
|
1320
|
+
...(sourceId != null ? { sourceId } : {}),
|
|
1321
|
+
...(seq != null ? { seq } : {}),
|
|
1322
|
+
...(timestampMs != null ? { timestampMs } : {}),
|
|
1323
|
+
...(payload ? { payload } : {}),
|
|
847
1324
|
};
|
|
848
1325
|
}
|
|
1326
|
+
static parseEventSourceIdentity(raw) {
|
|
1327
|
+
if (!raw || typeof raw !== "object") {
|
|
1328
|
+
return undefined;
|
|
1329
|
+
}
|
|
1330
|
+
const record = raw;
|
|
1331
|
+
const type = MeerkatClient.parseOptionalString(record.type);
|
|
1332
|
+
switch (type) {
|
|
1333
|
+
case "session": {
|
|
1334
|
+
const sessionId = MeerkatClient.parseOptionalString(record.session_id ?? record.sessionId);
|
|
1335
|
+
return sessionId != null ? { type: "session", sessionId } : undefined;
|
|
1336
|
+
}
|
|
1337
|
+
case "runtime": {
|
|
1338
|
+
const runtimeId = MeerkatClient.parseOptionalString(record.runtime_id ?? record.runtimeId);
|
|
1339
|
+
return runtimeId != null ? { type: "runtime", runtimeId } : undefined;
|
|
1340
|
+
}
|
|
1341
|
+
case "interaction": {
|
|
1342
|
+
const interactionId = MeerkatClient.parseOptionalString(record.interaction_id ?? record.interactionId);
|
|
1343
|
+
return interactionId != null ? { type: "interaction", interactionId } : undefined;
|
|
1344
|
+
}
|
|
1345
|
+
case "callback":
|
|
1346
|
+
return { type: "callback" };
|
|
1347
|
+
case "external": {
|
|
1348
|
+
const sourceId = MeerkatClient.parseOptionalString(record.source_id ?? record.sourceId);
|
|
1349
|
+
return sourceId != null ? { type: "external", sourceId } : undefined;
|
|
1350
|
+
}
|
|
1351
|
+
default:
|
|
1352
|
+
return undefined;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
static parseOptionalString(raw) {
|
|
1356
|
+
return typeof raw === "string" ? raw : undefined;
|
|
1357
|
+
}
|
|
1358
|
+
static parseOptionalNumber(raw) {
|
|
1359
|
+
return typeof raw === "number" && Number.isFinite(raw) ? raw : undefined;
|
|
1360
|
+
}
|
|
849
1361
|
static parseAttributedMobEvent(raw) {
|
|
850
1362
|
return {
|
|
851
1363
|
source: String(raw.source ?? ""),
|
|
@@ -861,9 +1373,6 @@ export class MeerkatClient {
|
|
|
861
1373
|
if (wireRefs) {
|
|
862
1374
|
params.skill_refs = wireRefs;
|
|
863
1375
|
}
|
|
864
|
-
if (options?.skillReferences) {
|
|
865
|
-
params.skill_references = options.skillReferences;
|
|
866
|
-
}
|
|
867
1376
|
if (options?.flowToolOverlay) {
|
|
868
1377
|
params.flow_tool_overlay = {
|
|
869
1378
|
allowed_tools: options.flowToolOverlay.allowedTools,
|
|
@@ -908,9 +1417,6 @@ export class MeerkatClient {
|
|
|
908
1417
|
if (wireRefs) {
|
|
909
1418
|
params.skill_refs = wireRefs;
|
|
910
1419
|
}
|
|
911
|
-
if (options?.skillReferences) {
|
|
912
|
-
params.skill_references = options.skillReferences;
|
|
913
|
-
}
|
|
914
1420
|
if (options?.flowToolOverlay) {
|
|
915
1421
|
params.flow_tool_overlay = {
|
|
916
1422
|
allowed_tools: options.flowToolOverlay.allowedTools,
|
|
@@ -955,6 +1461,51 @@ export class MeerkatClient {
|
|
|
955
1461
|
async _archive(sessionId) {
|
|
956
1462
|
await this.request("session/archive", { session_id: sessionId });
|
|
957
1463
|
}
|
|
1464
|
+
static retiredRuntimeSessionControlError() {
|
|
1465
|
+
return new MeerkatError("METHOD_NOT_FOUND", "Retired runtime session control methods are no longer supported by the public RPC surface.");
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* @internal
|
|
1469
|
+
* @deprecated Retired runtime/session control RPC method; always fails before transport.
|
|
1470
|
+
*/
|
|
1471
|
+
async _runtimeStatus(_params) {
|
|
1472
|
+
throw MeerkatClient.retiredRuntimeSessionControlError();
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* @internal
|
|
1476
|
+
* @deprecated Retired runtime/session control RPC method; always fails before transport.
|
|
1477
|
+
*/
|
|
1478
|
+
async _runtimeSubmit(_params) {
|
|
1479
|
+
throw MeerkatClient.retiredRuntimeSessionControlError();
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* @internal
|
|
1483
|
+
* @deprecated Retired runtime/session control RPC method; always fails before transport.
|
|
1484
|
+
*/
|
|
1485
|
+
async _runtimeSubmission(_params) {
|
|
1486
|
+
throw MeerkatClient.retiredRuntimeSessionControlError();
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* @internal
|
|
1490
|
+
* @deprecated Retired runtime/session control RPC method; always fails before transport.
|
|
1491
|
+
*/
|
|
1492
|
+
async _runtimeSubmissions(_params) {
|
|
1493
|
+
throw MeerkatClient.retiredRuntimeSessionControlError();
|
|
1494
|
+
}
|
|
1495
|
+
/**
|
|
1496
|
+
* @internal
|
|
1497
|
+
* @deprecated Retired runtime/session control RPC method; always fails before transport.
|
|
1498
|
+
*/
|
|
1499
|
+
async _runtimeRetire(_params) {
|
|
1500
|
+
throw MeerkatClient.retiredRuntimeSessionControlError();
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
* @internal
|
|
1504
|
+
* @deprecated Retired runtime/session control RPC method; always fails before transport.
|
|
1505
|
+
*/
|
|
1506
|
+
async _runtimeReset(_params) {
|
|
1507
|
+
throw MeerkatClient.retiredRuntimeSessionControlError();
|
|
1508
|
+
}
|
|
958
1509
|
/** @internal */
|
|
959
1510
|
async _send(sessionId, command) {
|
|
960
1511
|
return this.send(sessionId, command);
|
|
@@ -963,6 +1514,11 @@ export class MeerkatClient {
|
|
|
963
1514
|
async _peers(sessionId) {
|
|
964
1515
|
return this.peers(sessionId);
|
|
965
1516
|
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Send a typed comms command. Invalid discriminators (`source`, `stream`,
|
|
1519
|
+
* `handling_mode`, `status`) are rejected at the server's typed-serde
|
|
1520
|
+
* boundary.
|
|
1521
|
+
*/
|
|
966
1522
|
async send(sessionId, command) {
|
|
967
1523
|
const result = await this.request("comms/send", { session_id: sessionId, ...command });
|
|
968
1524
|
return MeerkatClient.parseCommsSendReceipt(result);
|
|
@@ -970,51 +1526,126 @@ export class MeerkatClient {
|
|
|
970
1526
|
async peers(sessionId) {
|
|
971
1527
|
return this.request("comms/peers", { session_id: sessionId });
|
|
972
1528
|
}
|
|
973
|
-
async
|
|
974
|
-
const result = await this.request("
|
|
975
|
-
|
|
976
|
-
|
|
1529
|
+
async runtimeRealtimeAttachmentStatus(sessionId) {
|
|
1530
|
+
const result = await this.request("session/realtime_attachment_status", {
|
|
1531
|
+
session_id: sessionId,
|
|
1532
|
+
});
|
|
1533
|
+
if (typeof result.status !== "string" || result.status.length === 0) {
|
|
1534
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid session/realtime_attachment_status response: missing status");
|
|
977
1535
|
}
|
|
978
1536
|
return result;
|
|
979
1537
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1538
|
+
/** Idempotent spawn: spawns or returns the existing member entry. */
|
|
1539
|
+
async mobEnsureMember(mobId, spec) {
|
|
1540
|
+
return await this.request("mob/ensure_member", {
|
|
1541
|
+
mob_id: mobId,
|
|
1542
|
+
spec,
|
|
1543
|
+
});
|
|
986
1544
|
}
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1545
|
+
/** Declarative reconcile: converge roster to the desired spec list. */
|
|
1546
|
+
async mobReconcile(mobId, desired, options) {
|
|
1547
|
+
const params = { mob_id: mobId, desired };
|
|
1548
|
+
if (options !== undefined)
|
|
1549
|
+
params.options = options;
|
|
1550
|
+
return await this.request("mob/reconcile", params);
|
|
1551
|
+
}
|
|
1552
|
+
/** Label-filtered member listing. */
|
|
1553
|
+
async mobListMembersMatching(mobId, filter) {
|
|
1554
|
+
return await this.request("mob/list_members_matching", {
|
|
1555
|
+
mob_id: mobId,
|
|
1556
|
+
filter,
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
async realtimeOpenInfo(request) {
|
|
1560
|
+
const result = await this.request("realtime/open_info", request);
|
|
1561
|
+
if (typeof result.ws_url !== "string" || result.ws_url.length === 0) {
|
|
1562
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid realtime/open_info response: missing ws_url");
|
|
991
1563
|
}
|
|
992
1564
|
return result;
|
|
993
1565
|
}
|
|
994
|
-
async
|
|
995
|
-
const result = await this.request("
|
|
996
|
-
if (typeof result.
|
|
997
|
-
throw new MeerkatError("INVALID_RESPONSE", "Invalid
|
|
1566
|
+
async realtimeStatus(params) {
|
|
1567
|
+
const result = await this.request("realtime/status", params);
|
|
1568
|
+
if (typeof result.status !== "object" || result.status === null) {
|
|
1569
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid realtime/status response: missing status");
|
|
998
1570
|
}
|
|
999
1571
|
return result;
|
|
1000
1572
|
}
|
|
1001
|
-
async
|
|
1002
|
-
const result = await this.request("
|
|
1003
|
-
if (result === null) {
|
|
1004
|
-
|
|
1005
|
-
}
|
|
1006
|
-
if (typeof result !== "object" || result === null) {
|
|
1007
|
-
throw new MeerkatError("INVALID_RESPONSE", "Invalid input/state response: expected object or null");
|
|
1573
|
+
async realtimeCapabilities(params) {
|
|
1574
|
+
const result = await this.request("realtime/capabilities", params);
|
|
1575
|
+
if (typeof result.capabilities !== "object" || result.capabilities === null) {
|
|
1576
|
+
throw new MeerkatError("INVALID_RESPONSE", "Invalid realtime/capabilities response: missing capabilities");
|
|
1008
1577
|
}
|
|
1009
1578
|
return result;
|
|
1010
1579
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1580
|
+
// -- Auth + realm (Phase 4d) --------------------------------------------
|
|
1581
|
+
//
|
|
1582
|
+
// These wrappers cover the RPC catalog's auth/* and realm/* methods.
|
|
1583
|
+
// Write-side methods (auth/profile/create, delete, login/start,
|
|
1584
|
+
// login/complete, login/device_start, logout) are currently server-stubbed
|
|
1585
|
+
// with typed INVALID_REQUEST pointing to the CLI; the wrappers surface
|
|
1586
|
+
// whatever the server returns so they stay honest about the state.
|
|
1587
|
+
async realmList() {
|
|
1588
|
+
return this.request("realm/list", {});
|
|
1589
|
+
}
|
|
1590
|
+
async realmGet(realmId) {
|
|
1591
|
+
return this.request("realm/get", { realm_id: realmId });
|
|
1592
|
+
}
|
|
1593
|
+
async authProfileList(realmId) {
|
|
1594
|
+
return this.request("auth/profile/list", { realm_id: realmId });
|
|
1595
|
+
}
|
|
1596
|
+
async authProfileGet(realmId, bindingId, profileId) {
|
|
1597
|
+
const params = {
|
|
1598
|
+
realm_id: realmId,
|
|
1599
|
+
binding_id: bindingId,
|
|
1600
|
+
};
|
|
1601
|
+
if (profileId)
|
|
1602
|
+
params.profile_id = profileId;
|
|
1603
|
+
return this.request("auth/profile/get", params);
|
|
1604
|
+
}
|
|
1605
|
+
async authProfileCreate(params) {
|
|
1606
|
+
return this.request("auth/profile/create", params);
|
|
1607
|
+
}
|
|
1608
|
+
async authProfileDelete(realmId, bindingId, profileId) {
|
|
1609
|
+
const params = {
|
|
1610
|
+
realm_id: realmId,
|
|
1611
|
+
binding_id: bindingId,
|
|
1612
|
+
};
|
|
1613
|
+
if (profileId)
|
|
1614
|
+
params.profile_id = profileId;
|
|
1615
|
+
return this.request("auth/profile/delete", params);
|
|
1616
|
+
}
|
|
1617
|
+
async authLoginStart(params) {
|
|
1618
|
+
return this.request("auth/login/start", params);
|
|
1619
|
+
}
|
|
1620
|
+
async authLoginComplete(params) {
|
|
1621
|
+
return this.request("auth/login/complete", params);
|
|
1622
|
+
}
|
|
1623
|
+
async authLoginDeviceStart(params) {
|
|
1624
|
+
return this.request("auth/login/device_start", params);
|
|
1625
|
+
}
|
|
1626
|
+
async authLoginDeviceComplete(params) {
|
|
1627
|
+
return this.request("auth/login/device_complete", params);
|
|
1628
|
+
}
|
|
1629
|
+
async authLoginProvisionApiKey(params) {
|
|
1630
|
+
return this.request("auth/login/provision_api_key", params);
|
|
1631
|
+
}
|
|
1632
|
+
async authStatusGet(realmId, bindingId, profileId) {
|
|
1633
|
+
const params = {
|
|
1634
|
+
realm_id: realmId,
|
|
1635
|
+
binding_id: bindingId,
|
|
1636
|
+
};
|
|
1637
|
+
if (profileId !== undefined)
|
|
1638
|
+
params.profile_id = profileId;
|
|
1639
|
+
return this.request("auth/status/get", params);
|
|
1640
|
+
}
|
|
1641
|
+
async authLogout(realmId, bindingId, profileId) {
|
|
1642
|
+
const params = {
|
|
1643
|
+
realm_id: realmId,
|
|
1644
|
+
binding_id: bindingId,
|
|
1645
|
+
};
|
|
1646
|
+
if (profileId !== undefined)
|
|
1647
|
+
params.profile_id = profileId;
|
|
1648
|
+
return this.request("auth/logout", params);
|
|
1018
1649
|
}
|
|
1019
1650
|
// -- Transport ----------------------------------------------------------
|
|
1020
1651
|
handleLine(line) {
|
|
@@ -1155,6 +1786,33 @@ export class MeerkatClient {
|
|
|
1155
1786
|
}
|
|
1156
1787
|
return String(raw);
|
|
1157
1788
|
}
|
|
1789
|
+
static requireRecord(raw, field, context) {
|
|
1790
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1791
|
+
throw new MeerkatError("INVALID_RESPONSE", `${context}: missing ${field}`);
|
|
1792
|
+
}
|
|
1793
|
+
return raw;
|
|
1794
|
+
}
|
|
1795
|
+
static requireStringField(raw, field, context) {
|
|
1796
|
+
const value = raw[field];
|
|
1797
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1798
|
+
throw new MeerkatError("INVALID_RESPONSE", `${context}: missing ${field}`);
|
|
1799
|
+
}
|
|
1800
|
+
return value;
|
|
1801
|
+
}
|
|
1802
|
+
static requireNumberField(raw, field, context, displayField = field) {
|
|
1803
|
+
const value = raw[field];
|
|
1804
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
1805
|
+
throw new MeerkatError("INVALID_RESPONSE", `${context}: ${displayField} must be number`);
|
|
1806
|
+
}
|
|
1807
|
+
return value;
|
|
1808
|
+
}
|
|
1809
|
+
static requireBooleanField(raw, field, context) {
|
|
1810
|
+
const value = raw[field];
|
|
1811
|
+
if (typeof value !== "boolean") {
|
|
1812
|
+
throw new MeerkatError("INVALID_RESPONSE", `${context}: ${field} must be boolean`);
|
|
1813
|
+
}
|
|
1814
|
+
return value;
|
|
1815
|
+
}
|
|
1158
1816
|
static parseSkillDiagnostics(raw) {
|
|
1159
1817
|
if (!raw || typeof raw !== "object")
|
|
1160
1818
|
return undefined;
|
|
@@ -1200,15 +1858,16 @@ export class MeerkatClient {
|
|
|
1200
1858
|
}
|
|
1201
1859
|
}
|
|
1202
1860
|
static parseRunResult(data) {
|
|
1203
|
-
const
|
|
1861
|
+
const context = "Invalid run result";
|
|
1862
|
+
const usageRaw = MeerkatClient.requireRecord(data.usage, "usage", context);
|
|
1204
1863
|
const usage = {
|
|
1205
|
-
inputTokens:
|
|
1206
|
-
outputTokens:
|
|
1864
|
+
inputTokens: MeerkatClient.requireNumberField(usageRaw, "input_tokens", context, "usage.input_tokens"),
|
|
1865
|
+
outputTokens: MeerkatClient.requireNumberField(usageRaw, "output_tokens", context, "usage.output_tokens"),
|
|
1207
1866
|
cacheCreationTokens: usageRaw?.cache_creation_tokens != null
|
|
1208
|
-
?
|
|
1867
|
+
? MeerkatClient.requireNumberField(usageRaw, "cache_creation_tokens", context, "usage.cache_creation_tokens")
|
|
1209
1868
|
: undefined,
|
|
1210
1869
|
cacheReadTokens: usageRaw?.cache_read_tokens != null
|
|
1211
|
-
?
|
|
1870
|
+
? MeerkatClient.requireNumberField(usageRaw, "cache_read_tokens", context, "usage.cache_read_tokens")
|
|
1212
1871
|
: undefined,
|
|
1213
1872
|
};
|
|
1214
1873
|
const rawWarnings = data.schema_warnings;
|
|
@@ -1217,14 +1876,26 @@ export class MeerkatClient {
|
|
|
1217
1876
|
path: String(w.path ?? ""),
|
|
1218
1877
|
message: String(w.message ?? ""),
|
|
1219
1878
|
}));
|
|
1879
|
+
const rawExtractionError = data.extraction_error;
|
|
1880
|
+
const extractionError = rawExtractionError && typeof rawExtractionError === "object"
|
|
1881
|
+
? {
|
|
1882
|
+
lastOutput: String(rawExtractionError.last_output ?? ""),
|
|
1883
|
+
attempts: MeerkatClient.requireNumberField(rawExtractionError, "attempts", context, "extraction_error.attempts"),
|
|
1884
|
+
reason: String(rawExtractionError.reason ?? ""),
|
|
1885
|
+
}
|
|
1886
|
+
: undefined;
|
|
1220
1887
|
return {
|
|
1221
1888
|
sessionId: String(data.session_id ?? ""),
|
|
1222
1889
|
sessionRef: data.session_ref != null ? String(data.session_ref) : undefined,
|
|
1223
1890
|
text: String(data.text ?? ""),
|
|
1224
|
-
turns:
|
|
1225
|
-
toolCalls:
|
|
1891
|
+
turns: MeerkatClient.requireNumberField(data, "turns", context),
|
|
1892
|
+
toolCalls: MeerkatClient.requireNumberField(data, "tool_calls", context),
|
|
1226
1893
|
usage,
|
|
1894
|
+
terminalCauseKind: typeof data.terminal_cause_kind === "string"
|
|
1895
|
+
? data.terminal_cause_kind
|
|
1896
|
+
: undefined,
|
|
1227
1897
|
structuredOutput: data.structured_output,
|
|
1898
|
+
extractionError,
|
|
1228
1899
|
schemaWarnings,
|
|
1229
1900
|
skillDiagnostics: MeerkatClient.parseSkillDiagnostics(data.skill_diagnostics),
|
|
1230
1901
|
};
|
|
@@ -1487,6 +2158,7 @@ export class MeerkatClient {
|
|
|
1487
2158
|
: [];
|
|
1488
2159
|
return {
|
|
1489
2160
|
role,
|
|
2161
|
+
createdAt: String(data.created_at ?? ""),
|
|
1490
2162
|
content: contentValue != null ? MeerkatClient.parseContentInput(contentValue) : undefined,
|
|
1491
2163
|
toolCalls: rawToolCalls.map((toolCall) => ({
|
|
1492
2164
|
id: String(toolCall.id ?? ""),
|
|
@@ -1545,12 +2217,22 @@ export class MeerkatClient {
|
|
|
1545
2217
|
}
|
|
1546
2218
|
static parseSessionAssistantBlock(data) {
|
|
1547
2219
|
const blockData = data.data ?? {};
|
|
2220
|
+
const blobRef = blockData.blob_ref;
|
|
2221
|
+
const revisedPrompt = blockData.revised_prompt != null && typeof blockData.revised_prompt === "object"
|
|
2222
|
+
? blockData.revised_prompt
|
|
2223
|
+
: undefined;
|
|
1548
2224
|
return {
|
|
1549
2225
|
blockType: String(data.block_type ?? ""),
|
|
1550
2226
|
text: blockData.text != null ? String(blockData.text) : undefined,
|
|
1551
2227
|
id: blockData.id != null ? String(blockData.id) : undefined,
|
|
1552
2228
|
name: blockData.name != null ? String(blockData.name) : undefined,
|
|
1553
2229
|
args: blockData.args,
|
|
2230
|
+
imageId: blockData.image_id != null ? String(blockData.image_id) : undefined,
|
|
2231
|
+
blobId: blobRef?.blob_id != null ? String(blobRef.blob_id) : undefined,
|
|
2232
|
+
mediaType: blockData.media_type != null ? String(blockData.media_type) : undefined,
|
|
2233
|
+
width: blockData.width != null ? Number(blockData.width) : undefined,
|
|
2234
|
+
height: blockData.height != null ? Number(blockData.height) : undefined,
|
|
2235
|
+
revisedPrompt,
|
|
1554
2236
|
meta: blockData.meta,
|
|
1555
2237
|
};
|
|
1556
2238
|
}
|
|
@@ -1652,13 +2334,12 @@ export class MeerkatClient {
|
|
|
1652
2334
|
params.budget_limits = options.budgetLimits;
|
|
1653
2335
|
if (options.providerParams != null)
|
|
1654
2336
|
params.provider_params = options.providerParams;
|
|
1655
|
-
if (options.preloadSkills != null)
|
|
1656
|
-
params.preload_skills = options.preloadSkills;
|
|
2337
|
+
if (options.preloadSkills != null) {
|
|
2338
|
+
params.preload_skills = skillKeysToWire(options.preloadSkills);
|
|
2339
|
+
}
|
|
1657
2340
|
const wireRefs = skillRefsToWire(options.skillRefs);
|
|
1658
2341
|
if (wireRefs)
|
|
1659
2342
|
params.skill_refs = wireRefs;
|
|
1660
|
-
if (options.skillReferences != null)
|
|
1661
|
-
params.skill_references = options.skillReferences;
|
|
1662
2343
|
if (options.labels != null)
|
|
1663
2344
|
params.labels = options.labels;
|
|
1664
2345
|
if (options.additionalInstructions != null) {
|
|
@@ -1830,9 +2511,9 @@ export class MeerkatClient {
|
|
|
1830
2511
|
static buildArgs(legacy, options) {
|
|
1831
2512
|
if (legacy)
|
|
1832
2513
|
return ["rpc"];
|
|
2514
|
+
const args = ["--realtime-ws", "127.0.0.1:0"];
|
|
1833
2515
|
if (!options)
|
|
1834
|
-
return
|
|
1835
|
-
const args = [];
|
|
2516
|
+
return args;
|
|
1836
2517
|
if (options.isolated)
|
|
1837
2518
|
args.push("--isolated");
|
|
1838
2519
|
if (options.realmId)
|