lynkr 7.2.5 → 8.0.1
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/README.md +3 -3
- package/config/model-tiers.json +89 -0
- package/install.sh +6 -1
- package/package.json +4 -2
- package/scripts/setup.js +0 -1
- package/src/agents/executor.js +14 -6
- package/src/api/middleware/session.js +15 -2
- package/src/api/openai-router.js +162 -37
- package/src/api/providers-handler.js +15 -1
- package/src/api/router.js +107 -2
- package/src/budget/index.js +4 -3
- package/src/clients/databricks.js +431 -234
- package/src/clients/gpt-utils.js +181 -0
- package/src/clients/ollama-utils.js +66 -140
- package/src/clients/routing.js +0 -1
- package/src/clients/standard-tools.js +99 -3
- package/src/config/index.js +133 -35
- package/src/context/toon.js +173 -0
- package/src/logger/index.js +23 -0
- package/src/orchestrator/index.js +688 -213
- package/src/routing/agentic-detector.js +320 -0
- package/src/routing/complexity-analyzer.js +202 -2
- package/src/routing/cost-optimizer.js +305 -0
- package/src/routing/index.js +168 -159
- package/src/routing/model-tiers.js +365 -0
- package/src/server.js +4 -14
- package/src/sessions/cleanup.js +3 -3
- package/src/sessions/record.js +10 -1
- package/src/sessions/store.js +7 -2
- package/src/tools/agent-task.js +48 -1
- package/src/tools/index.js +19 -2
- package/src/tools/lazy-loader.js +7 -0
- package/src/tools/tinyfish.js +358 -0
- package/src/tools/truncate.js +1 -0
- package/.github/FUNDING.yml +0 -15
- package/.github/workflows/README.md +0 -215
- package/.github/workflows/ci.yml +0 -69
- package/.github/workflows/index.yml +0 -62
- package/.github/workflows/web-tools-tests.yml +0 -56
- package/CITATIONS.bib +0 -6
- package/CLAWROUTER_ROUTING_PLAN.md +0 -910
- package/DEPLOYMENT.md +0 -1001
- package/LYNKR-TUI-PLAN.md +0 -984
- package/PERFORMANCE-REPORT.md +0 -866
- package/PLAN-per-client-model-routing.md +0 -252
- package/ROUTER_COMPARISON.md +0 -173
- package/TIER_ROUTING_PLAN.md +0 -771
- package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
- package/docs/BingSiteAuth.xml +0 -4
- package/docs/docs-style.css +0 -478
- package/docs/docs.html +0 -197
- package/docs/google5be250e608e6da39.html +0 -1
- package/docs/index.html +0 -577
- package/docs/index.md +0 -577
- package/docs/robots.txt +0 -4
- package/docs/sitemap.xml +0 -44
- package/docs/style.css +0 -1223
- package/documentation/README.md +0 -100
- package/documentation/api.md +0 -806
- package/documentation/claude-code-cli.md +0 -672
- package/documentation/codex-cli.md +0 -397
- package/documentation/contributing.md +0 -571
- package/documentation/cursor-integration.md +0 -731
- package/documentation/docker.md +0 -867
- package/documentation/embeddings.md +0 -760
- package/documentation/faq.md +0 -659
- package/documentation/features.md +0 -396
- package/documentation/headroom.md +0 -519
- package/documentation/installation.md +0 -706
- package/documentation/memory-system.md +0 -476
- package/documentation/production.md +0 -601
- package/documentation/providers.md +0 -906
- package/documentation/testing.md +0 -629
- package/documentation/token-optimization.md +0 -323
- package/documentation/tools.md +0 -697
- package/documentation/troubleshooting.md +0 -893
- package/final-test.js +0 -33
- package/headroom-sidecar/config.py +0 -93
- package/headroom-sidecar/requirements.txt +0 -14
- package/headroom-sidecar/server.py +0 -451
- package/monitor-agents.sh +0 -31
- package/scripts/audit-log-reader.js +0 -399
- package/scripts/compact-dictionary.js +0 -204
- package/scripts/test-deduplication.js +0 -448
- package/src/db/database.sqlite +0 -0
- package/test/README.md +0 -212
- package/test/azure-openai-config.test.js +0 -204
- package/test/azure-openai-error-resilience.test.js +0 -238
- package/test/azure-openai-format-conversion.test.js +0 -354
- package/test/azure-openai-integration.test.js +0 -281
- package/test/azure-openai-routing.test.js +0 -177
- package/test/azure-openai-streaming.test.js +0 -171
- package/test/bedrock-integration.test.js +0 -471
- package/test/comprehensive-test-suite.js +0 -928
- package/test/config-validation.test.js +0 -207
- package/test/cursor-integration.test.js +0 -484
- package/test/format-conversion.test.js +0 -578
- package/test/hybrid-routing-integration.test.js +0 -254
- package/test/hybrid-routing-performance.test.js +0 -418
- package/test/llamacpp-integration.test.js +0 -863
- package/test/lmstudio-integration.test.js +0 -335
- package/test/memory/extractor.test.js +0 -398
- package/test/memory/retriever.test.js +0 -613
- package/test/memory/retriever.test.js.bak +0 -585
- package/test/memory/search.test.js +0 -537
- package/test/memory/search.test.js.bak +0 -389
- package/test/memory/store.test.js +0 -344
- package/test/memory/store.test.js.bak +0 -312
- package/test/memory/surprise.test.js +0 -300
- package/test/memory-performance.test.js +0 -472
- package/test/openai-integration.test.js +0 -686
- package/test/openrouter-error-resilience.test.js +0 -418
- package/test/passthrough-mode.test.js +0 -385
- package/test/performance-benchmark.js +0 -351
- package/test/performance-tests.js +0 -528
- package/test/routing.test.js +0 -219
- package/test/web-tools.test.js +0 -329
- package/test-agents-simple.js +0 -43
- package/test-cli-connection.sh +0 -33
- package/test-learning-unit.js +0 -126
- package/test-learning.js +0 -112
- package/test-parallel-agents.sh +0 -124
- package/test-parallel-direct.js +0 -155
- package/test-subagents.sh +0 -117
|
@@ -1,385 +0,0 @@
|
|
|
1
|
-
const assert = require("assert");
|
|
2
|
-
const { describe, it, beforeEach, afterEach, mock } = require("node:test");
|
|
3
|
-
|
|
4
|
-
describe("Passthrough Mode (Client-Side Tool Execution)", () => {
|
|
5
|
-
let originalEnv;
|
|
6
|
-
let config;
|
|
7
|
-
let orchestrator;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
// Store original environment
|
|
11
|
-
originalEnv = { ...process.env };
|
|
12
|
-
|
|
13
|
-
// Ensure clean state for TOOL_EXECUTION_MODE
|
|
14
|
-
delete process.env.TOOL_EXECUTION_MODE;
|
|
15
|
-
|
|
16
|
-
// Set MODEL_PROVIDER to databricks for tests (not azure-openai from .env)
|
|
17
|
-
process.env.MODEL_PROVIDER = "databricks";
|
|
18
|
-
process.env.DATABRICKS_API_KEY = "test-key";
|
|
19
|
-
process.env.DATABRICKS_API_BASE = "http://test.com";
|
|
20
|
-
|
|
21
|
-
// Clear module cache
|
|
22
|
-
delete require.cache[require.resolve("../src/config")];
|
|
23
|
-
delete require.cache[require.resolve("../src/orchestrator/index")];
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
afterEach(() => {
|
|
27
|
-
// Restore environment
|
|
28
|
-
process.env = originalEnv;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe("Configuration", () => {
|
|
32
|
-
it("should accept 'client' mode", () => {
|
|
33
|
-
process.env.TOOL_EXECUTION_MODE = "client";
|
|
34
|
-
process.env.DATABRICKS_API_KEY = "test-key";
|
|
35
|
-
process.env.DATABRICKS_API_BASE = "http://test.com";
|
|
36
|
-
config = require("../src/config");
|
|
37
|
-
|
|
38
|
-
assert.strictEqual(config.toolExecutionMode, "client");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("should accept 'passthrough' mode (alias for client)", () => {
|
|
42
|
-
process.env.TOOL_EXECUTION_MODE = "passthrough";
|
|
43
|
-
process.env.DATABRICKS_API_KEY = "test-key";
|
|
44
|
-
process.env.DATABRICKS_API_BASE = "http://test.com";
|
|
45
|
-
config = require("../src/config");
|
|
46
|
-
|
|
47
|
-
assert.strictEqual(config.toolExecutionMode, "passthrough");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("should accept 'server' mode explicitly", () => {
|
|
51
|
-
process.env.TOOL_EXECUTION_MODE = "server";
|
|
52
|
-
process.env.DATABRICKS_API_KEY = "test-key";
|
|
53
|
-
process.env.DATABRICKS_API_BASE = "http://test.com";
|
|
54
|
-
config = require("../src/config");
|
|
55
|
-
|
|
56
|
-
assert.strictEqual(config.toolExecutionMode, "server");
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe("Response Format in Passthrough Mode", () => {
|
|
61
|
-
it("should return Anthropic-formatted response with tool_use blocks", () => {
|
|
62
|
-
// Mock response from provider with tool calls
|
|
63
|
-
const mockProviderResponse = {
|
|
64
|
-
ok: true,
|
|
65
|
-
status: 200,
|
|
66
|
-
json: {
|
|
67
|
-
choices: [
|
|
68
|
-
{
|
|
69
|
-
message: {
|
|
70
|
-
role: "assistant",
|
|
71
|
-
content: "I'll create that file for you.",
|
|
72
|
-
tool_calls: [
|
|
73
|
-
{
|
|
74
|
-
id: "call_123",
|
|
75
|
-
type: "function",
|
|
76
|
-
function: {
|
|
77
|
-
name: "Write",
|
|
78
|
-
arguments: JSON.stringify({
|
|
79
|
-
file_path: "/tmp/test.txt",
|
|
80
|
-
content: "Hello World"
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
},
|
|
86
|
-
finish_reason: "tool_calls"
|
|
87
|
-
}
|
|
88
|
-
],
|
|
89
|
-
model: "openai/gpt-4o-mini",
|
|
90
|
-
usage: {
|
|
91
|
-
prompt_tokens: 10,
|
|
92
|
-
completion_tokens: 20,
|
|
93
|
-
total_tokens: 30
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
// Expected Anthropic format
|
|
99
|
-
const expectedContent = [
|
|
100
|
-
{
|
|
101
|
-
type: "text",
|
|
102
|
-
text: "I'll create that file for you."
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
type: "tool_use",
|
|
106
|
-
id: "call_123",
|
|
107
|
-
name: "Write",
|
|
108
|
-
input: {
|
|
109
|
-
file_path: "/tmp/test.txt",
|
|
110
|
-
content: "Hello World"
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
// Test content conversion
|
|
116
|
-
const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
|
|
117
|
-
const anthropicResponse = convertOpenRouterResponseToAnthropic(
|
|
118
|
-
mockProviderResponse.json,
|
|
119
|
-
"claude-sonnet-4-5"
|
|
120
|
-
);
|
|
121
|
-
|
|
122
|
-
assert.strictEqual(anthropicResponse.role, "assistant");
|
|
123
|
-
assert.strictEqual(anthropicResponse.stop_reason, "tool_use");
|
|
124
|
-
assert.strictEqual(Array.isArray(anthropicResponse.content), true);
|
|
125
|
-
assert.strictEqual(anthropicResponse.content.length, 2);
|
|
126
|
-
assert.strictEqual(anthropicResponse.content[0].type, "text");
|
|
127
|
-
assert.strictEqual(anthropicResponse.content[1].type, "tool_use");
|
|
128
|
-
assert.strictEqual(anthropicResponse.content[1].name, "Write");
|
|
129
|
-
assert.deepStrictEqual(anthropicResponse.content[1].input, {
|
|
130
|
-
file_path: "/tmp/test.txt",
|
|
131
|
-
content: "Hello World"
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("should handle multiple tool calls in one response", () => {
|
|
136
|
-
const mockProviderResponse = {
|
|
137
|
-
choices: [
|
|
138
|
-
{
|
|
139
|
-
message: {
|
|
140
|
-
role: "assistant",
|
|
141
|
-
content: "I'll read the file and then write it.",
|
|
142
|
-
tool_calls: [
|
|
143
|
-
{
|
|
144
|
-
id: "call_1",
|
|
145
|
-
type: "function",
|
|
146
|
-
function: {
|
|
147
|
-
name: "Read",
|
|
148
|
-
arguments: JSON.stringify({ file_path: "/tmp/input.txt" })
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
id: "call_2",
|
|
153
|
-
type: "function",
|
|
154
|
-
function: {
|
|
155
|
-
name: "Write",
|
|
156
|
-
arguments: JSON.stringify({
|
|
157
|
-
file_path: "/tmp/output.txt",
|
|
158
|
-
content: "Modified"
|
|
159
|
-
})
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
},
|
|
164
|
-
finish_reason: "tool_calls"
|
|
165
|
-
}
|
|
166
|
-
],
|
|
167
|
-
model: "openai/gpt-4o-mini",
|
|
168
|
-
usage: { prompt_tokens: 10, completion_tokens: 30, total_tokens: 40 }
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
|
|
172
|
-
const anthropicResponse = convertOpenRouterResponseToAnthropic(
|
|
173
|
-
mockProviderResponse,
|
|
174
|
-
"claude-sonnet-4-5"
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
assert.strictEqual(anthropicResponse.content.length, 3); // 1 text + 2 tool_use
|
|
178
|
-
assert.strictEqual(anthropicResponse.content[1].type, "tool_use");
|
|
179
|
-
assert.strictEqual(anthropicResponse.content[1].name, "Read");
|
|
180
|
-
assert.strictEqual(anthropicResponse.content[2].type, "tool_use");
|
|
181
|
-
assert.strictEqual(anthropicResponse.content[2].name, "Write");
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it("should handle tool calls without text content", () => {
|
|
185
|
-
const mockProviderResponse = {
|
|
186
|
-
choices: [
|
|
187
|
-
{
|
|
188
|
-
message: {
|
|
189
|
-
role: "assistant",
|
|
190
|
-
content: null,
|
|
191
|
-
tool_calls: [
|
|
192
|
-
{
|
|
193
|
-
id: "call_1",
|
|
194
|
-
type: "function",
|
|
195
|
-
function: {
|
|
196
|
-
name: "Read",
|
|
197
|
-
arguments: JSON.stringify({ file_path: "/tmp/test.txt" })
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
]
|
|
201
|
-
},
|
|
202
|
-
finish_reason: "tool_calls"
|
|
203
|
-
}
|
|
204
|
-
],
|
|
205
|
-
model: "openai/gpt-4o-mini",
|
|
206
|
-
usage: { prompt_tokens: 10, completion_tokens: 15, total_tokens: 25 }
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
|
|
210
|
-
const anthropicResponse = convertOpenRouterResponseToAnthropic(
|
|
211
|
-
mockProviderResponse,
|
|
212
|
-
"claude-sonnet-4-5"
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
// Should only have tool_use block, no text block
|
|
216
|
-
assert.strictEqual(anthropicResponse.content.length, 1);
|
|
217
|
-
assert.strictEqual(anthropicResponse.content[0].type, "tool_use");
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
describe("Tool Result Processing", () => {
|
|
222
|
-
it("should accept tool_result blocks from CLI in next request", () => {
|
|
223
|
-
// Simulate a conversation with tool results coming back from CLI
|
|
224
|
-
const messagesWithToolResults = [
|
|
225
|
-
{
|
|
226
|
-
role: "user",
|
|
227
|
-
content: "Create a file /tmp/test.txt"
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
role: "assistant",
|
|
231
|
-
content: [
|
|
232
|
-
{ type: "text", text: "I'll create that file." },
|
|
233
|
-
{
|
|
234
|
-
type: "tool_use",
|
|
235
|
-
id: "toolu_123",
|
|
236
|
-
name: "Write",
|
|
237
|
-
input: {
|
|
238
|
-
file_path: "/tmp/test.txt",
|
|
239
|
-
content: "Hello"
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
]
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
role: "user",
|
|
246
|
-
content: [
|
|
247
|
-
{
|
|
248
|
-
type: "tool_result",
|
|
249
|
-
tool_use_id: "toolu_123",
|
|
250
|
-
content: "File created successfully"
|
|
251
|
-
}
|
|
252
|
-
]
|
|
253
|
-
}
|
|
254
|
-
];
|
|
255
|
-
|
|
256
|
-
// Verify structure
|
|
257
|
-
assert.strictEqual(messagesWithToolResults.length, 3);
|
|
258
|
-
assert.strictEqual(messagesWithToolResults[2].role, "user");
|
|
259
|
-
assert.strictEqual(Array.isArray(messagesWithToolResults[2].content), true);
|
|
260
|
-
assert.strictEqual(messagesWithToolResults[2].content[0].type, "tool_result");
|
|
261
|
-
assert.strictEqual(messagesWithToolResults[2].content[0].tool_use_id, "toolu_123");
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it("should convert tool_result blocks to OpenRouter format", () => {
|
|
265
|
-
// Must include assistant message with tool_use first
|
|
266
|
-
const anthropicMessages = [
|
|
267
|
-
{
|
|
268
|
-
role: "assistant",
|
|
269
|
-
content: [
|
|
270
|
-
{
|
|
271
|
-
type: "tool_use",
|
|
272
|
-
id: "toolu_123",
|
|
273
|
-
name: "Write",
|
|
274
|
-
input: { file_path: "/tmp/test.txt", content: "Hello" }
|
|
275
|
-
}
|
|
276
|
-
]
|
|
277
|
-
},
|
|
278
|
-
{
|
|
279
|
-
role: "user",
|
|
280
|
-
content: [
|
|
281
|
-
{
|
|
282
|
-
type: "tool_result",
|
|
283
|
-
tool_use_id: "toolu_123",
|
|
284
|
-
content: "File created successfully"
|
|
285
|
-
}
|
|
286
|
-
]
|
|
287
|
-
}
|
|
288
|
-
];
|
|
289
|
-
|
|
290
|
-
const { convertAnthropicMessagesToOpenRouter } = require("../src/clients/openrouter-utils");
|
|
291
|
-
const openRouterMessages = convertAnthropicMessagesToOpenRouter(anthropicMessages);
|
|
292
|
-
|
|
293
|
-
// Should convert to tool role message for OpenRouter
|
|
294
|
-
assert.strictEqual(openRouterMessages.length >= 2, true);
|
|
295
|
-
// OpenRouter expects tool results as separate tool messages
|
|
296
|
-
const toolMessage = openRouterMessages.find(m => m.role === "tool");
|
|
297
|
-
assert.ok(toolMessage, "Tool message should be present");
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
describe("Stop Reason Handling", () => {
|
|
302
|
-
it("should set stop_reason to 'tool_use' when tools are present", () => {
|
|
303
|
-
const mockResponse = {
|
|
304
|
-
choices: [
|
|
305
|
-
{
|
|
306
|
-
message: {
|
|
307
|
-
role: "assistant",
|
|
308
|
-
content: "Using tool",
|
|
309
|
-
tool_calls: [
|
|
310
|
-
{
|
|
311
|
-
id: "call_1",
|
|
312
|
-
function: {
|
|
313
|
-
name: "Read",
|
|
314
|
-
arguments: "{}"
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
]
|
|
318
|
-
},
|
|
319
|
-
finish_reason: "tool_calls"
|
|
320
|
-
}
|
|
321
|
-
],
|
|
322
|
-
model: "test-model",
|
|
323
|
-
usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 }
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
|
|
327
|
-
const result = convertOpenRouterResponseToAnthropic(mockResponse, "claude-sonnet-4-5");
|
|
328
|
-
|
|
329
|
-
assert.strictEqual(result.stop_reason, "tool_use");
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
it("should set stop_reason to 'end_turn' when no tools", () => {
|
|
333
|
-
const mockResponse = {
|
|
334
|
-
choices: [
|
|
335
|
-
{
|
|
336
|
-
message: {
|
|
337
|
-
role: "assistant",
|
|
338
|
-
content: "Simple response"
|
|
339
|
-
},
|
|
340
|
-
finish_reason: "stop"
|
|
341
|
-
}
|
|
342
|
-
],
|
|
343
|
-
model: "test-model",
|
|
344
|
-
usage: { prompt_tokens: 10, completion_tokens: 10, total_tokens: 20 }
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
const { convertOpenRouterResponseToAnthropic } = require("../src/clients/openrouter-utils");
|
|
348
|
-
const result = convertOpenRouterResponseToAnthropic(mockResponse, "claude-sonnet-4-5");
|
|
349
|
-
|
|
350
|
-
assert.strictEqual(result.stop_reason, "end_turn");
|
|
351
|
-
});
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
describe("Session Storage Format", () => {
|
|
355
|
-
it("should store tool_use blocks in Anthropic format for session", () => {
|
|
356
|
-
// Session content should always be in Anthropic format
|
|
357
|
-
// regardless of provider
|
|
358
|
-
const sessionContent = [
|
|
359
|
-
{
|
|
360
|
-
type: "text",
|
|
361
|
-
text: "I'll help with that."
|
|
362
|
-
},
|
|
363
|
-
{
|
|
364
|
-
type: "tool_use",
|
|
365
|
-
id: "toolu_abc",
|
|
366
|
-
name: "Write",
|
|
367
|
-
input: {
|
|
368
|
-
file_path: "/tmp/test.txt",
|
|
369
|
-
content: "data"
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
];
|
|
373
|
-
|
|
374
|
-
// Verify all blocks have correct structure
|
|
375
|
-
sessionContent.forEach(block => {
|
|
376
|
-
assert.strictEqual(typeof block.type, "string");
|
|
377
|
-
if (block.type === "tool_use") {
|
|
378
|
-
assert.strictEqual(typeof block.id, "string");
|
|
379
|
-
assert.strictEqual(typeof block.name, "string");
|
|
380
|
-
assert.strictEqual(typeof block.input, "object");
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
});
|
|
384
|
-
});
|
|
385
|
-
});
|