@dainprotocol/service-sdk 1.1.11 → 1.1.14

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 @@
1
+ export {};
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+ // File: src/__tests__/crypto-plugin.test.ts
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const tslib_1 = require("tslib");
5
+ const client_auth_1 = require("@/client/client-auth");
6
+ const client_1 = require("@/client/client");
7
+ const ed25519_1 = require("@noble/curves/ed25519");
8
+ const bs58_1 = tslib_1.__importDefault(require("bs58"));
9
+ const nodeService_1 = require("@/service/nodeService");
10
+ const core_1 = require("@/service/core");
11
+ const zod_1 = require("zod");
12
+ const crypto_plugin_1 = require("@/plugins/crypto-plugin");
13
+ const cuid2_1 = require("@paralleldrive/cuid2");
14
+ describe("DAIN Framework CryptoPlugin System", () => {
15
+ // Generate test keys
16
+ const servicePrivateKey = ed25519_1.ed25519.utils.randomPrivateKey();
17
+ const servicePublicKey = ed25519_1.ed25519.getPublicKey(servicePrivateKey);
18
+ const serviceAddress = bs58_1.default.encode(servicePublicKey);
19
+ const clientPrivateKey = ed25519_1.ed25519.utils.randomPrivateKey();
20
+ // Set up client authentication
21
+ const agentAuth = new client_auth_1.DainClientAuth({
22
+ privateKeyBase58: bs58_1.default.encode(clientPrivateKey),
23
+ agentId: "agent-crypto-test",
24
+ orgId: "org-crypto-test",
25
+ });
26
+ // Create a test wallet configuration
27
+ const testWallets = [
28
+ { chain: "sol", address: "Sol11111111111111111111111111111111111111111" },
29
+ { chain: "eth", address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" },
30
+ { chain: "arb", address: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" }
31
+ ];
32
+ // Create separate CryptoPlugin instances for client and service
33
+ const clientCryptoPlugin = new crypto_plugin_1.CryptoPlugin(testWallets);
34
+ const serviceCryptoPlugin = new crypto_plugin_1.CryptoPlugin(); // Service doesn't need wallet information
35
+ // Initialize the connection to the DAIN service with the client crypto plugin
36
+ const dainConnection = new client_1.DainServiceConnection("http://localhost:4485", agentAuth, {
37
+ plugins: [clientCryptoPlugin]
38
+ });
39
+ // Create a mock Solana transaction (added id field)
40
+ const mockSolanaTransaction = {
41
+ encodedTx: "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
42
+ chain: "sol",
43
+ signer: "Sol11111111111111111111111111111111111111111",
44
+ metadata: {
45
+ description: "Test SOL Transfer",
46
+ amount: 0.01,
47
+ recipient: "SolRecipient111111111111111111111111111111111"
48
+ }
49
+ };
50
+ // Create a mock Ethereum transaction (added id field)
51
+ const mockEthereumTransaction = {
52
+ encodedTx: "0xf86c0a85046c7cfe0083016dea94d1310c1e0aa1b9d5dfe80aa9ee4a8b0a48d0f2a780a46057361d00000000000000000000000000000000000000000000000000000000000003e880820a95a0f5d4c5201602ddf5110f112a85fb0cf39a85e3a3174cd237b8383670cab7a3b5a048f2be5cc9f0a0b3f22e60f709c649d5a6a4ad3d70ce44ec80b96ffe7843508c",
53
+ chain: "eth",
54
+ signer: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
55
+ metadata: {
56
+ description: "Test ETH Transfer",
57
+ amount: 0.1,
58
+ recipient: "0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
59
+ gasLimit: 21000
60
+ }
61
+ };
62
+ // Create a test tool that uses wallet information and creates unsigned transactions
63
+ const cryptoTransferTool = (0, core_1.createTool)({
64
+ id: "crypto-transfer",
65
+ name: "Cryptocurrency Transfer Tool",
66
+ description: "Creates unsigned transactions for cryptocurrency transfers",
67
+ input: zod_1.z.object({
68
+ amount: zod_1.z.number().positive(),
69
+ chain: zod_1.z.enum(["sol", "eth", "arb"]),
70
+ recipientAddress: zod_1.z.string()
71
+ }),
72
+ output: zod_1.z.object({
73
+ success: zod_1.z.boolean(),
74
+ message: zod_1.z.string(),
75
+ signatureRequests: zod_1.z.array(zod_1.z.object({
76
+ txs: zod_1.z.array(zod_1.z.object({
77
+ id: zod_1.z.string(),
78
+ encodedTx: zod_1.z.string(),
79
+ chain: zod_1.z.enum(["sol", "eth", "arb"]),
80
+ signer: zod_1.z.string(),
81
+ metadata: zod_1.z.any().optional()
82
+ }))
83
+ })).optional()
84
+ }),
85
+ handler: async ({ amount, chain, recipientAddress }, agentInfo, context) => {
86
+ // Use the SERVICE-SIDE plugin (serviceCryptoPlugin) helper to get the user's wallets
87
+ const wallets = serviceCryptoPlugin.getUserWallets(context);
88
+ console.log(`[SERVICE] Available user wallets:`, wallets);
89
+ // Get the wallet for the specified chain
90
+ const userWallet = serviceCryptoPlugin.getUserWalletForChain(context, chain);
91
+ if (!userWallet) {
92
+ return {
93
+ text: `No wallet found for ${chain} chain`,
94
+ data: {
95
+ success: false,
96
+ message: `No ${chain} wallet found for this user. Please connect a ${chain} wallet.`
97
+ },
98
+ ui: null
99
+ };
100
+ }
101
+ console.log(`[SERVICE] Using ${chain} wallet: ${userWallet} for transfer of ${amount} to ${recipientAddress}`);
102
+ // Create mock transactions based on the chain
103
+ let mockTransaction;
104
+ if (chain === "sol") {
105
+ mockTransaction = {
106
+ ...mockSolanaTransaction,
107
+ signer: userWallet,
108
+ metadata: {
109
+ ...mockSolanaTransaction.metadata,
110
+ amount: amount,
111
+ recipient: recipientAddress
112
+ }
113
+ };
114
+ }
115
+ else if (chain === "eth" || chain === "arb") {
116
+ mockTransaction = {
117
+ ...mockEthereumTransaction,
118
+ chain: chain,
119
+ signer: userWallet,
120
+ metadata: {
121
+ ...mockEthereumTransaction.metadata,
122
+ amount: amount,
123
+ recipient: recipientAddress
124
+ }
125
+ };
126
+ }
127
+ else {
128
+ return {
129
+ text: `Unsupported chain: ${chain}`,
130
+ data: {
131
+ success: false,
132
+ message: `Chain ${chain} is not supported yet.`
133
+ },
134
+ ui: null
135
+ };
136
+ }
137
+ // Create a transaction with a unique ID using the service plugin helper
138
+ const transactionWithId = serviceCryptoPlugin.createTransaction(mockTransaction);
139
+ // Log the transaction ID for debugging
140
+ console.log(`[SERVICE] Created transaction with ID: ${transactionWithId.id}`);
141
+ // Create a signature request using the SERVICE-SIDE plugin helper
142
+ const signatureRequest = serviceCryptoPlugin.createTransactionRequest([transactionWithId]);
143
+ return {
144
+ text: `Created unsigned ${chain} transaction for ${amount} to ${recipientAddress}`,
145
+ data: {
146
+ success: true,
147
+ message: `Created unsigned ${chain} transaction. Please sign to complete the transfer.`,
148
+ signatureRequests: [signatureRequest]
149
+ },
150
+ ui: null
151
+ };
152
+ },
153
+ });
154
+ // Initialize the DAIN service with the SERVICE crypto plugin instance
155
+ const dainService = (0, nodeService_1.defineDAINService)({
156
+ metadata: {
157
+ title: "Crypto Plugin Test Service",
158
+ description: "A DAIN service for testing the crypto plugin",
159
+ version: "1.0.0",
160
+ author: "Test Author",
161
+ tags: ["crypto", "plugin", "test"],
162
+ },
163
+ identity: {
164
+ publicKey: bs58_1.default.encode(servicePublicKey),
165
+ agentId: "crypto-agent",
166
+ orgId: "crypto-org",
167
+ privateKey: bs58_1.default.encode(servicePrivateKey),
168
+ },
169
+ tools: [cryptoTransferTool],
170
+ plugins: [serviceCryptoPlugin] // Using service-side plugin instance
171
+ });
172
+ let server;
173
+ beforeAll(async () => {
174
+ server = await dainService.startNode({ port: 4485 });
175
+ await new Promise(resolve => setTimeout(resolve, 500)); // Give server time to start
176
+ });
177
+ afterAll(async () => {
178
+ await server.shutdown();
179
+ });
180
+ it("should assign unique IDs to transactions", async () => {
181
+ console.log("[CLIENT] Using client plugin with wallets:", clientCryptoPlugin.getWallets());
182
+ console.log("[SERVICE] Using service plugin with wallets:", serviceCryptoPlugin.getWallets());
183
+ // Call the tool WITHOUT providing wallet information in the params
184
+ // The client plugin should automatically add wallet info
185
+ const params = {
186
+ amount: 0.05,
187
+ chain: "sol",
188
+ recipientAddress: "SolRecipient222222222222222222222222222222222"
189
+ // No wallets provided - they should come from the client plugin
190
+ };
191
+ // Call the tool
192
+ const result = await dainConnection.callTool("crypto-transfer", params);
193
+ console.log("[CLIENT] Received response:", JSON.stringify(result, null, 2));
194
+ // Verify the response
195
+ expect(result.data.success).toBe(true);
196
+ expect(result.data.message).toContain("Created unsigned sol transaction");
197
+ // Use the CLIENT plugin helper to extract transaction requests
198
+ const signatureRequests = clientCryptoPlugin.getRequestedCryptoSignatures(result);
199
+ console.log("[CLIENT] Extracted signature requests:", JSON.stringify(signatureRequests, null, 2));
200
+ expect(signatureRequests).toBeDefined();
201
+ expect(signatureRequests.length).toBe(1);
202
+ expect(signatureRequests[0].txs.length).toBe(1);
203
+ const transaction = signatureRequests[0].txs[0];
204
+ expect(transaction.chain).toBe("sol");
205
+ expect(transaction.signer).toBe(testWallets[0].address);
206
+ expect(transaction.encodedTx).toBeDefined();
207
+ // Verify the transaction has an ID
208
+ expect(transaction.id).toBeDefined();
209
+ expect(typeof transaction.id).toBe("string");
210
+ expect(transaction.id.length).toBeGreaterThan(10);
211
+ // Save the transaction ID for later use
212
+ const txId = transaction.id;
213
+ console.log(`[CLIENT] Transaction ID: ${txId}`);
214
+ // Test getTransactionById method
215
+ const foundTx = clientCryptoPlugin.getTransactionById(result, txId);
216
+ expect(foundTx).toBeDefined();
217
+ expect(foundTx?.id).toBe(txId);
218
+ });
219
+ it("should handle Ethereum transactions with unique IDs", async () => {
220
+ // Prepare the tool parameters without wallet information
221
+ const params = {
222
+ amount: 0.25,
223
+ chain: "eth",
224
+ recipientAddress: "0xRecipientEthereumAddress0123456789abcdef"
225
+ // No wallets provided - they should come from the client plugin
226
+ };
227
+ // Call the tool
228
+ const result = await dainConnection.callTool("crypto-transfer", params);
229
+ // Verify the response
230
+ expect(result.data.success).toBe(true);
231
+ expect(result.data.message).toContain("Created unsigned eth transaction");
232
+ // Get transaction requests using the CLIENT plugin
233
+ const signatureRequests = clientCryptoPlugin.getRequestedCryptoSignatures(result);
234
+ const transaction = signatureRequests[0].txs[0];
235
+ expect(transaction.chain).toBe("eth");
236
+ expect(transaction.signer).toBe(testWallets[1].address);
237
+ expect(transaction.metadata?.amount).toBe(0.25);
238
+ expect(transaction.metadata?.recipient).toBe("0xRecipientEthereumAddress0123456789abcdef");
239
+ // Verify the transaction has an ID
240
+ expect(transaction.id).toBeDefined();
241
+ expect(typeof transaction.id).toBe("string");
242
+ console.log(`[CLIENT] Ethereum transaction ID: ${transaction.id}`);
243
+ });
244
+ it("should show wallet information flow and transaction IDs", async () => {
245
+ // Add a new custom wallet to the client plugin
246
+ clientCryptoPlugin.addWallet({
247
+ chain: "sol",
248
+ address: "CustomSolAddress123456789"
249
+ });
250
+ // Call the tool with the updated client plugin
251
+ const result = await dainConnection.callTool("crypto-transfer", {
252
+ amount: 0.75,
253
+ chain: "sol",
254
+ recipientAddress: "NewRecipientAddress"
255
+ });
256
+ // Verify the result uses the updated wallet
257
+ const signatureRequests = clientCryptoPlugin.getRequestedCryptoSignatures(result);
258
+ const transaction = signatureRequests[0].txs[0];
259
+ // The address should be the new custom one we just added
260
+ expect(transaction.signer).toBe("CustomSolAddress123456789");
261
+ expect(transaction.metadata?.amount).toBe(0.75);
262
+ // Verify the transaction has an ID
263
+ expect(transaction.id).toBeDefined();
264
+ console.log(`[CLIENT] Updated wallet transaction ID: ${transaction.id}`);
265
+ });
266
+ it("should demonstrate creating and accessing transactions with IDs", async () => {
267
+ // Create a transaction directly with the createTransaction method
268
+ const txData = {
269
+ encodedTx: "0xManuallyCreatedTx",
270
+ chain: "eth",
271
+ signer: "0xManualAddress",
272
+ metadata: { test: true, purpose: "Demo" }
273
+ };
274
+ // Create a transaction with the client plugin
275
+ const tx1 = clientCryptoPlugin.createTransaction(txData);
276
+ // Create another transaction with the same data
277
+ const tx2 = clientCryptoPlugin.createTransaction(txData);
278
+ // Create a transaction with a predefined ID
279
+ const customId = (0, cuid2_1.createId)();
280
+ const tx3 = clientCryptoPlugin.createTransaction({
281
+ ...txData,
282
+ id: customId
283
+ });
284
+ // Verify each transaction has a unique ID
285
+ expect(tx1.id).toBeDefined();
286
+ expect(tx2.id).toBeDefined();
287
+ expect(tx3.id).toBeDefined();
288
+ // Transaction IDs should be unique
289
+ expect(tx1.id).not.toBe(tx2.id);
290
+ // Custom ID should be preserved
291
+ expect(tx3.id).toBe(customId);
292
+ console.log(`[TEST] Manual transaction IDs:`, {
293
+ tx1Id: tx1.id,
294
+ tx2Id: tx2.id,
295
+ tx3Id: tx3.id
296
+ });
297
+ // Create a signature request with multiple transactions
298
+ const signatureRequest = clientCryptoPlugin.createTransactionRequest([tx1, tx2, tx3]);
299
+ // Verify the signature request contains all transactions
300
+ expect(signatureRequest.txs.length).toBe(3);
301
+ expect(signatureRequest.txs.map(tx => tx.id)).toContain(tx1.id);
302
+ expect(signatureRequest.txs.map(tx => tx.id)).toContain(tx2.id);
303
+ expect(signatureRequest.txs.map(tx => tx.id)).toContain(tx3.id);
304
+ });
305
+ it("should allow service plugin to process transactions with additional data", async () => {
306
+ // Create a new test with a local function that adds metadata
307
+ // We'll use a real function instead of adding to the plugin instance
308
+ const addServiceMetadata = (tx) => {
309
+ return {
310
+ ...tx,
311
+ metadata: {
312
+ ...tx.metadata,
313
+ timestamp: Date.now(),
314
+ serviceId: "test-service-id",
315
+ enhanced: true
316
+ }
317
+ };
318
+ };
319
+ // Create a simple tool handler that would use this function
320
+ // This simulates what a service would do
321
+ const processTransaction = async (chain, userWallet) => {
322
+ // Create a basic transaction with ID
323
+ const baseTx = {
324
+ encodedTx: "0xBasicTransaction",
325
+ chain: chain,
326
+ signer: userWallet,
327
+ metadata: { basic: true }
328
+ };
329
+ // Create transaction with ID using the helper
330
+ const tx = serviceCryptoPlugin.createTransaction(baseTx);
331
+ // Enhance it with service-side metadata
332
+ const enhancedTx = addServiceMetadata(tx);
333
+ // Create the signature request
334
+ const request = {
335
+ txs: [enhancedTx]
336
+ };
337
+ return {
338
+ success: true,
339
+ signatureRequests: [request]
340
+ };
341
+ };
342
+ // Simulate processing with a simple test
343
+ const testWallet = "0xTestWalletAddress";
344
+ const result = await processTransaction("eth", testWallet);
345
+ // Verify the metadata was added
346
+ expect(result.signatureRequests[0].txs[0].metadata?.enhanced).toBe(true);
347
+ expect(result.signatureRequests[0].txs[0].metadata?.serviceId).toBe("test-service-id");
348
+ expect(result.signatureRequests[0].txs[0].metadata?.timestamp).toBeDefined();
349
+ expect(result.signatureRequests[0].txs[0].metadata?.basic).toBe(true); // Original data preserved
350
+ // Make sure the transaction info is correct
351
+ expect(result.signatureRequests[0].txs[0].chain).toBe("eth");
352
+ expect(result.signatureRequests[0].txs[0].signer).toBe(testWallet);
353
+ // Verify the transaction has an ID
354
+ expect(result.signatureRequests[0].txs[0].id).toBeDefined();
355
+ console.log(`[TEST] Service processed transaction ID: ${result.signatureRequests[0].txs[0].id}`);
356
+ });
357
+ });
358
+ //# sourceMappingURL=crypto-plugin.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto-plugin.test.js","sourceRoot":"","sources":["../../src/__tests__/crypto-plugin.test.ts"],"names":[],"mappings":"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"}
@@ -215,6 +215,42 @@ describe("DAIN Framework Integration", () => {
215
215
  ui: { type: "text" },
216
216
  }),
217
217
  });
218
+ // Create a dedicated error tool for testing
219
+ const errorTool = (0, nodeService_1.createTool)({
220
+ id: "integration-error-tool",
221
+ name: "Integration Error Tool",
222
+ description: "Tool that deliberately throws errors for testing",
223
+ input: zod_1.z.object({
224
+ errorType: zod_1.z.enum(["none", "synchronous", "async", "input"]),
225
+ errorMessage: zod_1.z.string().optional()
226
+ }),
227
+ output: zod_1.z.object({ result: zod_1.z.string() }),
228
+ handler: async ({ errorType, errorMessage = "Deliberate test error" }, agentInfo, context) => {
229
+ // Send UI update first to test partial success
230
+ if (context.updateUI) {
231
+ await context.updateUI({ ui: { type: "loading", message: "Starting error test..." } });
232
+ // Small delay to ensure UI update goes through
233
+ await new Promise(resolve => setTimeout(resolve, 200));
234
+ }
235
+ // Handle different error types
236
+ switch (errorType) {
237
+ case "none":
238
+ return {
239
+ text: "No error occurred",
240
+ data: { result: "success" },
241
+ ui: null
242
+ };
243
+ case "synchronous":
244
+ throw new Error(errorMessage);
245
+ case "async":
246
+ await new Promise(resolve => setTimeout(resolve, 300));
247
+ throw new Error(errorMessage);
248
+ case "input":
249
+ // This simulates validation errors
250
+ throw new Error(`Invalid input: ${errorMessage}`);
251
+ }
252
+ },
253
+ });
218
254
  const dainService = (0, nodeService_1.defineDAINService)({
219
255
  metadata: {
220
256
  title: "Weather DAIN Service",
@@ -230,7 +266,7 @@ describe("DAIN Framework Integration", () => {
230
266
  privateKey: bs58_1.default.encode(privateKey),
231
267
  },
232
268
  services: [weatherService],
233
- tools: [weatherTool, extraDataTool, confirmationTool, optionalParamsTool, noParamsTool],
269
+ tools: [weatherTool, extraDataTool, confirmationTool, optionalParamsTool, noParamsTool, errorTool],
234
270
  toolboxes: [weatherToolbox],
235
271
  contexts: [weatherContext],
236
272
  pinnables: [weatherPinnable],
@@ -241,7 +277,25 @@ describe("DAIN Framework Integration", () => {
241
277
  server = await dainService.startNode({ port: 3003 });
242
278
  });
243
279
  afterAll(async () => {
244
- await server.shutdown();
280
+ // Use a more robust approach to shutting down with proper cleanup
281
+ if (server) {
282
+ // Set a timeout for shutdown to complete
283
+ const timeout = setTimeout(() => {
284
+ console.warn('Server shutdown timed out, process may still have open handles');
285
+ }, 5000);
286
+ try {
287
+ await server.shutdown();
288
+ }
289
+ catch (err) {
290
+ console.error('Error shutting down server:', err);
291
+ }
292
+ finally {
293
+ clearTimeout(timeout);
294
+ server = null;
295
+ // Wait a moment to allow any lingering connections to close
296
+ await new Promise(resolve => setTimeout(resolve, 500));
297
+ }
298
+ }
245
299
  });
246
300
  test("Service metadata is correct", () => {
247
301
  const metadata = dainService.getMetadata();
@@ -249,7 +303,7 @@ describe("DAIN Framework Integration", () => {
249
303
  expect(metadata.tags).toContain("weather");
250
304
  });
251
305
  test("Service has correct tools and services", () => {
252
- expect(dainService.getTools()).toHaveLength(5);
306
+ expect(dainService.getTools()).toHaveLength(6);
253
307
  expect(dainService.getServices()).toHaveLength(1);
254
308
  expect(dainService.getToolboxes()).toHaveLength(1);
255
309
  });
@@ -362,6 +416,7 @@ describe("DAIN Framework Integration", () => {
362
416
  const port = app.port;
363
417
  const response = await dainConnection.makeRequest("GET", "/getAllToolsAsJsonSchema", {});
364
418
  console.log("JSON SCHEMA", JSON.stringify(response, null, 2));
419
+ // fs.writeFileSync("jsonSchema.json", JSON.stringify(response, null, 2));
365
420
  expect(response).toEqual({
366
421
  "tools": [
367
422
  {
@@ -460,16 +515,13 @@ describe("DAIN Framework Integration", () => {
460
515
  "type": "object",
461
516
  "properties": {
462
517
  "param1": {
463
- "type": "string",
464
- "optional": true
518
+ "type": "string"
465
519
  },
466
520
  "param2": {
467
- "type": "number",
468
- "optional": true
521
+ "type": "number"
469
522
  },
470
523
  "param3": {
471
- "type": "boolean",
472
- "optional": true
524
+ "type": "boolean"
473
525
  }
474
526
  },
475
527
  "additionalProperties": false,
@@ -501,6 +553,9 @@ describe("DAIN Framework Integration", () => {
501
553
  "name": "No Parameters Tool",
502
554
  "description": "Tool that requires no parameters",
503
555
  "inputSchema": {
556
+ "type": "object",
557
+ "properties": {},
558
+ "additionalProperties": false,
504
559
  "$schema": "http://json-schema.org/draft-07/schema#"
505
560
  },
506
561
  "outputSchema": {
@@ -516,6 +571,46 @@ describe("DAIN Framework Integration", () => {
516
571
  "additionalProperties": false,
517
572
  "$schema": "http://json-schema.org/draft-07/schema#"
518
573
  }
574
+ },
575
+ {
576
+ "id": "integration-error-tool",
577
+ "name": "Integration Error Tool",
578
+ "description": "Tool that deliberately throws errors for testing",
579
+ "inputSchema": {
580
+ "type": "object",
581
+ "properties": {
582
+ "errorType": {
583
+ "type": "string",
584
+ "enum": [
585
+ "none",
586
+ "synchronous",
587
+ "async",
588
+ "input"
589
+ ]
590
+ },
591
+ "errorMessage": {
592
+ "type": "string"
593
+ }
594
+ },
595
+ "required": [
596
+ "errorType"
597
+ ],
598
+ "additionalProperties": false,
599
+ "$schema": "http://json-schema.org/draft-07/schema#"
600
+ },
601
+ "outputSchema": {
602
+ "type": "object",
603
+ "properties": {
604
+ "result": {
605
+ "type": "string"
606
+ }
607
+ },
608
+ "required": [
609
+ "result"
610
+ ],
611
+ "additionalProperties": false,
612
+ "$schema": "http://json-schema.org/draft-07/schema#"
613
+ }
519
614
  }
520
615
  ],
521
616
  "reccomendedPrompts": [
@@ -828,5 +923,96 @@ describe("DAIN Framework Integration", () => {
828
923
  expect(result.data.message).toBe("Success - no parameters needed");
829
924
  });
830
925
  });
926
+ // Add a new test suite for error handling
927
+ describe("Error Handling", () => {
928
+ it("Handles synchronous errors in non-streaming mode", async () => {
929
+ const errorResult = await dainConnection.callTool("integration-error-tool", {
930
+ errorType: "synchronous",
931
+ errorMessage: "Test sync error"
932
+ });
933
+ // Verify the error format matches our expected structure
934
+ expect(errorResult).toHaveProperty('error');
935
+ expect(errorResult).toHaveProperty('text');
936
+ expect(errorResult.error).toBe("Test sync error");
937
+ expect(errorResult.text).toBe("Error: Test sync error");
938
+ expect(errorResult.data).toBeNull();
939
+ expect(errorResult.ui).toBeNull();
940
+ });
941
+ it("Handles asynchronous errors in non-streaming mode", async () => {
942
+ const errorResult = await dainConnection.callTool("integration-error-tool", {
943
+ errorType: "async",
944
+ errorMessage: "Test async error"
945
+ });
946
+ expect(errorResult).toHaveProperty('error');
947
+ expect(errorResult.error).toBe("Test async error");
948
+ expect(errorResult.data).toBeNull();
949
+ });
950
+ it("Formats errors correctly in context endpoint", async () => {
951
+ const errorResult = await dainConnection.callToolAndGetNewContext("integration-error-tool", {
952
+ errorType: "synchronous",
953
+ errorMessage: "Test context error"
954
+ });
955
+ // Verify the context endpoint error format
956
+ expect(errorResult).toHaveProperty('toolResult');
957
+ expect(errorResult).toHaveProperty('context');
958
+ expect(errorResult.toolResult).toHaveProperty('error');
959
+ expect(errorResult.toolResult.error).toBe("Test context error");
960
+ expect(errorResult.toolResult.text).toBe("Error: Test context error");
961
+ expect(errorResult.toolResult.data).toBeNull();
962
+ expect(errorResult.toolResult.ui).toBeNull();
963
+ expect(Array.isArray(errorResult.context)).toBe(true);
964
+ expect(errorResult.context.length).toBe(0);
965
+ });
966
+ it("Handles errors in streaming mode and sends error events", async () => {
967
+ const events = [];
968
+ const errorResult = await dainConnection.callTool("integration-error-tool", {
969
+ errorType: "async",
970
+ errorMessage: "Test streaming error"
971
+ }, {
972
+ onUIUpdate: (update) => {
973
+ events.push({ type: 'ui', data: update.ui });
974
+ }
975
+ });
976
+ // Verify we received UI updates before the error
977
+ expect(events.length).toBeGreaterThan(0);
978
+ expect(events[0].type).toBe('ui');
979
+ // Verify the error format in streaming mode
980
+ expect(errorResult).toHaveProperty('error');
981
+ expect(errorResult.error).toBe("Test streaming error");
982
+ expect(errorResult.text).toBe("Error: Test streaming error");
983
+ expect(errorResult.data).toBeNull();
984
+ expect(errorResult.ui).toBeNull();
985
+ });
986
+ it("Handles streaming errors in context endpoint", async () => {
987
+ const events = [];
988
+ const errorResult = await dainConnection.callToolAndGetNewContext("integration-error-tool", {
989
+ errorType: "async",
990
+ errorMessage: "Test streaming context error"
991
+ }, {
992
+ onUIUpdate: (update) => {
993
+ events.push({ type: 'ui', data: update.ui });
994
+ }
995
+ });
996
+ // Verify we received UI updates before the error
997
+ expect(events.length).toBeGreaterThan(0);
998
+ // Verify the context endpoint error format in streaming mode
999
+ expect(errorResult).toHaveProperty('toolResult');
1000
+ expect(errorResult).toHaveProperty('context');
1001
+ expect(errorResult.toolResult).toHaveProperty('error');
1002
+ expect(errorResult.toolResult.error).toBe("Test streaming context error");
1003
+ expect(errorResult.toolResult.data).toBeNull();
1004
+ expect(Array.isArray(errorResult.context)).toBe(true);
1005
+ });
1006
+ it("Verifies successful execution still works after error handling improvements", async () => {
1007
+ const result = await dainConnection.callTool("integration-error-tool", {
1008
+ errorType: "none"
1009
+ });
1010
+ expect(result).toEqual({
1011
+ text: "No error occurred",
1012
+ data: { result: "success" },
1013
+ ui: null
1014
+ });
1015
+ });
1016
+ });
831
1017
  });
832
1018
  //# sourceMappingURL=integration.test.js.map