@dainprotocol/service-sdk 2.0.54 → 2.0.56
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.
- package/dist/client/client.d.ts +4 -5
- package/dist/client/client.js +3 -73
- package/dist/client/client.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/convertToVercelTool.d.ts +2 -3
- package/dist/lib/convertToVercelTool.js +4 -47
- package/dist/lib/convertToVercelTool.js.map +1 -1
- package/dist/lib/schemaConversion.d.ts +35 -0
- package/dist/lib/schemaConversion.js +234 -0
- package/dist/lib/schemaConversion.js.map +1 -0
- package/dist/lib/schemaStructure.d.ts +5 -3
- package/dist/lib/schemaStructure.js +39 -152
- package/dist/lib/schemaStructure.js.map +1 -1
- package/package.json +10 -9
- package/dist/__tests__/api-sdk.test.d.ts +0 -1
- package/dist/__tests__/api-sdk.test.js +0 -102
- package/dist/__tests__/api-sdk.test.js.map +0 -1
- package/dist/__tests__/auth.test.d.ts +0 -1
- package/dist/__tests__/auth.test.js +0 -110
- package/dist/__tests__/auth.test.js.map +0 -1
- package/dist/__tests__/citations-plugin.test.d.ts +0 -1
- package/dist/__tests__/citations-plugin.test.js +0 -491
- package/dist/__tests__/citations-plugin.test.js.map +0 -1
- package/dist/__tests__/context-behavior.test.d.ts +0 -1
- package/dist/__tests__/context-behavior.test.js +0 -290
- package/dist/__tests__/context-behavior.test.js.map +0 -1
- package/dist/__tests__/convertToVercelTool.test.d.ts +0 -1
- package/dist/__tests__/convertToVercelTool.test.js +0 -527
- package/dist/__tests__/convertToVercelTool.test.js.map +0 -1
- package/dist/__tests__/core.test.d.ts +0 -1
- package/dist/__tests__/core.test.js +0 -154
- package/dist/__tests__/core.test.js.map +0 -1
- package/dist/__tests__/crypto-plugin.test.d.ts +0 -1
- package/dist/__tests__/crypto-plugin.test.js +0 -694
- package/dist/__tests__/crypto-plugin.test.js.map +0 -1
- package/dist/__tests__/humanActions.test.d.ts +0 -1
- package/dist/__tests__/humanActions.test.js +0 -221
- package/dist/__tests__/humanActions.test.js.map +0 -1
- package/dist/__tests__/integration.test.d.ts +0 -1
- package/dist/__tests__/integration.test.js +0 -1573
- package/dist/__tests__/integration.test.js.map +0 -1
- package/dist/__tests__/mealMeSchemas.test.d.ts +0 -576
- package/dist/__tests__/mealMeSchemas.test.js +0 -627
- package/dist/__tests__/mealMeSchemas.test.js.map +0 -1
- package/dist/__tests__/oauth-context-simple.test.d.ts +0 -1
- package/dist/__tests__/oauth-context-simple.test.js +0 -90
- package/dist/__tests__/oauth-context-simple.test.js.map +0 -1
- package/dist/__tests__/oauth-context.test.d.ts +0 -1
- package/dist/__tests__/oauth-context.test.js +0 -282
- package/dist/__tests__/oauth-context.test.js.map +0 -1
- package/dist/__tests__/oauth.test.d.ts +0 -1
- package/dist/__tests__/oauth.test.js +0 -378
- package/dist/__tests__/oauth.test.js.map +0 -1
- package/dist/__tests__/oauth2-client-context.test.d.ts +0 -1
- package/dist/__tests__/oauth2-client-context.test.js +0 -165
- package/dist/__tests__/oauth2-client-context.test.js.map +0 -1
- package/dist/__tests__/oauth2-client-integration.test.d.ts +0 -1
- package/dist/__tests__/oauth2-client-integration.test.js +0 -182
- package/dist/__tests__/oauth2-client-integration.test.js.map +0 -1
- package/dist/__tests__/oauth2-client-simple.test.d.ts +0 -1
- package/dist/__tests__/oauth2-client-simple.test.js +0 -144
- package/dist/__tests__/oauth2-client-simple.test.js.map +0 -1
- package/dist/__tests__/oauth2-context.test.d.ts +0 -1
- package/dist/__tests__/oauth2-context.test.js +0 -201
- package/dist/__tests__/oauth2-context.test.js.map +0 -1
- package/dist/__tests__/oauth2-datasource.test.d.ts +0 -1
- package/dist/__tests__/oauth2-datasource.test.js +0 -251
- package/dist/__tests__/oauth2-datasource.test.js.map +0 -1
- package/dist/__tests__/plugin.test.d.ts +0 -1
- package/dist/__tests__/plugin.test.js +0 -900
- package/dist/__tests__/plugin.test.js.map +0 -1
- package/dist/__tests__/processes.test.d.ts +0 -1
- package/dist/__tests__/processes.test.js +0 -239
- package/dist/__tests__/processes.test.js.map +0 -1
- package/dist/__tests__/streaming.test.d.ts +0 -1
- package/dist/__tests__/streaming.test.js +0 -592
- package/dist/__tests__/streaming.test.js.map +0 -1
- package/dist/__tests__/testEnums.d.ts +0 -1
- package/dist/__tests__/testEnums.js +0 -73
- package/dist/__tests__/testEnums.js.map +0 -1
- package/dist/__tests__/testOptionals.test.d.ts +0 -1
- package/dist/__tests__/testOptionals.test.js +0 -83
- package/dist/__tests__/testOptionals.test.js.map +0 -1
- package/dist/__tests__/types.test.d.ts +0 -1
- package/dist/__tests__/types.test.js +0 -98
- package/dist/__tests__/types.test.js.map +0 -1
- package/dist/service/zod-json-converter.d.ts +0 -14
- package/dist/service/zod-json-converter.js +0 -203
- package/dist/service/zod-json-converter.js.map +0 -1
|
@@ -1,900 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// File: src/__tests__/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 time_plugin_1 = require("@/plugins/time-plugin");
|
|
13
|
-
const crypto_plugin_1 = require("@/plugins/crypto-plugin");
|
|
14
|
-
describe("DAIN Framework Plugin System", () => {
|
|
15
|
-
const privateKey = ed25519_1.ed25519.utils.randomPrivateKey();
|
|
16
|
-
const publicKey = ed25519_1.ed25519.getPublicKey(privateKey);
|
|
17
|
-
const address = bs58_1.default.encode(publicKey);
|
|
18
|
-
const clientPrivateKey = ed25519_1.ed25519.utils.randomPrivateKey();
|
|
19
|
-
const agentAuth = new client_auth_1.DainClientAuth({
|
|
20
|
-
privateKeyBase58: bs58_1.default.encode(clientPrivateKey),
|
|
21
|
-
agentId: "agent-12",
|
|
22
|
-
orgId: "org-12",
|
|
23
|
-
});
|
|
24
|
-
// Create a TimePlugin instance
|
|
25
|
-
const timePlugin = new time_plugin_1.TimePlugin({ includeTimezone: true });
|
|
26
|
-
// Create a CryptoPlugin instance with test wallet data
|
|
27
|
-
const testWallets = [
|
|
28
|
-
{ chain: "sol", address: "SolTestAddress123456789" },
|
|
29
|
-
{ chain: "eth", address: "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" }
|
|
30
|
-
];
|
|
31
|
-
const cryptoPlugin = new crypto_plugin_1.CryptoPlugin(testWallets);
|
|
32
|
-
// Create a wallet info tool to specifically test crypto plugin
|
|
33
|
-
const walletInfoTool = (0, core_1.createTool)({
|
|
34
|
-
id: "wallet-info",
|
|
35
|
-
name: "Wallet Info Tool",
|
|
36
|
-
description: "Shows information about connected wallets",
|
|
37
|
-
input: zod_1.z.object({}),
|
|
38
|
-
output: zod_1.z.object({
|
|
39
|
-
connectedWallets: zod_1.z.array(zod_1.z.object({
|
|
40
|
-
chain: zod_1.z.string(),
|
|
41
|
-
address: zod_1.z.string()
|
|
42
|
-
})),
|
|
43
|
-
walletsCount: zod_1.z.number()
|
|
44
|
-
}),
|
|
45
|
-
handler: async ({}, agentInfo, context) => {
|
|
46
|
-
// Extract wallet information from crypto plugin
|
|
47
|
-
const cryptoData = context.extraData?.plugins?.['crypto-plugin'];
|
|
48
|
-
console.log(`Wallet handler: received crypto plugin data:`, cryptoData);
|
|
49
|
-
let wallets = [];
|
|
50
|
-
if (cryptoData && cryptoData.wallets) {
|
|
51
|
-
wallets = cryptoData.wallets;
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
text: `Found ${wallets.length} wallet(s)`,
|
|
55
|
-
data: {
|
|
56
|
-
connectedWallets: wallets,
|
|
57
|
-
walletsCount: wallets.length
|
|
58
|
-
},
|
|
59
|
-
ui: null
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
// Create a test context
|
|
64
|
-
const testContext = {
|
|
65
|
-
id: "test-context",
|
|
66
|
-
name: "Test Context",
|
|
67
|
-
description: "A test context for plugin testing",
|
|
68
|
-
getContextData: async (agentInfo, context) => {
|
|
69
|
-
// Use the time plugin data if available
|
|
70
|
-
const timeData = context?.plugins?.["time-plugin"] || {};
|
|
71
|
-
return {
|
|
72
|
-
message: "This is test context data",
|
|
73
|
-
timestamp: Date.now(),
|
|
74
|
-
pluginData: timeData
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
// Create a test widget
|
|
79
|
-
const testWidget = {
|
|
80
|
-
id: "test-widget",
|
|
81
|
-
name: "Test Widget",
|
|
82
|
-
description: "A test widget for plugin testing",
|
|
83
|
-
icon: "🧪",
|
|
84
|
-
getWidget: async (agentInfo, context) => {
|
|
85
|
-
// Use the crypto plugin data if available
|
|
86
|
-
const cryptoData = context?.plugins?.["crypto-plugin"] || {};
|
|
87
|
-
return {
|
|
88
|
-
text: "This is a test widget",
|
|
89
|
-
data: {
|
|
90
|
-
type: "text",
|
|
91
|
-
content: "This is a test widget",
|
|
92
|
-
timestamp: Date.now(),
|
|
93
|
-
wallets: cryptoData?.wallets || []
|
|
94
|
-
},
|
|
95
|
-
ui: { type: "text" }
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
// Initialize the connection to the DAIN service with both plugins
|
|
100
|
-
const dainConnection = new client_1.DainServiceConnection("http://localhost:4484", agentAuth, {
|
|
101
|
-
plugins: [timePlugin, cryptoPlugin]
|
|
102
|
-
});
|
|
103
|
-
// Create a test tool
|
|
104
|
-
const echoTool = (0, core_1.createTool)({
|
|
105
|
-
id: "echo",
|
|
106
|
-
name: "Echo Tool",
|
|
107
|
-
description: "Echoes back the input with plugin data",
|
|
108
|
-
input: zod_1.z.object({ message: zod_1.z.string() }),
|
|
109
|
-
output: zod_1.z.object({ message: zod_1.z.string(), plugins: zod_1.z.any() }),
|
|
110
|
-
handler: async ({ message }, agentInfo, context) => {
|
|
111
|
-
console.log("Context:", JSON.stringify(context, null, 2));
|
|
112
|
-
// Use the TimePlugin helper to get plugin data from context
|
|
113
|
-
const timeData = timePlugin.getTimeDataFromContext(context);
|
|
114
|
-
const clientTimezone = timePlugin.getClientTimezone(context);
|
|
115
|
-
console.log(`Tool handling: received client timestamp ${timeData.clientTimestamp}`);
|
|
116
|
-
if (clientTimezone) {
|
|
117
|
-
console.log(`Client timezone: ${clientTimezone}`);
|
|
118
|
-
}
|
|
119
|
-
return {
|
|
120
|
-
text: `Echoed: ${message}`,
|
|
121
|
-
data: {
|
|
122
|
-
message,
|
|
123
|
-
plugins: context.extraData?.plugins || {}
|
|
124
|
-
},
|
|
125
|
-
ui: null,
|
|
126
|
-
};
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
// Initialize the DAIN service with both plugins
|
|
130
|
-
const dainService = (0, nodeService_1.defineDAINService)({
|
|
131
|
-
metadata: {
|
|
132
|
-
title: "Plugin Test Service",
|
|
133
|
-
description: "A DAIN service for testing plugins",
|
|
134
|
-
version: "1.0.0",
|
|
135
|
-
author: "Test Author",
|
|
136
|
-
tags: ["plugin", "test"],
|
|
137
|
-
},
|
|
138
|
-
identity: {
|
|
139
|
-
publicKey: bs58_1.default.encode(publicKey),
|
|
140
|
-
agentId: "plugin-agent",
|
|
141
|
-
orgId: "plugin-org",
|
|
142
|
-
privateKey: bs58_1.default.encode(privateKey),
|
|
143
|
-
},
|
|
144
|
-
tools: [echoTool, walletInfoTool],
|
|
145
|
-
plugins: [timePlugin, cryptoPlugin],
|
|
146
|
-
contexts: [testContext],
|
|
147
|
-
widgets: [testWidget],
|
|
148
|
-
exampleQueries: [
|
|
149
|
-
{ category: "General", queries: ["How does this work?", "Show me the weather"] }
|
|
150
|
-
]
|
|
151
|
-
});
|
|
152
|
-
let server;
|
|
153
|
-
beforeAll(async () => {
|
|
154
|
-
server = await dainService.startNode({ port: 4484 });
|
|
155
|
-
await new Promise(resolve => setTimeout(resolve, 500)); // Give server time to start
|
|
156
|
-
});
|
|
157
|
-
afterAll(async () => {
|
|
158
|
-
await server.shutdown();
|
|
159
|
-
});
|
|
160
|
-
it("should process plugin data in requests and responses", async () => {
|
|
161
|
-
// Call the echo tool with a message
|
|
162
|
-
const result = await dainConnection.callTool("echo", { message: "Hello, plugins!" });
|
|
163
|
-
console.log("Tool result:", JSON.stringify(result, null, 2));
|
|
164
|
-
// Verify that the message was echoed correctly
|
|
165
|
-
expect(result.data.message).toBe("Hello, plugins!");
|
|
166
|
-
// Verify that the time plugin data is in the response
|
|
167
|
-
expect(result.plugins).toBeDefined();
|
|
168
|
-
expect(result.plugins["time-plugin"]).toBeDefined();
|
|
169
|
-
// Use the TimePlugin helper to get typed response data
|
|
170
|
-
const timeData = timePlugin.getResponseData(result);
|
|
171
|
-
expect(timeData).toBeDefined();
|
|
172
|
-
// Check the time plugin data
|
|
173
|
-
expect(timeData.clientTimestamp).toBeDefined();
|
|
174
|
-
expect(timeData.serviceTimestamp).toBeDefined();
|
|
175
|
-
expect(timeData.roundtripTime).toBeDefined();
|
|
176
|
-
expect(timeData.timezone).toBeDefined();
|
|
177
|
-
// The service timestamp should be later than the client timestamp
|
|
178
|
-
expect(timeData.serviceTimestamp).toBeGreaterThanOrEqual(timeData.clientTimestamp);
|
|
179
|
-
// The roundtrip time should be non-negative
|
|
180
|
-
expect(timeData.roundtripTime).toBeGreaterThanOrEqual(0);
|
|
181
|
-
// The timezone should be a non-empty string
|
|
182
|
-
expect(typeof timeData.timezone).toBe("string");
|
|
183
|
-
expect(timeData.timezone.length).toBeGreaterThan(0);
|
|
184
|
-
console.log("Time plugin data:", timeData);
|
|
185
|
-
// Use TimePlugin's helper methods for displaying timestamps nicely
|
|
186
|
-
console.log(`Request started at: ${timePlugin.formatTimestamp(timeData.clientTimestamp)}`);
|
|
187
|
-
console.log(`Response created at: ${timePlugin.formatTimestamp(timeData.serviceTimestamp)}`);
|
|
188
|
-
console.log(`Roundtrip time: ${timeData.roundtripTime}ms`);
|
|
189
|
-
console.log(`Client timezone: ${timeData.timezone}`);
|
|
190
|
-
// Demonstrate the elapsed time calculation helper
|
|
191
|
-
const processingTime = timePlugin.calculateElapsedTime(timeData.clientTimestamp, timeData.serviceTimestamp);
|
|
192
|
-
console.log(`Service processing time: ${processingTime}ms`);
|
|
193
|
-
});
|
|
194
|
-
it("should verify crypto plugin automatically sends wallet data to server", async () => {
|
|
195
|
-
// Call the wallet info tool
|
|
196
|
-
const result = await dainConnection.callTool("wallet-info", {});
|
|
197
|
-
console.log("Wallet info result:", JSON.stringify(result, null, 2));
|
|
198
|
-
// Verify that wallet information was received by the service
|
|
199
|
-
expect(result.data.walletsCount).toBe(testWallets.length);
|
|
200
|
-
expect(result.data.connectedWallets.length).toBe(testWallets.length);
|
|
201
|
-
// Check that the wallet information matches what we provided
|
|
202
|
-
const solWallet = result.data.connectedWallets.find(w => w.chain === "sol");
|
|
203
|
-
expect(solWallet).toBeDefined();
|
|
204
|
-
expect(solWallet?.address).toBe("SolTestAddress123456789");
|
|
205
|
-
const ethWallet = result.data.connectedWallets.find(w => w.chain === "eth");
|
|
206
|
-
expect(ethWallet).toBeDefined();
|
|
207
|
-
expect(ethWallet?.address).toBe("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266");
|
|
208
|
-
// Verify that time plugin data is also present in the response
|
|
209
|
-
// This confirms both plugins work together
|
|
210
|
-
expect(result.plugins).toBeDefined();
|
|
211
|
-
expect(result.plugins["time-plugin"]).toBeDefined();
|
|
212
|
-
console.log("Wallet information was successfully transferred from client to service");
|
|
213
|
-
});
|
|
214
|
-
it("should work with streaming responses", async () => {
|
|
215
|
-
const events = [];
|
|
216
|
-
// Call the echo tool with streaming enabled
|
|
217
|
-
const result = await dainConnection.callTool("echo", { message: "Hello with streaming!" }, {
|
|
218
|
-
onUIUpdate: (update) => {
|
|
219
|
-
events.push({ type: 'ui', timestamp: Date.now(), data: update });
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
// Add the final result to the events
|
|
223
|
-
events.push({ type: 'result', timestamp: Date.now(), data: result });
|
|
224
|
-
// Verify the result has plugin data
|
|
225
|
-
expect(result.plugins).toBeDefined();
|
|
226
|
-
expect(result.plugins["time-plugin"]).toBeDefined();
|
|
227
|
-
// Get typed plugin data using helper
|
|
228
|
-
const timeData = timePlugin.getResponseData(result);
|
|
229
|
-
expect(timeData).toBeDefined();
|
|
230
|
-
expect(timeData.roundtripTime).toBeDefined();
|
|
231
|
-
console.log("Streaming result time data:", timeData);
|
|
232
|
-
console.log(`Streaming roundtrip time: ${timeData.roundtripTime}ms`);
|
|
233
|
-
});
|
|
234
|
-
it("should work when calling a tool and getting context", async () => {
|
|
235
|
-
// Call the echo tool and get context
|
|
236
|
-
const result = await dainConnection.callToolAndGetNewContext("echo", {
|
|
237
|
-
message: "Hello with context!"
|
|
238
|
-
});
|
|
239
|
-
// Verify the result has plugin data
|
|
240
|
-
expect(result.plugins).toBeDefined();
|
|
241
|
-
expect(result.plugins["time-plugin"]).toBeDefined();
|
|
242
|
-
// Get typed plugin data using helper
|
|
243
|
-
const timeData = timePlugin.getResponseData(result);
|
|
244
|
-
expect(timeData).toBeDefined();
|
|
245
|
-
expect(timeData.roundtripTime).toBeDefined();
|
|
246
|
-
// Verify the tool result
|
|
247
|
-
expect(result.toolResult.data.message).toBe("Hello with context!");
|
|
248
|
-
console.log("Context result time data:", timeData);
|
|
249
|
-
console.log(`Context roundtrip time: ${timeData.roundtripTime}ms`);
|
|
250
|
-
});
|
|
251
|
-
it("should use helper methods to create custom time responses", async () => {
|
|
252
|
-
// Create a mock context with plugin data
|
|
253
|
-
const mockContext = {
|
|
254
|
-
extraData: {
|
|
255
|
-
plugins: {
|
|
256
|
-
"time-plugin": {
|
|
257
|
-
clientTimestamp: Date.now() - 100, // 100ms ago
|
|
258
|
-
timezone: "Europe/London"
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
// Use helper to extract the plugin data
|
|
264
|
-
const inputData = timePlugin.getTimeDataFromContext(mockContext);
|
|
265
|
-
expect(inputData.clientTimestamp).toBeDefined();
|
|
266
|
-
expect(inputData.timezone).toBe("Europe/London");
|
|
267
|
-
// Use helper to create a response
|
|
268
|
-
const response = timePlugin.createTimestampResponse(inputData);
|
|
269
|
-
expect(response.clientTimestamp).toBe(inputData.clientTimestamp);
|
|
270
|
-
expect(response.serviceTimestamp).toBeDefined();
|
|
271
|
-
expect(response.timezone).toBe("Europe/London");
|
|
272
|
-
// Calculate processing time
|
|
273
|
-
const processingTime = timePlugin.calculateElapsedTime(response.clientTimestamp, response.serviceTimestamp);
|
|
274
|
-
console.log(`Mock request: client timestamp is ${timePlugin.formatTimestamp(inputData.clientTimestamp)}`);
|
|
275
|
-
console.log(`Mock response: service timestamp is ${timePlugin.formatTimestamp(response.serviceTimestamp)}`);
|
|
276
|
-
console.log(`Mock processing time: ${processingTime}ms`);
|
|
277
|
-
});
|
|
278
|
-
it("should demonstrate the createResponse method for plugin responses", async () => {
|
|
279
|
-
console.log("=== DEMONSTRATING createResponse METHOD ===");
|
|
280
|
-
// Scenario 1: Create a minimal response with just required fields
|
|
281
|
-
const minimalResponse = timePlugin.createResponse({
|
|
282
|
-
clientTimestamp: 1742160000000,
|
|
283
|
-
serviceTimestamp: 1742160000050
|
|
284
|
-
});
|
|
285
|
-
console.log("Minimal Response:", minimalResponse);
|
|
286
|
-
expect(minimalResponse.clientTimestamp).toBe(1742160000000);
|
|
287
|
-
expect(minimalResponse.serviceTimestamp).toBe(1742160000050);
|
|
288
|
-
expect(minimalResponse.timezone).toBeUndefined();
|
|
289
|
-
expect(minimalResponse.roundtripTime).toBeUndefined();
|
|
290
|
-
// Scenario 2: Create a complete response with all fields
|
|
291
|
-
const completeResponse = timePlugin.createResponse({
|
|
292
|
-
clientTimestamp: 1742160000100,
|
|
293
|
-
serviceTimestamp: 1742160000150,
|
|
294
|
-
timezone: "America/Chicago",
|
|
295
|
-
roundtripTime: 75
|
|
296
|
-
});
|
|
297
|
-
console.log("Complete Response:", completeResponse);
|
|
298
|
-
expect(completeResponse.clientTimestamp).toBe(1742160000100);
|
|
299
|
-
expect(completeResponse.serviceTimestamp).toBe(1742160000150);
|
|
300
|
-
expect(completeResponse.timezone).toBe("America/Chicago");
|
|
301
|
-
expect(completeResponse.roundtripTime).toBe(75);
|
|
302
|
-
// Scenario 3: Using createResponse to transform or annotate data
|
|
303
|
-
const rawData = {
|
|
304
|
-
clientTimestamp: Date.now() - 200,
|
|
305
|
-
serviceTimestamp: Date.now() - 100
|
|
306
|
-
};
|
|
307
|
-
// Add a timezone and calculate a roundtrip time
|
|
308
|
-
const enhancedResponse = timePlugin.createResponse({
|
|
309
|
-
...rawData,
|
|
310
|
-
timezone: "UTC",
|
|
311
|
-
roundtripTime: rawData.serviceTimestamp - rawData.clientTimestamp
|
|
312
|
-
});
|
|
313
|
-
console.log("Enhanced Response:", enhancedResponse);
|
|
314
|
-
expect(enhancedResponse.timezone).toBe("UTC");
|
|
315
|
-
expect(enhancedResponse.roundtripTime).toBe(100);
|
|
316
|
-
// Scenario 4: Practical example - modifying an existing plugin response
|
|
317
|
-
const existingResponse = {
|
|
318
|
-
clientTimestamp: 1742160000200,
|
|
319
|
-
serviceTimestamp: 1742160000300,
|
|
320
|
-
timezone: "Europe/Berlin"
|
|
321
|
-
};
|
|
322
|
-
// Add roundtrip time to an existing response
|
|
323
|
-
const updatedResponse = timePlugin.createResponse({
|
|
324
|
-
...existingResponse,
|
|
325
|
-
roundtripTime: 120 // Custom roundtrip calculation
|
|
326
|
-
});
|
|
327
|
-
console.log("Updated Response:", updatedResponse);
|
|
328
|
-
expect(updatedResponse).toEqual({
|
|
329
|
-
clientTimestamp: 1742160000200,
|
|
330
|
-
serviceTimestamp: 1742160000300,
|
|
331
|
-
timezone: "Europe/Berlin",
|
|
332
|
-
roundtripTime: 120
|
|
333
|
-
});
|
|
334
|
-
// Scenario 5: Integration with other helper methods
|
|
335
|
-
const now = Date.now();
|
|
336
|
-
const sampleInput = { clientTimestamp: now - 150, timezone: "Asia/Tokyo" };
|
|
337
|
-
// Create a response using multiple helper methods together
|
|
338
|
-
const integratedResponse = timePlugin.createResponse({
|
|
339
|
-
clientTimestamp: sampleInput.clientTimestamp,
|
|
340
|
-
serviceTimestamp: now,
|
|
341
|
-
timezone: sampleInput.timezone,
|
|
342
|
-
roundtripTime: timePlugin.calculateElapsedTime(sampleInput.clientTimestamp, now)
|
|
343
|
-
});
|
|
344
|
-
console.log("Integrated Response:", integratedResponse);
|
|
345
|
-
console.log(`From ${timePlugin.formatTimestamp(integratedResponse.clientTimestamp)}`);
|
|
346
|
-
console.log(`To ${timePlugin.formatTimestamp(integratedResponse.serviceTimestamp)}`);
|
|
347
|
-
console.log(`Elapsed: ${integratedResponse.roundtripTime}ms in ${integratedResponse.timezone}`);
|
|
348
|
-
expect(integratedResponse.roundtripTime).toBe(150);
|
|
349
|
-
expect(integratedResponse.timezone).toBe("Asia/Tokyo");
|
|
350
|
-
});
|
|
351
|
-
it("should demonstrate practical usage of createTimingResponse for real-world scenarios", async () => {
|
|
352
|
-
console.log("\n=== DEMONSTRATING PRACTICAL USAGE OF TIME PLUGIN ===\n");
|
|
353
|
-
// Example 1: Measuring execution time of an expensive operation
|
|
354
|
-
const simulateExpensiveOperation = async (duration) => {
|
|
355
|
-
return new Promise(resolve => setTimeout(() => resolve(`Operation completed`), duration));
|
|
356
|
-
};
|
|
357
|
-
console.log("Example 1: Measuring database query performance");
|
|
358
|
-
console.log("----------------------------------------------");
|
|
359
|
-
const dbQueryStart = Date.now();
|
|
360
|
-
// Simulate a database query that takes 50ms
|
|
361
|
-
await simulateExpensiveOperation(50);
|
|
362
|
-
// Generate timing information for this operation
|
|
363
|
-
const dbQueryTiming = timePlugin.createTimingResponse(dbQueryStart, {
|
|
364
|
-
operationType: "database-query",
|
|
365
|
-
includeTimezone: true,
|
|
366
|
-
metadata: {
|
|
367
|
-
table: "users",
|
|
368
|
-
rowsReturned: 250,
|
|
369
|
-
indexUsed: "user_id_idx"
|
|
370
|
-
}
|
|
371
|
-
});
|
|
372
|
-
console.log(`Database query timing: ${JSON.stringify(dbQueryTiming, null, 2)}`);
|
|
373
|
-
console.log(`Query started at: ${timePlugin.formatTimestamp(dbQueryTiming.clientTimestamp)}`);
|
|
374
|
-
console.log(`Query completed at: ${timePlugin.formatTimestamp(dbQueryTiming.serviceTimestamp)}`);
|
|
375
|
-
console.log(`Query took approximately: ${dbQueryTiming.roundtripTime}ms`);
|
|
376
|
-
expect(dbQueryTiming.roundtripTime).toBeGreaterThanOrEqual(50);
|
|
377
|
-
expect(dbQueryTiming.timezone).toBeDefined();
|
|
378
|
-
// Example 2: API request/response cycle with multiple operations
|
|
379
|
-
console.log("\nExample 2: Full API request cycle with multiple operations");
|
|
380
|
-
console.log("------------------------------------------------------");
|
|
381
|
-
// Simulate a complete API request handler with multiple operations
|
|
382
|
-
const handleApiRequest = async (requestData) => {
|
|
383
|
-
// 1. Record request start time
|
|
384
|
-
const requestStart = Date.now();
|
|
385
|
-
// 2. Validate request (10ms)
|
|
386
|
-
await simulateExpensiveOperation(10);
|
|
387
|
-
const validationTiming = timePlugin.createTimingResponse(requestStart, {
|
|
388
|
-
operationType: "request-validation"
|
|
389
|
-
});
|
|
390
|
-
// 3. Process data (30ms)
|
|
391
|
-
const processingStart = Date.now();
|
|
392
|
-
await simulateExpensiveOperation(30);
|
|
393
|
-
const processingTiming = timePlugin.createTimingResponse(processingStart, {
|
|
394
|
-
operationType: "data-processing"
|
|
395
|
-
});
|
|
396
|
-
// 4. Generate response with detailed timing information
|
|
397
|
-
return {
|
|
398
|
-
data: { result: "Success", id: requestData.id },
|
|
399
|
-
timing: {
|
|
400
|
-
total: timePlugin.createTimingResponse(requestStart),
|
|
401
|
-
validation: validationTiming,
|
|
402
|
-
processing: processingTiming
|
|
403
|
-
}
|
|
404
|
-
};
|
|
405
|
-
};
|
|
406
|
-
// Simulate an API request
|
|
407
|
-
const apiResponse = await handleApiRequest({ id: 12345, action: "getData" });
|
|
408
|
-
console.log("API Response:", JSON.stringify(apiResponse, null, 2));
|
|
409
|
-
console.log(`Total request time: ${apiResponse.timing.total.roundtripTime}ms`);
|
|
410
|
-
console.log(`- Validation time: ${apiResponse.timing.validation.roundtripTime}ms`);
|
|
411
|
-
console.log(`- Processing time: ${apiResponse.timing.processing.roundtripTime}ms`);
|
|
412
|
-
expect(apiResponse.timing.total.roundtripTime).toBeGreaterThanOrEqual(40);
|
|
413
|
-
expect(apiResponse.timing.validation.roundtripTime).toBeGreaterThanOrEqual(10);
|
|
414
|
-
expect(apiResponse.timing.processing.roundtripTime).toBeGreaterThanOrEqual(30);
|
|
415
|
-
// Show how this would be integrated into a real DAIN plugin response
|
|
416
|
-
const pluginResponse = {
|
|
417
|
-
data: apiResponse.data,
|
|
418
|
-
plugins: {
|
|
419
|
-
"time-plugin": timePlugin.createTimingResponse(apiResponse.timing.total.clientTimestamp, {
|
|
420
|
-
includeTimezone: true
|
|
421
|
-
})
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
console.log("\nFinal plugin response:");
|
|
425
|
-
console.log(JSON.stringify(pluginResponse, null, 2));
|
|
426
|
-
expect(pluginResponse.plugins["time-plugin"].roundtripTime).toBeGreaterThanOrEqual(40);
|
|
427
|
-
expect(pluginResponse.plugins["time-plugin"].timezone).toBeDefined();
|
|
428
|
-
});
|
|
429
|
-
it("should verify multiple plugins can work together and consistently provide data", async () => {
|
|
430
|
-
// We'll call wallet-info tool multiple times sequentially to ensure different timestamps
|
|
431
|
-
const result1 = await dainConnection.callTool("wallet-info", {});
|
|
432
|
-
// Small delay to ensure different timestamps
|
|
433
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
434
|
-
const result2 = await dainConnection.callTool("wallet-info", {});
|
|
435
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
436
|
-
const result3 = await dainConnection.callTool("wallet-info", {});
|
|
437
|
-
const results = [result1, result2, result3];
|
|
438
|
-
// Verify all calls received wallet data
|
|
439
|
-
results.forEach((result, index) => {
|
|
440
|
-
console.log(`Call ${index + 1} wallet count:`, result.data.walletsCount);
|
|
441
|
-
expect(result.data.walletsCount).toBe(testWallets.length);
|
|
442
|
-
// Each call should also have time plugin data
|
|
443
|
-
expect(result.plugins["time-plugin"]).toBeDefined();
|
|
444
|
-
// Times should be different for each call (now that we're using sequential requests)
|
|
445
|
-
if (index > 0) {
|
|
446
|
-
const prevTimeData = timePlugin.getResponseData(results[index - 1]);
|
|
447
|
-
const currTimeData = timePlugin.getResponseData(result);
|
|
448
|
-
// With sequential requests and delay, timestamps should now be different
|
|
449
|
-
expect(currTimeData?.clientTimestamp).not.toBe(prevTimeData?.clientTimestamp);
|
|
450
|
-
expect(currTimeData?.serviceTimestamp).not.toBe(prevTimeData?.serviceTimestamp);
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
// Modify wallet data during the test
|
|
454
|
-
const newWallet = { chain: "arb", address: "0xArbTestWalletAddress" };
|
|
455
|
-
cryptoPlugin.addWallet(newWallet);
|
|
456
|
-
// Call again and verify the new wallet data was sent
|
|
457
|
-
const finalResult = await dainConnection.callTool("wallet-info", {});
|
|
458
|
-
expect(finalResult.data.walletsCount).toBe(testWallets.length + 1); // Added one more wallet
|
|
459
|
-
// Verify the new wallet is in the result
|
|
460
|
-
const arbWallet = finalResult.data.connectedWallets.find(w => w.chain === "arb");
|
|
461
|
-
expect(arbWallet).toBeDefined();
|
|
462
|
-
expect(arbWallet?.address).toBe("0xArbTestWalletAddress");
|
|
463
|
-
console.log("Multiple plugin test complete - wallet data is consistently provided");
|
|
464
|
-
});
|
|
465
|
-
it("should ensure getAllContexts returns an array when plugins are used", async () => {
|
|
466
|
-
// Get all contexts using a connection with plugins enabled
|
|
467
|
-
const contexts = await dainConnection.getAllContexts();
|
|
468
|
-
// Log out the contexts for debugging
|
|
469
|
-
console.log("Contexts with plugins:", contexts);
|
|
470
|
-
// Verify that the result is an array
|
|
471
|
-
expect(Array.isArray(contexts)).toBe(true);
|
|
472
|
-
// Contexts might be empty in this test, but the type should be correct
|
|
473
|
-
// The point is to verify we're not getting an object with plugins property instead of an array
|
|
474
|
-
if (contexts.length > 0) {
|
|
475
|
-
// If there are contexts, verify they have the expected structure
|
|
476
|
-
expect(contexts[0]).toHaveProperty('id');
|
|
477
|
-
expect(contexts[0]).toHaveProperty('name');
|
|
478
|
-
expect(contexts[0]).toHaveProperty('description');
|
|
479
|
-
expect(contexts[0]).toHaveProperty('data');
|
|
480
|
-
}
|
|
481
|
-
});
|
|
482
|
-
it("should ensure getContext returns a context object when plugins are used", async () => {
|
|
483
|
-
// Only run this test if there are contexts available
|
|
484
|
-
const allContexts = await dainConnection.getAllContexts();
|
|
485
|
-
if (allContexts.length === 0) {
|
|
486
|
-
console.log("Skipping getContext test as no contexts are available");
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
// Get the first context using a connection with plugins enabled
|
|
490
|
-
const contextId = allContexts[0].id;
|
|
491
|
-
const context = await dainConnection.getContext(contextId);
|
|
492
|
-
// Log out the context for debugging
|
|
493
|
-
console.log("Context with plugins:", context);
|
|
494
|
-
// Verify that the result is a context object, not a response with plugins
|
|
495
|
-
expect(context).toHaveProperty('id');
|
|
496
|
-
expect(context).toHaveProperty('name');
|
|
497
|
-
expect(context).toHaveProperty('description');
|
|
498
|
-
expect(context).toHaveProperty('data');
|
|
499
|
-
// Make sure the context has the correct ID
|
|
500
|
-
expect(context.id).toBe(contextId);
|
|
501
|
-
});
|
|
502
|
-
it("should ensure getAllWidgets returns an array when plugins are used", async () => {
|
|
503
|
-
// Get all widgets using a connection with plugins enabled
|
|
504
|
-
const widgets = await dainConnection.getAllWidgets();
|
|
505
|
-
// Log out the widgets for debugging
|
|
506
|
-
console.log("Widgets with plugins:", widgets);
|
|
507
|
-
// Verify that the result is an array
|
|
508
|
-
expect(Array.isArray(widgets)).toBe(true);
|
|
509
|
-
// Widgets might be empty in this test, but the type should be correct
|
|
510
|
-
// The point is to verify we're not getting an object with plugins property instead of an array
|
|
511
|
-
if (widgets.length > 0) {
|
|
512
|
-
// If there are widgets, verify they have the expected structure
|
|
513
|
-
expect(widgets[0]).toHaveProperty('id');
|
|
514
|
-
expect(widgets[0]).toHaveProperty('name');
|
|
515
|
-
expect(widgets[0]).toHaveProperty('description');
|
|
516
|
-
expect(widgets[0]).toHaveProperty('icon');
|
|
517
|
-
expect(widgets[0]).toHaveProperty('text');
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
it("should ensure getWidget returns a widget object when plugins are used", async () => {
|
|
521
|
-
// Only run this test if there are widgets available
|
|
522
|
-
const allWidgets = await dainConnection.getAllWidgets();
|
|
523
|
-
if (allWidgets.length === 0) {
|
|
524
|
-
console.log("Skipping getWidget test as no widgets are available");
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
// Get the first widget using a connection with plugins enabled
|
|
528
|
-
const widgetId = allWidgets[0].id;
|
|
529
|
-
const widget = await dainConnection.getWidget(widgetId);
|
|
530
|
-
// Log out the widget for debugging
|
|
531
|
-
console.log("Widget with plugins:", widget);
|
|
532
|
-
// Verify that the result is a widget object, not a response with plugins
|
|
533
|
-
expect(widget).toHaveProperty('id');
|
|
534
|
-
expect(widget).toHaveProperty('name');
|
|
535
|
-
expect(widget).toHaveProperty('description');
|
|
536
|
-
expect(widget).toHaveProperty('icon');
|
|
537
|
-
expect(widget).toHaveProperty('text');
|
|
538
|
-
// Make sure the widget has the correct ID
|
|
539
|
-
expect(widget.id).toBe(widgetId);
|
|
540
|
-
});
|
|
541
|
-
it("should ensure listDatasources and postAllDatasources handle plugins correctly", async () => {
|
|
542
|
-
// Try calling the methods to ensure they work properly with plugins enabled
|
|
543
|
-
const datasources1 = await dainConnection.listDatasources();
|
|
544
|
-
expect(Array.isArray(datasources1)).toBe(true);
|
|
545
|
-
const datasources2 = await dainConnection.postAllDatasources();
|
|
546
|
-
expect(Array.isArray(datasources2)).toBe(true);
|
|
547
|
-
});
|
|
548
|
-
it("should ensure getDatasource returns a datasource object when plugins are used", async () => {
|
|
549
|
-
// Skip the datasource test until we have a proper way to register datasources for testing
|
|
550
|
-
console.log("Skipping active getDatasource test as it requires datasource registration");
|
|
551
|
-
});
|
|
552
|
-
it("should ensure getAllToolsAsJsonSchema properly handles plugin data", async () => {
|
|
553
|
-
// Call getAllToolsAsJsonSchema with plugins enabled
|
|
554
|
-
const result = await dainConnection.getAllToolsAsJsonSchema();
|
|
555
|
-
// Log for debugging
|
|
556
|
-
console.log("getAllToolsAsJsonSchema result:", result);
|
|
557
|
-
// Verify the result structure
|
|
558
|
-
expect(result).toHaveProperty('tools');
|
|
559
|
-
expect(result).toHaveProperty('reccomendedPrompts');
|
|
560
|
-
expect(Array.isArray(result.tools)).toBe(true);
|
|
561
|
-
// Verify tools contain expected properties
|
|
562
|
-
if (result.tools.length > 0) {
|
|
563
|
-
const tool = result.tools[0];
|
|
564
|
-
expect(tool).toHaveProperty('id');
|
|
565
|
-
expect(tool).toHaveProperty('name');
|
|
566
|
-
expect(tool).toHaveProperty('description');
|
|
567
|
-
expect(tool).toHaveProperty('inputSchema');
|
|
568
|
-
}
|
|
569
|
-
// The plugins themselves shouldn't be in the result - they should be handled internally
|
|
570
|
-
expect(result).not.toHaveProperty('plugins');
|
|
571
|
-
});
|
|
572
|
-
it("should ensure getMetadata properly handles plugin data", async () => {
|
|
573
|
-
// Call getMetadata with plugins enabled
|
|
574
|
-
const metadata = await dainConnection.getMetadata();
|
|
575
|
-
// Log for debugging
|
|
576
|
-
console.log("getMetadata result:", metadata);
|
|
577
|
-
// Verify metadata structure
|
|
578
|
-
expect(metadata).toHaveProperty('title');
|
|
579
|
-
expect(metadata).toHaveProperty('description');
|
|
580
|
-
expect(metadata).toHaveProperty('version');
|
|
581
|
-
// The plugins themselves shouldn't be in the result - they should be handled internally
|
|
582
|
-
expect(metadata).not.toHaveProperty('plugins');
|
|
583
|
-
});
|
|
584
|
-
it("should ensure getWidgets properly handles plugin data", async () => {
|
|
585
|
-
// Call getWidgets with plugins enabled
|
|
586
|
-
const widgets = await dainConnection.getWidgets();
|
|
587
|
-
// Log for debugging
|
|
588
|
-
console.log("getWidgets result:", widgets);
|
|
589
|
-
// Verify the result is an array, even when plugins are used
|
|
590
|
-
expect(Array.isArray(widgets)).toBe(true);
|
|
591
|
-
// Verify widgets structure if any exist
|
|
592
|
-
if (widgets.length > 0) {
|
|
593
|
-
const widgetId = widgets[0];
|
|
594
|
-
expect(typeof widgetId).toBe('string');
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
|
-
it("should ensure getExampleQueries properly handles plugin data", async () => {
|
|
598
|
-
// Call getExampleQueries with plugins enabled
|
|
599
|
-
const queries = await dainConnection.getExampleQueries();
|
|
600
|
-
// Log for debugging
|
|
601
|
-
console.log("getExampleQueries result:", queries);
|
|
602
|
-
// Verify the result is an array, even when plugins are used
|
|
603
|
-
expect(Array.isArray(queries)).toBe(true);
|
|
604
|
-
// The plugins themselves shouldn't be in the result - they should be handled internally
|
|
605
|
-
if (queries.length > 0) {
|
|
606
|
-
// Example queries can be strings or objects with category and queries
|
|
607
|
-
const firstQuery = queries[0];
|
|
608
|
-
if (typeof firstQuery === 'string') {
|
|
609
|
-
expect(typeof firstQuery).toBe('string');
|
|
610
|
-
}
|
|
611
|
-
else {
|
|
612
|
-
expect(firstQuery).toHaveProperty('category');
|
|
613
|
-
expect(firstQuery).toHaveProperty('queries');
|
|
614
|
-
expect(Array.isArray(firstQuery.queries)).toBe(true);
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
});
|
|
618
|
-
});
|
|
619
|
-
/**
|
|
620
|
-
* Additional plugin tests specifically for handling plugin data in API responses
|
|
621
|
-
* Tests all API methods both with and without data, ensuring proper handling of plugin-wrapped responses
|
|
622
|
-
*/
|
|
623
|
-
describe("Plugin Data Handling in API Responses", () => {
|
|
624
|
-
// Generate keys for both services
|
|
625
|
-
const fullPrivateKey = ed25519_1.ed25519.utils.randomPrivateKey();
|
|
626
|
-
const fullPublicKey = ed25519_1.ed25519.getPublicKey(fullPrivateKey);
|
|
627
|
-
const emptyPrivateKey = ed25519_1.ed25519.utils.randomPrivateKey();
|
|
628
|
-
const emptyPublicKey = ed25519_1.ed25519.getPublicKey(emptyPrivateKey);
|
|
629
|
-
// Client auth
|
|
630
|
-
const clientPrivateKey = ed25519_1.ed25519.utils.randomPrivateKey();
|
|
631
|
-
const clientAuth = new client_auth_1.DainClientAuth({
|
|
632
|
-
privateKeyBase58: bs58_1.default.encode(clientPrivateKey),
|
|
633
|
-
agentId: "api-client",
|
|
634
|
-
orgId: "api-org",
|
|
635
|
-
});
|
|
636
|
-
// Create test plugins
|
|
637
|
-
const timePlugin = new time_plugin_1.TimePlugin({ includeTimezone: true });
|
|
638
|
-
const testWallets = [
|
|
639
|
-
{ chain: "sol", address: "ApiTestSolAddress123" }
|
|
640
|
-
];
|
|
641
|
-
const cryptoPlugin = new crypto_plugin_1.CryptoPlugin(testWallets);
|
|
642
|
-
// Create test context, pinnable, datasource
|
|
643
|
-
const testContext = {
|
|
644
|
-
id: "api-context",
|
|
645
|
-
name: "API Test Context",
|
|
646
|
-
description: "Context for API plugin tests",
|
|
647
|
-
getContextData: async (agentInfo, context) => {
|
|
648
|
-
// Include plugin data in the response for verification
|
|
649
|
-
return {
|
|
650
|
-
value: "Context data",
|
|
651
|
-
timestamp: Date.now(),
|
|
652
|
-
pluginInfo: context?.plugins || {}
|
|
653
|
-
};
|
|
654
|
-
}
|
|
655
|
-
};
|
|
656
|
-
const testWidget = {
|
|
657
|
-
id: "api-widget",
|
|
658
|
-
name: "API Test Widget",
|
|
659
|
-
description: "Widget for API plugin tests",
|
|
660
|
-
icon: "🔧",
|
|
661
|
-
getWidget: async (agentInfo, context) => {
|
|
662
|
-
return {
|
|
663
|
-
text: "API Test Widget",
|
|
664
|
-
data: {
|
|
665
|
-
type: "text",
|
|
666
|
-
content: "API Test Widget",
|
|
667
|
-
timestamp: Date.now(),
|
|
668
|
-
pluginInfo: context?.plugins || {}
|
|
669
|
-
},
|
|
670
|
-
ui: { type: "text" }
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
};
|
|
674
|
-
const testDatasource = {
|
|
675
|
-
id: "api-datasource",
|
|
676
|
-
name: "API Test Datasource",
|
|
677
|
-
description: "Datasource for API plugin tests",
|
|
678
|
-
type: "json",
|
|
679
|
-
input: zod_1.z.object({
|
|
680
|
-
query: zod_1.z.string().optional()
|
|
681
|
-
}),
|
|
682
|
-
getDatasource: async (agentInfo, params, context) => {
|
|
683
|
-
return {
|
|
684
|
-
results: ["Result 1", "Result 2"],
|
|
685
|
-
timestamp: Date.now(),
|
|
686
|
-
pluginInfo: context?.plugins || {}
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
// Create test tool
|
|
691
|
-
const testTool = (0, core_1.createTool)({
|
|
692
|
-
id: "api-tool",
|
|
693
|
-
name: "API Test Tool",
|
|
694
|
-
description: "Tool for API plugin tests",
|
|
695
|
-
input: zod_1.z.object({ data: zod_1.z.string() }),
|
|
696
|
-
output: zod_1.z.object({ result: zod_1.z.string() }),
|
|
697
|
-
handler: async ({ data }, agentInfo, context) => {
|
|
698
|
-
return {
|
|
699
|
-
text: `Processed: ${data}`,
|
|
700
|
-
data: {
|
|
701
|
-
result: data,
|
|
702
|
-
pluginInfo: context.extraData?.plugins || {}
|
|
703
|
-
},
|
|
704
|
-
ui: null
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
});
|
|
708
|
-
// Service with all data types
|
|
709
|
-
const fullService = (0, nodeService_1.defineDAINService)({
|
|
710
|
-
metadata: {
|
|
711
|
-
title: "Full API Test Service",
|
|
712
|
-
description: "Service with all data types for testing plugin handling",
|
|
713
|
-
version: "1.0.0",
|
|
714
|
-
author: "Test",
|
|
715
|
-
tags: ["test"]
|
|
716
|
-
},
|
|
717
|
-
identity: {
|
|
718
|
-
publicKey: bs58_1.default.encode(fullPublicKey),
|
|
719
|
-
agentId: "full-agent",
|
|
720
|
-
orgId: "full-org",
|
|
721
|
-
privateKey: bs58_1.default.encode(fullPrivateKey)
|
|
722
|
-
},
|
|
723
|
-
tools: [testTool],
|
|
724
|
-
plugins: [timePlugin, cryptoPlugin],
|
|
725
|
-
contexts: [testContext],
|
|
726
|
-
widgets: [testWidget],
|
|
727
|
-
datasources: [testDatasource],
|
|
728
|
-
exampleQueries: [
|
|
729
|
-
{ category: "Test", queries: ["Test query 1", "Test query 2"] }
|
|
730
|
-
]
|
|
731
|
-
});
|
|
732
|
-
// Service with minimal data
|
|
733
|
-
const emptyService = (0, nodeService_1.defineDAINService)({
|
|
734
|
-
metadata: {
|
|
735
|
-
title: "Empty API Test Service",
|
|
736
|
-
description: "Service with minimal data for testing plugin handling",
|
|
737
|
-
version: "1.0.0",
|
|
738
|
-
author: "Test",
|
|
739
|
-
tags: ["test"]
|
|
740
|
-
},
|
|
741
|
-
identity: {
|
|
742
|
-
publicKey: bs58_1.default.encode(emptyPublicKey),
|
|
743
|
-
agentId: "empty-agent",
|
|
744
|
-
orgId: "empty-org",
|
|
745
|
-
privateKey: bs58_1.default.encode(emptyPrivateKey)
|
|
746
|
-
},
|
|
747
|
-
tools: [testTool],
|
|
748
|
-
plugins: [timePlugin, cryptoPlugin],
|
|
749
|
-
contexts: [],
|
|
750
|
-
widgets: [],
|
|
751
|
-
datasources: [],
|
|
752
|
-
exampleQueries: []
|
|
753
|
-
});
|
|
754
|
-
// Client connections
|
|
755
|
-
const fullConnection = new client_1.DainServiceConnection("http://localhost:4581", clientAuth, { plugins: [timePlugin, cryptoPlugin] });
|
|
756
|
-
const emptyConnection = new client_1.DainServiceConnection("http://localhost:4582", clientAuth, { plugins: [timePlugin, cryptoPlugin] });
|
|
757
|
-
// Server instances
|
|
758
|
-
let fullServer;
|
|
759
|
-
let emptyServer;
|
|
760
|
-
beforeAll(async () => {
|
|
761
|
-
fullServer = await fullService.startNode({ port: 4581 });
|
|
762
|
-
emptyServer = await emptyService.startNode({ port: 4582 });
|
|
763
|
-
await new Promise(resolve => setTimeout(resolve, 500)); // Server startup time
|
|
764
|
-
});
|
|
765
|
-
afterAll(async () => {
|
|
766
|
-
await fullServer?.shutdown();
|
|
767
|
-
await emptyServer?.shutdown();
|
|
768
|
-
});
|
|
769
|
-
// TEST METADATA
|
|
770
|
-
it("getMetadata handles plugins with either service", async () => {
|
|
771
|
-
// With data
|
|
772
|
-
const fullMetadata = await fullConnection.getMetadata();
|
|
773
|
-
expect(fullMetadata).toHaveProperty('title');
|
|
774
|
-
expect(fullMetadata).not.toHaveProperty('plugins');
|
|
775
|
-
// Without data
|
|
776
|
-
const emptyMetadata = await emptyConnection.getMetadata();
|
|
777
|
-
expect(emptyMetadata).toHaveProperty('title');
|
|
778
|
-
expect(emptyMetadata).not.toHaveProperty('plugins');
|
|
779
|
-
});
|
|
780
|
-
// TEST TOOLS
|
|
781
|
-
it("getTools handles plugins with either service", async () => {
|
|
782
|
-
// With data
|
|
783
|
-
const fullTools = await fullConnection.getTools();
|
|
784
|
-
expect(Array.isArray(fullTools)).toBe(true);
|
|
785
|
-
expect(fullTools.length).toBeGreaterThan(0);
|
|
786
|
-
expect(fullTools[0]).not.toHaveProperty('plugins');
|
|
787
|
-
// Without data
|
|
788
|
-
const emptyTools = await emptyConnection.getTools();
|
|
789
|
-
expect(Array.isArray(emptyTools)).toBe(true);
|
|
790
|
-
expect(emptyTools.length).toBeGreaterThan(0);
|
|
791
|
-
expect(emptyTools[0]).not.toHaveProperty('plugins');
|
|
792
|
-
});
|
|
793
|
-
it("getAllToolsAsJsonSchema handles plugins with either service", async () => {
|
|
794
|
-
// With data
|
|
795
|
-
const fullTools = await fullConnection.getAllToolsAsJsonSchema();
|
|
796
|
-
expect(fullTools).toHaveProperty('tools');
|
|
797
|
-
expect(Array.isArray(fullTools.tools)).toBe(true);
|
|
798
|
-
expect(fullTools).not.toHaveProperty('plugins');
|
|
799
|
-
// Without data
|
|
800
|
-
const emptyTools = await emptyConnection.getAllToolsAsJsonSchema();
|
|
801
|
-
expect(emptyTools).toHaveProperty('tools');
|
|
802
|
-
expect(Array.isArray(emptyTools.tools)).toBe(true);
|
|
803
|
-
expect(emptyTools).not.toHaveProperty('plugins');
|
|
804
|
-
});
|
|
805
|
-
// TEST CONTEXTS
|
|
806
|
-
it("getAllContexts handles plugins with either service", async () => {
|
|
807
|
-
// With data
|
|
808
|
-
const fullContexts = await fullConnection.getAllContexts();
|
|
809
|
-
expect(Array.isArray(fullContexts)).toBe(true);
|
|
810
|
-
expect(fullContexts.length).toBeGreaterThan(0);
|
|
811
|
-
expect(fullContexts[0]).toHaveProperty('data');
|
|
812
|
-
expect(fullContexts[0]).not.toHaveProperty('plugins');
|
|
813
|
-
// Without data - should return empty array, not object with plugins
|
|
814
|
-
const emptyContexts = await emptyConnection.getAllContexts();
|
|
815
|
-
expect(Array.isArray(emptyContexts)).toBe(true);
|
|
816
|
-
expect(emptyContexts.length).toBe(0);
|
|
817
|
-
});
|
|
818
|
-
it("getContext handles plugins with full service", async () => {
|
|
819
|
-
const contexts = await fullConnection.getAllContexts();
|
|
820
|
-
const context = await fullConnection.getContext(contexts[0].id);
|
|
821
|
-
expect(context).toHaveProperty('id');
|
|
822
|
-
expect(context).toHaveProperty('data');
|
|
823
|
-
expect(context).not.toHaveProperty('plugins');
|
|
824
|
-
// Context data should have the structure defined in testContext
|
|
825
|
-
expect(context.data).toHaveProperty('value');
|
|
826
|
-
expect(context.data).toHaveProperty('timestamp');
|
|
827
|
-
});
|
|
828
|
-
// TEST WIDGETS
|
|
829
|
-
it("getAllWidgets handles plugins with either service", async () => {
|
|
830
|
-
// With data
|
|
831
|
-
const fullWidgets = await fullConnection.getAllWidgets();
|
|
832
|
-
expect(Array.isArray(fullWidgets)).toBe(true);
|
|
833
|
-
expect(fullWidgets.length).toBeGreaterThan(0);
|
|
834
|
-
expect(fullWidgets[0]).toHaveProperty('icon');
|
|
835
|
-
expect(fullWidgets[0]).toHaveProperty('text');
|
|
836
|
-
expect(fullWidgets[0]).not.toHaveProperty('plugins');
|
|
837
|
-
// Without data - should return empty array, not object with plugins
|
|
838
|
-
const emptyWidgets = await emptyConnection.getAllWidgets();
|
|
839
|
-
expect(Array.isArray(emptyWidgets)).toBe(true);
|
|
840
|
-
expect(emptyWidgets.length).toBe(0);
|
|
841
|
-
});
|
|
842
|
-
it("getWidget handles plugins with full service", async () => {
|
|
843
|
-
const widgets = await fullConnection.getAllWidgets();
|
|
844
|
-
const widget = await fullConnection.getWidget(widgets[0].id);
|
|
845
|
-
expect(widget).toHaveProperty('id');
|
|
846
|
-
expect(widget).toHaveProperty('icon');
|
|
847
|
-
expect(widget).toHaveProperty('text');
|
|
848
|
-
expect(widget).not.toHaveProperty('plugins');
|
|
849
|
-
// Widget data should have the structure defined in testWidget or be empty
|
|
850
|
-
// Some implementations might return empty widget objects in tests
|
|
851
|
-
if (widget.data && Object.keys(widget.data).length > 0) {
|
|
852
|
-
expect(widget.data).toHaveProperty('content');
|
|
853
|
-
expect(widget.data).toHaveProperty('timestamp');
|
|
854
|
-
}
|
|
855
|
-
});
|
|
856
|
-
it("getWidgets handles plugins with either service", async () => {
|
|
857
|
-
// With data
|
|
858
|
-
const fullWidgetIds = await fullConnection.getWidgets();
|
|
859
|
-
expect(Array.isArray(fullWidgetIds)).toBe(true);
|
|
860
|
-
expect(fullWidgetIds.length).toBeGreaterThan(0);
|
|
861
|
-
expect(typeof fullWidgetIds[0]).toBe('string');
|
|
862
|
-
// Without data
|
|
863
|
-
const emptyWidgetIds = await emptyConnection.getWidgets();
|
|
864
|
-
expect(Array.isArray(emptyWidgetIds)).toBe(true);
|
|
865
|
-
expect(emptyWidgetIds.length).toBe(0);
|
|
866
|
-
});
|
|
867
|
-
// TEST DATASOURCES
|
|
868
|
-
it("listDatasources handles plugins with either service", async () => {
|
|
869
|
-
// With data
|
|
870
|
-
const fullDatasources = await fullConnection.listDatasources();
|
|
871
|
-
expect(Array.isArray(fullDatasources)).toBe(true);
|
|
872
|
-
expect(fullDatasources.length).toBeGreaterThan(0);
|
|
873
|
-
expect(fullDatasources[0]).not.toHaveProperty('plugins');
|
|
874
|
-
// Without data
|
|
875
|
-
const emptyDatasources = await emptyConnection.listDatasources();
|
|
876
|
-
expect(Array.isArray(emptyDatasources)).toBe(true);
|
|
877
|
-
expect(emptyDatasources.length).toBe(0);
|
|
878
|
-
});
|
|
879
|
-
it("getDatasource handles plugins with full service", async () => {
|
|
880
|
-
const datasource = await fullConnection.getDatasource("api-datasource", { query: "test" });
|
|
881
|
-
expect(datasource).toHaveProperty('id');
|
|
882
|
-
expect(datasource).toHaveProperty('data');
|
|
883
|
-
expect(datasource).not.toHaveProperty('plugins');
|
|
884
|
-
// Datasource data should have the structure defined in testDatasource
|
|
885
|
-
expect(datasource.data).toHaveProperty('results');
|
|
886
|
-
expect(Array.isArray(datasource.data.results)).toBe(true);
|
|
887
|
-
});
|
|
888
|
-
// TEST EXAMPLE QUERIES
|
|
889
|
-
it("getExampleQueries handles plugins with either service", async () => {
|
|
890
|
-
// With data
|
|
891
|
-
const fullQueries = await fullConnection.getExampleQueries();
|
|
892
|
-
expect(Array.isArray(fullQueries)).toBe(true);
|
|
893
|
-
expect(fullQueries.length).toBeGreaterThan(0);
|
|
894
|
-
// Without data
|
|
895
|
-
const emptyQueries = await emptyConnection.getExampleQueries();
|
|
896
|
-
expect(Array.isArray(emptyQueries)).toBe(true);
|
|
897
|
-
expect(emptyQueries.length).toBe(0);
|
|
898
|
-
});
|
|
899
|
-
});
|
|
900
|
-
//# sourceMappingURL=plugin.test.js.map
|