@teneo-protocol/sdk 3.0.1 → 3.1.2

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 (36) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +234 -4
  3. package/dist/managers/message-router.d.ts +35 -0
  4. package/dist/managers/message-router.d.ts.map +1 -1
  5. package/dist/managers/message-router.js +143 -2
  6. package/dist/managers/message-router.js.map +1 -1
  7. package/dist/payments/networks.js +1 -1
  8. package/dist/payments/networks.js.map +1 -1
  9. package/dist/payments/payment-client.d.ts.map +1 -1
  10. package/dist/payments/payment-client.js +5 -3
  11. package/dist/payments/payment-client.js.map +1 -1
  12. package/dist/teneo-sdk.d.ts +5 -4
  13. package/dist/teneo-sdk.d.ts.map +1 -1
  14. package/dist/teneo-sdk.js +26 -5
  15. package/dist/teneo-sdk.js.map +1 -1
  16. package/dist/types/config.d.ts +29 -3
  17. package/dist/types/config.d.ts.map +1 -1
  18. package/dist/types/config.js +21 -2
  19. package/dist/types/config.js.map +1 -1
  20. package/dist/types/error-codes.d.ts +3 -0
  21. package/dist/types/error-codes.d.ts.map +1 -1
  22. package/dist/types/error-codes.js +4 -0
  23. package/dist/types/error-codes.js.map +1 -1
  24. package/dist/types/events.d.ts +3 -0
  25. package/dist/types/events.d.ts.map +1 -1
  26. package/dist/types/events.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/managers/message-router.ts +183 -3
  29. package/src/payments/networks.ts +1 -1
  30. package/src/payments/payment-client.ts +6 -3
  31. package/src/teneo-sdk.ts +28 -5
  32. package/src/types/config.ts +23 -2
  33. package/src/types/error-codes.ts +5 -0
  34. package/src/types/events.ts +5 -0
  35. package/tests/unit/managers/message-router-autosummon.test.ts +338 -0
  36. package/tests/unit/sdk-new-methods.test.ts +26 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ All notable changes to the Teneo Protocol SDK will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.1.1] - 2026-02-19
9
+
10
+ ### ✨ Pre-Flight Auto-Summon
11
+
12
+ The SDK now automatically adds missing agents to your room before sending commands, eliminating coordinator reject→retry cycles.
13
+
14
+ - **Pre-flight cache check**: Before sending a command, the SDK checks if the target agent is already in the room
15
+ - **Automatic addition**: If the agent is missing, it's added to the room before the command is sent
16
+ - **Lifecycle events**: `autosummon:start`, `autosummon:success`, `autosummon:failed` for full observability
17
+ - **Fallback path**: If pre-flight fails or cache is empty, falls back to coordinator-triggered auto-summon
18
+ - **Configuration**: Enable with `autoSummon: true` or `.withAutoSummon(true)` in the builder
19
+
20
+ ### 🔐 Private Key Validation
21
+
22
+ - Constructor now validates private key format (64 hex characters / 32 bytes)
23
+ - Catches empty strings, malformed keys, and too-short keys immediately
24
+ - Prevents cryptic signing errors downstream
25
+
26
+
27
+ ---
28
+
8
29
  ## [3.0.0] - 2026-01-28
9
30
 
10
31
  *Built on top of v2.3.0 multi-network support*
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Connect your app to the Teneo AI Agent Network**
4
4
 
5
- [![npm version](https://img.shields.io/badge/version-3.0.0-blue)](https://www.npmjs.com/package/@teneo-protocol/sdk)
5
+ [![npm version](https://img.shields.io/badge/version-3.1.2-blue)](https://www.npmjs.com/package/@teneo-protocol/sdk)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue)](https://www.typescriptlang.org/)
7
7
  [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green)](https://nodejs.org/)
8
8
  [![Tests](https://img.shields.io/badge/tests-671%20passing-success)](/)
@@ -15,6 +15,46 @@ The Teneo Protocol SDK lets you connect your application to a **decentralized ne
15
15
 
16
16
  ---
17
17
 
18
+ ## 🎉 What's New in v3.1.1
19
+
20
+ ### 🤖 Pre-Flight Auto-Summon
21
+
22
+ The SDK now automatically detects when an agent is missing from your room and adds it **before** sending your command — no more failed requests or retry cycles:
23
+
24
+ ```typescript
25
+ const sdk = new TeneoSDK({
26
+ wsUrl: process.env.WS_URL,
27
+ privateKey: process.env.PRIVATE_KEY,
28
+ autoSummon: true // Enable auto-summon
29
+ });
30
+
31
+ // Agent not in room? SDK handles it automatically:
32
+ // 1. Checks local cache → agent missing
33
+ // 2. Fires autosummon:start
34
+ // 3. Adds agent to room
35
+ // 4. Fires autosummon:success
36
+ // 5. Sends your command
37
+ await sdk.sendDirectCommand({
38
+ agent: "example-agent",
39
+ command: "latest 2h",
40
+ room: roomId
41
+ }, true);
42
+ ```
43
+
44
+ **Lifecycle events** for full visibility:
45
+
46
+ - `autosummon:start` — agent addition initiated
47
+ - `autosummon:success` — agent added, command proceeding
48
+ - `autosummon:failed` — agent not found or addition failed, falls back to coordinator
49
+
50
+ ### 🔐 Private Key Validation
51
+
52
+ Constructor now validates private key format immediately, catching empty or malformed keys before they cause cryptic signing errors downstream.
53
+
54
+ [See Full CHANGELOG](CHANGELOG.md#311---2026-02-19)
55
+
56
+ ---
57
+
18
58
  ## 🎉 What's New in v3.0
19
59
 
20
60
  Version 3.0 introduces **API Naming Improvements** for better clarity and consistency:
@@ -623,6 +663,71 @@ sdk.on("agent_room:list_available_error", (error) => {
623
663
  });
624
664
  ```
625
665
 
666
+ ### Auto-Summon
667
+
668
+ When you send a command to an agent that isn't in your room yet, the SDK can automatically add it for you. No manual `addAgentToRoom()` call needed — just send your command and the SDK handles the rest.
669
+
670
+ #### Setup
671
+
672
+ ```typescript
673
+ const sdk = new TeneoSDK(
674
+ TeneoSDK.builder()
675
+ .withWebSocketUrl(process.env.TENEO_WS_URL!)
676
+ .withAuthentication(process.env.PRIVATE_KEY!)
677
+ .withAutoSummon(true) // Enable auto-summon
678
+ .withNetwork("base")
679
+ .build()
680
+ );
681
+
682
+ await sdk.connect();
683
+ ```
684
+
685
+ #### How It Works
686
+
687
+ ```typescript
688
+ // Just send a command — the agent doesn't need to be in your room
689
+ const response = await sdk.sendDirectCommand({
690
+ agent: "example-agent",
691
+ command: "latest 2h",
692
+ room: roomId
693
+ }, true);
694
+
695
+ // Behind the scenes:
696
+ // 1. SDK checks if agent is in the room (instant cache lookup)
697
+ // 2. If not -> automatically adds the agent to your room
698
+ // 3. Sends your command to the agent
699
+ // 4. Returns the response
700
+ console.log(response.humanized);
701
+ ```
702
+
703
+ #### Auto-Summon Events
704
+
705
+ Track the auto-summon lifecycle to show loading states in your UI:
706
+
707
+ ```typescript
708
+ // Agent is being added to the room
709
+ sdk.on("autosummon:start", (agentName, roomId) => {
710
+ showLoadingState(`Adding ${agentName} to your room...`);
711
+ });
712
+
713
+ // Agent was successfully added — command is now being processed
714
+ sdk.on("autosummon:success", (agentName, agentId, roomId) => {
715
+ showNotification(`${agentName} joined your room`);
716
+ });
717
+
718
+ // Agent could not be added (doesn't exist, is offline, etc.)
719
+ sdk.on("autosummon:failed", (agentName, roomId, reason) => {
720
+ showError(`Could not add ${agentName}: ${reason}`);
721
+ });
722
+ ```
723
+
724
+ #### Behavior Notes
725
+
726
+ - **No duplicates**: If the agent is already in the room, the SDK skips the summon and sends your command directly.
727
+ - **Works with any message method**: Auto-summon triggers from both `sendDirectCommand()` and `sendMessage()` when the message targets an `@agent`.
728
+ - **Graceful fallback**: If the local cache is empty (e.g., first connection), the SDK falls back to server-side detection — your command still works, just with a small extra round trip.
729
+ - **Room ownership required**: Auto-summon only works in rooms you own, since adding agents requires owner permissions.
730
+
626
731
  ### Complete Example: Room Setup
627
732
 
628
733
  ```typescript
@@ -726,8 +831,8 @@ console.log(NETWORKS); // {}
726
831
  await sdk.connect();
727
832
 
728
833
  // After connect: NETWORKS populated with backend configuration
729
- console.log(NETWORKS); // { peaq: {...}, base: {...}, avalanche: {...} }
730
- const networks = getSupportedNetworks(); // ["peaq", "base", "avalanche"]
834
+ console.log(NETWORKS); // { peaq: {...}, base: {...}, avalanche: {...}, "x-layer": {...} }
835
+ const networks = getSupportedNetworks(); // ["peaq", "base", "avalanche", "x-layer"]
731
836
  ```
732
837
 
733
838
  **Key Features:**
@@ -753,7 +858,7 @@ await sdk.connect();
753
858
 
754
859
  // Get all supported networks (dynamically loaded from backend)
755
860
  const networks = getSupportedNetworks();
756
- console.log(networks); // e.g., ["peaq", "base", "avalanche"]
861
+ console.log(networks); // e.g., ["peaq", "base", "avalanche", "x-layer"]
757
862
 
758
863
  // Get network by name
759
864
  const baseNetwork = getNetwork("base");
@@ -803,6 +908,10 @@ These networks are currently supported (fetched dynamically from backend):
803
908
  - High-throughput blockchain
804
909
  - Sub-second finality
805
910
 
911
+ **X Layer Mainnet (chainId: 196)**
912
+ - OKX's Layer 2 network
913
+ - Low gas fees (OKB native token)
914
+
806
915
  > **Note:** Network configurations are fetched from the backend and may change. Use `getSupportedNetworks()` to get the current list. The SDK automatically handles network selection based on agent requirements.
807
916
 
808
917
  #### Settlement Router Integration (x402 v2.5)
@@ -1142,6 +1251,117 @@ Your App Teneo Backend Agent
1142
1251
 
1143
1252
  ---
1144
1253
 
1254
+ ## 🔗 Wallet Transaction Flow (On-Chain Actions)
1255
+
1256
+ Some agents (e.g., Squid Router for cross-chain swaps) need your wallet to sign and submit on-chain transactions. The SDK handles this through a simple event-driven flow.
1257
+
1258
+ ### How It Works
1259
+
1260
+ 1. **Agent requests a transaction** — the SDK emits a `wallet:tx_requested` event with the transaction details
1261
+ 2. **Your app signs and submits** — using your wallet/signer of choice (ethers, viem, web3.js, etc.)
1262
+ 3. **Your app reports the result** — call `sendTxResult()` so the agent knows what happened
1263
+ 4. **Agent may request more transactions** — for multi-step operations (e.g., approve + swap), the agent sends additional `trigger_wallet_tx` messages after each result
1264
+
1265
+ ```
1266
+ Your App Teneo Backend Agent
1267
+ │ │ │
1268
+ │ │<── trigger_wallet_tx ────│ (e.g., "approve USDC")
1269
+ │<── wallet:tx_requested ─────│ │
1270
+ │ │ │
1271
+ │ [Sign & submit tx] │ │
1272
+ │ │ │
1273
+ │──── tx_result ─────────────>│──── tx_result ──────────>│
1274
+ │ (confirmed + txHash) │ │
1275
+ │ │ │
1276
+ │ │<── trigger_wallet_tx ────│ (e.g., "execute swap")
1277
+ │<── wallet:tx_requested ─────│ │
1278
+ │ │ │
1279
+ │ [Sign & submit tx] │ │
1280
+ │ │ │
1281
+ │──── tx_result ─────────────>│──── tx_result ──────────>│
1282
+ │ │ │
1283
+ │<───── task_response ────────│<────── response ─────────│
1284
+ └ └ └
1285
+ ```
1286
+
1287
+ ### Basic Usage
1288
+
1289
+ ```typescript
1290
+ sdk.on("wallet:tx_requested", async (data) => {
1291
+ console.log(`Transaction requested by ${data.agentName}: ${data.description}`);
1292
+ console.log(`Chain: ${data.tx.chainId}, To: ${data.tx.to}, Value: ${data.tx.value}`);
1293
+
1294
+ try {
1295
+ // Sign and submit using your preferred library
1296
+ const txHash = await wallet.sendTransaction({
1297
+ to: data.tx.to,
1298
+ value: data.tx.value,
1299
+ data: data.tx.data,
1300
+ chainId: data.tx.chainId,
1301
+ });
1302
+
1303
+ // Wait for confirmation
1304
+ const receipt = await provider.waitForTransaction(txHash);
1305
+
1306
+ // Report success — include data.room so the server can route it back to the agent
1307
+ await sdk.sendTxResult(data.taskId, "confirmed", txHash, undefined, data.room);
1308
+ } catch (err) {
1309
+ // Report failure
1310
+ await sdk.sendTxResult(data.taskId, "failed", undefined, err.message, data.room);
1311
+ }
1312
+ });
1313
+ ```
1314
+
1315
+ ### Rejecting a Transaction
1316
+
1317
+ If the transaction is optional (`data.optional === true`) or you don't want to sign:
1318
+
1319
+ ```typescript
1320
+ await sdk.sendTxResult(data.taskId, "rejected", undefined, undefined, data.room);
1321
+ ```
1322
+
1323
+ ### Event: `wallet:tx_requested`
1324
+
1325
+ | Field | Type | Description |
1326
+ |-------|------|-------------|
1327
+ | `taskId` | `string` | Task identifier — pass this back in `sendTxResult()` |
1328
+ | `agentName` | `string?` | Name of the agent requesting the transaction |
1329
+ | `tx.to` | `string` | Target contract/address |
1330
+ | `tx.value` | `string` | Value in wei |
1331
+ | `tx.data` | `string?` | Encoded calldata (for contract interactions) |
1332
+ | `tx.chainId` | `number` | Target chain (e.g., `8453` for Base) |
1333
+ | `description` | `string?` | Human-readable description of the transaction |
1334
+ | `optional` | `boolean` | Whether the user can skip this transaction |
1335
+ | `room` | `string?` | Room ID — **must** be passed back in `sendTxResult()` for routing |
1336
+
1337
+ ### Method: `sendTxResult()`
1338
+
1339
+ ```typescript
1340
+ await sdk.sendTxResult(taskId, status, txHash?, error?, room?)
1341
+ ```
1342
+
1343
+ | Parameter | Type | Description |
1344
+ |-----------|------|-------------|
1345
+ | `taskId` | `string` | The `taskId` from the `wallet:tx_requested` event |
1346
+ | `status` | `"confirmed" \| "rejected" \| "failed"` | Transaction outcome |
1347
+ | `txHash` | `string?` | On-chain transaction hash (required for `"confirmed"`) |
1348
+ | `error` | `string?` | Error message (for `"failed"` status) |
1349
+ | `room` | `string?` | Room ID from the `wallet:tx_requested` event (required for routing) |
1350
+
1351
+ > **Important:** Always pass `data.room` from the event back into `sendTxResult()`. The server uses this to route the result to the correct agent. Without it, the agent won't receive your response and multi-step transactions will stall.
1352
+
1353
+ ### Multi-Step Transactions
1354
+
1355
+ Some operations require multiple sequential transactions (e.g., ERC-20 approve followed by a swap). The agent handles sequencing — your code just needs to keep listening:
1356
+
1357
+ 1. Agent sends `trigger_wallet_tx` #1 (approve) → you sign → you call `sendTxResult()`
1358
+ 2. Agent receives the result, then sends `trigger_wallet_tx` #2 (swap) → you sign → you call `sendTxResult()`
1359
+ 3. Agent sends `task_response` with the final outcome
1360
+
1361
+ Your `wallet:tx_requested` listener stays active for the entire lifecycle. Each transaction arrives as a separate event with the **same `taskId`** but different `tx` data. The task is only resolved when the agent sends the final `task_response`.
1362
+
1363
+ ---
1364
+
1145
1365
  ## 🎨 Event System
1146
1366
 
1147
1367
  The SDK is fully event-driven. Subscribe to what matters:
@@ -1196,6 +1416,16 @@ sdk.on("room:unsubscribed", (data) => {
1196
1416
  });
1197
1417
  ```
1198
1418
 
1419
+ ### Wallet Transaction Events
1420
+
1421
+ ```typescript
1422
+ sdk.on("wallet:tx_requested", async (data) => {
1423
+ console.log(`🔗 ${data.agentName} requests tx on chain ${data.tx.chainId}`);
1424
+ console.log(` ${data.description}`);
1425
+ // See "Wallet Transaction Flow" section for full handling
1426
+ });
1427
+ ```
1428
+
1199
1429
  ---
1200
1430
 
1201
1431
  ## ⚙️ Configuration
@@ -9,6 +9,7 @@ import { WebhookHandler } from "../handlers/webhook-handler";
9
9
  import { ResponseFormatter, FormattedResponse } from "../formatters/response-formatter";
10
10
  import { Logger, ResponseFormat, PricingInfo } from "../types";
11
11
  import { SDKEvents } from "../types/events";
12
+ import type { AgentRoomManager } from "./agent-room-manager";
12
13
  import type { SecurePrivateKey } from "../utils/secure-private-key";
13
14
  export interface SendMessageOptions {
14
15
  room: string;
@@ -61,6 +62,7 @@ export interface MessageRouterConfig {
61
62
  paymentNetwork?: string;
62
63
  paymentAsset?: string;
63
64
  network?: string;
65
+ autoSummon?: boolean;
64
66
  }
65
67
  export declare class MessageRouter extends EventEmitter<SDKEvents> {
66
68
  private readonly wsClient;
@@ -78,6 +80,8 @@ export declare class MessageRouter extends EventEmitter<SDKEvents> {
78
80
  private readonly paymentNetwork;
79
81
  private readonly paymentAsset;
80
82
  private readonly networkName;
83
+ private readonly autoSummon;
84
+ private agentRoomManager;
81
85
  constructor(wsClient: WebSocketClient, webhookHandler: WebhookHandler, responseFormatter: ResponseFormatter, logger: Logger, config: MessageRouterConfig);
82
86
  /**
83
87
  * Gets the payment network CAIP-2 identifier, resolving from network name or default.
@@ -94,6 +98,10 @@ export declare class MessageRouter extends EventEmitter<SDKEvents> {
94
98
  * Must be called before using requestQuote/confirmQuote with paid tasks.
95
99
  */
96
100
  setPaymentClient(secureKey: SecurePrivateKey, walletAddress: string): void;
101
+ /**
102
+ * Sets the agent room manager for auto-summon functionality (v2.4.0).
103
+ */
104
+ setAgentRoomManager(manager: AgentRoomManager): void;
97
105
  /**
98
106
  * Sends a message to agents via the coordinator.
99
107
  * The coordinator intelligently selects the most appropriate agent.
@@ -164,6 +172,33 @@ export declare class MessageRouter extends EventEmitter<SDKEvents> {
164
172
  * Returns the quote data for manual confirmation.
165
173
  */
166
174
  requestQuote(content: string, room: string, networkOverride?: string | number): Promise<QuoteResult>;
175
+ /**
176
+ * Internal quote request with error racing and auto-summon support.
177
+ * @param isRetry - true on auto-summon retry to prevent infinite loops
178
+ */
179
+ private _requestQuoteInternal;
180
+ /**
181
+ * Pre-flight autosummon: adds agent to room before sending the command.
182
+ * Called when cache confirms agent is NOT in room, avoiding the reject-retry cycle.
183
+ */
184
+ private preFlightAutoSummon;
185
+ /**
186
+ * Handles auto-summon: finds the agent, adds it to the room, and retries the quote.
187
+ * Fallback path triggered by coordinator reject when pre-flight was skipped (cache empty).
188
+ */
189
+ private handleAutoSummon;
190
+ /**
191
+ * Checks if a message string indicates an agent-access error from the backend.
192
+ * Matches patterns like:
193
+ * - "agent X not found"
194
+ * - "agent X does not have access to room Y"
195
+ * - "Agent not found. Check the agent name..."
196
+ */
197
+ private isAgentAccessErrorMessage;
198
+ /**
199
+ * Checks if an error is an "Agent not found / not in room" error from the backend.
200
+ */
201
+ private isAgentNotFoundError;
167
202
  /**
168
203
  * Confirms a quote and executes the task with payment.
169
204
  * Can optionally wait for the task response.
@@ -1 +1 @@
1
- {"version":3,"file":"message-router.d.ts","sourceRoot":"","sources":["../../src/managers/message-router.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"message-router.d.ts","sourceRoot":"","sources":["../../src/managers/message-router.ts"],"names":[],"mappings":"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"}
@@ -33,6 +33,9 @@ class MessageRouter extends eventemitter3_1.EventEmitter {
33
33
  paymentNetwork; // CAIP-2 format if set
34
34
  paymentAsset;
35
35
  networkName; // Network name (peaq, base, avalanche)
36
+ // Auto-summon (v2.4.0)
37
+ autoSummon;
38
+ agentRoomManager = null;
36
39
  constructor(wsClient, webhookHandler, responseFormatter, logger, config) {
37
40
  super();
38
41
  this.wsClient = wsClient;
@@ -51,6 +54,7 @@ class MessageRouter extends eventemitter3_1.EventEmitter {
51
54
  this.paymentNetwork = config.paymentNetwork ?? "";
52
55
  this.paymentAsset = config.paymentAsset ?? "";
53
56
  this.networkName = config.network ?? "";
57
+ this.autoSummon = config.autoSummon ?? false;
54
58
  this.setupEventForwarding();
55
59
  }
56
60
  /**
@@ -98,6 +102,12 @@ class MessageRouter extends eventemitter3_1.EventEmitter {
98
102
  asset: this.getResolvedPaymentAsset()
99
103
  });
100
104
  }
105
+ /**
106
+ * Sets the agent room manager for auto-summon functionality (v2.4.0).
107
+ */
108
+ setAgentRoomManager(manager) {
109
+ this.agentRoomManager = manager;
110
+ }
101
111
  /**
102
112
  * Sends a message to agents via the coordinator.
103
113
  * The coordinator intelligently selects the most appropriate agent.
@@ -251,18 +261,82 @@ class MessageRouter extends eventemitter3_1.EventEmitter {
251
261
  * Returns the quote data for manual confirmation.
252
262
  */
253
263
  async requestQuote(content, room, networkOverride) {
264
+ return this._requestQuoteInternal(content, room, networkOverride, false);
265
+ }
266
+ /**
267
+ * Internal quote request with error racing and auto-summon support.
268
+ * @param isRetry - true on auto-summon retry to prevent infinite loops
269
+ */
270
+ async _requestQuoteInternal(content, room, networkOverride, isRetry) {
254
271
  if (!this.wsClient.isConnected) {
255
272
  throw new events_1.SDKError("Not connected to Teneo network", error_codes_1.ErrorCode.NOT_CONNECTED);
256
273
  }
257
274
  // Include payment network in request so backend returns correct contract addresses
258
275
  const resolvedNetwork = this.getResolvedPaymentNetwork(networkOverride);
259
276
  const message = (0, types_1.createRequestTask)(content, room, resolvedNetwork);
260
- this.logger.debug("MessageRouter: Requesting quote", { content, room, network: resolvedNetwork });
277
+ this.logger.debug("MessageRouter: Requesting quote", { content, room, network: resolvedNetwork, isRetry });
278
+ // Pre-flight autosummon: check cache before sending to avoid reject-retry cycle
279
+ if (this.autoSummon && this.agentRoomManager && !isRetry) {
280
+ const match = content.match(/^@(\S+)/);
281
+ if (match) {
282
+ const agentName = match[1];
283
+ const inRoom = this.agentRoomManager.checkAgentInRoom(room, agentName);
284
+ if (inRoom === false) {
285
+ this.logger.info("MessageRouter: Pre-flight autosummon", { agentName, room });
286
+ try {
287
+ await this.preFlightAutoSummon(agentName, room);
288
+ }
289
+ catch (e) {
290
+ this.logger.debug("MessageRouter: Pre-flight failed, falling back", { error: e.message });
291
+ }
292
+ }
293
+ }
294
+ }
261
295
  await this.wsClient.sendMessage(message);
262
- const quote = await (0, event_waiter_1.waitForEvent)(this.wsClient, "quote:received", {
296
+ // Race quote:received against error events to detect "Agent not found" quickly.
297
+ // The backend may signal "agent not in room" via:
298
+ // 1. An "error" event with "agent ... not found"
299
+ // 2. An "agent:response" from the coordinator with content like
300
+ // "agent X does not have access to room Y"
301
+ // We race all three to catch whichever arrives first.
302
+ const quotePromise = (0, event_waiter_1.waitForEvent)(this.wsClient, "quote:received", {
263
303
  timeout: this.quoteTimeout,
264
304
  timeoutMessage: `Quote request timed out after ${this.quoteTimeout}ms`
265
305
  });
306
+ const errorPromise = (0, event_waiter_1.waitForEvent)(this.wsClient, "error", {
307
+ timeout: this.quoteTimeout + 1000,
308
+ filter: (err) => {
309
+ const msg = (err.message || "").toLowerCase();
310
+ return this.isAgentAccessErrorMessage(msg);
311
+ }
312
+ });
313
+ // Also race against agent:response that contains an access-denied error from the coordinator
314
+ const agentErrorPromise = (0, event_waiter_1.waitForEvent)(this.wsClient, "agent:response", {
315
+ timeout: this.quoteTimeout + 1000,
316
+ filter: (resp) => {
317
+ const msg = (resp.content || "").toLowerCase();
318
+ return this.isAgentAccessErrorMessage(msg);
319
+ }
320
+ });
321
+ let quote;
322
+ try {
323
+ quote = await Promise.race([
324
+ quotePromise,
325
+ errorPromise.then((err) => { throw err; }),
326
+ agentErrorPromise.then((resp) => {
327
+ throw new events_1.SDKError(resp.content, error_codes_1.ErrorCode.AGENT_NOT_IN_ROOM);
328
+ })
329
+ ]);
330
+ }
331
+ catch (error) {
332
+ if (this.isAgentNotFoundError(error) && !isRetry) {
333
+ if (this.autoSummon) {
334
+ return this.handleAutoSummon(content, room, networkOverride);
335
+ }
336
+ throw new events_1.SDKError("Agent not found in room. Enable autoSummon to automatically add agents.", error_codes_1.ErrorCode.AGENT_NOT_IN_ROOM);
337
+ }
338
+ throw error;
339
+ }
266
340
  const result = {
267
341
  taskId: quote.data.task_id,
268
342
  agentId: quote.data.agent_id,
@@ -290,6 +364,73 @@ class MessageRouter extends eventemitter3_1.EventEmitter {
290
364
  this.pendingQuotes.set(result.taskId, result);
291
365
  return result;
292
366
  }
367
+ /**
368
+ * Pre-flight autosummon: adds agent to room before sending the command.
369
+ * Called when cache confirms agent is NOT in room, avoiding the reject-retry cycle.
370
+ */
371
+ async preFlightAutoSummon(agentName, room) {
372
+ if (!this.agentRoomManager) {
373
+ throw new events_1.SDKError("Auto-summon requires AgentRoomManager", error_codes_1.ErrorCode.AUTOSUMMON_FAILED);
374
+ }
375
+ this.wsClient.emit("autosummon:start", agentName, room);
376
+ const available = await this.agentRoomManager.listAvailableAgents(room, false);
377
+ const agent = available.find((a) => a.agent_id === agentName || a.agent_name === agentName);
378
+ if (!agent) {
379
+ this.wsClient.emit("autosummon:failed", agentName, room, "Agent not found or offline");
380
+ throw new events_1.SDKError(`Agent '${agentName}' does not exist or is offline`, error_codes_1.ErrorCode.AGENT_NOT_FOUND);
381
+ }
382
+ await this.agentRoomManager.addAgentToRoom(room, agent.agent_id);
383
+ this.wsClient.emit("autosummon:success", agentName, agent.agent_id, room);
384
+ this.logger.info("MessageRouter: Pre-flight autosummon succeeded", { agentId: agent.agent_id });
385
+ }
386
+ /**
387
+ * Handles auto-summon: finds the agent, adds it to the room, and retries the quote.
388
+ * Fallback path triggered by coordinator reject when pre-flight was skipped (cache empty).
389
+ */
390
+ async handleAutoSummon(content, room, networkOverride) {
391
+ if (!this.agentRoomManager) {
392
+ throw new events_1.SDKError("Auto-summon requires AgentRoomManager", error_codes_1.ErrorCode.AUTOSUMMON_FAILED);
393
+ }
394
+ const match = content.match(/^@(\S+)/);
395
+ if (!match) {
396
+ throw new events_1.SDKError("Cannot extract agent name for auto-summon", error_codes_1.ErrorCode.AUTOSUMMON_FAILED);
397
+ }
398
+ const agentName = match[1];
399
+ this.logger.info("MessageRouter: Auto-summoning agent", { agentName, room });
400
+ this.wsClient.emit("autosummon:start", agentName, room);
401
+ const available = await this.agentRoomManager.listAvailableAgents(room, false);
402
+ const agent = available.find((a) => a.agent_id === agentName || a.agent_name === agentName);
403
+ if (!agent) {
404
+ this.wsClient.emit("autosummon:failed", agentName, room, "Agent not found or offline");
405
+ throw new events_1.SDKError(`Agent '${agentName}' does not exist or is offline`, error_codes_1.ErrorCode.AGENT_NOT_FOUND);
406
+ }
407
+ await this.agentRoomManager.addAgentToRoom(room, agent.agent_id);
408
+ this.wsClient.emit("autosummon:success", agentName, agent.agent_id, room);
409
+ this.logger.info("MessageRouter: Agent auto-summoned, retrying", { agentId: agent.agent_id });
410
+ return this._requestQuoteInternal(content, room, networkOverride, true);
411
+ }
412
+ /**
413
+ * Checks if a message string indicates an agent-access error from the backend.
414
+ * Matches patterns like:
415
+ * - "agent X not found"
416
+ * - "agent X does not have access to room Y"
417
+ * - "Agent not found. Check the agent name..."
418
+ */
419
+ isAgentAccessErrorMessage(msg) {
420
+ if (!msg.includes("agent"))
421
+ return false;
422
+ return (msg.includes("not found") ||
423
+ msg.includes("does not have access") ||
424
+ msg.includes("not in room") ||
425
+ msg.includes("no access"));
426
+ }
427
+ /**
428
+ * Checks if an error is an "Agent not found / not in room" error from the backend.
429
+ */
430
+ isAgentNotFoundError(error) {
431
+ const msg = (error instanceof Error ? error.message : String(error)).toLowerCase();
432
+ return this.isAgentAccessErrorMessage(msg);
433
+ }
293
434
  /**
294
435
  * Confirms a quote and executes the task with payment.
295
436
  * Can optionally wait for the task response.