@rkat/sdk 0.4.13 → 0.5.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/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";
@@ -347,6 +348,14 @@ export class MeerkatClient {
347
348
  }
348
349
  return this.request("skills/inspect", params);
349
350
  }
351
+ async getBlob(blobId) {
352
+ const result = await this.request("blob/get", { blob_id: blobId });
353
+ return {
354
+ blobId: String(result.blob_id ?? blobId),
355
+ mediaType: String(result.media_type ?? ""),
356
+ dataBase64: String(result.data ?? ""),
357
+ };
358
+ }
350
359
  async listMobPrefabs() {
351
360
  const result = await this.request("mob/prefabs", {});
352
361
  return result.prefabs ?? [];
@@ -401,6 +410,10 @@ export class MeerkatClient {
401
410
  meerkatId: String(member.meerkat_id ?? member.meerkatId ?? ""),
402
411
  profile: String(member.profile_name ?? member.profile ?? ""),
403
412
  memberRef: member.member_ref,
413
+ peerId: member.peer_id != null ? String(member.peer_id) : undefined,
414
+ externalPeerSpecs: member.external_peer_specs && typeof member.external_peer_specs === "object"
415
+ ? Object.fromEntries(Object.entries(member.external_peer_specs).map(([key, value]) => [key, (value ?? {})]))
416
+ : undefined,
404
417
  runtimeMode: member.runtime_mode != null ? String(member.runtime_mode) : undefined,
405
418
  state: member.state != null ? String(member.state) : undefined,
406
419
  wiredTo: Array.isArray(member.wired_to)
@@ -409,6 +422,10 @@ export class MeerkatClient {
409
422
  labels: member.labels && typeof member.labels === 'object'
410
423
  ? Object.fromEntries(Object.entries(member.labels).map(([key, value]) => [key, String(value)]))
411
424
  : undefined,
425
+ status: member.status != null ? String(member.status) : undefined,
426
+ error: member.error != null ? String(member.error) : undefined,
427
+ isFinal: member.is_final != null ? Boolean(member.is_final) : undefined,
428
+ currentSessionId: member.current_session_id != null ? String(member.current_session_id) : undefined,
412
429
  sessionId: member.member_ref && typeof member.member_ref === 'object'
413
430
  ? member.member_ref.session_id != null
414
431
  ? String(member.member_ref.session_id)
@@ -434,19 +451,169 @@ export class MeerkatClient {
434
451
  await this.request("mob/retire", { mob_id: mobId, meerkat_id: meerkatId });
435
452
  }
436
453
  async respawnMobMember(mobId, meerkatId, initialMessage) {
437
- await this.request("mob/respawn", { mob_id: mobId, meerkat_id: meerkatId, initial_message: initialMessage });
454
+ const result = await this.request("mob/respawn", {
455
+ mob_id: mobId,
456
+ meerkat_id: meerkatId,
457
+ initial_message: initialMessage,
458
+ });
459
+ const status = String(result.status ?? "completed");
460
+ const rawFailed = Array.isArray(result.failed_peer_ids)
461
+ ? result.failed_peer_ids
462
+ : [];
463
+ const receipt = result.receipt;
464
+ if (!receipt || typeof receipt !== "object") {
465
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/respawn response: missing receipt");
466
+ }
467
+ return {
468
+ status: status === "topology_restore_failed" ? "topology_restore_failed" : "completed",
469
+ receipt: {
470
+ memberId: String(receipt.member_id ?? meerkatId),
471
+ oldSessionId: receipt.old_session_id != null ? String(receipt.old_session_id) : undefined,
472
+ newSessionId: receipt.new_session_id != null ? String(receipt.new_session_id) : undefined,
473
+ },
474
+ failedPeerIds: rawFailed.map((peerId) => String(peerId)),
475
+ };
476
+ }
477
+ async forceCancelMobMember(mobId, meerkatId) {
478
+ await this.request("mob/force_cancel", { mob_id: mobId, meerkat_id: meerkatId });
479
+ }
480
+ async mobMemberStatus(mobId, meerkatId) {
481
+ const result = await this.request("mob/member_status", { mob_id: mobId, meerkat_id: meerkatId });
482
+ const rawConnectivity = result.peer_connectivity && typeof result.peer_connectivity === "object"
483
+ ? result.peer_connectivity
484
+ : undefined;
485
+ return {
486
+ status: String(result.status ?? "unknown"),
487
+ outputPreview: result.output_preview != null ? String(result.output_preview) : undefined,
488
+ error: result.error != null ? String(result.error) : undefined,
489
+ tokensUsed: Number(result.tokens_used ?? 0),
490
+ isFinal: Boolean(result.is_final),
491
+ currentSessionId: result.current_session_id != null ? String(result.current_session_id) : undefined,
492
+ peerConnectivity: rawConnectivity
493
+ ? {
494
+ reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
495
+ unknownPeerCount: Number(rawConnectivity.unknown_peer_count ?? 0),
496
+ unreachablePeers: Array.isArray(rawConnectivity.unreachable_peers)
497
+ ? rawConnectivity.unreachable_peers.map((peer) => {
498
+ const rawPeer = peer && typeof peer === "object" ? peer : {};
499
+ return {
500
+ peer: String(rawPeer.peer ?? ""),
501
+ reason: rawPeer.reason != null ? String(rawPeer.reason) : undefined,
502
+ };
503
+ })
504
+ : [],
505
+ }
506
+ : undefined,
507
+ };
508
+ }
509
+ async waitMobKickoff(mobId, options) {
510
+ const params = { mob_id: mobId };
511
+ if (options?.memberIds !== undefined) {
512
+ params.member_ids = options.memberIds;
513
+ }
514
+ if (options?.timeoutMs !== undefined) {
515
+ params.timeout_ms = options.timeoutMs;
516
+ }
517
+ const result = await this.request("mob/wait_kickoff", params);
518
+ const members = Array.isArray(result.members) ? result.members : [];
519
+ return members.map((entry) => {
520
+ const member = entry && typeof entry === "object" ? entry : {};
521
+ const rawConnectivity = member.peer_connectivity && typeof member.peer_connectivity === "object"
522
+ ? member.peer_connectivity
523
+ : undefined;
524
+ return {
525
+ meerkatId: String(member.meerkat_id ?? ""),
526
+ status: String(member.status ?? "unknown"),
527
+ outputPreview: member.output_preview != null ? String(member.output_preview) : undefined,
528
+ error: member.error != null ? String(member.error) : undefined,
529
+ tokensUsed: Number(member.tokens_used ?? 0),
530
+ isFinal: Boolean(member.is_final),
531
+ currentSessionId: member.current_session_id != null ? String(member.current_session_id) : undefined,
532
+ peerConnectivity: rawConnectivity
533
+ ? {
534
+ reachablePeerCount: Number(rawConnectivity.reachable_peer_count ?? 0),
535
+ unknownPeerCount: Number(rawConnectivity.unknown_peer_count ?? 0),
536
+ unreachablePeers: Array.isArray(rawConnectivity.unreachable_peers)
537
+ ? rawConnectivity.unreachable_peers.map((peer) => {
538
+ const rawPeer = peer && typeof peer === "object" ? peer : {};
539
+ return {
540
+ peer: String(rawPeer.peer ?? ""),
541
+ reason: rawPeer.reason != null ? String(rawPeer.reason) : undefined,
542
+ };
543
+ })
544
+ : [],
545
+ }
546
+ : undefined,
547
+ };
548
+ });
438
549
  }
439
- async wireMobMembers(mobId, a, b) {
440
- await this.request("mob/wire", { mob_id: mobId, a, b });
550
+ async wait_mob_kickoff(mobId, options) {
551
+ return this.waitMobKickoff(mobId, options);
441
552
  }
442
- async unwireMobMembers(mobId, a, b) {
443
- await this.request("mob/unwire", { mob_id: mobId, a, b });
553
+ async spawnMobHelper(mobId, prompt, options) {
554
+ const result = await this.request("mob/spawn_helper", {
555
+ mob_id: mobId,
556
+ prompt,
557
+ meerkat_id: options?.meerkatId,
558
+ profile_name: options?.profileName,
559
+ runtime_mode: options?.runtimeMode,
560
+ backend: options?.backend,
561
+ });
562
+ return {
563
+ output: result.output != null ? String(result.output) : undefined,
564
+ tokensUsed: Number(result.tokens_used ?? 0),
565
+ sessionId: result.session_id != null ? String(result.session_id) : undefined,
566
+ };
567
+ }
568
+ async forkMobHelper(mobId, sourceMemberId, prompt, options) {
569
+ const result = await this.request("mob/fork_helper", {
570
+ mob_id: mobId,
571
+ source_member_id: sourceMemberId,
572
+ prompt,
573
+ meerkat_id: options?.meerkatId,
574
+ profile_name: options?.profileName,
575
+ fork_context: options?.forkContext,
576
+ runtime_mode: options?.runtimeMode,
577
+ backend: options?.backend,
578
+ });
579
+ return {
580
+ output: result.output != null ? String(result.output) : undefined,
581
+ tokensUsed: Number(result.tokens_used ?? 0),
582
+ sessionId: result.session_id != null ? String(result.session_id) : undefined,
583
+ };
584
+ }
585
+ async wireMobMembers(mobId, member, peer) {
586
+ const payload = typeof peer === "string"
587
+ ? { member, peer: { local: peer } }
588
+ : { member, peer };
589
+ await this.request("mob/wire", { mob_id: mobId, ...payload });
590
+ }
591
+ async unwireMobMembers(mobId, member, peer) {
592
+ const payload = typeof peer === "string"
593
+ ? { member, peer: { local: peer } }
594
+ : { member, peer };
595
+ await this.request("mob/unwire", { mob_id: mobId, ...payload });
444
596
  }
445
597
  async mobLifecycle(mobId, action) {
446
598
  await this.request("mob/lifecycle", { mob_id: mobId, action });
447
599
  }
448
- async sendMobMessage(mobId, meerkatId, message) {
449
- await this.request("mob/send", { mob_id: mobId, meerkat_id: meerkatId, message });
600
+ async sendMobMemberContent(mobId, meerkatId, content, options) {
601
+ const result = await this.request("mob/send", {
602
+ mob_id: mobId,
603
+ meerkat_id: meerkatId,
604
+ content,
605
+ handling_mode: options?.handlingMode ?? "queue",
606
+ render_metadata: options?.renderMetadata,
607
+ });
608
+ const sessionId = result.session_id;
609
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
610
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid mob/send response: missing session_id");
611
+ }
612
+ return {
613
+ memberId: String(result.member_id ?? meerkatId),
614
+ sessionId,
615
+ handlingMode: String(result.handling_mode ?? options?.handlingMode ?? "queue"),
616
+ };
450
617
  }
451
618
  async appendMobSystemContext(mobId, meerkatId, text, options) {
452
619
  return this.request("mob/append_system_context", {
@@ -547,8 +714,8 @@ export class MeerkatClient {
547
714
  blocked_tools: options.flowToolOverlay.blockedTools,
548
715
  };
549
716
  }
550
- if (options?.hostMode != null)
551
- params.host_mode = options.hostMode;
717
+ if (options?.keepAlive != null)
718
+ params.keep_alive = options.keepAlive;
552
719
  if (options?.model)
553
720
  params.model = options.model;
554
721
  if (options?.provider)
@@ -623,6 +790,52 @@ export class MeerkatClient {
623
790
  async peers(sessionId) {
624
791
  return this.request("comms/peers", { session_id: sessionId });
625
792
  }
793
+ async runtimeState(sessionId) {
794
+ const result = await this.request("runtime/state", { session_id: sessionId });
795
+ if (typeof result.state !== "string" || result.state.length === 0) {
796
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/state response: missing state");
797
+ }
798
+ return result;
799
+ }
800
+ async runtimeAccept(sessionId, input) {
801
+ const result = await this.request("runtime/accept", { session_id: sessionId, input });
802
+ if (typeof result.outcome_type !== "string" || result.outcome_type.length === 0) {
803
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/accept response: missing outcome_type");
804
+ }
805
+ return result;
806
+ }
807
+ async runtimeRetire(sessionId) {
808
+ const result = await this.request("runtime/retire", { session_id: sessionId });
809
+ if (typeof result.inputs_abandoned !== "number") {
810
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/retire response: missing inputs_abandoned");
811
+ }
812
+ return result;
813
+ }
814
+ async runtimeReset(sessionId) {
815
+ const result = await this.request("runtime/reset", { session_id: sessionId });
816
+ if (typeof result.inputs_abandoned !== "number") {
817
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid runtime/reset response: missing inputs_abandoned");
818
+ }
819
+ return result;
820
+ }
821
+ async inputState(sessionId, inputId) {
822
+ const result = await this.request("input/state", { session_id: sessionId, input_id: inputId });
823
+ if (result === null) {
824
+ return null;
825
+ }
826
+ if (typeof result !== "object" || result === null) {
827
+ throw new MeerkatError("INVALID_RESPONSE", "Invalid input/state response: expected object or null");
828
+ }
829
+ return result;
830
+ }
831
+ async inputList(sessionId) {
832
+ const result = (await this.request("input/list", {
833
+ session_id: sessionId,
834
+ }));
835
+ return Array.isArray(result.input_ids)
836
+ ? result.input_ids.map((inputId) => String(inputId))
837
+ : [];
838
+ }
626
839
  // -- Transport ----------------------------------------------------------
627
840
  handleLine(line) {
628
841
  let data;
@@ -643,7 +856,8 @@ export class MeerkatClient {
643
856
  this.pendingRequests.delete(data.id);
644
857
  const error = data.error;
645
858
  if (error) {
646
- pending.reject(new MeerkatError(String(error.code ?? "UNKNOWN"), String(error.message ?? "Unknown error")));
859
+ const normalized = MeerkatClient.parseRpcErrorPayload(error);
860
+ pending.reject(new MeerkatError(normalized.code, normalized.message, normalized.details));
647
861
  }
648
862
  else {
649
863
  pending.resolve((data.result ?? {}));
@@ -657,7 +871,7 @@ export class MeerkatClient {
657
871
  const streamId = String(params.stream_id ?? "");
658
872
  const queue = this.streamQueues.get(streamId);
659
873
  const rawEvent = (params.event ?? params);
660
- // Preserve scope fields when present (sub-agent / mob-member scoped events).
874
+ // Preserve scope fields when present (delegated-branch / mob-member scoped events).
661
875
  const scopeId = params.scope_id;
662
876
  const scopePath = params.scope_path;
663
877
  const event = scopeId != null || scopePath != null
@@ -702,6 +916,38 @@ export class MeerkatClient {
702
916
  }
703
917
  }
704
918
  }
919
+ static parseRpcErrorPayload(error) {
920
+ const rawData = error.data;
921
+ if (typeof rawData === "object" && rawData !== null) {
922
+ const parsed = rawData;
923
+ return {
924
+ code: String(parsed.code ?? error.code ?? "UNKNOWN"),
925
+ message: String(parsed.message ?? error.message ?? "Unknown error"),
926
+ details: parsed.details ?? parsed.reason ?? rawData,
927
+ };
928
+ }
929
+ const rawMessage = error.message;
930
+ if (typeof rawMessage === "string") {
931
+ try {
932
+ const parsed = JSON.parse(rawMessage);
933
+ if (parsed && typeof parsed === "object") {
934
+ return {
935
+ code: String(parsed.code ?? error.code ?? "UNKNOWN"),
936
+ message: String(parsed.message ?? rawMessage),
937
+ details: parsed.details ?? parsed.reason ?? error.data,
938
+ };
939
+ }
940
+ }
941
+ catch {
942
+ // Fall back to the outer JSON-RPC error payload.
943
+ }
944
+ }
945
+ return {
946
+ code: String(error.code ?? "UNKNOWN"),
947
+ message: String(rawMessage ?? "Unknown error"),
948
+ details: error.data,
949
+ };
950
+ }
705
951
  request(method, params) {
706
952
  if (!this.process?.stdin) {
707
953
  throw new MeerkatError("NOT_CONNECTED", "Client not connected");
@@ -829,7 +1075,7 @@ export class MeerkatClient {
829
1075
  : [];
830
1076
  return {
831
1077
  role: String(data.role ?? ""),
832
- content: data.content != null ? String(data.content) : undefined,
1078
+ content: data.content != null ? MeerkatClient.parseContentInput(data.content) : undefined,
833
1079
  toolCalls: rawToolCalls.map((toolCall) => ({
834
1080
  id: String(toolCall.id ?? ""),
835
1081
  name: String(toolCall.name ?? ""),
@@ -839,11 +1085,43 @@ export class MeerkatClient {
839
1085
  blocks: rawBlocks.map((block) => MeerkatClient.parseSessionAssistantBlock(block)),
840
1086
  results: rawResults.map((result) => ({
841
1087
  toolUseId: String(result.tool_use_id ?? ""),
842
- content: String(result.content ?? ""),
1088
+ content: MeerkatClient.parseContentInput(result.content),
843
1089
  isError: Boolean(result.is_error ?? false),
844
1090
  })),
845
1091
  };
846
1092
  }
1093
+ static parseContentInput(value) {
1094
+ if (Array.isArray(value)) {
1095
+ return value
1096
+ .filter((item) => typeof item === "object" && item !== null)
1097
+ .map((block) => MeerkatClient.parseContentBlock(block));
1098
+ }
1099
+ return String(value ?? "");
1100
+ }
1101
+ static parseContentBlock(data) {
1102
+ const type = String(data.type ?? "");
1103
+ if (type === "text") {
1104
+ return { type: "text", text: String(data.text ?? "") };
1105
+ }
1106
+ if (type === "image") {
1107
+ const source = String(data.source ?? "inline");
1108
+ if (source === "blob") {
1109
+ return {
1110
+ type: "image",
1111
+ media_type: String(data.media_type ?? ""),
1112
+ source: "blob",
1113
+ blob_id: String(data.blob_id ?? ""),
1114
+ };
1115
+ }
1116
+ return {
1117
+ type: "image",
1118
+ media_type: String(data.media_type ?? ""),
1119
+ source: "inline",
1120
+ data: String(data.data ?? ""),
1121
+ };
1122
+ }
1123
+ return { type: "text", text: "" };
1124
+ }
847
1125
  static parseSessionAssistantBlock(data) {
848
1126
  const blockData = data.data ?? {};
849
1127
  return {
@@ -928,32 +1206,30 @@ export class MeerkatClient {
928
1206
  params.system_prompt = options.systemPrompt;
929
1207
  if (options.maxTokens)
930
1208
  params.max_tokens = options.maxTokens;
931
- if (options.outputSchema)
1209
+ if (options.outputSchema != null)
932
1210
  params.output_schema = options.outputSchema;
933
- if (options.structuredOutputRetries != null && options.structuredOutputRetries !== 2) {
1211
+ if (options.structuredOutputRetries != null) {
934
1212
  params.structured_output_retries = options.structuredOutputRetries;
935
1213
  }
936
- if (options.hooksOverride)
1214
+ if (options.hooksOverride != null)
937
1215
  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;
1216
+ if (options.enableBuiltins != null)
1217
+ params.enable_builtins = options.enableBuiltins;
1218
+ if (options.enableShell != null)
1219
+ params.enable_shell = options.enableShell;
1220
+ if (options.enableMemory != null)
1221
+ params.enable_memory = options.enableMemory;
1222
+ if (options.enableMob != null)
1223
+ params.enable_mob = options.enableMob;
1224
+ if (options.keepAlive != null)
1225
+ params.keep_alive = options.keepAlive;
950
1226
  if (options.commsName)
951
1227
  params.comms_name = options.commsName;
952
1228
  if (options.peerMeta != null)
953
1229
  params.peer_meta = options.peerMeta;
954
1230
  if (options.budgetLimits != null)
955
1231
  params.budget_limits = options.budgetLimits;
956
- if (options.providerParams)
1232
+ if (options.providerParams != null)
957
1233
  params.provider_params = options.providerParams;
958
1234
  if (options.preloadSkills != null)
959
1235
  params.preload_skills = options.preloadSkills;
@@ -1024,7 +1300,8 @@ export class MeerkatClient {
1024
1300
  }
1025
1301
  static async runCommand(command, args) {
1026
1302
  return new Promise((resolve, reject) => {
1027
- const proc = spawn(command, args, { stdio: ["ignore", "inherit", "pipe"] });
1303
+ const options = { stdio: ["ignore", "inherit", "pipe"] };
1304
+ const proc = spawn(command, args, options);
1028
1305
  let stderr = "";
1029
1306
  proc.stderr?.on("data", (chunk) => { stderr += String(chunk); });
1030
1307
  proc.on("error", (error) => { reject(error); });