@rkat/sdk 0.4.5 → 0.4.7

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
@@ -31,8 +31,11 @@ import path from "node:path";
31
31
  import { createInterface } from "node:readline";
32
32
  import { MeerkatError, CapabilityUnavailableError } from "./generated/errors.js";
33
33
  import { CONTRACT_VERSION, } from "./generated/types.js";
34
- import { Session } from "./session.js";
35
- import { CommsEventStream, EventStream, AsyncQueue } from "./streaming.js";
34
+ import { DeferredSession, Session } from "./session.js";
35
+ import { Mob } from "./mob.js";
36
+ import { parseCoreEvent } from "./events.js";
37
+ import { EventStream, AsyncQueue } from "./streaming.js";
38
+ import { EventSubscription } from "./subscription.js";
36
39
  const MEERKAT_REPO = "lukacf/meerkat";
37
40
  const MEERKAT_RELEASE_BINARY = "rkat-rpc";
38
41
  const MEERKAT_BINARY_CACHE_ROOT = path.join(os.homedir(), ".cache", "meerkat", "bin", MEERKAT_RELEASE_BINARY);
@@ -63,17 +66,43 @@ export class MeerkatClient {
63
66
  process = null;
64
67
  requestId = 0;
65
68
  _capabilities = [];
69
+ _methods = new Set();
66
70
  rkatPath;
67
71
  pendingRequests = new Map();
68
72
  eventQueues = new Map();
69
- commsStreamQueues = new Map();
73
+ streamQueues = new Map();
70
74
  pendingStreamQueue = null;
71
75
  pendingStreamRequestId = null;
72
76
  unmatchedStreamBuffer = new Map();
77
+ unmatchedStandaloneStreamBuffer = new Map();
78
+ unmatchedStandaloneStreamEnd = new Map();
79
+ streamTerminalOutcomes = new Map();
73
80
  rl = null;
81
+ toolHandlers = new Map();
74
82
  constructor(rkatPath = "rkat-rpc") {
75
83
  this.rkatPath = rkatPath;
76
84
  }
85
+ /**
86
+ * Register a callback tool handler.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * client.registerTool("search", "Search the web", { type: "object" }, async (args) => {
91
+ * return `Results for ${args.q}`;
92
+ * });
93
+ * ```
94
+ */
95
+ registerTool(name, description, inputSchema, handler) {
96
+ this.toolHandlers.set(name, { description, inputSchema, handler });
97
+ // If already connected, register the new tool with the server immediately.
98
+ if (this.process?.stdin) {
99
+ this.request("tools/register", {
100
+ tools: [{ name, description, input_schema: inputSchema }],
101
+ }).catch(() => {
102
+ // Best-effort: tool registration may fail if connection is closing.
103
+ });
104
+ }
105
+ }
77
106
  // -- Connection ---------------------------------------------------------
78
107
  async connect(options) {
79
108
  if (options?.realmId && options?.isolated) {
@@ -96,6 +125,9 @@ export class MeerkatClient {
96
125
  if (!MeerkatClient.checkVersionCompatible(serverVersion, CONTRACT_VERSION)) {
97
126
  throw new MeerkatError("VERSION_MISMATCH", `Server version ${serverVersion} incompatible with SDK ${CONTRACT_VERSION}`);
98
127
  }
128
+ this._methods = new Set(Array.isArray(initResult.methods)
129
+ ? initResult.methods.map((method) => String(method))
130
+ : []);
99
131
  // Fetch capabilities
100
132
  const capsResult = await this.request("capabilities/get", {});
101
133
  const rawCaps = capsResult.capabilities ?? [];
@@ -104,6 +136,15 @@ export class MeerkatClient {
104
136
  description: String(cap.description ?? ""),
105
137
  status: MeerkatClient.normalizeStatus(cap.status),
106
138
  }));
139
+ // Register callback tools if any were declared.
140
+ if (this.toolHandlers.size > 0) {
141
+ const tools = Array.from(this.toolHandlers.entries()).map(([name, { description, inputSchema }]) => ({
142
+ name,
143
+ description,
144
+ input_schema: inputSchema,
145
+ }));
146
+ await this.request("tools/register", { tools });
147
+ }
107
148
  return this;
108
149
  }
109
150
  async close() {
@@ -123,10 +164,11 @@ export class MeerkatClient {
123
164
  queue.put(null);
124
165
  }
125
166
  this.eventQueues.clear();
126
- for (const [, queue] of this.commsStreamQueues) {
167
+ for (const [, queue] of this.streamQueues) {
127
168
  queue.put(null);
128
169
  }
129
- this.commsStreamQueues.clear();
170
+ this.streamQueues.clear();
171
+ this.streamTerminalOutcomes.clear();
130
172
  if (this.pendingStreamQueue) {
131
173
  this.pendingStreamQueue.put(null);
132
174
  this.pendingStreamQueue = null;
@@ -196,6 +238,18 @@ export class MeerkatClient {
196
238
  parseResult: MeerkatClient.parseRunResult,
197
239
  });
198
240
  }
241
+ /**
242
+ * Create a new session without running the first turn.
243
+ *
244
+ * Returns a {@link DeferredSession} whose `startTurn()` executes the first
245
+ * turn with optional per-turn overrides.
246
+ */
247
+ async createDeferredSession(prompt, options) {
248
+ const params = MeerkatClient.buildCreateParams(prompt, options);
249
+ params.initial_turn = "deferred";
250
+ const raw = await this.request("session/create", params);
251
+ return new DeferredSession(this, String(raw.session_id ?? ""), raw.session_ref != null ? String(raw.session_ref) : undefined);
252
+ }
199
253
  // -- Session queries ----------------------------------------------------
200
254
  async listSessions() {
201
255
  const result = await this.request("session/list", {});
@@ -213,11 +267,27 @@ export class MeerkatClient {
213
267
  async readSession(sessionId) {
214
268
  return this.request("session/read", { session_id: sessionId });
215
269
  }
270
+ async readSessionHistory(sessionId, options) {
271
+ const params = {
272
+ session_id: sessionId,
273
+ offset: options?.offset ?? 0,
274
+ };
275
+ if (options?.limit !== undefined) {
276
+ params.limit = options.limit;
277
+ }
278
+ const raw = await this.request("session/history", params);
279
+ return MeerkatClient.parseSessionHistory(raw);
280
+ }
216
281
  // -- Capabilities -------------------------------------------------------
217
282
  get capabilities() {
218
283
  return this._capabilities;
219
284
  }
220
285
  hasCapability(capabilityId) {
286
+ if (capabilityId === "mob") {
287
+ return (this._methods.has("mob/create")
288
+ || this._methods.has("mob/list")
289
+ || this._methods.has("mob/call"));
290
+ }
221
291
  return this._capabilities.some((c) => c.id === capabilityId && c.status === "Available");
222
292
  }
223
293
  requireCapability(capabilityId) {
@@ -294,6 +364,172 @@ export class MeerkatClient {
294
364
  arguments: argumentsPayload ?? {},
295
365
  });
296
366
  }
367
+ async subscribeSessionEvents(sessionId) {
368
+ return this.openEventSubscription("session/stream_open", { session_id: sessionId }, "session/stream_close", MeerkatClient.parseAgentEventEnvelope);
369
+ }
370
+ async createMob(options) {
371
+ this.requireCapability("mob");
372
+ const result = await this.request("mob/create", options);
373
+ return new Mob(this, String(result.mob_id ?? ""));
374
+ }
375
+ mob(mobId) {
376
+ return new Mob(this, mobId);
377
+ }
378
+ async listMobs() {
379
+ this.requireCapability("mob");
380
+ const result = await this.request("mob/list", {});
381
+ const mobs = result.mobs ?? [];
382
+ return mobs.map((mob) => ({
383
+ mobId: String(mob.mob_id ?? mob.mobId ?? ""),
384
+ status: String(mob.status ?? ""),
385
+ }));
386
+ }
387
+ async mobStatus(mobId) {
388
+ const result = await this.request("mob/status", { mob_id: mobId });
389
+ const rawStatus = result.status;
390
+ const status = typeof rawStatus === "string"
391
+ ? rawStatus
392
+ : (typeof rawStatus === "object" && rawStatus !== null
393
+ ? String(Object.keys(rawStatus)[0] ?? "unknown")
394
+ : String(rawStatus ?? "unknown"));
395
+ return { mobId: String(result.mob_id ?? mobId), status };
396
+ }
397
+ async listMobMembers(mobId) {
398
+ const result = await this.request("mob/members", { mob_id: mobId });
399
+ const members = result.members ?? [];
400
+ return members.map((member) => ({
401
+ meerkatId: String(member.meerkat_id ?? member.meerkatId ?? ""),
402
+ profile: String(member.profile_name ?? member.profile ?? ""),
403
+ memberRef: member.member_ref,
404
+ runtimeMode: member.runtime_mode != null ? String(member.runtime_mode) : undefined,
405
+ state: member.state != null ? String(member.state) : undefined,
406
+ wiredTo: Array.isArray(member.wired_to)
407
+ ? member.wired_to.map((peer) => String(peer))
408
+ : undefined,
409
+ labels: member.labels && typeof member.labels === 'object'
410
+ ? Object.fromEntries(Object.entries(member.labels).map(([key, value]) => [key, String(value)]))
411
+ : undefined,
412
+ sessionId: member.member_ref && typeof member.member_ref === 'object'
413
+ ? member.member_ref.session_id != null
414
+ ? String(member.member_ref.session_id)
415
+ : undefined
416
+ : undefined,
417
+ }));
418
+ }
419
+ async spawnMobMember(mobId, options) {
420
+ return this.request("mob/spawn", {
421
+ mob_id: mobId,
422
+ profile: options.profile,
423
+ meerkat_id: options.meerkatId,
424
+ initial_message: options.initialMessage,
425
+ runtime_mode: options.runtimeMode,
426
+ backend: options.backend,
427
+ resume_session_id: options.resumeSessionId,
428
+ labels: options.labels,
429
+ context: options.context,
430
+ additional_instructions: options.additionalInstructions,
431
+ });
432
+ }
433
+ async retireMobMember(mobId, meerkatId) {
434
+ await this.request("mob/retire", { mob_id: mobId, meerkat_id: meerkatId });
435
+ }
436
+ async respawnMobMember(mobId, meerkatId, initialMessage) {
437
+ await this.request("mob/respawn", { mob_id: mobId, meerkat_id: meerkatId, initial_message: initialMessage });
438
+ }
439
+ async wireMobMembers(mobId, a, b) {
440
+ await this.request("mob/wire", { mob_id: mobId, a, b });
441
+ }
442
+ async unwireMobMembers(mobId, a, b) {
443
+ await this.request("mob/unwire", { mob_id: mobId, a, b });
444
+ }
445
+ async mobLifecycle(mobId, action) {
446
+ await this.request("mob/lifecycle", { mob_id: mobId, action });
447
+ }
448
+ async sendMobMessage(mobId, meerkatId, message) {
449
+ await this.request("mob/send", { mob_id: mobId, meerkat_id: meerkatId, message });
450
+ }
451
+ async appendMobSystemContext(mobId, meerkatId, text, options) {
452
+ return this.request("mob/append_system_context", {
453
+ mob_id: mobId,
454
+ meerkat_id: meerkatId,
455
+ text,
456
+ source: options?.source,
457
+ idempotency_key: options?.idempotencyKey,
458
+ });
459
+ }
460
+ async listMobFlows(mobId) {
461
+ const result = await this.request("mob/flows", { mob_id: mobId });
462
+ return result.flows ?? [];
463
+ }
464
+ async runMobFlow(mobId, flowId, params = {}) {
465
+ const result = await this.request("mob/flow_run", { mob_id: mobId, flow_id: flowId, params });
466
+ return String(result.run_id ?? "");
467
+ }
468
+ async getMobFlowStatus(mobId, runId) {
469
+ const result = await this.request("mob/flow_status", { mob_id: mobId, run_id: runId });
470
+ return result.run == null ? null : { run: result.run };
471
+ }
472
+ async cancelMobFlow(mobId, runId) {
473
+ await this.request("mob/flow_cancel", { mob_id: mobId, run_id: runId });
474
+ }
475
+ async subscribeMobEvents(mobId) {
476
+ return this.openEventSubscription("mob/stream_open", { mob_id: mobId }, "mob/stream_close", MeerkatClient.parseAttributedMobEvent);
477
+ }
478
+ async subscribeMobMemberEvents(mobId, meerkatId) {
479
+ return this.openEventSubscription("mob/stream_open", { mob_id: mobId, member_id: meerkatId }, "mob/stream_close", MeerkatClient.parseAgentEventEnvelope);
480
+ }
481
+ async openEventSubscription(openMethod, params, closeMethod, parse) {
482
+ const result = this.process?.stdin
483
+ ? await (async () => {
484
+ this.requestId++;
485
+ const requestId = this.requestId;
486
+ const responsePromise = this.registerRequest(requestId);
487
+ const rpcRequest = { jsonrpc: "2.0", id: requestId, method: openMethod, params };
488
+ this.process.stdin.write(JSON.stringify(rpcRequest) + "\n");
489
+ return responsePromise;
490
+ })()
491
+ : await this.request(openMethod, params);
492
+ const streamId = String(result.stream_id ?? "");
493
+ if (!streamId) {
494
+ throw new MeerkatError("INVALID_RESPONSE", `${openMethod} did not return stream_id`);
495
+ }
496
+ const queue = new AsyncQueue();
497
+ this.streamQueues.set(streamId, queue);
498
+ const buffered = this.unmatchedStandaloneStreamBuffer.get(streamId) ?? [];
499
+ for (const event of buffered) {
500
+ queue.put(event);
501
+ }
502
+ this.unmatchedStandaloneStreamBuffer.delete(streamId);
503
+ if (this.unmatchedStandaloneStreamEnd.delete(streamId)) {
504
+ queue.put(null);
505
+ }
506
+ return new EventSubscription({
507
+ streamId,
508
+ queue,
509
+ closeRemote: async (id) => {
510
+ this.streamQueues.delete(id);
511
+ await this.request(closeMethod, { stream_id: id });
512
+ },
513
+ parseEvent: parse,
514
+ getTerminalOutcome: () => this.streamTerminalOutcomes.get(streamId),
515
+ });
516
+ }
517
+ static parseAgentEventEnvelope(raw) {
518
+ return {
519
+ eventId: String(raw.event_id ?? raw.eventId ?? ""),
520
+ sourceId: String(raw.source_id ?? raw.sourceId ?? ""),
521
+ seq: Number(raw.seq ?? 0),
522
+ timestampMs: Number(raw.timestamp_ms ?? raw.timestampMs ?? 0),
523
+ payload: parseCoreEvent((raw.payload ?? {})),
524
+ };
525
+ }
526
+ static parseAttributedMobEvent(raw) {
527
+ return {
528
+ source: String(raw.source ?? ""),
529
+ profile: String(raw.profile ?? ""),
530
+ envelope: MeerkatClient.parseAgentEventEnvelope((raw.envelope ?? {})),
531
+ };
532
+ }
297
533
  // -- Internal methods used by Session -----------------------------------
298
534
  /** @internal */
299
535
  async _startTurn(sessionId, prompt, options) {
@@ -311,6 +547,23 @@ export class MeerkatClient {
311
547
  blocked_tools: options.flowToolOverlay.blockedTools,
312
548
  };
313
549
  }
550
+ if (options?.hostMode != null)
551
+ params.host_mode = options.hostMode;
552
+ if (options?.model)
553
+ params.model = options.model;
554
+ if (options?.provider)
555
+ params.provider = options.provider;
556
+ if (options?.maxTokens)
557
+ params.max_tokens = options.maxTokens;
558
+ if (options?.systemPrompt)
559
+ params.system_prompt = options.systemPrompt;
560
+ if (options?.outputSchema)
561
+ params.output_schema = options.outputSchema;
562
+ if (options?.structuredOutputRetries != null) {
563
+ params.structured_output_retries = options.structuredOutputRetries;
564
+ }
565
+ if (options?.providerParams)
566
+ params.provider_params = options.providerParams;
314
567
  const raw = await this.request("turn/start", params);
315
568
  return MeerkatClient.parseRunResult(raw);
316
569
  }
@@ -370,54 +623,6 @@ export class MeerkatClient {
370
623
  async peers(sessionId) {
371
624
  return this.request("comms/peers", { session_id: sessionId });
372
625
  }
373
- async openCommsStream(sessionId, options) {
374
- const scope = options?.scope ?? "session";
375
- const params = { session_id: sessionId, scope };
376
- if (options?.interactionId) {
377
- params.interaction_id = options.interactionId;
378
- }
379
- const opened = await this.request("comms/stream_open", params);
380
- const streamId = String(opened.stream_id ?? "");
381
- if (!streamId) {
382
- throw new MeerkatError("INVALID_RESPONSE", "Missing stream_id in comms/stream_open response");
383
- }
384
- const queue = new AsyncQueue();
385
- this.commsStreamQueues.set(streamId, queue);
386
- return new CommsEventStream({
387
- streamId,
388
- eventQueue: queue,
389
- onClose: async (id) => {
390
- await this.request("comms/stream_close", { stream_id: id });
391
- const q = this.commsStreamQueues.get(id);
392
- if (q) {
393
- q.put(null);
394
- }
395
- this.commsStreamQueues.delete(id);
396
- },
397
- });
398
- }
399
- async open_comms_stream(sessionId, options) {
400
- return this.openCommsStream(sessionId, options);
401
- }
402
- async sendAndStream(sessionId, command) {
403
- const receipt = await this.send(sessionId, command);
404
- const interactionId = String(receipt.interaction_id ?? "");
405
- const streamReserved = Boolean(receipt.stream_reserved ?? false);
406
- if (!interactionId) {
407
- throw new MeerkatError("INVALID_RESPONSE", "comms/send response missing interaction_id for sendAndStream");
408
- }
409
- if (!streamReserved) {
410
- throw new MeerkatError("INVALID_RESPONSE", "comms/send response did not reserve stream for sendAndStream");
411
- }
412
- const stream = await this.openCommsStream(sessionId, {
413
- scope: "interaction",
414
- interactionId,
415
- });
416
- return { receipt, stream };
417
- }
418
- async send_and_stream(sessionId, command) {
419
- return this.sendAndStream(sessionId, command);
420
- }
421
626
  // -- Transport ----------------------------------------------------------
422
627
  handleLine(line) {
423
628
  let data;
@@ -427,6 +632,11 @@ export class MeerkatClient {
427
632
  catch {
428
633
  return;
429
634
  }
635
+ // Server→client callback request (has both id and method).
636
+ if ("id" in data && "method" in data) {
637
+ this.handleCallbackRequest(data);
638
+ return;
639
+ }
430
640
  if ("id" in data && typeof data.id === "number") {
431
641
  const pending = this.pendingRequests.get(data.id);
432
642
  if (pending) {
@@ -441,16 +651,42 @@ export class MeerkatClient {
441
651
  }
442
652
  }
443
653
  else if ("method" in data) {
444
- if (data.method === "comms/stream_event") {
445
- const params = (data.params ?? {});
654
+ const method = String(data.method ?? "");
655
+ const params = (data.params ?? {});
656
+ if (method === "session/stream_event" || method === "mob/stream_event") {
657
+ const streamId = String(params.stream_id ?? "");
658
+ const queue = this.streamQueues.get(streamId);
659
+ const rawEvent = (params.event ?? params);
660
+ // Preserve scope fields when present (sub-agent / mob-member scoped events).
661
+ const scopeId = params.scope_id;
662
+ const scopePath = params.scope_path;
663
+ const event = scopeId != null || scopePath != null
664
+ ? { event: rawEvent, scope_id: scopeId, scope_path: scopePath }
665
+ : rawEvent;
666
+ if (queue && event) {
667
+ queue.put(event);
668
+ }
669
+ else if (streamId && event) {
670
+ const buffered = this.unmatchedStandaloneStreamBuffer.get(streamId) ?? [];
671
+ buffered.push(event);
672
+ this.unmatchedStandaloneStreamBuffer.set(streamId, buffered);
673
+ }
674
+ return;
675
+ }
676
+ if (method === "session/stream_end" || method === "mob/stream_end") {
446
677
  const streamId = String(params.stream_id ?? "");
447
- const queue = this.commsStreamQueues.get(streamId);
678
+ if (streamId) {
679
+ this.streamTerminalOutcomes.set(streamId, params);
680
+ }
681
+ const queue = this.streamQueues.get(streamId);
448
682
  if (queue) {
449
- queue.put(params);
683
+ queue.put(null);
684
+ }
685
+ else if (streamId) {
686
+ this.unmatchedStandaloneStreamEnd.set(streamId, params);
450
687
  }
451
688
  return;
452
689
  }
453
- const params = (data.params ?? {});
454
690
  const sessionId = String(params.session_id ?? "");
455
691
  const event = params.event;
456
692
  if (event) {
@@ -567,6 +803,58 @@ export class MeerkatClient {
567
803
  skillDiagnostics: MeerkatClient.parseSkillDiagnostics(data.skill_diagnostics),
568
804
  };
569
805
  }
806
+ static parseSessionHistory(data) {
807
+ const rawMessages = Array.isArray(data.messages)
808
+ ? data.messages
809
+ : [];
810
+ return {
811
+ sessionId: String(data.session_id ?? ""),
812
+ sessionRef: data.session_ref != null ? String(data.session_ref) : undefined,
813
+ messageCount: Number(data.message_count ?? 0),
814
+ offset: Number(data.offset ?? 0),
815
+ limit: data.limit != null ? Number(data.limit) : undefined,
816
+ hasMore: Boolean(data.has_more ?? false),
817
+ messages: rawMessages.map((message) => MeerkatClient.parseSessionMessage(message)),
818
+ };
819
+ }
820
+ static parseSessionMessage(data) {
821
+ const rawToolCalls = Array.isArray(data.tool_calls)
822
+ ? data.tool_calls
823
+ : [];
824
+ const rawBlocks = Array.isArray(data.blocks)
825
+ ? data.blocks
826
+ : [];
827
+ const rawResults = Array.isArray(data.results)
828
+ ? data.results
829
+ : [];
830
+ return {
831
+ role: String(data.role ?? ""),
832
+ content: data.content != null ? String(data.content) : undefined,
833
+ toolCalls: rawToolCalls.map((toolCall) => ({
834
+ id: String(toolCall.id ?? ""),
835
+ name: String(toolCall.name ?? ""),
836
+ args: toolCall.args,
837
+ })),
838
+ stopReason: data.stop_reason != null ? String(data.stop_reason) : undefined,
839
+ blocks: rawBlocks.map((block) => MeerkatClient.parseSessionAssistantBlock(block)),
840
+ results: rawResults.map((result) => ({
841
+ toolUseId: String(result.tool_use_id ?? ""),
842
+ content: String(result.content ?? ""),
843
+ isError: Boolean(result.is_error ?? false),
844
+ })),
845
+ };
846
+ }
847
+ static parseSessionAssistantBlock(data) {
848
+ const blockData = data.data ?? {};
849
+ return {
850
+ blockType: String(data.block_type ?? ""),
851
+ text: blockData.text != null ? String(blockData.text) : undefined,
852
+ id: blockData.id != null ? String(blockData.id) : undefined,
853
+ name: blockData.name != null ? String(blockData.name) : undefined,
854
+ args: blockData.args,
855
+ meta: blockData.meta,
856
+ };
857
+ }
570
858
  static parseMcpLiveOpResponse(raw) {
571
859
  const sessionId = raw.session_id;
572
860
  const operation = raw.operation;
@@ -586,6 +874,48 @@ export class MeerkatClient {
586
874
  }
587
875
  return raw;
588
876
  }
877
+ handleCallbackRequest(data) {
878
+ const requestId = data.id;
879
+ const method = String(data.method ?? "");
880
+ const params = (data.params ?? {});
881
+ if (method === "tool/execute") {
882
+ const toolName = String(params.name ?? "");
883
+ const handler = this.toolHandlers.get(toolName);
884
+ if (handler) {
885
+ const args = (params.arguments ?? {});
886
+ handler
887
+ .handler(args)
888
+ .then((content) => {
889
+ this.writeCallbackResponse(requestId, { content, is_error: false });
890
+ })
891
+ .catch((err) => {
892
+ this.writeCallbackResponse(requestId, {
893
+ content: `Tool error: ${err}`,
894
+ is_error: true,
895
+ });
896
+ });
897
+ }
898
+ else {
899
+ this.writeCallbackResponse(requestId, {
900
+ content: `Unknown tool: ${toolName}`,
901
+ is_error: true,
902
+ });
903
+ }
904
+ }
905
+ else {
906
+ // Unknown callback method.
907
+ const response = {
908
+ jsonrpc: "2.0",
909
+ id: requestId,
910
+ error: { code: -32601, message: `Method not supported: ${method}` },
911
+ };
912
+ this.process?.stdin?.write(JSON.stringify(response) + "\n");
913
+ }
914
+ }
915
+ writeCallbackResponse(requestId, result) {
916
+ const response = { jsonrpc: "2.0", id: requestId, result };
917
+ this.process?.stdin?.write(JSON.stringify(response) + "\n");
918
+ }
589
919
  static buildCreateParams(prompt, options) {
590
920
  const params = { prompt };
591
921
  if (!options)