agent-relay 3.2.2 → 3.2.4

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.
Files changed (246) hide show
  1. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  2. package/bin/agent-relay-broker-darwin-x64 +0 -0
  3. package/bin/agent-relay-broker-linux-arm64 +0 -0
  4. package/bin/agent-relay-broker-linux-x64 +0 -0
  5. package/dist/index.cjs +1358 -941
  6. package/dist/src/cli/commands/agent-management.d.ts +2 -2
  7. package/dist/src/cli/commands/agent-management.d.ts.map +1 -1
  8. package/dist/src/cli/commands/agent-management.js +41 -240
  9. package/dist/src/cli/commands/agent-management.js.map +1 -1
  10. package/dist/src/cli/commands/messaging.d.ts +1 -1
  11. package/dist/src/cli/commands/messaging.d.ts.map +1 -1
  12. package/dist/src/cli/commands/messaging.js +14 -5
  13. package/dist/src/cli/commands/messaging.js.map +1 -1
  14. package/dist/src/cli/lib/agent-management-listing.d.ts +4 -1
  15. package/dist/src/cli/lib/agent-management-listing.d.ts.map +1 -1
  16. package/dist/src/cli/lib/agent-management-listing.js +27 -2
  17. package/dist/src/cli/lib/agent-management-listing.js.map +1 -1
  18. package/package.json +11 -10
  19. package/packages/acp-bridge/package.json +2 -2
  20. package/packages/config/package.json +1 -1
  21. package/packages/hooks/package.json +4 -4
  22. package/packages/memory/package.json +2 -2
  23. package/packages/openclaw/package.json +2 -2
  24. package/packages/policy/package.json +2 -2
  25. package/packages/sdk/ADAPTER_REVIEW.md +109 -0
  26. package/packages/sdk/dist/client.d.ts +66 -0
  27. package/packages/sdk/dist/client.d.ts.map +1 -1
  28. package/packages/sdk/dist/client.js +230 -0
  29. package/packages/sdk/dist/client.js.map +1 -1
  30. package/packages/sdk/dist/communicate/a2a-bridge.d.ts +25 -0
  31. package/packages/sdk/dist/communicate/a2a-bridge.d.ts.map +1 -0
  32. package/packages/sdk/dist/communicate/a2a-bridge.js +89 -0
  33. package/packages/sdk/dist/communicate/a2a-bridge.js.map +1 -0
  34. package/packages/sdk/dist/communicate/a2a-server.d.ts +31 -0
  35. package/packages/sdk/dist/communicate/a2a-server.d.ts.map +1 -0
  36. package/packages/sdk/dist/communicate/a2a-server.js +220 -0
  37. package/packages/sdk/dist/communicate/a2a-server.js.map +1 -0
  38. package/packages/sdk/dist/communicate/a2a-transport.d.ts +48 -0
  39. package/packages/sdk/dist/communicate/a2a-transport.d.ts.map +1 -0
  40. package/packages/sdk/dist/communicate/a2a-transport.js +302 -0
  41. package/packages/sdk/dist/communicate/a2a-transport.js.map +1 -0
  42. package/packages/sdk/dist/communicate/a2a-types.d.ts +107 -0
  43. package/packages/sdk/dist/communicate/a2a-types.d.ts.map +1 -0
  44. package/packages/sdk/dist/communicate/a2a-types.js +209 -0
  45. package/packages/sdk/dist/communicate/a2a-types.js.map +1 -0
  46. package/packages/sdk/dist/communicate/adapters/claude-sdk.d.ts +28 -0
  47. package/packages/sdk/dist/communicate/adapters/claude-sdk.d.ts.map +1 -0
  48. package/packages/sdk/dist/communicate/adapters/claude-sdk.js +47 -0
  49. package/packages/sdk/dist/communicate/adapters/claude-sdk.js.map +1 -0
  50. package/packages/sdk/dist/communicate/adapters/crewai.d.ts +42 -0
  51. package/packages/sdk/dist/communicate/adapters/crewai.d.ts.map +1 -0
  52. package/packages/sdk/dist/communicate/adapters/crewai.js +95 -0
  53. package/packages/sdk/dist/communicate/adapters/crewai.js.map +1 -0
  54. package/packages/sdk/dist/communicate/adapters/google-adk.d.ts +53 -0
  55. package/packages/sdk/dist/communicate/adapters/google-adk.d.ts.map +1 -0
  56. package/packages/sdk/dist/communicate/adapters/google-adk.js +77 -0
  57. package/packages/sdk/dist/communicate/adapters/google-adk.js.map +1 -0
  58. package/packages/sdk/dist/communicate/adapters/index.d.ts +7 -0
  59. package/packages/sdk/dist/communicate/adapters/index.d.ts.map +1 -0
  60. package/packages/sdk/dist/communicate/adapters/index.js +7 -0
  61. package/packages/sdk/dist/communicate/adapters/index.js.map +1 -0
  62. package/packages/sdk/dist/communicate/adapters/langgraph.d.ts +40 -0
  63. package/packages/sdk/dist/communicate/adapters/langgraph.d.ts.map +1 -0
  64. package/packages/sdk/dist/communicate/adapters/langgraph.js +77 -0
  65. package/packages/sdk/dist/communicate/adapters/langgraph.js.map +1 -0
  66. package/packages/sdk/dist/communicate/adapters/openai-agents.d.ts +25 -0
  67. package/packages/sdk/dist/communicate/adapters/openai-agents.d.ts.map +1 -0
  68. package/packages/sdk/dist/communicate/adapters/openai-agents.js +70 -0
  69. package/packages/sdk/dist/communicate/adapters/openai-agents.js.map +1 -0
  70. package/packages/sdk/dist/communicate/adapters/pi.d.ts +45 -0
  71. package/packages/sdk/dist/communicate/adapters/pi.d.ts.map +1 -0
  72. package/packages/sdk/dist/communicate/adapters/pi.js +59 -0
  73. package/packages/sdk/dist/communicate/adapters/pi.js.map +1 -0
  74. package/packages/sdk/dist/communicate/core.d.ts +58 -0
  75. package/packages/sdk/dist/communicate/core.d.ts.map +1 -0
  76. package/packages/sdk/dist/communicate/core.js +128 -0
  77. package/packages/sdk/dist/communicate/core.js.map +1 -0
  78. package/packages/sdk/dist/communicate/index.d.ts +4 -0
  79. package/packages/sdk/dist/communicate/index.d.ts.map +1 -0
  80. package/packages/sdk/dist/communicate/index.js +4 -0
  81. package/packages/sdk/dist/communicate/index.js.map +1 -0
  82. package/packages/sdk/dist/communicate/transport.d.ts +36 -0
  83. package/packages/sdk/dist/communicate/transport.d.ts.map +1 -0
  84. package/packages/sdk/dist/communicate/transport.js +371 -0
  85. package/packages/sdk/dist/communicate/transport.js.map +1 -0
  86. package/packages/sdk/dist/communicate/types.d.ts +58 -0
  87. package/packages/sdk/dist/communicate/types.d.ts.map +1 -0
  88. package/packages/sdk/dist/communicate/types.js +66 -0
  89. package/packages/sdk/dist/communicate/types.js.map +1 -0
  90. package/packages/sdk/dist/workflows/builder.d.ts +35 -5
  91. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -1
  92. package/packages/sdk/dist/workflows/builder.js +81 -7
  93. package/packages/sdk/dist/workflows/builder.js.map +1 -1
  94. package/packages/sdk/dist/workflows/cli.js +14 -1
  95. package/packages/sdk/dist/workflows/cli.js.map +1 -1
  96. package/packages/sdk/dist/workflows/runner.d.ts +10 -2
  97. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  98. package/packages/sdk/dist/workflows/runner.js +95 -1
  99. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  100. package/packages/sdk/dist/workflows/types.d.ts +11 -0
  101. package/packages/sdk/dist/workflows/types.d.ts.map +1 -1
  102. package/packages/sdk/examples/communicate/claude_sdk_example.ts +5 -0
  103. package/packages/sdk/examples/communicate/pi_example.ts +8 -0
  104. package/packages/sdk/package.json +48 -2
  105. package/packages/sdk/src/__tests__/builder-deterministic.test.ts +132 -0
  106. package/packages/sdk/src/__tests__/communicate/a2a-bridge.test.ts +211 -0
  107. package/packages/sdk/src/__tests__/communicate/a2a-server.test.ts +359 -0
  108. package/packages/sdk/src/__tests__/communicate/a2a-transport.test.ts +537 -0
  109. package/packages/sdk/src/__tests__/communicate/a2a-types.test.ts +297 -0
  110. package/packages/sdk/src/__tests__/communicate/adapters/claude-sdk.test.ts +163 -0
  111. package/packages/sdk/src/__tests__/communicate/adapters/crewai.test.ts +219 -0
  112. package/packages/sdk/src/__tests__/communicate/adapters/e2e-crewai.test.ts +101 -0
  113. package/packages/sdk/src/__tests__/communicate/adapters/e2e-google-adk.test.ts +166 -0
  114. package/packages/sdk/src/__tests__/communicate/adapters/e2e-langgraph.test.ts +181 -0
  115. package/packages/sdk/src/__tests__/communicate/adapters/e2e-openai-agents.test.ts +137 -0
  116. package/packages/sdk/src/__tests__/communicate/adapters/e2e-pi.test.ts +140 -0
  117. package/packages/sdk/src/__tests__/communicate/adapters/google-adk.test.ts +200 -0
  118. package/packages/sdk/src/__tests__/communicate/adapters/langgraph.test.ts +162 -0
  119. package/packages/sdk/src/__tests__/communicate/adapters/openai-agents.test.ts +166 -0
  120. package/packages/sdk/src/__tests__/communicate/adapters/pi.test.ts +140 -0
  121. package/packages/sdk/src/__tests__/communicate/core.test.ts +574 -0
  122. package/packages/sdk/src/__tests__/communicate/integration/cross-framework.test.ts +353 -0
  123. package/packages/sdk/src/__tests__/communicate/transport.test.ts +613 -0
  124. package/packages/sdk/src/__tests__/start-from.test.ts +346 -0
  125. package/packages/sdk/src/client.ts +301 -0
  126. package/packages/sdk/src/communicate/a2a-bridge.ts +111 -0
  127. package/packages/sdk/src/communicate/a2a-server.ts +277 -0
  128. package/packages/sdk/src/communicate/a2a-transport.ts +395 -0
  129. package/packages/sdk/src/communicate/a2a-types.ts +338 -0
  130. package/packages/sdk/src/communicate/adapters/claude-sdk.ts +85 -0
  131. package/packages/sdk/src/communicate/adapters/crewai.ts +141 -0
  132. package/packages/sdk/src/communicate/adapters/google-adk.ts +139 -0
  133. package/packages/sdk/src/communicate/adapters/index.ts +6 -0
  134. package/packages/sdk/src/communicate/adapters/langgraph.ts +112 -0
  135. package/packages/sdk/src/communicate/adapters/openai-agents.ts +113 -0
  136. package/packages/sdk/src/communicate/adapters/pi.ts +105 -0
  137. package/packages/sdk/src/communicate/core.ts +157 -0
  138. package/packages/sdk/src/communicate/index.ts +3 -0
  139. package/packages/sdk/src/communicate/transport.ts +489 -0
  140. package/packages/sdk/src/communicate/types.ts +106 -0
  141. package/packages/sdk/src/examples/workflows/fix-dashboard-user-registration.yaml +182 -0
  142. package/packages/sdk/src/workflows/builder.ts +97 -9
  143. package/packages/sdk/src/workflows/cli.ts +16 -1
  144. package/packages/sdk/src/workflows/runner.ts +110 -1
  145. package/packages/sdk/src/workflows/types.ts +14 -0
  146. package/packages/sdk/tsconfig.build.json +1 -7
  147. package/packages/sdk/tsconfig.json +1 -7
  148. package/packages/sdk-py/README.md +67 -25
  149. package/packages/sdk-py/examples/communicate/agno_example.py +8 -0
  150. package/packages/sdk-py/examples/communicate/claude_sdk_example.py +6 -0
  151. package/packages/sdk-py/examples/communicate/crewai_example.py +7 -0
  152. package/packages/sdk-py/examples/communicate/google_adk_example.py +7 -0
  153. package/packages/sdk-py/examples/communicate/openai_agents_example.py +8 -0
  154. package/packages/sdk-py/examples/communicate/swarms_example.py +7 -0
  155. package/packages/sdk-py/pyproject.toml +12 -1
  156. package/packages/sdk-py/src/agent_relay/__init__.py +8 -0
  157. package/packages/sdk-py/src/agent_relay/builder.py +65 -26
  158. package/packages/sdk-py/src/agent_relay/communicate/__init__.py +6 -0
  159. package/packages/sdk-py/src/agent_relay/communicate/a2a_bridge.py +138 -0
  160. package/packages/sdk-py/src/agent_relay/communicate/a2a_server.py +242 -0
  161. package/packages/sdk-py/src/agent_relay/communicate/a2a_transport.py +366 -0
  162. package/packages/sdk-py/src/agent_relay/communicate/a2a_types.py +294 -0
  163. package/packages/sdk-py/src/agent_relay/communicate/adapters/__init__.py +10 -0
  164. package/packages/sdk-py/src/agent_relay/communicate/adapters/agno.py +74 -0
  165. package/packages/sdk-py/src/agent_relay/communicate/adapters/claude_sdk.py +78 -0
  166. package/packages/sdk-py/src/agent_relay/communicate/adapters/crewai.py +143 -0
  167. package/packages/sdk-py/src/agent_relay/communicate/adapters/google_adk.py +69 -0
  168. package/packages/sdk-py/src/agent_relay/communicate/adapters/openai_agents.py +86 -0
  169. package/packages/sdk-py/src/agent_relay/communicate/adapters/pi.py +175 -0
  170. package/packages/sdk-py/src/agent_relay/communicate/adapters/swarms.py +44 -0
  171. package/packages/sdk-py/src/agent_relay/communicate/core.py +293 -0
  172. package/packages/sdk-py/src/agent_relay/communicate/transport.py +502 -0
  173. package/packages/sdk-py/src/agent_relay/communicate/types.py +89 -0
  174. package/packages/sdk-py/src/agent_relay/types.py +2 -1
  175. package/packages/sdk-py/tests/communicate/__init__.py +0 -0
  176. package/packages/sdk-py/tests/communicate/adapters/__init__.py +0 -0
  177. package/packages/sdk-py/tests/communicate/adapters/e2e_test_agno.py +154 -0
  178. package/packages/sdk-py/tests/communicate/adapters/e2e_test_claude_sdk.py +428 -0
  179. package/packages/sdk-py/tests/communicate/adapters/e2e_test_crewai.py +234 -0
  180. package/packages/sdk-py/tests/communicate/adapters/e2e_test_google_adk.py +182 -0
  181. package/packages/sdk-py/tests/communicate/adapters/e2e_test_langgraph.py +262 -0
  182. package/packages/sdk-py/tests/communicate/adapters/e2e_test_openai_agents.py +88 -0
  183. package/packages/sdk-py/tests/communicate/adapters/e2e_test_pi.py +156 -0
  184. package/packages/sdk-py/tests/communicate/adapters/e2e_test_swarms.py +239 -0
  185. package/packages/sdk-py/tests/communicate/adapters/test_agno.py +140 -0
  186. package/packages/sdk-py/tests/communicate/adapters/test_claude_sdk.py +147 -0
  187. package/packages/sdk-py/tests/communicate/adapters/test_crewai.py +136 -0
  188. package/packages/sdk-py/tests/communicate/adapters/test_google_adk.py +125 -0
  189. package/packages/sdk-py/tests/communicate/adapters/test_openai_agents.py +99 -0
  190. package/packages/sdk-py/tests/communicate/adapters/test_pi.py +270 -0
  191. package/packages/sdk-py/tests/communicate/adapters/test_swarms.py +113 -0
  192. package/packages/sdk-py/tests/communicate/conftest.py +555 -0
  193. package/packages/sdk-py/tests/communicate/integration/__init__.py +1 -0
  194. package/packages/sdk-py/tests/communicate/integration/test_cross_framework.py +331 -0
  195. package/packages/sdk-py/tests/communicate/integration/test_end_to_end.py +151 -0
  196. package/packages/sdk-py/tests/communicate/test_a2a_bridge.py +363 -0
  197. package/packages/sdk-py/tests/communicate/test_a2a_server.py +346 -0
  198. package/packages/sdk-py/tests/communicate/test_a2a_transport.py +561 -0
  199. package/packages/sdk-py/tests/communicate/test_a2a_types.py +342 -0
  200. package/packages/sdk-py/tests/communicate/test_auto_detect.py +67 -0
  201. package/packages/sdk-py/tests/communicate/test_core.py +331 -0
  202. package/packages/sdk-py/tests/communicate/test_transport.py +373 -0
  203. package/packages/sdk-py/tests/communicate/test_types.py +285 -0
  204. package/packages/sdk-py/tests/test_builder_deterministic.py +118 -0
  205. package/packages/telemetry/package.json +1 -1
  206. package/packages/trajectory/package.json +2 -2
  207. package/packages/user-directory/package.json +2 -2
  208. package/packages/utils/package.json +2 -2
  209. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts +0 -14
  210. package/packages/sdk/dist/__tests__/completion-pipeline.test.d.ts.map +0 -1
  211. package/packages/sdk/dist/__tests__/completion-pipeline.test.js +0 -1476
  212. package/packages/sdk/dist/__tests__/completion-pipeline.test.js.map +0 -1
  213. package/packages/sdk/dist/__tests__/contract-fixtures.test.d.ts +0 -2
  214. package/packages/sdk/dist/__tests__/contract-fixtures.test.d.ts.map +0 -1
  215. package/packages/sdk/dist/__tests__/contract-fixtures.test.js +0 -152
  216. package/packages/sdk/dist/__tests__/contract-fixtures.test.js.map +0 -1
  217. package/packages/sdk/dist/__tests__/e2e-owner-review.test.d.ts +0 -16
  218. package/packages/sdk/dist/__tests__/e2e-owner-review.test.d.ts.map +0 -1
  219. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js +0 -640
  220. package/packages/sdk/dist/__tests__/e2e-owner-review.test.js.map +0 -1
  221. package/packages/sdk/dist/__tests__/facade.test.d.ts +0 -2
  222. package/packages/sdk/dist/__tests__/facade.test.d.ts.map +0 -1
  223. package/packages/sdk/dist/__tests__/facade.test.js +0 -305
  224. package/packages/sdk/dist/__tests__/facade.test.js.map +0 -1
  225. package/packages/sdk/dist/__tests__/integration.test.d.ts +0 -2
  226. package/packages/sdk/dist/__tests__/integration.test.d.ts.map +0 -1
  227. package/packages/sdk/dist/__tests__/integration.test.js +0 -205
  228. package/packages/sdk/dist/__tests__/integration.test.js.map +0 -1
  229. package/packages/sdk/dist/__tests__/pty.test.d.ts +0 -2
  230. package/packages/sdk/dist/__tests__/pty.test.d.ts.map +0 -1
  231. package/packages/sdk/dist/__tests__/pty.test.js +0 -20
  232. package/packages/sdk/dist/__tests__/pty.test.js.map +0 -1
  233. package/packages/sdk/dist/__tests__/quickstart.test.d.ts +0 -2
  234. package/packages/sdk/dist/__tests__/quickstart.test.d.ts.map +0 -1
  235. package/packages/sdk/dist/__tests__/quickstart.test.js +0 -176
  236. package/packages/sdk/dist/__tests__/quickstart.test.js.map +0 -1
  237. package/packages/sdk/dist/__tests__/spawn-from-env.test.d.ts +0 -2
  238. package/packages/sdk/dist/__tests__/spawn-from-env.test.d.ts.map +0 -1
  239. package/packages/sdk/dist/__tests__/spawn-from-env.test.js +0 -222
  240. package/packages/sdk/dist/__tests__/spawn-from-env.test.js.map +0 -1
  241. package/packages/sdk/dist/__tests__/unit.test.d.ts +0 -2
  242. package/packages/sdk/dist/__tests__/unit.test.d.ts.map +0 -1
  243. package/packages/sdk/dist/__tests__/unit.test.js +0 -357
  244. package/packages/sdk/dist/__tests__/unit.test.js.map +0 -1
  245. package/packages/sdk-py/agent_relay/__init__.py +0 -21
  246. package/packages/sdk-py/agent_relay/models.py +0 -398
@@ -0,0 +1,112 @@
1
+ import { Relay } from '../core.js';
2
+ import { formatRelayInbox, formatRelayMessage, type Message, type MessageCallback } from '../types.js';
3
+
4
+ /** Minimal shape of a LangGraph CompiledStateGraph for relay integration. */
5
+ type CompiledGraphLike = {
6
+ invoke(input: Record<string, unknown>, config?: Record<string, unknown>): Promise<Record<string, unknown>>;
7
+ nodes: Record<string, unknown>;
8
+ };
9
+
10
+ type RelayLike = {
11
+ send(to: string, text: string): Promise<void>;
12
+ post(channel: string, text: string): Promise<void>;
13
+ inbox(): Promise<Message[]>;
14
+ agents(): Promise<string[]>;
15
+ onMessage(callback: MessageCallback): () => void;
16
+ };
17
+
18
+ /** A tool definition compatible with LangGraph ToolNode. */
19
+ export interface RelayToolDef {
20
+ name: string;
21
+ description: string;
22
+ schema: Record<string, unknown>;
23
+ invoke(input: Record<string, string>): Promise<string>;
24
+ }
25
+
26
+ function createRelayTools(relay: RelayLike): RelayToolDef[] {
27
+ return [
28
+ {
29
+ name: 'relay_send',
30
+ description: 'Send a direct message to another relay agent.',
31
+ schema: {
32
+ type: 'object',
33
+ properties: {
34
+ to: { type: 'string', description: 'Recipient agent name' },
35
+ text: { type: 'string', description: 'Message text' },
36
+ },
37
+ required: ['to', 'text'],
38
+ },
39
+ async invoke(input: Record<string, string>) {
40
+ await relay.send(input.to, input.text);
41
+ return `Sent relay message to ${input.to}.`;
42
+ },
43
+ },
44
+ {
45
+ name: 'relay_inbox',
46
+ description: 'Drain and inspect newly received relay messages.',
47
+ schema: { type: 'object', properties: {}, required: [] },
48
+ async invoke() {
49
+ return formatRelayInbox(await relay.inbox());
50
+ },
51
+ },
52
+ {
53
+ name: 'relay_post',
54
+ description: 'Post a message to a relay channel.',
55
+ schema: {
56
+ type: 'object',
57
+ properties: {
58
+ channel: { type: 'string', description: 'Channel name' },
59
+ text: { type: 'string', description: 'Message text' },
60
+ },
61
+ required: ['channel', 'text'],
62
+ },
63
+ async invoke(input: Record<string, string>) {
64
+ await relay.post(input.channel, input.text);
65
+ return `Posted relay message to #${input.channel}.`;
66
+ },
67
+ },
68
+ {
69
+ name: 'relay_agents',
70
+ description: 'List currently online relay agents.',
71
+ schema: { type: 'object', properties: {}, required: [] },
72
+ async invoke() {
73
+ return (await relay.agents()).join('\n');
74
+ },
75
+ },
76
+ ];
77
+ }
78
+
79
+ export interface LangGraphRelayResult {
80
+ /** Relay tool definitions to pass to a LangGraph ToolNode. */
81
+ tools: RelayToolDef[];
82
+ /** Unsubscribe from incoming relay messages. */
83
+ unsubscribe: () => void;
84
+ }
85
+
86
+ /**
87
+ * Attach relay communication tools and message routing to a LangGraph compiled graph.
88
+ *
89
+ * Tools are returned as objects compatible with LangGraph's ToolNode. Incoming
90
+ * relay messages are routed into the graph via `graph.invoke()` with a
91
+ * `messages` state update.
92
+ *
93
+ * @param graph - A compiled LangGraph state graph.
94
+ * @param relayOrName - Optional pre-configured Relay instance or agent name string (defaults to 'langgraph').
95
+ * @returns Relay tools and an unsubscribe handle.
96
+ */
97
+ export function onRelay(
98
+ graph: CompiledGraphLike,
99
+ relayOrName?: RelayLike | string,
100
+ ): LangGraphRelayResult {
101
+ const r: RelayLike = typeof relayOrName === 'string'
102
+ ? new Relay(relayOrName) as unknown as RelayLike
103
+ : relayOrName ?? (new Relay('langgraph') as unknown as RelayLike);
104
+ const tools = createRelayTools(r);
105
+
106
+ const unsubscribe = r.onMessage(async (message) => {
107
+ const prompt = formatRelayMessage(message);
108
+ await graph.invoke({ messages: [{ role: 'user', content: prompt }] });
109
+ });
110
+
111
+ return { tools, unsubscribe };
112
+ }
@@ -0,0 +1,113 @@
1
+ import { Relay } from '../core.js';
2
+ import { formatRelayInbox, formatRelayMessage, type Message, type MessageCallback } from '../types.js';
3
+
4
+ type RelayLike = {
5
+ send(to: string, text: string): Promise<void>;
6
+ post(channel: string, text: string): Promise<void>;
7
+ inbox(): Promise<Message[]>;
8
+ agents(): Promise<string[]>;
9
+ onMessage(callback: MessageCallback): () => void;
10
+ };
11
+
12
+ type JsonObjectSchema = {
13
+ type: 'object';
14
+ properties: Record<string, Record<string, unknown>>;
15
+ required: string[];
16
+ additionalProperties: boolean;
17
+ };
18
+
19
+ type FunctionToolLike = {
20
+ type: 'function';
21
+ name: string;
22
+ description: string;
23
+ parameters: JsonObjectSchema;
24
+ strict: boolean;
25
+ invoke: (runContext: unknown, input: string) => Promise<string>;
26
+ needsApproval: false;
27
+ isEnabled: true;
28
+ };
29
+
30
+ type AgentLike = {
31
+ name: string;
32
+ instructions: string | ((...args: unknown[]) => string | Promise<string>);
33
+ tools: unknown[];
34
+ };
35
+
36
+ function schema(props: Record<string, Record<string, unknown>>, required: string[]): JsonObjectSchema {
37
+ return { type: 'object', properties: props, required, additionalProperties: false };
38
+ }
39
+
40
+ function createRelayTools(relay: RelayLike): FunctionToolLike[] {
41
+ const defs: Array<[string, string, JsonObjectSchema, (p: Record<string, string>) => Promise<string>]> = [
42
+ ['relay_send', 'Send a direct message to another relay agent.',
43
+ schema({ to: { type: 'string' }, text: { type: 'string' } }, ['to', 'text']),
44
+ async (p) => { await relay.send(p.to, p.text); return `Sent relay message to ${p.to}.`; }],
45
+ ['relay_inbox', 'Drain and inspect newly received relay messages.',
46
+ schema({}, []),
47
+ async () => formatRelayInbox(await relay.inbox())],
48
+ ['relay_post', 'Post a message to a relay channel.',
49
+ schema({ channel: { type: 'string' }, text: { type: 'string' } }, ['channel', 'text']),
50
+ async (p) => { await relay.post(p.channel, p.text); return `Posted relay message to #${p.channel}.`; }],
51
+ ['relay_agents', 'List currently online relay agents.',
52
+ schema({}, []),
53
+ async () => (await relay.agents()).join('\n')],
54
+ ];
55
+
56
+ return defs.map(([name, description, parameters, run]) => ({
57
+ type: 'function' as const,
58
+ name,
59
+ description,
60
+ parameters,
61
+ strict: false,
62
+ needsApproval: false as const,
63
+ isEnabled: true as const,
64
+ async invoke(_runContext: unknown, input: string): Promise<string> {
65
+ const params = input ? JSON.parse(input) : {};
66
+ return run(params);
67
+ },
68
+ }));
69
+ }
70
+
71
+ /**
72
+ * Attach relay communication tools and message routing to an OpenAI Agent.
73
+ * @param agent - OpenAI Agent instance to augment with relay tools.
74
+ * @param relay - Optional pre-configured Relay instance.
75
+ * @returns Object with the augmented agent and a cleanup function.
76
+ */
77
+ export function onRelay<TAgent extends AgentLike>(
78
+ agent: TAgent,
79
+ relay: RelayLike = new Relay(agent.name),
80
+ ): { agent: TAgent; cleanup: () => void } {
81
+ const relayTools = createRelayTools(relay);
82
+ agent.tools = [...agent.tools, ...relayTools];
83
+
84
+ const pendingMessages: string[] = [];
85
+ const originalInstructions = agent.instructions;
86
+
87
+ const unsubscribe = relay.onMessage(async (message) => {
88
+ pendingMessages.push(formatRelayMessage(message));
89
+ });
90
+
91
+ agent.instructions = async (...args: unknown[]): Promise<string> => {
92
+ let base: string;
93
+ if (typeof originalInstructions === 'function') {
94
+ base = await originalInstructions(...args);
95
+ } else {
96
+ base = originalInstructions ?? '';
97
+ }
98
+
99
+ if (pendingMessages.length > 0) {
100
+ const msgs = pendingMessages.splice(0, pendingMessages.length);
101
+ return `${base}\n\n--- Relay Messages ---\n${msgs.join('\n')}`;
102
+ }
103
+ return base;
104
+ };
105
+
106
+ const cleanup = (): void => {
107
+ unsubscribe();
108
+ agent.instructions = originalInstructions;
109
+ agent.tools = agent.tools.filter((t) => !relayTools.includes(t as FunctionToolLike));
110
+ };
111
+
112
+ return { agent, cleanup };
113
+ }
@@ -0,0 +1,105 @@
1
+ import { Type } from '@sinclair/typebox';
2
+
3
+ import { Relay } from '../core.js';
4
+ import { formatRelayInbox, formatRelayMessage, type Message, type MessageCallback } from '../types.js';
5
+
6
+ type ToolResult = {
7
+ content: Array<{ type: 'text'; text: string }>;
8
+ details: Record<string, unknown>;
9
+ };
10
+
11
+ type RelayTool = {
12
+ name: string;
13
+ label: string;
14
+ description: string;
15
+ parameters: unknown;
16
+ execute: (
17
+ toolCallId: string,
18
+ params: any,
19
+ signal?: AbortSignal,
20
+ onUpdate?: unknown
21
+ ) => Promise<ToolResult>;
22
+ };
23
+
24
+ type PiSessionLike = {
25
+ isStreaming: boolean;
26
+ steer(text: string): Promise<void>;
27
+ followUp(text: string): Promise<void>;
28
+ };
29
+
30
+ type PiConfigLike = {
31
+ customTools?: RelayTool[];
32
+ onSessionCreated?: (session: PiSessionLike) => void | Promise<void>;
33
+ };
34
+
35
+ type RelayLike = {
36
+ send(to: string, text: string): Promise<void>;
37
+ post(channel: string, text: string): Promise<void>;
38
+ inbox(): Promise<Message[]>;
39
+ agents(): Promise<string[]>;
40
+ onMessage(callback: MessageCallback): () => void;
41
+ };
42
+
43
+ const txt = (text: string): ToolResult => ({ content: [{ type: 'text', text }], details: {} });
44
+
45
+ function createRelayTools(relay: RelayLike): RelayTool[] {
46
+ const toolDefs: Array<[string, string, unknown, (p: Record<string, string>) => Promise<string>]> = [
47
+ ['relay_send', 'Send a direct message to another relay agent.',
48
+ Type.Object({ to: Type.String(), text: Type.String() }),
49
+ async (p) => { await relay.send(p.to, p.text); return `Sent relay message to ${p.to}.`; }],
50
+ ['relay_inbox', 'Drain and inspect newly received relay messages.',
51
+ Type.Object({}),
52
+ async () => formatRelayInbox(await relay.inbox())],
53
+ ['relay_post', 'Post a message to a relay channel.',
54
+ Type.Object({ channel: Type.String(), text: Type.String() }),
55
+ async (p) => { await relay.post(p.channel, p.text); return `Posted relay message to #${p.channel}.`; }],
56
+ ['relay_agents', 'List currently online relay agents.',
57
+ Type.Object({}),
58
+ async () => (await relay.agents()).join('\n')],
59
+ ];
60
+ return toolDefs.map(([name, description, parameters, run]) => ({
61
+ name, label: name.replace('_', ' '), description, parameters,
62
+ async execute(_id: string, params: Record<string, string>) { return txt(await run(params)); },
63
+ }));
64
+ }
65
+
66
+ /**
67
+ * Attach relay communication tools and message routing to a Pi agent config.
68
+ * @param name - Agent name for relay registration.
69
+ * @param config - Pi agent session config to augment.
70
+ * @param relay - Optional pre-configured Relay instance.
71
+ * @returns Augmented config with relay tools and session hook.
72
+ */
73
+ export function onRelay<TConfig extends PiConfigLike>(
74
+ name: string,
75
+ config: TConfig,
76
+ relay: RelayLike = new Relay(name)
77
+ ): TConfig & { customTools: RelayTool[]; onSessionCreated: (session: PiSessionLike) => Promise<void>; cleanup: () => void } {
78
+ const customTools = [...(config.customTools ?? []), ...createRelayTools(relay)];
79
+ const originalOnSessionCreated = config.onSessionCreated;
80
+ let unsubscribe: (() => void) | undefined;
81
+
82
+ return {
83
+ ...config,
84
+ customTools,
85
+ async onSessionCreated(session: PiSessionLike): Promise<void> {
86
+ if (originalOnSessionCreated) {
87
+ await originalOnSessionCreated(session);
88
+ }
89
+
90
+ unsubscribe?.();
91
+ unsubscribe = relay.onMessage(async (message) => {
92
+ const prompt = formatRelayMessage(message);
93
+ if (session.isStreaming) {
94
+ await session.steer(prompt);
95
+ return;
96
+ }
97
+ await session.followUp(prompt);
98
+ });
99
+ },
100
+ cleanup() {
101
+ unsubscribe?.();
102
+ unsubscribe = undefined;
103
+ },
104
+ };
105
+ }
@@ -0,0 +1,157 @@
1
+ import { RelayTransport } from './transport.js';
2
+ import {
3
+ type Message,
4
+ type MessageCallback,
5
+ type RelayConfig,
6
+ resolveRelayConfig,
7
+ } from './types.js';
8
+
9
+ const MAX_PENDING_MESSAGES = 10_000;
10
+
11
+ /**
12
+ * Core relay client for inter-agent communication.
13
+ *
14
+ * Lazily connects on first API call. Buffers incoming WebSocket messages
15
+ * for {@link inbox} when no callbacks are registered.
16
+ */
17
+ export class Relay {
18
+ readonly agentName: string;
19
+ readonly config;
20
+ readonly transport: RelayTransport;
21
+
22
+ private pending: Message[] = [];
23
+ private callbacks = new Set<MessageCallback>();
24
+ private connectPromise?: Promise<void>;
25
+ private connected = false;
26
+ private readonly exitHandler?: () => void;
27
+
28
+ constructor(agentName: string, config: RelayConfig = {}) {
29
+ this.agentName = agentName;
30
+ this.config = resolveRelayConfig(config);
31
+ this.transport = new RelayTransport(agentName, this.config);
32
+ this.transport.onWsMessage((message) => this.handleTransportMessage(message));
33
+
34
+ if (this.config.autoCleanup) {
35
+ this.exitHandler = () => {
36
+ void this.close();
37
+ };
38
+ process.once('beforeExit', this.exitHandler);
39
+ process.once('SIGTERM', this.exitHandler);
40
+ process.once('SIGINT', this.exitHandler);
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Send a direct message to another agent.
46
+ * @param to - Recipient agent name.
47
+ * @param text - Message content.
48
+ */
49
+ async send(to: string, text: string): Promise<void> {
50
+ await this.ensureConnected();
51
+ await this.transport.sendDm(to, text);
52
+ }
53
+
54
+ /**
55
+ * Post a message to a channel.
56
+ * @param channel - Target channel name.
57
+ * @param text - Message content.
58
+ */
59
+ async post(channel: string, text: string): Promise<void> {
60
+ await this.ensureConnected();
61
+ await this.transport.postMessage(channel, text);
62
+ }
63
+
64
+ /**
65
+ * Reply to a specific message in a thread.
66
+ * @param messageId - ID of the message to reply to.
67
+ * @param text - Reply content.
68
+ */
69
+ async reply(messageId: string, text: string): Promise<void> {
70
+ await this.ensureConnected();
71
+ await this.transport.reply(messageId, text);
72
+ }
73
+
74
+ /**
75
+ * Drain and return all buffered messages, clearing the buffer.
76
+ * @returns Array of buffered messages.
77
+ */
78
+ async inbox(): Promise<Message[]> {
79
+ await this.ensureConnected();
80
+ const messages = [...this.pending];
81
+ this.pending = [];
82
+ return messages;
83
+ }
84
+
85
+ /**
86
+ * Register a callback for incoming messages.
87
+ * @param callback - Invoked for each received message.
88
+ * @returns Unsubscribe function.
89
+ */
90
+ onMessage(callback: MessageCallback): () => void {
91
+ this.callbacks.add(callback);
92
+ void this.ensureConnected();
93
+
94
+ return () => {
95
+ this.callbacks.delete(callback);
96
+ };
97
+ }
98
+
99
+ /**
100
+ * List currently online agents.
101
+ * @returns Array of agent names.
102
+ */
103
+ async agents(): Promise<string[]> {
104
+ await this.ensureConnected();
105
+ return this.transport.listAgents();
106
+ }
107
+
108
+ /** Unregister the agent, close the WebSocket, and clean up. */
109
+ async close(): Promise<void> {
110
+ if (this.exitHandler) {
111
+ process.removeListener('beforeExit', this.exitHandler);
112
+ process.removeListener('SIGTERM', this.exitHandler);
113
+ process.removeListener('SIGINT', this.exitHandler);
114
+ }
115
+
116
+ this.connected = false;
117
+ this.connectPromise = undefined;
118
+ await this.transport.disconnect();
119
+ }
120
+
121
+ private async ensureConnected(): Promise<void> {
122
+ if (this.connected) {
123
+ return;
124
+ }
125
+
126
+ if (!this.connectPromise) {
127
+ this.connectPromise = this.transport.connect().then(
128
+ () => {
129
+ this.connected = true;
130
+ },
131
+ (err) => {
132
+ // Clear cached promise so the next call can retry
133
+ this.connectPromise = undefined;
134
+ throw err;
135
+ },
136
+ );
137
+ }
138
+
139
+ await this.connectPromise;
140
+ }
141
+
142
+ private async handleTransportMessage(message: Message): Promise<void> {
143
+ // Always buffer the message (spec: "both" case — callbacks AND inbox)
144
+ if (this.pending.length >= MAX_PENDING_MESSAGES) {
145
+ this.pending.shift();
146
+ process.emitWarning(
147
+ 'Relay pending buffer exceeded 10,000 messages; dropping oldest message.',
148
+ 'RelayWarning'
149
+ );
150
+ }
151
+ this.pending.push(message);
152
+
153
+ for (const callback of [...this.callbacks]) {
154
+ await callback(message);
155
+ }
156
+ }
157
+ }
@@ -0,0 +1,3 @@
1
+ export * from './types.js';
2
+ export { Relay } from './core.js';
3
+ export { onPiRelay, onClaudeRelay } from './adapters/index.js';