agent-relay 3.2.4 → 3.2.6

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 (58) hide show
  1. package/README.md +25 -0
  2. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  3. package/bin/agent-relay-broker-darwin-x64 +0 -0
  4. package/bin/agent-relay-broker-linux-arm64 +0 -0
  5. package/bin/agent-relay-broker-linux-x64 +0 -0
  6. package/dist/index.cjs +182 -7
  7. package/package.json +8 -8
  8. package/packages/acp-bridge/package.json +2 -2
  9. package/packages/config/dist/cli-registry.generated.d.ts +58 -1
  10. package/packages/config/dist/cli-registry.generated.d.ts.map +1 -1
  11. package/packages/config/dist/cli-registry.generated.js +195 -7
  12. package/packages/config/dist/cli-registry.generated.js.map +1 -1
  13. package/packages/config/package.json +1 -1
  14. package/packages/config/src/cli-registry.generated.ts +218 -8
  15. package/packages/hooks/package.json +4 -4
  16. package/packages/memory/package.json +2 -2
  17. package/packages/openclaw/package.json +2 -2
  18. package/packages/policy/package.json +2 -2
  19. package/packages/sdk/dist/client.d.ts +5 -0
  20. package/packages/sdk/dist/client.d.ts.map +1 -1
  21. package/packages/sdk/dist/client.js +8 -0
  22. package/packages/sdk/dist/client.js.map +1 -1
  23. package/packages/sdk/dist/communicate/adapters/ai-sdk.d.ts +63 -0
  24. package/packages/sdk/dist/communicate/adapters/ai-sdk.d.ts.map +1 -0
  25. package/packages/sdk/dist/communicate/adapters/ai-sdk.js +114 -0
  26. package/packages/sdk/dist/communicate/adapters/ai-sdk.js.map +1 -0
  27. package/packages/sdk/dist/communicate/adapters/index.d.ts +1 -0
  28. package/packages/sdk/dist/communicate/adapters/index.d.ts.map +1 -1
  29. package/packages/sdk/dist/communicate/adapters/index.js +1 -0
  30. package/packages/sdk/dist/communicate/adapters/index.js.map +1 -1
  31. package/packages/sdk/dist/communicate/index.d.ts +1 -1
  32. package/packages/sdk/dist/communicate/index.d.ts.map +1 -1
  33. package/packages/sdk/dist/communicate/index.js +1 -1
  34. package/packages/sdk/dist/communicate/index.js.map +1 -1
  35. package/packages/sdk/dist/models.d.ts +1 -1
  36. package/packages/sdk/dist/models.d.ts.map +1 -1
  37. package/packages/sdk/dist/models.js +2 -2
  38. package/packages/sdk/dist/models.js.map +1 -1
  39. package/packages/sdk/dist/protocol.d.ts +14 -0
  40. package/packages/sdk/dist/protocol.d.ts.map +1 -1
  41. package/packages/sdk/package.json +11 -2
  42. package/packages/sdk/src/__tests__/communicate/adapters/ai-sdk.test.ts +131 -0
  43. package/packages/sdk/src/__tests__/models.test.ts +61 -0
  44. package/packages/sdk/src/client.ts +13 -0
  45. package/packages/sdk/src/communicate/adapters/ai-sdk.ts +200 -0
  46. package/packages/sdk/src/communicate/adapters/index.ts +1 -0
  47. package/packages/sdk/src/communicate/index.ts +1 -1
  48. package/packages/sdk/src/models.ts +6 -0
  49. package/packages/sdk/src/protocol.ts +9 -0
  50. package/packages/sdk/src/workflows/README.md +55 -0
  51. package/packages/sdk/tsconfig.build.json +5 -0
  52. package/packages/sdk-py/pyproject.toml +1 -1
  53. package/packages/shared/cli-registry.yaml +14 -0
  54. package/packages/shared/codegen-ts.mjs +105 -3
  55. package/packages/telemetry/package.json +1 -1
  56. package/packages/trajectory/package.json +2 -2
  57. package/packages/user-directory/package.json +2 -2
  58. package/packages/utils/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-relay/sdk",
3
- "version": "3.2.4",
3
+ "version": "3.2.6",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -64,6 +64,11 @@
64
64
  "types": "./dist/communicate/adapters/claude-sdk.d.ts",
65
65
  "import": "./dist/communicate/adapters/claude-sdk.js",
66
66
  "default": "./dist/communicate/adapters/claude-sdk.js"
67
+ },
68
+ "./communicate/adapters/ai-sdk": {
69
+ "types": "./dist/communicate/adapters/ai-sdk.d.ts",
70
+ "import": "./dist/communicate/adapters/ai-sdk.js",
71
+ "default": "./dist/communicate/adapters/ai-sdk.js"
67
72
  }
68
73
  },
69
74
  "files": [
@@ -97,7 +102,7 @@
97
102
  "typescript": "^5.7.3"
98
103
  },
99
104
  "dependencies": {
100
- "@agent-relay/config": "3.2.4",
105
+ "@agent-relay/config": "3.2.6",
101
106
  "@relaycast/sdk": "^0.4.0",
102
107
  "@sinclair/typebox": "^0.34.48",
103
108
  "ws": "^8.18.3",
@@ -109,6 +114,7 @@
109
114
  "@langchain/langgraph": ">=1.2.0",
110
115
  "@mariozechner/pi-coding-agent": ">=0.50.0",
111
116
  "@openai/agents": ">=0.7.0",
117
+ "ai": ">=5.0.0",
112
118
  "crewai": ">=1.0.0"
113
119
  },
114
120
  "peerDependenciesMeta": {
@@ -127,6 +133,9 @@
127
133
  "@openai/agents": {
128
134
  "optional": true
129
135
  },
136
+ "ai": {
137
+ "optional": true
138
+ },
130
139
  "crewai": {
131
140
  "optional": true
132
141
  }
@@ -0,0 +1,131 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ const adapterModulePath = '../../../communicate/adapters/ai-sdk.js';
5
+
6
+ async function loadModule(): Promise<any> {
7
+ return import(adapterModulePath);
8
+ }
9
+
10
+ class FakeRelay {
11
+ private callbacks: Array<(message: any) => void | Promise<void>> = [];
12
+
13
+ sent: Array<{ to: string; text: string }> = [];
14
+ posted: Array<{ channel: string; text: string }> = [];
15
+ inboxMessages: any[] = [];
16
+
17
+ async send(to: string, text: string): Promise<void> {
18
+ this.sent.push({ to, text });
19
+ }
20
+
21
+ async post(channel: string, text: string): Promise<void> {
22
+ this.posted.push({ channel, text });
23
+ }
24
+
25
+ async inbox(): Promise<any[]> {
26
+ const messages = [...this.inboxMessages];
27
+ this.inboxMessages = [];
28
+ return messages;
29
+ }
30
+
31
+ async agents(): Promise<string[]> {
32
+ return ['Lead', 'Researcher'];
33
+ }
34
+
35
+ onMessage(callback: (message: any) => void | Promise<void>): () => void {
36
+ this.callbacks.push(callback);
37
+ return () => {
38
+ this.callbacks = this.callbacks.filter((entry) => entry !== callback);
39
+ };
40
+ }
41
+
42
+ async emit(message: any): Promise<void> {
43
+ for (const callback of [...this.callbacks]) {
44
+ await callback(message);
45
+ }
46
+ }
47
+ }
48
+
49
+ test('AI SDK onRelay returns relay tool definitions', async () => {
50
+ const { onRelay } = await loadModule();
51
+ const relay = new FakeRelay();
52
+
53
+ const session = onRelay({ name: 'AiSdkTester' }, relay);
54
+ const toolNames = Object.keys(session.tools);
55
+
56
+ assert.deepEqual(toolNames, ['relay_send', 'relay_inbox', 'relay_post', 'relay_agents']);
57
+ assert.equal(typeof session.middleware.transformParams, 'function');
58
+ assert.equal(typeof session.cleanup, 'function');
59
+ });
60
+
61
+ test('AI SDK relay tools execute against the relay client', async () => {
62
+ const { onRelay } = await loadModule();
63
+ const relay = new FakeRelay();
64
+ relay.inboxMessages = [{ sender: 'Lead', text: 'Check status', messageId: 'msg-1' }];
65
+
66
+ const session = onRelay({ name: 'AiSdkTester' }, relay);
67
+
68
+ await session.tools.relay_send.execute?.({ to: 'Lead', text: 'Working on it' });
69
+ await session.tools.relay_post.execute?.({ channel: 'ops', text: 'status update' });
70
+ const inboxResult = await session.tools.relay_inbox.execute?.({});
71
+ const agentsResult = await session.tools.relay_agents.execute?.({});
72
+
73
+ assert.deepEqual(relay.sent, [{ to: 'Lead', text: 'Working on it' }]);
74
+ assert.deepEqual(relay.posted, [{ channel: 'ops', text: 'status update' }]);
75
+ assert.match(String((inboxResult as any).text), /Check status/);
76
+ assert.deepEqual((agentsResult as any).agents, ['Lead', 'Researcher']);
77
+ });
78
+
79
+ test('AI SDK middleware appends relay instructions and pending messages to system', async () => {
80
+ const { onRelay } = await loadModule();
81
+ const relay = new FakeRelay();
82
+ const session = onRelay({ name: 'AiSdkTester', instructions: 'Escalate blockers quickly.' }, relay);
83
+
84
+ await relay.emit({ sender: 'Lead', text: 'Need an update', messageId: 'msg-2' });
85
+
86
+ const first = await session.middleware.transformParams?.({ params: { system: 'Base system.' } });
87
+ const second = await session.middleware.transformParams?.({ params: { system: 'Base system.' } });
88
+
89
+ assert.match(String(first?.system), /Base system\./);
90
+ assert.match(String(first?.system), /Use relay_send/);
91
+ assert.match(String(first?.system), /Escalate blockers quickly\./);
92
+ assert.match(String(first?.system), /Need an update/);
93
+ assert.equal(second?.system?.includes('Need an update'), false);
94
+ });
95
+
96
+ test('AI SDK middleware prepends a synthetic system message for message-array calls', async () => {
97
+ const { onRelay } = await loadModule();
98
+ const relay = new FakeRelay();
99
+ const session = onRelay({ name: 'AiSdkTester', instructions: 'Escalate blockers quickly.' }, relay);
100
+
101
+ await relay.emit({ sender: 'Reviewer', text: 'Need approval on the fix', messageId: 'msg-4' });
102
+
103
+ const result = await session.middleware.transformParams?.({
104
+ params: {
105
+ system: 'Base system.',
106
+ messages: [{ role: 'user', content: 'Can you ship this?' }],
107
+ },
108
+ });
109
+
110
+ assert.equal(Array.isArray(result?.messages), true);
111
+ assert.equal(result?.messages?.[0]?.role, 'system');
112
+ assert.match(String(result?.messages?.[0]?.content), /Use relay_send/);
113
+ assert.match(String(result?.messages?.[0]?.content), /Escalate blockers quickly\./);
114
+ assert.match(String(result?.messages?.[0]?.content), /Need approval on the fix/);
115
+ assert.equal(result?.messages?.[1]?.role, 'user');
116
+ assert.equal(result?.system, 'Base system.');
117
+ assert.doesNotMatch(String(result?.system), /Use relay_send/);
118
+ assert.doesNotMatch(String(result?.system), /Need approval on the fix/);
119
+ });
120
+
121
+ test('AI SDK cleanup unsubscribes from live relay messages', async () => {
122
+ const { onRelay } = await loadModule();
123
+ const relay = new FakeRelay();
124
+ const session = onRelay({ name: 'AiSdkTester' }, relay);
125
+
126
+ session.cleanup();
127
+ await relay.emit({ sender: 'Lead', text: 'Late ping', messageId: 'msg-3' });
128
+ const result = await session.middleware.transformParams?.({ params: {} });
129
+
130
+ assert.equal(String(result?.system).includes('Late ping'), false);
131
+ });
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Model metadata tests.
3
+ *
4
+ * Run:
5
+ * npm run build && node --test dist/__tests__/models.test.js
6
+ */
7
+ import assert from 'node:assert/strict';
8
+ import test from 'node:test';
9
+
10
+ import {
11
+ ModelMetadata,
12
+ ModelOptions,
13
+ Models,
14
+ ReasoningEfforts,
15
+ getDefaultReasoningEffort,
16
+ getModelMetadata,
17
+ getSupportedReasoningEfforts,
18
+ } from '../models.js';
19
+
20
+ test('codex model options include reasoning effort metadata', () => {
21
+ const mini = ModelOptions.Codex.find((model) => model.value === Models.Codex.GPT_5_1_CODEX_MINI);
22
+ const frontier = ModelOptions.Codex.find((model) => model.value === Models.Codex.GPT_5_4);
23
+
24
+ assert.deepEqual(mini?.reasoningEfforts, [ReasoningEfforts.MEDIUM, ReasoningEfforts.HIGH]);
25
+ assert.equal(mini?.defaultReasoningEffort, ReasoningEfforts.HIGH);
26
+
27
+ assert.deepEqual(frontier?.reasoningEfforts, [
28
+ ReasoningEfforts.LOW,
29
+ ReasoningEfforts.MEDIUM,
30
+ ReasoningEfforts.HIGH,
31
+ ReasoningEfforts.XHIGH,
32
+ ]);
33
+ assert.equal(frontier?.defaultReasoningEffort, ReasoningEfforts.XHIGH);
34
+ });
35
+
36
+ test('reasoning helper lookups return codex defaults and supported values', () => {
37
+ assert.equal(
38
+ getDefaultReasoningEffort('codex', Models.Codex.GPT_5_1_CODEX_MINI),
39
+ ReasoningEfforts.HIGH,
40
+ );
41
+ assert.equal(
42
+ getDefaultReasoningEffort('codex', Models.Codex.GPT_5_4),
43
+ ReasoningEfforts.XHIGH,
44
+ );
45
+ assert.deepEqual(
46
+ getSupportedReasoningEfforts('codex', Models.Codex.GPT_5_1_CODEX_MINI),
47
+ [ReasoningEfforts.MEDIUM, ReasoningEfforts.HIGH],
48
+ );
49
+ assert.equal(getDefaultReasoningEffort('claude', Models.Claude.SONNET), undefined);
50
+ });
51
+
52
+ test('model metadata is keyed by model id for direct lookup', () => {
53
+ assert.deepEqual(
54
+ ModelMetadata.Codex[Models.Codex.GPT_5_1_CODEX_MINI],
55
+ getModelMetadata('codex', Models.Codex.GPT_5_1_CODEX_MINI),
56
+ );
57
+ assert.equal(
58
+ ModelMetadata.Codex[Models.Codex.GPT_5_1_CODEX_MINI].defaultReasoningEffort,
59
+ ReasoningEfforts.HIGH,
60
+ );
61
+ });
@@ -369,6 +369,19 @@ export class AgentRelayClient {
369
369
  return this.requestOk<{ name: string; bytes_written: number }>('send_input', { name, data });
370
370
  }
371
371
 
372
+ async resizePty(
373
+ name: string,
374
+ rows: number,
375
+ cols: number
376
+ ): Promise<{ name: string; rows: number; cols: number }> {
377
+ await this.start();
378
+ return this.requestOk<{ name: string; rows: number; cols: number }>('resize_pty', {
379
+ name,
380
+ rows,
381
+ cols,
382
+ });
383
+ }
384
+
372
385
  async setModel(
373
386
  name: string,
374
387
  model: string,
@@ -0,0 +1,200 @@
1
+ import { Relay } from '../core.js';
2
+ import { formatRelayMessage, type Message, type MessageCallback } from '../types.js';
3
+
4
+ const DEFAULT_RELAY_SYSTEM_INSTRUCTIONS = [
5
+ 'You are connected to Agent Relay.',
6
+ 'Use relay_send for direct messages, relay_post for channel updates, relay_agents to inspect who is online, and relay_inbox to fetch buffered messages.',
7
+ 'When relay messages are injected below, treat them as the latest coordination context and respond or delegate as needed.',
8
+ ].join(' ');
9
+
10
+ type JsonObjectSchema = {
11
+ type: 'object';
12
+ properties: Record<string, Record<string, unknown>>;
13
+ required: string[];
14
+ additionalProperties: boolean;
15
+ };
16
+
17
+ export type AiSdkToolLike = {
18
+ description?: string;
19
+ inputSchema: JsonObjectSchema;
20
+ execute?: (input: Record<string, string>) => Promise<unknown>;
21
+ };
22
+
23
+ export type AiSdkTools = Record<string, AiSdkToolLike>;
24
+
25
+ export type AiSdkMessageLike = {
26
+ role?: string;
27
+ content?: unknown;
28
+ [key: string]: unknown;
29
+ };
30
+
31
+ export type AiSdkCallParams = {
32
+ system?: string;
33
+ messages?: AiSdkMessageLike[];
34
+ prompt?: string;
35
+ [key: string]: unknown;
36
+ };
37
+
38
+ export type AiSdkMiddlewareLike = {
39
+ transformParams?: (input: { params: AiSdkCallParams }) => Promise<AiSdkCallParams> | AiSdkCallParams;
40
+ };
41
+
42
+ export type RelayLike = {
43
+ send(to: string, text: string): Promise<void>;
44
+ post(channel: string, text: string): Promise<void>;
45
+ inbox(): Promise<Message[]>;
46
+ agents(): Promise<string[]>;
47
+ onMessage(callback: MessageCallback): () => void;
48
+ };
49
+
50
+ export interface AiSdkRelayOptions {
51
+ /** Agent name used when registering with Relaycast. */
52
+ name: string;
53
+ /** Optional custom instructions appended to the system prompt on every model call. */
54
+ instructions?: string;
55
+ /** Disable the default relay instructions if you want to provide your own. */
56
+ includeDefaultInstructions?: boolean;
57
+ }
58
+
59
+ export interface AiSdkRelaySession {
60
+ /** AI SDK-compatible tool map for generateText/streamText. */
61
+ tools: AiSdkTools;
62
+ /** AI SDK language model middleware that injects pending relay messages into system. */
63
+ middleware: AiSdkMiddlewareLike;
64
+ /** Underlying relay client. */
65
+ relay: RelayLike;
66
+ /** Stop live routing and clear any injected-message state. */
67
+ cleanup: () => void;
68
+ }
69
+
70
+ function schema(props: Record<string, Record<string, unknown>>, required: string[]): JsonObjectSchema {
71
+ return { type: 'object', properties: props, required, additionalProperties: false };
72
+ }
73
+
74
+ function createRelayTools(relay: RelayLike): AiSdkTools {
75
+ return {
76
+ relay_send: {
77
+ description: 'Send a direct message to another relay agent.',
78
+ inputSchema: schema({ to: { type: 'string' }, text: { type: 'string' } }, ['to', 'text']),
79
+ async execute(input) {
80
+ await relay.send(input.to, input.text);
81
+ return { ok: true, status: `Sent relay message to ${input.to}.` };
82
+ },
83
+ },
84
+ relay_inbox: {
85
+ description: 'Drain and inspect newly received relay messages.',
86
+ inputSchema: schema({}, []),
87
+ async execute() {
88
+ const messages = await relay.inbox();
89
+ return {
90
+ ok: true,
91
+ messages,
92
+ text: messages.length === 0 ? 'No new relay messages.' : messages.map(formatRelayMessage).join('\n'),
93
+ };
94
+ },
95
+ },
96
+ relay_post: {
97
+ description: 'Post a message to a relay channel.',
98
+ inputSchema: schema({ channel: { type: 'string' }, text: { type: 'string' } }, ['channel', 'text']),
99
+ async execute(input) {
100
+ await relay.post(input.channel, input.text);
101
+ return { ok: true, status: `Posted relay message to #${input.channel}.` };
102
+ },
103
+ },
104
+ relay_agents: {
105
+ description: 'List currently online relay agents.',
106
+ inputSchema: schema({}, []),
107
+ async execute() {
108
+ const agents = await relay.agents();
109
+ return { ok: true, agents, text: agents.join('\n') };
110
+ },
111
+ },
112
+ };
113
+ }
114
+
115
+ function composeRelayInstructions(pendingMessages: string[], options: AiSdkRelayOptions): string {
116
+ const sections = [
117
+ options.includeDefaultInstructions === false ? '' : DEFAULT_RELAY_SYSTEM_INSTRUCTIONS,
118
+ options.instructions?.trim() ?? '',
119
+ pendingMessages.length > 0 ? `--- Relay Messages ---\n${pendingMessages.join('\n')}` : '',
120
+ ].filter((value) => value.length > 0);
121
+
122
+ return sections.join('\n\n');
123
+ }
124
+
125
+ function composeSystemPrompt(baseSystem: string | undefined, pendingMessages: string[], options: AiSdkRelayOptions): string {
126
+ const sections: string[] = [];
127
+
128
+ if (baseSystem && baseSystem.trim().length > 0) {
129
+ sections.push(baseSystem.trim());
130
+ }
131
+
132
+ const relayInstructions = composeRelayInstructions(pendingMessages, options);
133
+ if (relayInstructions.length > 0) {
134
+ sections.push(relayInstructions);
135
+ }
136
+
137
+ return sections.join('\n\n');
138
+ }
139
+
140
+ function injectSyntheticSystemMessage(
141
+ messages: AiSdkMessageLike[] | undefined,
142
+ pendingMessages: string[],
143
+ options: AiSdkRelayOptions,
144
+ ): AiSdkMessageLike[] | undefined {
145
+ if (!Array.isArray(messages)) {
146
+ return messages;
147
+ }
148
+
149
+ const relayInstructions = composeRelayInstructions(pendingMessages, options);
150
+ if (relayInstructions.length === 0) {
151
+ return messages;
152
+ }
153
+
154
+ return [{ role: 'system', content: relayInstructions }, ...messages];
155
+ }
156
+
157
+ /**
158
+ * Create AI SDK tools + middleware for putting a model-driven app on Agent Relay.
159
+ *
160
+ * Typical usage pairs the returned `middleware` with `wrapLanguageModel(...)`
161
+ * from `ai`, and the returned `tools` with `generateText(...)` or `streamText(...)`.
162
+ */
163
+ export function onRelay(
164
+ options: AiSdkRelayOptions,
165
+ relay: RelayLike = new Relay(options.name),
166
+ ): AiSdkRelaySession {
167
+ const tools = createRelayTools(relay);
168
+ const pendingMessages: string[] = [];
169
+
170
+ const unsubscribe = relay.onMessage(async (message) => {
171
+ pendingMessages.push(formatRelayMessage(message));
172
+ });
173
+
174
+ return {
175
+ tools,
176
+ relay,
177
+ middleware: {
178
+ async transformParams({ params }): Promise<AiSdkCallParams> {
179
+ const liveMessages = pendingMessages.splice(0, pendingMessages.length);
180
+ const hasMessages = Array.isArray(params.messages);
181
+ const baseSystem = typeof params.system === 'string' ? params.system : undefined;
182
+ const nextMessages = injectSyntheticSystemMessage(
183
+ hasMessages ? [...(params.messages ?? [])] : params.messages,
184
+ liveMessages,
185
+ options,
186
+ );
187
+
188
+ return {
189
+ ...params,
190
+ messages: nextMessages,
191
+ system: hasMessages ? baseSystem : composeSystemPrompt(baseSystem, liveMessages, options),
192
+ };
193
+ },
194
+ },
195
+ cleanup() {
196
+ unsubscribe();
197
+ pendingMessages.splice(0, pendingMessages.length);
198
+ },
199
+ };
200
+ }
@@ -4,3 +4,4 @@ export { onRelay as onCrewAIRelay, onCrewRelay } from './crewai.js';
4
4
  export { onRelay as onOpenAIAgentsRelay } from './openai-agents.js';
5
5
  export { onRelay as onLangGraphRelay } from './langgraph.js';
6
6
  export { onRelay as onGoogleAdkRelay } from './google-adk.js';
7
+ export { onRelay as onAiSdkRelay } from './ai-sdk.js';
@@ -1,3 +1,3 @@
1
1
  export * from './types.js';
2
2
  export { Relay } from './core.js';
3
- export { onPiRelay, onClaudeRelay } from './adapters/index.js';
3
+ export { onPiRelay, onClaudeRelay, onAiSdkRelay } from './adapters/index.js';
@@ -11,6 +11,7 @@ export {
11
11
  CLIs,
12
12
  CLIVersions,
13
13
  CLIRegistry,
14
+ ReasoningEfforts,
14
15
  // Model constants
15
16
  ClaudeModels,
16
17
  CodexModels,
@@ -23,7 +24,11 @@ export {
23
24
  CODEX_MODEL_OPTIONS,
24
25
  GEMINI_MODEL_OPTIONS,
25
26
  CURSOR_MODEL_OPTIONS,
27
+ ModelMetadata,
26
28
  ModelOptions,
29
+ getDefaultReasoningEffort,
30
+ getModelMetadata,
31
+ getSupportedReasoningEfforts,
27
32
  // Swarm patterns (type is in workflows/types.ts)
28
33
  SwarmPatterns,
29
34
  // Types
@@ -33,4 +38,5 @@ export {
33
38
  type GeminiModel,
34
39
  type CursorModel,
35
40
  type ModelOption,
41
+ type ReasoningEffort,
36
42
  } from '@agent-relay/config';
@@ -104,6 +104,11 @@ export type SdkToBroker =
104
104
  * the cache instead of waiting on individual HTTP registrations. */
105
105
  type: 'preflight_agents';
106
106
  payload: { agents: Array<{ name: string; cli: string }> };
107
+ }
108
+ | {
109
+ /** Resize a PTY agent's terminal dimensions. */
110
+ type: 'resize_pty';
111
+ payload: { name: string; rows: number; cols: number };
107
112
  };
108
113
 
109
114
  export interface PendingDeliveryInfo {
@@ -365,6 +370,10 @@ export type BrokerToWorker =
365
370
  | {
366
371
  type: 'ping';
367
372
  payload: { ts_ms: number };
373
+ }
374
+ | {
375
+ type: 'resize_pty';
376
+ payload: { rows: number; cols: number };
368
377
  };
369
378
 
370
379
  export type WorkerToBroker =
@@ -67,6 +67,61 @@ result = (
67
67
  )
68
68
  ```
69
69
 
70
+ ## Consumer-Facing Apps + AI SDK Communicate Flows
71
+
72
+ A good production split is:
73
+
74
+ 1. **AI SDK app** handles the user conversation and streaming UI
75
+ 2. **Communicate / `onRelay()`** lets that point-person coordinate with specialists over Relay
76
+ 3. **Workflows / `runWorkflow()`** take over when a request needs multi-step execution, verification, or handoffs
77
+
78
+ ```typescript
79
+ import { streamText, wrapLanguageModel } from 'ai';
80
+ import { openai } from '@ai-sdk/openai';
81
+ import { Relay } from '@agent-relay/sdk/communicate';
82
+ import { onRelay } from '@agent-relay/sdk/communicate/adapters/ai-sdk';
83
+ import { runWorkflow } from '@agent-relay/sdk/workflows';
84
+
85
+ export async function POST(req: Request) {
86
+ const { prompt, escalate, repo } = await req.json();
87
+
88
+ const relay = new Relay('AppLead');
89
+ const relaySession = onRelay({
90
+ name: 'AppLead',
91
+ instructions: 'You are the customer-facing lead. Keep the user updated and delegate implementation via Relay when needed.',
92
+ }, relay);
93
+
94
+ const model = wrapLanguageModel({
95
+ model: openai('gpt-4o-mini'),
96
+ middleware: relaySession.middleware,
97
+ });
98
+
99
+ if (escalate) {
100
+ const workflow = await runWorkflow('workflows/feature-dev.yaml', {
101
+ vars: { task: prompt, repo },
102
+ });
103
+
104
+ return Response.json({ status: workflow.status, runId: workflow.runId });
105
+ }
106
+
107
+ return streamText({
108
+ model,
109
+ tools: relaySession.tools,
110
+ system: 'Answer directly when possible; coordinate internally when the task needs specialists.',
111
+ prompt,
112
+ }).toUIMessageStreamResponse({
113
+ onFinish() {
114
+ relaySession.cleanup();
115
+ void relay.close();
116
+ },
117
+ });
118
+ }
119
+ ```
120
+
121
+ That pattern keeps the user experience snappy while still letting longer Relay workflows run with proper ownership, retries, and verification.
122
+
123
+ A compact end-to-end example app for this pattern lives in `examples/ai-sdk-relay-helpdesk/`.
124
+
70
125
  ## YAML Format
71
126
 
72
127
  Workflows are defined as `relay.yaml` files:
@@ -3,6 +3,11 @@
3
3
  "target": "ES2022",
4
4
  "module": "ES2022",
5
5
  "moduleResolution": "Bundler",
6
+ "baseUrl": ".",
7
+ "paths": {
8
+ "@agent-relay/config": ["../config/dist/index.d.ts"],
9
+ "@agent-relay/config/*": ["../config/dist/*"]
10
+ },
6
11
  "strict": true,
7
12
  "declaration": true,
8
13
  "declarationMap": true,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "agent-relay-sdk"
7
- version = "3.2.4"
7
+ version = "3.2.6"
8
8
  description = "Python SDK for Agent Relay workflows"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -37,24 +37,38 @@ clis:
37
37
  id: "gpt-5.4"
38
38
  label: "GPT-5.4 — Latest frontier agentic coding model"
39
39
  default: true
40
+ reasoning_efforts: ["low", "medium", "high", "xhigh"]
41
+ default_reasoning_effort: "xhigh"
40
42
  gpt_5_3_codex:
41
43
  id: "gpt-5.3-codex"
42
44
  label: "GPT-5.3 Codex — Frontier agentic coding model"
45
+ reasoning_efforts: ["low", "medium", "high", "xhigh"]
46
+ default_reasoning_effort: "xhigh"
43
47
  gpt_5_3_codex_spark:
44
48
  id: "gpt-5.3-codex-spark"
45
49
  label: "GPT-5.3 Codex Spark — Ultra-fast coding model"
50
+ reasoning_efforts: ["low", "medium", "high", "xhigh"]
51
+ default_reasoning_effort: "xhigh"
46
52
  gpt_5_2_codex:
47
53
  id: "gpt-5.2-codex"
48
54
  label: "GPT-5.2 Codex — Frontier agentic coding model"
55
+ reasoning_efforts: ["low", "medium", "high", "xhigh"]
56
+ default_reasoning_effort: "xhigh"
49
57
  gpt_5_2:
50
58
  id: "gpt-5.2"
51
59
  label: "GPT-5.2 — Frontier model, knowledge & reasoning"
60
+ reasoning_efforts: ["low", "medium", "high", "xhigh"]
61
+ default_reasoning_effort: "xhigh"
52
62
  gpt_5_1_codex_max:
53
63
  id: "gpt-5.1-codex-max"
54
64
  label: "GPT-5.1 Codex Max — Deep and fast reasoning"
65
+ reasoning_efforts: ["low", "medium", "high", "xhigh"]
66
+ default_reasoning_effort: "xhigh"
55
67
  gpt_5_1_codex_mini:
56
68
  id: "gpt-5.1-codex-mini"
57
69
  label: "GPT-5.1 Codex Mini — Cheaper, faster"
70
+ reasoning_efforts: ["medium", "high"]
71
+ default_reasoning_effort: "high"
58
72
 
59
73
  gemini:
60
74
  name: "Gemini CLI"