@narumitw/pi-subagents 3.0.1 → 3.1.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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/attachment-utils.ts"],
4
+ "sourcesContent": ["import { createHash } from \"node:crypto\";\nimport { realpathSync } from \"node:fs\";\nimport { readFile, stat } from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport type ignore from \"ignore\";\nimport { sanitizeTerminalText } from \"./message-broker.js\";\n\nconst ATTACHMENT_IGNORE_FILE_NAMES = [\".gitignore\", \".ignore\", \".fdignore\"];\n\nexport type IgnoreMatcher = ReturnType<typeof ignore>;\n\nfunction throwInvalidAttachmentIgnoreFile(): never {\n throw new Error(\"Subagent attachment ignore files must be regular files.\");\n}\n\nexport function throwIfAttachmentAborted(signal: AbortSignal | undefined): void {\n if (!signal?.aborted) return;\n const error = new Error(\"Subagent attachment validation was cancelled.\");\n error.name = \"AbortError\";\n throw error;\n}\n\nexport function isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n\nfunction prefixIgnorePattern(line: string, prefix: string): string | null {\n const trimmed = line.trim();\n if (!trimmed || (trimmed.startsWith(\"#\") && !trimmed.startsWith(\"\\\\#\"))) return null;\n let pattern = line;\n let negated = false;\n if (pattern.startsWith(\"!\")) {\n negated = true;\n pattern = pattern.slice(1);\n } else if (pattern.startsWith(\"\\\\!\")) {\n pattern = pattern.slice(1);\n }\n if (pattern.startsWith(\"/\")) pattern = pattern.slice(1);\n const prefixed = prefix ? `${prefix}${pattern}` : pattern;\n return negated ? `!${prefixed}` : prefixed;\n}\n\nexport async function addAttachmentIgnoreRules(\n ignoreMatcher: IgnoreMatcher,\n directory: string,\n rootDirectory: string,\n signal: AbortSignal | undefined,\n accountForFile: (ignorePath: string, bytes: number) => void,\n): Promise<void> {\n const relativeDirectory = path.relative(rootDirectory, directory);\n const prefix = relativeDirectory ? `${toPosixPath(relativeDirectory)}/` : \"\";\n for (const filename of ATTACHMENT_IGNORE_FILE_NAMES) {\n throwIfAttachmentAborted(signal);\n const ignorePath = path.join(directory, filename);\n let ignoreStats: Awaited<ReturnType<typeof stat>>;\n try {\n ignoreStats = await stat(ignorePath);\n } catch (error) {\n if (isAbortError(error)) throw error;\n throwIfAttachmentAborted(signal);\n continue;\n }\n if (!ignoreStats.isFile()) throwInvalidAttachmentIgnoreFile();\n accountForFile(ignorePath, ignoreStats.size);\n try {\n const content = await readFile(ignorePath, { encoding: \"utf8\", signal });\n throwIfAttachmentAborted(signal);\n const patterns = content\n .split(/\\r?\\n/u)\n .map((line) => prefixIgnorePattern(line, prefix))\n .filter((line): line is string => line !== null);\n if (patterns.length > 0) ignoreMatcher.add(patterns);\n } catch (error) {\n if (isAbortError(error)) throw error;\n throwIfAttachmentAborted(signal);\n // Pi ignores unreadable ignore files.\n }\n }\n}\n\nexport function toPosixPath(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n\nexport function toolSourceId(value: string): string {\n return createHash(\"sha256\").update(value).digest(\"hex\");\n}\n\nexport function realpath(value: string, label: string): string {\n try {\n return realpathSync(value);\n } catch {\n throw new Error(`${label} path does not exist: ${sanitizeTerminalText(value).slice(0, 512)}`);\n }\n}\n\nexport function isWithin(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === \"\" || (!relative.startsWith(`..${path.sep}`) && relative !== \"..\" && !path.isAbsolute(relative));\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["relative"]
7
+ }
@@ -129,9 +129,7 @@ var MessageBroker = class {
129
129
  }
130
130
  }
131
131
  hasPendingMainRequest() {
132
- return [...this.requests.values()].some(
133
- (request) => request.origin === "child" && request.response === void 0
134
- );
132
+ return [...this.requests.values()].some((request) => request.origin === "child" && request.response === void 0);
135
133
  }
136
134
  takePendingInboundResponse() {
137
135
  const pending = this.pendingInboundResponse;
@@ -198,9 +196,7 @@ var MessageBroker = class {
198
196
  (request2) => request2.jobId === job.jobId && request2.consumedAt === void 0
199
197
  ).length;
200
198
  if (outstanding >= MAX_OUTSTANDING_REQUESTS) {
201
- throw new Error(
202
- `Subagent job may have at most ${MAX_OUTSTANDING_REQUESTS} outstanding requests.`
203
- );
199
+ throw new Error(`Subagent job may have at most ${MAX_OUTSTANDING_REQUESTS} outstanding requests.`);
204
200
  }
205
201
  const request = {
206
202
  requestId: `req_${randomUUID()}`,
@@ -374,11 +370,7 @@ var MessageBroker = class {
374
370
  return;
375
371
  }
376
372
  if (record.response !== void 0) {
377
- this.respond(
378
- socket,
379
- { ok: true, response: record.response },
380
- () => this.markConsumed(record)
381
- );
373
+ this.respond(socket, { ok: true, response: record.response }, () => this.markConsumed(record));
382
374
  return;
383
375
  }
384
376
  if (this.hasQueuedRequestForChild(job.jobId)) {
@@ -402,13 +394,8 @@ var MessageBroker = class {
402
394
  markConsumed(request) {
403
395
  if (this.requests.get(request.requestId) !== request || request.response === void 0) return;
404
396
  request.consumedAt ??= this.now();
405
- const consumed = [...this.requests.values()].filter(
406
- (candidate) => candidate.jobId === request.jobId && candidate.consumedAt !== void 0
407
- ).sort((left, right) => (left.consumedAt ?? 0) - (right.consumedAt ?? 0));
408
- for (const expired of consumed.slice(
409
- 0,
410
- Math.max(0, consumed.length - MAX_RETAINED_CONSUMED_REQUESTS)
411
- )) {
397
+ const consumed = [...this.requests.values()].filter((candidate) => candidate.jobId === request.jobId && candidate.consumedAt !== void 0).sort((left, right) => (left.consumedAt ?? 0) - (right.consumedAt ?? 0));
398
+ for (const expired of consumed.slice(0, Math.max(0, consumed.length - MAX_RETAINED_CONSUMED_REQUESTS))) {
412
399
  this.requests.delete(expired.requestId);
413
400
  }
414
401
  }
@@ -489,41 +476,83 @@ function isLoopbackAddress(address) {
489
476
  import * as fs from "node:fs";
490
477
  var BROKER_CREDENTIAL_FD = 3;
491
478
  var BROKER_CREDENTIAL_FD_ENV = "PI_SUBAGENT_BROKER_FD";
492
- var MAX_CREDENTIAL_BYTES = 1024;
493
- function brokerCredentialEnvironment() {
494
- return { [BROKER_CREDENTIAL_FD_ENV]: String(BROKER_CREDENTIAL_FD) };
479
+ var CHILD_READINESS_FD = 4;
480
+ var CHILD_READINESS_FD_ENV = "PI_SUBAGENT_READINESS_FD";
481
+ var MAX_READINESS_FRAME_BYTES = 16 * 1024;
482
+ var MAX_BOOTSTRAP_BYTES = 16 * 1024;
483
+ var MAX_EXPECTED_TOOLS = 66;
484
+ var MAX_TOOL_NAME_LENGTH = 128;
485
+ var READINESS_STATE_KEY = /* @__PURE__ */ Symbol.for("@narumitw/pi-subagents/child-readiness");
486
+ function childBootstrapEnvironment(expectReadiness) {
487
+ return {
488
+ [BROKER_CREDENTIAL_FD_ENV]: String(BROKER_CREDENTIAL_FD),
489
+ ...expectReadiness ? { [CHILD_READINESS_FD_ENV]: String(CHILD_READINESS_FD) } : {}
490
+ };
495
491
  }
496
- function serializeBrokerCredentials(credentials) {
497
- return JSON.stringify(credentials);
492
+ function serializeChildBootstrap(bootstrap) {
493
+ return JSON.stringify(bootstrap);
498
494
  }
499
- function captureBrokerCredentials(readCredentials = readCredentialPipe) {
500
- const descriptor = process.env[BROKER_CREDENTIAL_FD_ENV];
495
+ function assertChildBootstrapCapacity(expectedTools) {
496
+ const serialized = serializeChildBootstrap({
497
+ communication: { host: "127.0.0.1", port: 65535, token: "f".repeat(64) },
498
+ expectedTools
499
+ });
500
+ if (Buffer.byteLength(serialized, "utf8") > MAX_BOOTSTRAP_BYTES) {
501
+ throw new Error(`Subagent selected tool names exceed the ${MAX_BOOTSTRAP_BYTES}-byte child bootstrap size limit.`);
502
+ }
503
+ }
504
+ function captureChildBootstrap(readBootstrap = readBootstrapPipe) {
505
+ const credentialDescriptor = process.env[BROKER_CREDENTIAL_FD_ENV];
506
+ const readinessDescriptor = process.env[CHILD_READINESS_FD_ENV];
501
507
  delete process.env[BROKER_CREDENTIAL_FD_ENV];
502
- if (descriptor === void 0) return void 0;
503
- if (descriptor !== String(BROKER_CREDENTIAL_FD)) {
508
+ delete process.env[CHILD_READINESS_FD_ENV];
509
+ setCapturedReadiness(void 0);
510
+ if (credentialDescriptor === void 0) {
511
+ if (readinessDescriptor !== void 0) throw new Error("Unexpected pi-subagents readiness descriptor.");
512
+ return void 0;
513
+ }
514
+ if (credentialDescriptor !== String(BROKER_CREDENTIAL_FD)) {
504
515
  throw new Error("Invalid pi-subagents broker credential descriptor.");
505
516
  }
506
517
  let serialized;
507
518
  try {
508
- serialized = readCredentials();
519
+ serialized = readBootstrap();
509
520
  } catch {
510
- throw new Error("Unable to read pi-subagents broker credentials.");
521
+ throw new Error("Unable to read pi-subagents child bootstrap.");
511
522
  }
512
- if (Buffer.byteLength(serialized, "utf8") > MAX_CREDENTIAL_BYTES) {
513
- throw new Error("Invalid pi-subagents broker credentials.");
523
+ if (Buffer.byteLength(serialized, "utf8") > MAX_BOOTSTRAP_BYTES) {
524
+ throw new Error("Invalid pi-subagents child bootstrap.");
514
525
  }
515
526
  let value;
516
527
  try {
517
528
  value = JSON.parse(serialized);
518
529
  } catch {
519
- throw new Error("Invalid pi-subagents broker credentials.");
530
+ throw new Error("Invalid pi-subagents child bootstrap.");
520
531
  }
521
- if (!isBrokerCredentials(value)) {
522
- throw new Error("Invalid pi-subagents broker credentials.");
532
+ if (!isChildBootstrap(value)) throw new Error("Invalid pi-subagents child bootstrap.");
533
+ if (value.expectedTools.length > 0) {
534
+ if (readinessDescriptor !== String(CHILD_READINESS_FD)) {
535
+ throw new Error("Invalid pi-subagents readiness descriptor.");
536
+ }
537
+ setCapturedReadiness({ fd: CHILD_READINESS_FD, expectedTools: [...value.expectedTools] });
538
+ return { ...value, readinessFd: CHILD_READINESS_FD };
523
539
  }
540
+ if (readinessDescriptor !== void 0) throw new Error("Unexpected pi-subagents readiness descriptor.");
541
+ setCapturedReadiness(void 0);
524
542
  return value;
525
543
  }
526
- function readCredentialPipe() {
544
+ function takeCapturedReadiness() {
545
+ const store = globalThis;
546
+ const readiness = store[READINESS_STATE_KEY];
547
+ delete store[READINESS_STATE_KEY];
548
+ return readiness ? { fd: readiness.fd, expectedTools: [...readiness.expectedTools] } : void 0;
549
+ }
550
+ function setCapturedReadiness(readiness) {
551
+ const store = globalThis;
552
+ if (readiness) store[READINESS_STATE_KEY] = readiness;
553
+ else delete store[READINESS_STATE_KEY];
554
+ }
555
+ function readBootstrapPipe() {
527
556
  try {
528
557
  return fs.readFileSync(BROKER_CREDENTIAL_FD, "utf8");
529
558
  } finally {
@@ -533,121 +562,26 @@ function readCredentialPipe() {
533
562
  }
534
563
  }
535
564
  }
536
- function isBrokerCredentials(value) {
537
- if (!value || typeof value !== "object" || Array.isArray(value)) return false;
538
- const candidate = value;
539
- return Object.keys(candidate).length === 3 && candidate.host === "127.0.0.1" && Number.isSafeInteger(candidate.port) && candidate.port >= 1 && candidate.port <= 65535 && typeof candidate.token === "string" && /^[a-f0-9]{64}$/u.test(candidate.token);
565
+ function isChildBootstrap(value) {
566
+ if (!isRecord2(value) || Object.keys(value).length !== 2) return false;
567
+ if (!isBrokerCredentials(value.communication)) return false;
568
+ if (!Array.isArray(value.expectedTools) || value.expectedTools.length > MAX_EXPECTED_TOOLS) return false;
569
+ return value.expectedTools.every(
570
+ (tool) => typeof tool === "string" && tool.length > 0 && tool.length <= MAX_TOOL_NAME_LENGTH && !tool.includes(",") && !hasControlCharacter(tool)
571
+ );
540
572
  }
541
-
542
- // src/child-communication-tools.ts
543
- import { Type } from "typebox";
544
- var CHILD_COMMUNICATION_TOOL_NAMES = ["subagent_send", "subagent_wait"];
545
- var MAX_TIMEOUT_MS2 = 2147483647;
546
- var MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS2 / 1e3;
547
- var SendParameters = Type.Object(
548
- {
549
- requestId: Type.Optional(
550
- Type.String({
551
- description: "Pending main-agent request to answer. Omit when starting a new request.",
552
- minLength: 1,
553
- maxLength: MAX_IDENTIFIER_LENGTH
554
- })
555
- ),
556
- message: Type.String({
557
- description: "Plain-text request or response. Maximum 48 KiB of UTF-8 text and 1,992 lines.",
558
- minLength: 1,
559
- maxLength: MAX_MESSAGE_BYTES
560
- })
561
- },
562
- { additionalProperties: false }
563
- );
564
- var WaitParameters = Type.Object(
565
- {
566
- requestId: Type.String({
567
- description: "Request ID returned by subagent_send.",
568
- minLength: 1,
569
- maxLength: MAX_IDENTIFIER_LENGTH
570
- }),
571
- timeout: Type.Optional(
572
- Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })
573
- )
574
- },
575
- { additionalProperties: false }
576
- );
577
- function createChildCommunicationExtension(client) {
578
- return (pi) => {
579
- pi.registerTool({
580
- name: "subagent_send",
581
- label: "Subagent \xB7 Send to Main",
582
- description: "Use subagent_send to send one request to the main agent or answer one pending main-agent request. Omit requestId to start a request. Provide requestId to answer that request.",
583
- promptSnippet: "Use subagent_send to send or answer one main-agent message",
584
- parameters: SendParameters,
585
- async execute(_toolCallId, params, signal) {
586
- validateMessage(params.message, "Subagent message");
587
- const requestId = optionalIdentifier(params.requestId, "requestId");
588
- const acknowledgement = await client.send(
589
- requestId === void 0 ? { recipient: "main", message: params.message } : { requestId, message: params.message },
590
- signal
591
- );
592
- return {
593
- content: [{ type: "text", text: JSON.stringify(acknowledgement) }],
594
- details: acknowledgement
595
- };
596
- }
597
- });
598
- pi.registerTool({
599
- name: "subagent_wait",
600
- label: "Subagent \xB7 Wait for Main Agent",
601
- description: "Use subagent_wait with a request ID from subagent_send to wait for the main agent's plain-text response. A timeout, caller cancellation, or incoming main-agent request stops only this wait and does not cancel the original request. Retry the wait when its response is still needed.",
602
- promptSnippet: "Use subagent_wait to receive a requested main-agent response",
603
- parameters: WaitParameters,
604
- prepareArguments: prepareWaitArguments,
605
- async execute(_toolCallId, params, signal) {
606
- const requestId = requiredIdentifier(params.requestId, "requestId");
607
- const response = await client.wait(requestId, resolveTimeoutMs(params.timeout), signal);
608
- return {
609
- content: [{ type: "text", text: sanitizeTerminalText(response) }],
610
- details: { requestId }
611
- };
612
- }
613
- });
614
- };
615
- }
616
- function resolveTimeoutMs(timeout) {
617
- if (timeout === void 0) return void 0;
618
- if (!Number.isFinite(timeout) || timeout <= 0) {
619
- throw new Error("Invalid timeout: must be a finite number of seconds");
620
- }
621
- const timeoutMs = timeout * 1e3;
622
- if (timeoutMs > MAX_TIMEOUT_MS2) {
623
- throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);
624
- }
625
- return timeoutMs;
626
- }
627
- function prepareWaitArguments(args) {
628
- if (!args || typeof args !== "object") return args;
629
- if (!Object.hasOwn(args, "timeoutMs")) return args;
630
- const record = args;
631
- if (typeof record.timeoutMs !== "number") return record;
632
- const { timeoutMs, ...prepared } = record;
633
- if (prepared.timeout === void 0) {
634
- return { ...prepared, timeout: timeoutMs / 1e3 };
635
- }
636
- return prepared;
637
- }
638
- function optionalIdentifier(value, field) {
639
- return value === void 0 ? void 0 : requiredIdentifier(value, field);
573
+ function isBrokerCredentials(value) {
574
+ if (!isRecord2(value) || Object.keys(value).length !== 3) return false;
575
+ return value.host === "127.0.0.1" && Number.isSafeInteger(value.port) && value.port >= 1 && value.port <= 65535 && typeof value.token === "string" && /^[a-f0-9]{64}$/u.test(value.token);
640
576
  }
641
- function requiredIdentifier(value, field) {
642
- if (typeof value !== "string" || !value.trim()) throw new Error(`Subagent ${field} is required.`);
643
- const identifier = value.trim();
644
- if (identifier.length > MAX_IDENTIFIER_LENGTH || [...identifier].some((character) => {
577
+ function hasControlCharacter(value) {
578
+ return [...value].some((character) => {
645
579
  const codePoint = character.codePointAt(0) ?? 0;
646
580
  return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
647
- })) {
648
- throw new Error(`Subagent ${field} is invalid.`);
649
- }
650
- return identifier;
581
+ });
582
+ }
583
+ function isRecord2(value) {
584
+ return typeof value === "object" && value !== null && !Array.isArray(value);
651
585
  }
652
586
 
653
587
  export {
@@ -658,10 +592,13 @@ export {
658
592
  validateMessage,
659
593
  sanitizeTerminalText,
660
594
  BROKER_CREDENTIAL_FD,
661
- brokerCredentialEnvironment,
662
- serializeBrokerCredentials,
663
- captureBrokerCredentials,
664
- CHILD_COMMUNICATION_TOOL_NAMES,
665
- createChildCommunicationExtension
595
+ CHILD_READINESS_FD,
596
+ CHILD_READINESS_FD_ENV,
597
+ MAX_READINESS_FRAME_BYTES,
598
+ childBootstrapEnvironment,
599
+ serializeChildBootstrap,
600
+ assertChildBootstrapCapacity,
601
+ captureChildBootstrap,
602
+ takeCapturedReadiness
666
603
  };
667
- //# sourceMappingURL=chunk-UKTWUQRM.js.map
604
+ //# sourceMappingURL=chunk-YMVSJ5GE.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/message-broker.ts", "../../src/broker-credentials.ts"],
4
+ "sourcesContent": ["import { randomBytes, randomUUID } from \"node:crypto\";\nimport net, { type AddressInfo, type Server, type Socket } from \"node:net\";\nimport type { BrokerCredentials } from \"./types.js\";\n\nexport const BROKER_HOST = \"127.0.0.1\" as const;\nexport const MAX_MESSAGE_BYTES = 48 * 1024;\nexport const MAX_MESSAGE_LINES = 1_992;\nexport const MAX_FRAME_BYTES = 384 * 1024;\nexport const MAX_ERROR_BYTES = 8 * 1024;\nexport const MAX_OUTSTANDING_REQUESTS = 4;\nexport const MAX_IDENTIFIER_LENGTH = 128;\n\nconst MAX_CONNECTIONS = 32;\nconst REQUEST_FRAME_TIMEOUT_MS = 2_000;\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_RETAINED_CONSUMED_REQUESTS = 4;\nconst CHILD_WAIT_INTERRUPTED_ERROR =\n \"Subagent wait was interrupted by an incoming main-agent request. The original request remains active.\";\n\nexport type BrokerRequestOrigin = \"main\" | \"child\";\n\nexport interface BrokerInboundMessage {\n kind: \"request\" | \"response\";\n requestId: string;\n jobId: string;\n message: string;\n}\n\nexport interface BrokerSendAcknowledgement {\n requestId: string;\n accepted: boolean;\n duplicate: boolean;\n}\n\nexport interface MessageBrokerOptions {\n onMessage(message: BrokerInboundMessage): void;\n createServer?: (listener: (socket: Socket) => void) => Server;\n now?: () => number;\n requestFrameTimeoutMs?: number;\n}\n\ninterface JobRecord {\n jobId: string;\n generation: number;\n token: string;\n}\n\ninterface RequestWaiter {\n socket: Socket;\n timer?: NodeJS.Timeout;\n}\n\ninterface RequestRecord {\n requestId: string;\n jobId: string;\n generation: number;\n origin: BrokerRequestOrigin;\n expectedResponder: BrokerRequestOrigin;\n message: string;\n createdAt: number;\n response?: string;\n consumedAt?: number;\n deliveryQueued?: boolean;\n waiter?: RequestWaiter;\n}\n\ntype BrokerRequest =\n | {\n type: \"send\";\n token: string;\n recipient?: string;\n requestId?: string;\n message: string;\n }\n | { type: \"wait\"; token: string; requestId: string; timeoutMs?: number };\n\n/** Session-scoped authenticated loopback transport for bidirectional requests and responses. */\nexport class MessageBroker {\n private server?: Server;\n private starting?: Promise<void>;\n private address?: { host: typeof BROKER_HOST; port: number };\n private failure?: string;\n private generation = 0;\n private readonly sockets = new Set<Socket>();\n private readonly jobsByToken = new Map<string, JobRecord>();\n private readonly tokenByJob = new Map<string, string>();\n private readonly requests = new Map<string, RequestRecord>();\n private readonly inboundMessageListeners = new Set<() => void>();\n private pendingInboundResponse = false;\n private readonly createServer: (listener: (socket: Socket) => void) => Server;\n private readonly now: () => number;\n private readonly requestFrameTimeoutMs: number;\n\n constructor(private readonly options: MessageBrokerOptions) {\n this.createServer = options.createServer ?? ((listener) => net.createServer(listener));\n this.now = options.now ?? Date.now;\n this.requestFrameTimeoutMs = options.requestFrameTimeoutMs ?? REQUEST_FRAME_TIMEOUT_MS;\n if (!Number.isFinite(this.requestFrameTimeoutMs) || this.requestFrameTimeoutMs <= 0) {\n throw new Error(\"Subagent broker frame timeout must be positive.\");\n }\n }\n\n async start(): Promise<void> {\n if (this.server && this.address && !this.failure) return;\n if (this.starting) return this.starting;\n const ownerGeneration = ++this.generation;\n this.failure = undefined;\n this.starting = new Promise<void>((resolve, reject) => {\n const server = this.createServer((socket) => this.accept(socket));\n server.maxConnections = MAX_CONNECTIONS;\n const onStartError = (error: Error) => {\n server.close(() => undefined);\n reject(error);\n };\n server.once(\"error\", onStartError);\n server.listen({ host: BROKER_HOST, port: 0 }, () => {\n server.off(\"error\", onStartError);\n if (ownerGeneration !== this.generation) {\n server.close(() => undefined);\n reject(new Error(\"Subagent message broker start was superseded.\"));\n return;\n }\n const address = server.address();\n if (!isLoopbackAddress(address)) {\n server.close(() => undefined);\n reject(new Error(\"Subagent message broker did not bind to loopback.\"));\n return;\n }\n this.server = server;\n this.address = { host: BROKER_HOST, port: address.port };\n server.on(\"error\", (error) => this.fail(error));\n server.unref();\n resolve();\n });\n })\n .catch((error) => {\n const message = truncateError(error instanceof Error ? error.message : String(error));\n this.failure = message;\n throw new Error(`Subagent message broker failed to start: ${message}`);\n })\n .finally(() => {\n this.starting = undefined;\n });\n return this.starting;\n }\n\n assertReady(): void {\n if (this.server && this.address && !this.failure) return;\n throw new Error(\n this.failure\n ? `Subagent messaging is unavailable: ${this.failure}`\n : \"Subagent messaging is unavailable because the session broker is not ready.\",\n );\n }\n\n issueCredentials(input: { jobId: string; generation: number }): BrokerCredentials {\n this.assertReady();\n if (this.tokenByJob.has(input.jobId)) {\n throw new Error(`Subagent messaging credentials already exist for ${input.jobId}.`);\n }\n const token = randomBytes(32).toString(\"hex\");\n const record: JobRecord = { ...input, token };\n this.jobsByToken.set(token, record);\n this.tokenByJob.set(input.jobId, token);\n return { host: BROKER_HOST, port: this.address?.port ?? 0, token };\n }\n\n createMainRequest(jobId: string, message: string): BrokerSendAcknowledgement {\n this.assertReady();\n const job = this.requireJob(jobId);\n return this.createRequest(job, \"main\", message);\n }\n\n replyFromMain(requestId: string, message: string): BrokerSendAcknowledgement {\n this.assertReady();\n return this.acceptResponse(\"main\", undefined, requestId, message);\n }\n\n rollbackMainRequest(requestId: string): void {\n const request = this.requests.get(requestId);\n if (request?.origin === \"main\" && request.response === undefined) {\n this.clearWaiter(request);\n this.requests.delete(requestId);\n }\n }\n\n revokeJob(jobId: string, reason = \"Subagent job is no longer active.\"): void {\n const token = this.tokenByJob.get(jobId);\n if (token) {\n this.tokenByJob.delete(jobId);\n this.jobsByToken.delete(token);\n }\n for (const request of [...this.requests.values()]) {\n if (request.jobId !== jobId) continue;\n if (request.waiter) this.respondError(request.waiter.socket, reason);\n this.clearWaiter(request);\n this.requests.delete(request.requestId);\n }\n }\n\n hasPendingMainRequest(): boolean {\n return [...this.requests.values()].some((request) => request.origin === \"child\" && request.response === undefined);\n }\n\n takePendingInboundResponse(): boolean {\n const pending = this.pendingInboundResponse;\n this.pendingInboundResponse = false;\n return pending;\n }\n\n markMainRequestQueued(requestId: string): boolean {\n const request = this.requests.get(requestId);\n if (request?.origin !== \"main\") {\n throw new Error(\"Unknown or expired main-agent subagent request.\");\n }\n request.deliveryQueued = true;\n return request.response === undefined;\n }\n\n interruptChildWaits(jobId: string): number {\n let interrupted = 0;\n for (const request of this.requests.values()) {\n if (request.jobId !== jobId || request.origin !== \"child\" || !request.waiter) continue;\n const socket = request.waiter.socket;\n this.clearWaiter(request);\n this.respondError(socket, CHILD_WAIT_INTERRUPTED_ERROR);\n interrupted++;\n }\n return interrupted;\n }\n\n subscribeInboundMessage(listener: () => void): () => void {\n this.inboundMessageListeners.add(listener);\n if (this.hasPendingMainRequest()) listener();\n return () => this.inboundMessageListeners.delete(listener);\n }\n\n async shutdown(): Promise<void> {\n ++this.generation;\n const starting = this.starting;\n if (starting) await starting.catch(() => undefined);\n for (const jobId of [...this.tokenByJob.keys()]) {\n this.revokeJob(jobId, \"Subagent session shut down.\");\n }\n this.requests.clear();\n this.inboundMessageListeners.clear();\n this.pendingInboundResponse = false;\n for (const socket of this.sockets) socket.destroy();\n this.sockets.clear();\n const server = this.server;\n this.server = undefined;\n this.address = undefined;\n this.failure = undefined;\n if (!server?.listening) return;\n await new Promise<void>((resolve) => server.close(() => resolve()));\n }\n\n private requireJob(jobId: string): JobRecord {\n const token = this.tokenByJob.get(jobId);\n const job = token ? this.jobsByToken.get(token) : undefined;\n if (!job) throw new Error(\"Unknown or inactive subagent job.\");\n return job;\n }\n\n private hasQueuedRequestForChild(jobId: string): boolean {\n return [...this.requests.values()].some(\n (request) =>\n request.jobId === jobId &&\n request.origin === \"main\" &&\n request.deliveryQueued === true &&\n request.response === undefined,\n );\n }\n\n private createRequest(job: JobRecord, origin: BrokerRequestOrigin, message: string): BrokerSendAcknowledgement {\n validateMessage(message, \"Subagent request\");\n const outstanding = [...this.requests.values()].filter(\n (request) => request.jobId === job.jobId && request.consumedAt === undefined,\n ).length;\n if (outstanding >= MAX_OUTSTANDING_REQUESTS) {\n throw new Error(`Subagent job may have at most ${MAX_OUTSTANDING_REQUESTS} outstanding requests.`);\n }\n const request: RequestRecord = {\n requestId: `req_${randomUUID()}`,\n jobId: job.jobId,\n generation: job.generation,\n origin,\n expectedResponder: origin === \"main\" ? \"child\" : \"main\",\n message,\n createdAt: this.now(),\n };\n this.requests.set(request.requestId, request);\n if (origin === \"child\") {\n try {\n this.deliverInbound({\n kind: \"request\",\n requestId: request.requestId,\n jobId: request.jobId,\n message: request.message,\n });\n } catch (error) {\n this.requests.delete(request.requestId);\n throw error;\n }\n }\n return { requestId: request.requestId, accepted: true, duplicate: false };\n }\n\n private acceptResponse(\n responder: BrokerRequestOrigin,\n job: JobRecord | undefined,\n requestId: string,\n message: string,\n ): BrokerSendAcknowledgement {\n validateRequestId(requestId);\n validateMessage(message, \"Subagent response\");\n const request = this.requests.get(requestId);\n if (\n !request ||\n request.expectedResponder !== responder ||\n (job && (request.jobId !== job.jobId || request.generation !== job.generation))\n ) {\n throw new Error(\"Unknown, expired, or unauthorized subagent request.\");\n }\n if (request.response !== undefined) {\n return { requestId, accepted: false, duplicate: true };\n }\n request.response = message;\n if (responder === \"child\") {\n try {\n this.deliverInbound({\n kind: \"response\",\n requestId,\n jobId: request.jobId,\n message,\n });\n this.markConsumed(request);\n } catch (error) {\n request.response = undefined;\n throw error;\n }\n } else if (request.waiter) {\n const socket = request.waiter.socket;\n this.clearWaiter(request);\n this.respond(socket, { ok: true, response: message }, () => this.markConsumed(request));\n }\n return { requestId, accepted: true, duplicate: false };\n }\n\n private deliverInbound(message: BrokerInboundMessage): void {\n this.options.onMessage(message);\n if (message.kind === \"response\" && this.inboundMessageListeners.size === 0) {\n this.pendingInboundResponse = true;\n }\n for (const listener of [...this.inboundMessageListeners]) {\n try {\n listener();\n } catch {\n // Runtime wait observers cannot interrupt broker delivery.\n }\n }\n }\n\n private accept(socket: Socket): void {\n if (!this.server || this.failure || this.sockets.size >= MAX_CONNECTIONS) {\n socket.destroy();\n return;\n }\n this.sockets.add(socket);\n socket.setNoDelay(true);\n let frame = Buffer.alloc(0);\n let handled = false;\n const frameTimer = setTimeout(() => {\n if (handled) return;\n handled = true;\n this.respondError(socket, \"Subagent broker request frame timed out.\");\n }, this.requestFrameTimeoutMs);\n frameTimer.unref();\n const cleanup = () => {\n clearTimeout(frameTimer);\n this.sockets.delete(socket);\n for (const request of this.requests.values()) {\n if (request.waiter?.socket === socket) this.clearWaiter(request);\n }\n };\n socket.on(\"data\", (chunk: Buffer) => {\n if (handled) return;\n frame = Buffer.concat([frame, chunk]);\n if (frame.byteLength > MAX_FRAME_BYTES) {\n handled = true;\n clearTimeout(frameTimer);\n this.respondError(socket, \"Subagent broker request exceeded its size limit.\");\n return;\n }\n const newline = frame.indexOf(0x0a);\n if (newline < 0) return;\n handled = true;\n clearTimeout(frameTimer);\n socket.removeAllListeners(\"data\");\n const trailing = frame\n .subarray(newline + 1)\n .toString(\"utf8\")\n .trim();\n if (trailing) {\n this.respondError(socket, \"Subagent broker accepts one request per connection.\");\n return;\n }\n this.handleFrame(socket, frame.subarray(0, newline).toString(\"utf8\"));\n });\n socket.once(\"close\", cleanup);\n socket.once(\"error\", cleanup);\n }\n\n private handleFrame(socket: Socket, frame: string): void {\n let request: BrokerRequest;\n try {\n const parsed = JSON.parse(frame) as unknown;\n if (!isRecord(parsed)) throw new Error();\n request = parsed as BrokerRequest;\n } catch {\n this.respondError(socket, \"Malformed subagent broker request.\");\n return;\n }\n const job = typeof request.token === \"string\" ? this.jobsByToken.get(request.token) : undefined;\n if (!job) {\n this.respondError(socket, \"Unauthenticated subagent broker request.\");\n return;\n }\n try {\n if (request.type === \"send\") {\n this.handleSend(socket, job, request);\n return;\n }\n if (request.type === \"wait\") {\n this.handleWait(socket, job, request);\n return;\n }\n throw new Error(\"Unsupported subagent broker request.\");\n } catch (error) {\n this.respondError(socket, error instanceof Error ? error.message : String(error));\n }\n }\n\n private handleSend(socket: Socket, job: JobRecord, request: Extract<BrokerRequest, { type: \"send\" }>): void {\n if (typeof request.message !== \"string\") {\n throw new Error(\"subagent_send requires a message string.\");\n }\n const hasRecipient = typeof request.recipient === \"string\";\n const hasRequestId = typeof request.requestId === \"string\";\n if (hasRecipient === hasRequestId) {\n throw new Error(\"subagent_send requires exactly one of recipient or requestId.\");\n }\n const acknowledgement = hasRecipient\n ? request.recipient === \"main\"\n ? this.createRequest(job, \"child\", request.message)\n : (() => {\n throw new Error('A subagent may send new requests only to recipient \"main\".');\n })()\n : this.acceptResponse(\"child\", job, request.requestId ?? \"\", request.message);\n this.respond(socket, { ok: true, ...acknowledgement });\n }\n\n private handleWait(socket: Socket, job: JobRecord, request: Extract<BrokerRequest, { type: \"wait\" }>): void {\n if (typeof request.requestId !== \"string\") {\n throw new Error(\"Subagent wait requires a request ID.\");\n }\n validateRequestId(request.requestId);\n if (request.timeoutMs !== undefined) validateTimeout(request.timeoutMs);\n const record = this.requests.get(request.requestId);\n if (record?.origin !== \"child\" || record.jobId !== job.jobId || record.generation !== job.generation) {\n throw new Error(\"Unknown or expired subagent request.\");\n }\n if (record.consumedAt !== undefined && record.response !== undefined) {\n this.respond(socket, { ok: true, response: record.response });\n return;\n }\n if (record.response !== undefined) {\n this.respond(socket, { ok: true, response: record.response }, () => this.markConsumed(record));\n return;\n }\n if (this.hasQueuedRequestForChild(job.jobId)) {\n this.respondError(socket, CHILD_WAIT_INTERRUPTED_ERROR);\n return;\n }\n if (record.waiter) {\n throw new Error(`A wait is already active for subagent request ${request.requestId}.`);\n }\n const waiter: RequestWaiter = { socket };\n record.waiter = waiter;\n if (request.timeoutMs !== undefined) {\n waiter.timer = setTimeout(() => {\n if (record.waiter !== waiter) return;\n this.clearWaiter(record);\n this.respondError(socket, \"Subagent response wait timed out.\");\n }, request.timeoutMs);\n waiter.timer.unref();\n }\n }\n\n private markConsumed(request: RequestRecord): void {\n if (this.requests.get(request.requestId) !== request || request.response === undefined) return;\n request.consumedAt ??= this.now();\n const consumed = [...this.requests.values()]\n .filter((candidate) => candidate.jobId === request.jobId && candidate.consumedAt !== undefined)\n .sort((left, right) => (left.consumedAt ?? 0) - (right.consumedAt ?? 0));\n for (const expired of consumed.slice(0, Math.max(0, consumed.length - MAX_RETAINED_CONSUMED_REQUESTS))) {\n this.requests.delete(expired.requestId);\n }\n }\n\n private clearWaiter(request: RequestRecord): void {\n if (request.waiter?.timer) clearTimeout(request.waiter.timer);\n request.waiter = undefined;\n }\n\n private respondError(socket: Socket, error: string): void {\n this.respond(socket, { ok: false, error: truncateError(error) });\n }\n\n private respond(socket: Socket, value: Record<string, unknown>, onFlushed?: () => void): void {\n if (socket.destroyed) return;\n let content = `${JSON.stringify(value)}\\n`;\n if (Buffer.byteLength(content, \"utf8\") > MAX_FRAME_BYTES) {\n content = `${JSON.stringify({ ok: false, error: \"Subagent broker response exceeded its size limit.\" })}\\n`;\n }\n socket.end(content, onFlushed);\n }\n\n private fail(error: Error): void {\n this.failure = truncateError(error.message);\n for (const jobId of [...this.tokenByJob.keys()]) {\n this.revokeJob(jobId, \"Subagent message broker failed.\");\n }\n for (const socket of this.sockets) socket.destroy();\n this.sockets.clear();\n this.address = undefined;\n }\n}\n\nexport function validateMessage(message: string, label: string): void {\n if (!message.trim()) throw new Error(`${label} is required.`);\n if (message.includes(\"\\0\")) throw new Error(`${label} must not contain NUL bytes.`);\n if (Buffer.byteLength(message, \"utf8\") > MAX_MESSAGE_BYTES) {\n throw new Error(`${label} must be at most ${MAX_MESSAGE_BYTES} UTF-8 bytes.`);\n }\n if (lineCount(message) > MAX_MESSAGE_LINES) {\n throw new Error(`${label} must contain at most ${MAX_MESSAGE_LINES} lines.`);\n }\n}\n\nexport function sanitizeTerminalText(value: string): string {\n return [...value]\n .filter((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n if (character === \"\\n\" || character === \"\\t\") return true;\n if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) return false;\n return !((codePoint >= 0x202a && codePoint <= 0x202e) || (codePoint >= 0x2066 && codePoint <= 0x2069));\n })\n .join(\"\");\n}\n\nfunction validateRequestId(requestId: string): void {\n if (\n requestId.length > MAX_IDENTIFIER_LENGTH ||\n !/^req_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(requestId)\n ) {\n throw new Error(\"Invalid subagent request ID.\");\n }\n}\n\nfunction validateTimeout(timeoutMs: number): void {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_TIMEOUT_MS) {\n throw new Error(\"Subagent wait timeout is outside the supported range.\");\n }\n}\n\nfunction lineCount(value: string): number {\n let count = 1;\n for (const character of value) if (character === \"\\n\") count++;\n return count;\n}\n\nfunction truncateError(error: string): string {\n const bytes = Buffer.from(error, \"utf8\");\n if (bytes.length <= MAX_ERROR_BYTES) return error;\n return `${bytes\n .subarray(0, Math.max(0, MAX_ERROR_BYTES - 18))\n .toString(\"utf8\")\n .replace(/\uFFFD+$/gu, \"\")}\\n\u2026 [truncated]`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isLoopbackAddress(address: AddressInfo | string | null): address is AddressInfo {\n return Boolean(address && typeof address !== \"string\" && address.address === BROKER_HOST);\n}\n", "import * as fs from \"node:fs\";\nimport type { BrokerCredentials } from \"./types.js\";\n\nexport const BROKER_CREDENTIAL_FD = 3;\nexport const BROKER_CREDENTIAL_FD_ENV = \"PI_SUBAGENT_BROKER_FD\";\nexport const CHILD_READINESS_FD = 4;\nexport const CHILD_READINESS_FD_ENV = \"PI_SUBAGENT_READINESS_FD\";\nexport const MAX_READINESS_FRAME_BYTES = 16 * 1024;\n\nconst MAX_BOOTSTRAP_BYTES = 16 * 1024;\nconst MAX_EXPECTED_TOOLS = 66;\nconst MAX_TOOL_NAME_LENGTH = 128;\nconst READINESS_STATE_KEY = Symbol.for(\"@narumitw/pi-subagents/child-readiness\");\n\nexport interface ChildBootstrap {\n communication: BrokerCredentials;\n expectedTools: string[];\n}\n\nexport interface CapturedChildBootstrap extends ChildBootstrap {\n readinessFd?: number;\n}\n\nexport function childBootstrapEnvironment(expectReadiness: boolean): NodeJS.ProcessEnv {\n return {\n [BROKER_CREDENTIAL_FD_ENV]: String(BROKER_CREDENTIAL_FD),\n ...(expectReadiness ? { [CHILD_READINESS_FD_ENV]: String(CHILD_READINESS_FD) } : {}),\n };\n}\n\nexport function serializeChildBootstrap(bootstrap: ChildBootstrap): string {\n return JSON.stringify(bootstrap);\n}\n\nexport function assertChildBootstrapCapacity(expectedTools: string[]): void {\n const serialized = serializeChildBootstrap({\n communication: { host: \"127.0.0.1\", port: 65_535, token: \"f\".repeat(64) },\n expectedTools,\n });\n if (Buffer.byteLength(serialized, \"utf8\") > MAX_BOOTSTRAP_BYTES) {\n throw new Error(`Subagent selected tool names exceed the ${MAX_BOOTSTRAP_BYTES}-byte child bootstrap size limit.`);\n }\n}\n\nexport function captureChildBootstrap(\n readBootstrap: () => string = readBootstrapPipe,\n): CapturedChildBootstrap | undefined {\n const credentialDescriptor = process.env[BROKER_CREDENTIAL_FD_ENV];\n const readinessDescriptor = process.env[CHILD_READINESS_FD_ENV];\n delete process.env[BROKER_CREDENTIAL_FD_ENV];\n delete process.env[CHILD_READINESS_FD_ENV];\n setCapturedReadiness(undefined);\n if (credentialDescriptor === undefined) {\n if (readinessDescriptor !== undefined) throw new Error(\"Unexpected pi-subagents readiness descriptor.\");\n return undefined;\n }\n if (credentialDescriptor !== String(BROKER_CREDENTIAL_FD)) {\n throw new Error(\"Invalid pi-subagents broker credential descriptor.\");\n }\n let serialized: string;\n try {\n serialized = readBootstrap();\n } catch {\n throw new Error(\"Unable to read pi-subagents child bootstrap.\");\n }\n if (Buffer.byteLength(serialized, \"utf8\") > MAX_BOOTSTRAP_BYTES) {\n throw new Error(\"Invalid pi-subagents child bootstrap.\");\n }\n let value: unknown;\n try {\n value = JSON.parse(serialized);\n } catch {\n throw new Error(\"Invalid pi-subagents child bootstrap.\");\n }\n if (!isChildBootstrap(value)) throw new Error(\"Invalid pi-subagents child bootstrap.\");\n\n if (value.expectedTools.length > 0) {\n if (readinessDescriptor !== String(CHILD_READINESS_FD)) {\n throw new Error(\"Invalid pi-subagents readiness descriptor.\");\n }\n setCapturedReadiness({ fd: CHILD_READINESS_FD, expectedTools: [...value.expectedTools] });\n return { ...value, readinessFd: CHILD_READINESS_FD };\n }\n if (readinessDescriptor !== undefined) throw new Error(\"Unexpected pi-subagents readiness descriptor.\");\n setCapturedReadiness(undefined);\n return value;\n}\n\nexport function takeCapturedReadiness(): { fd: number; expectedTools: string[] } | undefined {\n const store = globalThis as unknown as Record<symbol, { fd: number; expectedTools: string[] } | undefined>;\n const readiness = store[READINESS_STATE_KEY];\n delete store[READINESS_STATE_KEY];\n return readiness ? { fd: readiness.fd, expectedTools: [...readiness.expectedTools] } : undefined;\n}\n\nfunction setCapturedReadiness(readiness: { fd: number; expectedTools: string[] } | undefined): void {\n const store = globalThis as unknown as Record<symbol, { fd: number; expectedTools: string[] } | undefined>;\n if (readiness) store[READINESS_STATE_KEY] = readiness;\n else delete store[READINESS_STATE_KEY];\n}\n\nfunction readBootstrapPipe(): string {\n try {\n return fs.readFileSync(BROKER_CREDENTIAL_FD, \"utf8\");\n } finally {\n try {\n fs.closeSync(BROKER_CREDENTIAL_FD);\n } catch {\n // The descriptor may already be closed after a failed read.\n }\n }\n}\n\nfunction isChildBootstrap(value: unknown): value is ChildBootstrap {\n if (!isRecord(value) || Object.keys(value).length !== 2) return false;\n if (!isBrokerCredentials(value.communication)) return false;\n if (!Array.isArray(value.expectedTools) || value.expectedTools.length > MAX_EXPECTED_TOOLS) return false;\n return value.expectedTools.every(\n (tool) =>\n typeof tool === \"string\" &&\n tool.length > 0 &&\n tool.length <= MAX_TOOL_NAME_LENGTH &&\n !tool.includes(\",\") &&\n !hasControlCharacter(tool),\n );\n}\n\nfunction isBrokerCredentials(value: unknown): value is BrokerCredentials {\n if (!isRecord(value) || Object.keys(value).length !== 3) return false;\n return (\n value.host === \"127.0.0.1\" &&\n Number.isSafeInteger(value.port) &&\n (value.port as number) >= 1 &&\n (value.port as number) <= 65_535 &&\n typeof value.token === \"string\" &&\n /^[a-f0-9]{64}$/u.test(value.token)\n );\n}\n\nfunction hasControlCharacter(value: string): boolean {\n return [...value].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f);\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["request", "isRecord"]
7
+ }
@@ -0,0 +1,130 @@
1
+ // @generated by scripts/build-runtime.mjs; do not edit.
2
+ // @ts-nocheck -- generated entries use .ts extensions for Pi's Jiti loader.
3
+ import {
4
+ MAX_IDENTIFIER_LENGTH,
5
+ MAX_MESSAGE_BYTES,
6
+ sanitizeTerminalText,
7
+ validateMessage
8
+ } from "./chunk-YMVSJ5GE.ts";
9
+
10
+ // src/child-communication-tools.ts
11
+ import { Type } from "typebox";
12
+
13
+ // src/timeout.ts
14
+ var MAX_TIMEOUT_MS = 2147483647;
15
+ var MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1e3;
16
+ function resolveTimeoutMs(timeout) {
17
+ if (timeout === void 0) return void 0;
18
+ if (!Number.isFinite(timeout) || timeout <= 0) {
19
+ throw new Error("Invalid timeout: must be a finite number of seconds");
20
+ }
21
+ const timeoutMs = timeout * 1e3;
22
+ if (timeoutMs > MAX_TIMEOUT_MS) {
23
+ throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);
24
+ }
25
+ return timeoutMs;
26
+ }
27
+ function prepareTimeoutArguments(args) {
28
+ if (!args || typeof args !== "object") return args;
29
+ if (!Object.hasOwn(args, "timeoutMs")) return args;
30
+ const record = args;
31
+ if (typeof record.timeoutMs !== "number") return record;
32
+ const { timeoutMs, ...prepared } = record;
33
+ if (prepared.timeout === void 0) return { ...prepared, timeout: timeoutMs / 1e3 };
34
+ return prepared;
35
+ }
36
+
37
+ // src/child-communication-tools.ts
38
+ var CHILD_COMMUNICATION_TOOL_NAMES = ["subagent_send", "subagent_wait"];
39
+ var SendParameters = Type.Object(
40
+ {
41
+ requestId: Type.Optional(
42
+ Type.String({
43
+ description: "Pending main-agent request to answer. Omit when starting a new request.",
44
+ minLength: 1,
45
+ maxLength: MAX_IDENTIFIER_LENGTH
46
+ })
47
+ ),
48
+ message: Type.String({
49
+ description: "Plain-text request or response. Maximum 48 KiB of UTF-8 text and 1,992 lines.",
50
+ minLength: 1,
51
+ maxLength: MAX_MESSAGE_BYTES
52
+ })
53
+ },
54
+ { additionalProperties: false }
55
+ );
56
+ var WaitParameters = Type.Object(
57
+ {
58
+ requestId: Type.String({
59
+ description: "Request ID returned by subagent_send.",
60
+ minLength: 1,
61
+ maxLength: MAX_IDENTIFIER_LENGTH
62
+ }),
63
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" }))
64
+ },
65
+ { additionalProperties: false }
66
+ );
67
+ function createChildCommunicationExtension(client) {
68
+ return (pi) => {
69
+ pi.registerTool({
70
+ name: "subagent_send",
71
+ label: "Subagent \xB7 Send to Main",
72
+ description: "Use subagent_send to send one request to the main agent or answer one pending main-agent request. Omit requestId to start a request. Provide requestId to answer that request.",
73
+ promptSnippet: "Use subagent_send to send or answer one main-agent message",
74
+ parameters: SendParameters,
75
+ async execute(_toolCallId, params, signal) {
76
+ validateMessage(params.message, "Subagent message");
77
+ const requestId = optionalIdentifier(params.requestId, "requestId");
78
+ const acknowledgement = await client.send(
79
+ requestId === void 0 ? { recipient: "main", message: params.message } : { requestId, message: params.message },
80
+ signal
81
+ );
82
+ return {
83
+ content: [{ type: "text", text: JSON.stringify(acknowledgement) }],
84
+ details: acknowledgement
85
+ };
86
+ }
87
+ });
88
+ pi.registerTool({
89
+ name: "subagent_wait",
90
+ label: "Subagent \xB7 Wait for Main Agent",
91
+ description: "Use subagent_wait with a request ID from subagent_send to wait for the main agent's plain-text response. A timeout, caller cancellation, or incoming main-agent request stops only this wait and does not cancel the original request. Retry the wait when its response is still needed.",
92
+ promptSnippet: "Use subagent_wait to receive a requested main-agent response",
93
+ parameters: WaitParameters,
94
+ prepareArguments: prepareWaitArguments,
95
+ async execute(_toolCallId, params, signal) {
96
+ const requestId = requiredIdentifier(params.requestId, "requestId");
97
+ const response = await client.wait(requestId, resolveTimeoutMs(params.timeout), signal);
98
+ return {
99
+ content: [{ type: "text", text: sanitizeTerminalText(response) }],
100
+ details: { requestId }
101
+ };
102
+ }
103
+ });
104
+ };
105
+ }
106
+ function prepareWaitArguments(args) {
107
+ return prepareTimeoutArguments(args);
108
+ }
109
+ function optionalIdentifier(value, field) {
110
+ return value === void 0 ? void 0 : requiredIdentifier(value, field);
111
+ }
112
+ function requiredIdentifier(value, field) {
113
+ if (typeof value !== "string" || !value.trim()) throw new Error(`Subagent ${field} is required.`);
114
+ const identifier = value.trim();
115
+ if (identifier.length > MAX_IDENTIFIER_LENGTH || [...identifier].some((character) => {
116
+ const codePoint = character.codePointAt(0) ?? 0;
117
+ return codePoint <= 31 || codePoint >= 127 && codePoint <= 159;
118
+ })) {
119
+ throw new Error(`Subagent ${field} is invalid.`);
120
+ }
121
+ return identifier;
122
+ }
123
+
124
+ export {
125
+ resolveTimeoutMs,
126
+ prepareTimeoutArguments,
127
+ CHILD_COMMUNICATION_TOOL_NAMES,
128
+ createChildCommunicationExtension
129
+ };
130
+ //# sourceMappingURL=chunk-ZOAFWLDJ.ts.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/child-communication-tools.ts", "../../src/timeout.ts"],
4
+ "sourcesContent": ["import type { ExtensionFactory } from \"@earendil-works/pi-coding-agent\";\nimport { type Static, Type } from \"typebox\";\nimport {\n type BrokerSendAcknowledgement,\n MAX_IDENTIFIER_LENGTH,\n MAX_MESSAGE_BYTES,\n sanitizeTerminalText,\n validateMessage,\n} from \"./message-broker.js\";\nimport { prepareTimeoutArguments, resolveTimeoutMs } from \"./timeout.js\";\n\nexport const CHILD_COMMUNICATION_TOOL_NAMES = [\"subagent_send\", \"subagent_wait\"] as const;\n\nconst SendParameters = Type.Object(\n {\n requestId: Type.Optional(\n Type.String({\n description: \"Pending main-agent request to answer. Omit when starting a new request.\",\n minLength: 1,\n maxLength: MAX_IDENTIFIER_LENGTH,\n }),\n ),\n message: Type.String({\n description: \"Plain-text request or response. Maximum 48 KiB of UTF-8 text and 1,992 lines.\",\n minLength: 1,\n maxLength: MAX_MESSAGE_BYTES,\n }),\n },\n { additionalProperties: false },\n);\n\nconst WaitParameters = Type.Object(\n {\n requestId: Type.String({\n description: \"Request ID returned by subagent_send.\",\n minLength: 1,\n maxLength: MAX_IDENTIFIER_LENGTH,\n }),\n timeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n },\n { additionalProperties: false },\n);\n\ntype ChildBrokerSendArguments = { recipient: \"main\"; message: string } | { requestId: string; message: string };\n\ntype WaitArguments = Static<typeof WaitParameters>;\n\nexport interface ChildCommunicationClient {\n send(params: ChildBrokerSendArguments, signal?: AbortSignal): Promise<BrokerSendAcknowledgement>;\n wait(requestId: string, timeoutMs: number | undefined, signal?: AbortSignal): Promise<string>;\n}\n\nexport function createChildCommunicationExtension(client: ChildCommunicationClient): ExtensionFactory {\n return (pi) => {\n pi.registerTool({\n name: \"subagent_send\",\n label: \"Subagent \u00B7 Send to Main\",\n description:\n \"Use subagent_send to send one request to the main agent or answer one pending main-agent request. Omit requestId to start a request. Provide requestId to answer that request.\",\n promptSnippet: \"Use subagent_send to send or answer one main-agent message\",\n parameters: SendParameters,\n async execute(_toolCallId, params, signal) {\n validateMessage(params.message, \"Subagent message\");\n const requestId = optionalIdentifier(params.requestId, \"requestId\");\n const acknowledgement = await client.send(\n requestId === undefined\n ? { recipient: \"main\", message: params.message }\n : { requestId, message: params.message },\n signal,\n );\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(acknowledgement) }],\n details: acknowledgement,\n };\n },\n });\n\n pi.registerTool({\n name: \"subagent_wait\",\n label: \"Subagent \u00B7 Wait for Main Agent\",\n description:\n \"Use subagent_wait with a request ID from subagent_send to wait for the main agent's plain-text response. A timeout, caller cancellation, or incoming main-agent request stops only this wait and does not cancel the original request. Retry the wait when its response is still needed.\",\n promptSnippet: \"Use subagent_wait to receive a requested main-agent response\",\n parameters: WaitParameters,\n prepareArguments: prepareWaitArguments,\n async execute(_toolCallId, params, signal) {\n const requestId = requiredIdentifier(params.requestId, \"requestId\");\n const response = await client.wait(requestId, resolveTimeoutMs(params.timeout), signal);\n return {\n content: [{ type: \"text\" as const, text: sanitizeTerminalText(response) }],\n details: { requestId },\n };\n },\n });\n };\n}\n\nfunction prepareWaitArguments(args: unknown): WaitArguments {\n return prepareTimeoutArguments(args) as WaitArguments;\n}\n\nfunction optionalIdentifier(value: unknown, field: string): string | undefined {\n return value === undefined ? undefined : requiredIdentifier(value, field);\n}\n\nfunction requiredIdentifier(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value.trim()) throw new Error(`Subagent ${field} is required.`);\n const identifier = value.trim();\n if (\n identifier.length > MAX_IDENTIFIER_LENGTH ||\n [...identifier].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f);\n })\n ) {\n throw new Error(`Subagent ${field} is invalid.`);\n }\n return identifier;\n}\n", "const MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nexport function resolveTimeoutMs(timeout: number | undefined): number | undefined {\n if (timeout === undefined) return undefined;\n if (!Number.isFinite(timeout) || timeout <= 0) {\n throw new Error(\"Invalid timeout: must be a finite number of seconds\");\n }\n const timeoutMs = timeout * 1000;\n if (timeoutMs > MAX_TIMEOUT_MS) {\n throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n }\n return timeoutMs;\n}\n\nexport function prepareTimeoutArguments(args: unknown): Record<string, unknown> {\n if (!args || typeof args !== \"object\") return args as Record<string, unknown>;\n if (!Object.hasOwn(args, \"timeoutMs\")) return args as Record<string, unknown>;\n const record = args as Record<string, unknown>;\n if (typeof record.timeoutMs !== \"number\") return record;\n const { timeoutMs, ...prepared } = record;\n if (prepared.timeout === undefined) return { ...prepared, timeout: timeoutMs / 1000 };\n return prepared;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }