@rkat/sdk 0.4.13 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -29,10 +29,11 @@ import { chmodSync, existsSync, mkdirSync, unlinkSync, writeFileSync, } from "no
29
29
  import os from "node:os";
30
30
  import path from "node:path";
31
31
  import { createInterface } from "node:readline";
32
+ import { Buffer } from "node:buffer";
32
33
  import { MeerkatError, CapabilityUnavailableError } from "./generated/errors.js";
33
34
  import { CONTRACT_VERSION, } from "./generated/types.js";
34
35
  import { DeferredSession, Session } from "./session.js";
35
- import { Mob } from "./mob.js";
36
+ import { Mob, } from "./mob.js";
36
37
  import { parseCoreEvent } from "./events.js";
37
38
  import { EventStream, AsyncQueue } from "./streaming.js";
38
39
  import { EventSubscription } from "./subscription.js";
@@ -285,8 +286,7 @@ export class MeerkatClient {
285
286
  hasCapability(capabilityId) {
286
287
  if (capabilityId === "mob") {
287
288
  return (this._methods.has("mob/create")
288
- || this._methods.has("mob/list")
289
- || this._methods.has("mob/call"));
289
+ || this._methods.has("mob/list"));
290
290
  }
291
291
  return this._capabilities.some((c) => c.id === capabilityId && c.status === "Available");
292
292
  }
@@ -347,22 +347,13 @@ export class MeerkatClient {
347
347
  }
348
348
  return this.request("skills/inspect", params);
349
349
  }
350
- async listMobPrefabs() {
351
- const result = await this.request("mob/prefabs", {});
352
- return result.prefabs ?? [];
353
- }
354
- async list_mob_prefabs() {
355
- return this.listMobPrefabs();
356
- }
357
- async listMobTools() {
358
- const result = await this.request("mob/tools", {});
359
- return result.tools ?? [];
360
- }
361
- async callMobTool(name, argumentsPayload) {
362
- return this.request("mob/call", {
363
- name,
364
- arguments: argumentsPayload ?? {},
365
- });
350
+ async getBlob(blobId) {
351
+ const result = await this.request("blob/get", { blob_id: blobId });
352
+ return {
353
+ blobId: String(result.blob_id ?? blobId),
354
+ mediaType: String(result.media_type ?? ""),
355
+ dataBase64: String(result.data ?? ""),
356
+ };
366
357
  }
367
358
  async subscribeSessionEvents(sessionId) {
368
359
  return this.openEventSubscription("session/stream_open", { session_id: sessionId }, "session/stream_close", MeerkatClient.parseAgentEventEnvelope);
@@ -401,6 +392,10 @@ export class MeerkatClient {
401
392
  meerkatId: String(member.meerkat_id ?? member.meerkatId ?? ""),
402
393
  profile: String(member.profile_name ?? member.profile ?? ""),
403
394
  memberRef: member.member_ref,
395
+ peerId: member.peer_id != null ? String(member.peer_id) : undefined,
396
+ externalPeerSpecs: member.external_peer_specs && typeof member.external_peer_specs === "object"
397
+ ? Object.fromEntries(Object.entries(member.external_peer_specs).map(([key, value]) => [key, (value ?? {})]))
398
+ : undefined,
404
399
  runtimeMode: member.runtime_mode != null ? String(member.runtime_mode) : undefined,
405
400
  state: member.state != null ? String(member.state) : undefined,
406
401
  wiredTo: Array.isArray(member.wired_to)
@@ -409,6 +404,10 @@ export class MeerkatClient {
409
404
  labels: member.labels && typeof member.labels === 'object'
410
405
  ? Object.fromEntries(Object.entries(member.labels).map(([key, value]) => [key, String(value)]))
411
406
  : undefined,
407
+ status: member.status != null ? String(member.status) : undefined,
408
+ error: member.error != null ? String(member.error) : undefined,
409
+ isFinal: member.is_final != null ? Boolean(member.is_final) : undefined,
410
+ currentSessionId: member.current_session_id != null ? String(member.current_session_id) : undefined,
412
411
  sessionId: member.member_ref && typeof member.member_ref === 'object'
413
412
  ? member.member_ref.session_id != null
414
413
  ? String(member.member_ref.session_id)
@@ -416,6 +415,28 @@ export class MeerkatClient {
416
415
  : undefined,
417
416
  }));
418
417
  }
418
+ async sendMobMemberContent(mobId, meerkatId, content, options) {
419
+ const result = await this.request("mob/member_send", {
420
+ mob_id: mobId,
421
+ meerkat_id: meerkatId,
422
+ content,
423
+ handling_mode: options?.handlingMode,
424
+ render_metadata: options?.renderMetadata,
425
+ });
426
+ const sessionId = result.session_id;
427
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
428
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/member_send response: missing session_id");
429
+ }
430
+ return {
431
+ memberId: typeof result.member_id === "string" && result.member_id.length > 0
432
+ ? result.member_id
433
+ : meerkatId,
434
+ sessionId,
435
+ handlingMode: result.handling_mode === "steer" || result.handling_mode === "queue"
436
+ ? result.handling_mode
437
+ : (options?.handlingMode ?? "queue"),
438
+ };
439
+ }
419
440
  async spawnMobMember(mobId, options) {
420
441
  return this.request("mob/spawn", {
421
442
  mob_id: mobId,
@@ -434,20 +455,152 @@ export class MeerkatClient {
434
455
  await this.request("mob/retire", { mob_id: mobId, meerkat_id: meerkatId });
435
456
  }
436
457
  async respawnMobMember(mobId, meerkatId, initialMessage) {
437
- await this.request("mob/respawn", { mob_id: mobId, meerkat_id: meerkatId, initial_message: initialMessage });
458
+ const result = await this.request("mob/respawn", {
459
+ mob_id: mobId,
460
+ meerkat_id: meerkatId,
461
+ initial_message: initialMessage,
462
+ });
463
+ const status = String(result.status ?? "completed");
464
+ const rawFailed = Array.isArray(result.failed_peer_ids)
465
+ ? result.failed_peer_ids
466
+ : [];
467
+ const receipt = result.receipt;
468
+ if (!receipt || typeof receipt !== "object") {
469
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/respawn response: missing receipt");
470
+ }
471
+ return {
472
+ status: status === "topology_restore_failed" ? "topology_restore_failed" : "completed",
473
+ receipt: {
474
+ memberId: String(receipt.member_id ?? meerkatId),
475
+ oldSessionId: receipt.old_session_id != null ? String(receipt.old_session_id) : undefined,
476
+ newSessionId: receipt.new_session_id != null ? String(receipt.new_session_id) : undefined,
477
+ },
478
+ failedPeerIds: rawFailed.map((peerId) => String(peerId)),
479
+ };
480
+ }
481
+ async forceCancelMobMember(mobId, meerkatId) {
482
+ await this.request("mob/force_cancel", { mob_id: mobId, meerkat_id: meerkatId });
483
+ }
484
+ async mobMemberStatus(mobId, meerkatId) {
485
+ const result = await this.request("mob/member_status", { mob_id: mobId, meerkat_id: meerkatId });
486
+ const rawConnectivity = result.peer_connectivity && typeof result.peer_connectivity === "object"
487
+ ? result.peer_connectivity
488
+ : undefined;
489
+ return {
490
+ status: String(result.status ?? "unknown"),
491
+ outputPreview: result.output_preview != null ? String(result.output_preview) : undefined,
492
+ error: result.error != null ? String(result.error) : undefined,
493
+ tokensUsed: Number(result.tokens_used ?? 0),
494
+ isFinal: Boolean(result.is_final),
495
+ currentSessionId: result.current_session_id != null ? String(result.current_session_id) : undefined,
496
+ peerConnectivity: rawConnectivity
497
+ ? {
498
+ reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
499
+ unknownPeerCount: Number(rawConnectivity.unknown_peer_count ?? 0),
500
+ unreachablePeers: Array.isArray(rawConnectivity.unreachable_peers)
501
+ ? rawConnectivity.unreachable_peers.map((peer) => {
502
+ const rawPeer = peer && typeof peer === "object" ? peer : {};
503
+ return {
504
+ peer: String(rawPeer.peer ?? ""),
505
+ reason: rawPeer.reason != null ? String(rawPeer.reason) : undefined,
506
+ };
507
+ })
508
+ : [],
509
+ }
510
+ : undefined,
511
+ };
512
+ }
513
+ async waitMobKickoff(mobId, options) {
514
+ const params = { mob_id: mobId };
515
+ if (options?.memberIds !== undefined) {
516
+ params.member_ids = options.memberIds;
517
+ }
518
+ if (options?.timeoutMs !== undefined) {
519
+ params.timeout_ms = options.timeoutMs;
520
+ }
521
+ const result = await this.request("mob/wait_kickoff", params);
522
+ const members = Array.isArray(result.members) ? result.members : [];
523
+ return members.map((entry) => {
524
+ const member = entry && typeof entry === "object" ? entry : {};
525
+ const rawConnectivity = member.peer_connectivity && typeof member.peer_connectivity === "object"
526
+ ? member.peer_connectivity
527
+ : undefined;
528
+ return {
529
+ meerkatId: String(member.meerkat_id ?? ""),
530
+ status: String(member.status ?? "unknown"),
531
+ outputPreview: member.output_preview != null ? String(member.output_preview) : undefined,
532
+ error: member.error != null ? String(member.error) : undefined,
533
+ tokensUsed: Number(member.tokens_used ?? 0),
534
+ isFinal: Boolean(member.is_final),
535
+ currentSessionId: member.current_session_id != null ? String(member.current_session_id) : undefined,
536
+ peerConnectivity: rawConnectivity
537
+ ? {
538
+ reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
539
+ unknownPeerCount: Number(rawConnectivity.unknown_peer_count ?? 0),
540
+ unreachablePeers: Array.isArray(rawConnectivity.unreachable_peers)
541
+ ? rawConnectivity.unreachable_peers.map((peer) => {
542
+ const rawPeer = peer && typeof peer === "object" ? peer : {};
543
+ return {
544
+ peer: String(rawPeer.peer ?? ""),
545
+ reason: rawPeer.reason != null ? String(rawPeer.reason) : undefined,
546
+ };
547
+ })
548
+ : [],
549
+ }
550
+ : undefined,
551
+ };
552
+ });
553
+ }
554
+ async wait_mob_kickoff(mobId, options) {
555
+ return this.waitMobKickoff(mobId, options);
556
+ }
557
+ async spawnMobHelper(mobId, prompt, options) {
558
+ const result = await this.request("mob/spawn_helper", {
559
+ mob_id: mobId,
560
+ prompt,
561
+ meerkat_id: options?.meerkatId,
562
+ profile_name: options?.profileName,
563
+ runtime_mode: options?.runtimeMode,
564
+ backend: options?.backend,
565
+ });
566
+ return {
567
+ output: result.output != null ? String(result.output) : undefined,
568
+ tokensUsed: Number(result.tokens_used ?? 0),
569
+ sessionId: result.session_id != null ? String(result.session_id) : undefined,
570
+ };
438
571
  }
439
- async wireMobMembers(mobId, a, b) {
440
- await this.request("mob/wire", { mob_id: mobId, a, b });
572
+ async forkMobHelper(mobId, sourceMemberId, prompt, options) {
573
+ const result = await this.request("mob/fork_helper", {
574
+ mob_id: mobId,
575
+ source_member_id: sourceMemberId,
576
+ prompt,
577
+ meerkat_id: options?.meerkatId,
578
+ profile_name: options?.profileName,
579
+ fork_context: options?.forkContext,
580
+ runtime_mode: options?.runtimeMode,
581
+ backend: options?.backend,
582
+ });
583
+ return {
584
+ output: result.output != null ? String(result.output) : undefined,
585
+ tokensUsed: Number(result.tokens_used ?? 0),
586
+ sessionId: result.session_id != null ? String(result.session_id) : undefined,
587
+ };
588
+ }
589
+ async wireMobMembers(mobId, member, peer) {
590
+ const payload = typeof peer === "string"
591
+ ? { member, peer: { local: peer } }
592
+ : { member, peer };
593
+ await this.request("mob/wire", { mob_id: mobId, ...payload });
441
594
  }
442
- async unwireMobMembers(mobId, a, b) {
443
- await this.request("mob/unwire", { mob_id: mobId, a, b });
595
+ async unwireMobMembers(mobId, member, peer) {
596
+ const payload = typeof peer === "string"
597
+ ? { member, peer: { local: peer } }
598
+ : { member, peer };
599
+ await this.request("mob/unwire", { mob_id: mobId, ...payload });
444
600
  }
445
601
  async mobLifecycle(mobId, action) {
446
602
  await this.request("mob/lifecycle", { mob_id: mobId, action });
447
603
  }
448
- async sendMobMessage(mobId, meerkatId, message) {
449
- await this.request("mob/send", { mob_id: mobId, meerkat_id: meerkatId, message });
450
- }
451
604
  async appendMobSystemContext(mobId, meerkatId, text, options) {
452
605
  return this.request("mob/append_system_context", {
453
606
  mob_id: mobId,
@@ -547,8 +700,8 @@ export class MeerkatClient {
547
700
  blocked_tools: options.flowToolOverlay.blockedTools,
548
701
  };
549
702
  }
550
- if (options?.hostMode != null)
551
- params.host_mode = options.hostMode;
703
+ if (options?.keepAlive != null)
704
+ params.keep_alive = options.keepAlive;
552
705
  if (options?.model)
553
706
  params.model = options.model;
554
707
  if (options?.provider)
@@ -623,6 +776,52 @@ export class MeerkatClient {
623
776
  async peers(sessionId) {
624
777
  return this.request("comms/peers", { session_id: sessionId });
625
778
  }
779
+ async runtimeState(sessionId) {
780
+ const result = await this.request("runtime/state", { session_id: sessionId });
781
+ if (typeof result.state !== "string" || result.state.length === 0) {
782
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/state response: missing state");
783
+ }
784
+ return result;
785
+ }
786
+ async runtimeAccept(sessionId, input) {
787
+ const result = await this.request("runtime/accept", { session_id: sessionId, input });
788
+ if (typeof result.outcome_type !== "string" || result.outcome_type.length === 0) {
789
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/accept response: missing outcome_type");
790
+ }
791
+ return result;
792
+ }
793
+ async runtimeRetire(sessionId) {
794
+ const result = await this.request("runtime/retire", { session_id: sessionId });
795
+ if (typeof result.inputs_abandoned !== "number") {
796
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/retire response: missing inputs_abandoned");
797
+ }
798
+ return result;
799
+ }
800
+ async runtimeReset(sessionId) {
801
+ const result = await this.request("runtime/reset", { session_id: sessionId });
802
+ if (typeof result.inputs_abandoned !== "number") {
803
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/reset response: missing inputs_abandoned");
804
+ }
805
+ return result;
806
+ }
807
+ async inputState(sessionId, inputId) {
808
+ const result = await this.request("input/state", { session_id: sessionId, input_id: inputId });
809
+ if (result === null) {
810
+ return null;
811
+ }
812
+ if (typeof result !== "object" || result === null) {
813
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid input/state response: expected object or null");
814
+ }
815
+ return result;
816
+ }
817
+ async inputList(sessionId) {
818
+ const result = (await this.request("input/list", {
819
+ session_id: sessionId,
820
+ }));
821
+ return Array.isArray(result.input_ids)
822
+ ? result.input_ids.map((inputId) => String(inputId))
823
+ : [];
824
+ }
626
825
  // -- Transport ----------------------------------------------------------
627
826
  handleLine(line) {
628
827
  let data;
@@ -643,7 +842,8 @@ export class MeerkatClient {
643
842
  this.pendingRequests.delete(data.id);
644
843
  const error = data.error;
645
844
  if (error) {
646
- pending.reject(new MeerkatError(String(error.code ?? "UNKNOWN"), String(error.message ?? "Unknown error")));
845
+ const normalized = MeerkatClient.parseRpcErrorPayload(error);
846
+ pending.reject(new MeerkatError(normalized.code, normalized.message, normalized.details));
647
847
  }
648
848
  else {
649
849
  pending.resolve((data.result ?? {}));
@@ -657,7 +857,7 @@ export class MeerkatClient {
657
857
  const streamId = String(params.stream_id ?? "");
658
858
  const queue = this.streamQueues.get(streamId);
659
859
  const rawEvent = (params.event ?? params);
660
- // Preserve scope fields when present (sub-agent / mob-member scoped events).
860
+ // Preserve scope fields when present (delegated-branch / mob-member scoped events).
661
861
  const scopeId = params.scope_id;
662
862
  const scopePath = params.scope_path;
663
863
  const event = scopeId != null || scopePath != null
@@ -702,6 +902,38 @@ export class MeerkatClient {
702
902
  }
703
903
  }
704
904
  }
905
+ static parseRpcErrorPayload(error) {
906
+ const rawData = error.data;
907
+ if (typeof rawData === "object" && rawData !== null) {
908
+ const parsed = rawData;
909
+ return {
910
+ code: String(parsed.code ?? error.code ?? "UNKNOWN"),
911
+ message: String(parsed.message ?? error.message ?? "Unknown error"),
912
+ details: parsed.details ?? parsed.reason ?? rawData,
913
+ };
914
+ }
915
+ const rawMessage = error.message;
916
+ if (typeof rawMessage === "string") {
917
+ try {
918
+ const parsed = JSON.parse(rawMessage);
919
+ if (parsed && typeof parsed === "object") {
920
+ return {
921
+ code: String(parsed.code ?? error.code ?? "UNKNOWN"),
922
+ message: String(parsed.message ?? rawMessage),
923
+ details: parsed.details ?? parsed.reason ?? error.data,
924
+ };
925
+ }
926
+ }
927
+ catch {
928
+ // Fall back to the outer JSON-RPC error payload.
929
+ }
930
+ }
931
+ return {
932
+ code: String(error.code ?? "UNKNOWN"),
933
+ message: String(rawMessage ?? "Unknown error"),
934
+ details: error.data,
935
+ };
936
+ }
705
937
  request(method, params) {
706
938
  if (!this.process?.stdin) {
707
939
  throw new MeerkatError("NOT_CONNECTED", "Client not connected");
@@ -829,7 +1061,7 @@ export class MeerkatClient {
829
1061
  : [];
830
1062
  return {
831
1063
  role: String(data.role ?? ""),
832
- content: data.content != null ? String(data.content) : undefined,
1064
+ content: data.content != null ? MeerkatClient.parseContentInput(data.content) : undefined,
833
1065
  toolCalls: rawToolCalls.map((toolCall) => ({
834
1066
  id: String(toolCall.id ?? ""),
835
1067
  name: String(toolCall.name ?? ""),
@@ -839,11 +1071,52 @@ export class MeerkatClient {
839
1071
  blocks: rawBlocks.map((block) => MeerkatClient.parseSessionAssistantBlock(block)),
840
1072
  results: rawResults.map((result) => ({
841
1073
  toolUseId: String(result.tool_use_id ?? ""),
842
- content: String(result.content ?? ""),
1074
+ content: MeerkatClient.parseContentInput(result.content),
843
1075
  isError: Boolean(result.is_error ?? false),
844
1076
  })),
845
1077
  };
846
1078
  }
1079
+ static parseContentInput(value) {
1080
+ if (Array.isArray(value)) {
1081
+ return value
1082
+ .filter((item) => typeof item === "object" && item !== null)
1083
+ .map((block) => MeerkatClient.parseContentBlock(block));
1084
+ }
1085
+ return String(value ?? "");
1086
+ }
1087
+ static parseContentBlock(data) {
1088
+ const type = String(data.type ?? "");
1089
+ if (type === "text") {
1090
+ return { type: "text", text: String(data.text ?? "") };
1091
+ }
1092
+ if (type === "image") {
1093
+ const source = String(data.source ?? "inline");
1094
+ if (source === "blob") {
1095
+ return {
1096
+ type: "image",
1097
+ media_type: String(data.media_type ?? ""),
1098
+ source: "blob",
1099
+ blob_id: String(data.blob_id ?? ""),
1100
+ };
1101
+ }
1102
+ return {
1103
+ type: "image",
1104
+ media_type: String(data.media_type ?? ""),
1105
+ source: "inline",
1106
+ data: String(data.data ?? ""),
1107
+ };
1108
+ }
1109
+ if (type === "video") {
1110
+ return {
1111
+ type: "video",
1112
+ media_type: String(data.media_type ?? ""),
1113
+ duration_ms: Number(data.duration_ms ?? 0),
1114
+ source: "inline",
1115
+ data: String(data.data ?? ""),
1116
+ };
1117
+ }
1118
+ return { type: "text", text: "" };
1119
+ }
847
1120
  static parseSessionAssistantBlock(data) {
848
1121
  const blockData = data.data ?? {};
849
1122
  return {
@@ -928,32 +1201,30 @@ export class MeerkatClient {
928
1201
  params.system_prompt = options.systemPrompt;
929
1202
  if (options.maxTokens)
930
1203
  params.max_tokens = options.maxTokens;
931
- if (options.outputSchema)
1204
+ if (options.outputSchema != null)
932
1205
  params.output_schema = options.outputSchema;
933
- if (options.structuredOutputRetries != null && options.structuredOutputRetries !== 2) {
1206
+ if (options.structuredOutputRetries != null) {
934
1207
  params.structured_output_retries = options.structuredOutputRetries;
935
1208
  }
936
- if (options.hooksOverride)
1209
+ if (options.hooksOverride != null)
937
1210
  params.hooks_override = options.hooksOverride;
938
- if (options.enableBuiltins)
939
- params.enable_builtins = true;
940
- if (options.enableShell)
941
- params.enable_shell = true;
942
- if (options.enableSubagents)
943
- params.enable_subagents = true;
944
- if (options.enableMemory)
945
- params.enable_memory = true;
946
- if (options.enableMob)
947
- params.enable_mob = true;
948
- if (options.hostMode)
949
- params.host_mode = true;
1211
+ if (options.enableBuiltins != null)
1212
+ params.enable_builtins = options.enableBuiltins;
1213
+ if (options.enableShell != null)
1214
+ params.enable_shell = options.enableShell;
1215
+ if (options.enableMemory != null)
1216
+ params.enable_memory = options.enableMemory;
1217
+ if (options.enableMob != null)
1218
+ params.enable_mob = options.enableMob;
1219
+ if (options.keepAlive != null)
1220
+ params.keep_alive = options.keepAlive;
950
1221
  if (options.commsName)
951
1222
  params.comms_name = options.commsName;
952
1223
  if (options.peerMeta != null)
953
1224
  params.peer_meta = options.peerMeta;
954
1225
  if (options.budgetLimits != null)
955
1226
  params.budget_limits = options.budgetLimits;
956
- if (options.providerParams)
1227
+ if (options.providerParams != null)
957
1228
  params.provider_params = options.providerParams;
958
1229
  if (options.preloadSkills != null)
959
1230
  params.preload_skills = options.preloadSkills;
@@ -1024,7 +1295,8 @@ export class MeerkatClient {
1024
1295
  }
1025
1296
  static async runCommand(command, args) {
1026
1297
  return new Promise((resolve, reject) => {
1027
- const proc = spawn(command, args, { stdio: ["ignore", "inherit", "pipe"] });
1298
+ const options = { stdio: ["ignore", "inherit", "pipe"] };
1299
+ const proc = spawn(command, args, options);
1028
1300
  let stderr = "";
1029
1301
  proc.stderr?.on("data", (chunk) => { stderr += String(chunk); });
1030
1302
  proc.on("error", (error) => { reject(error); });