opencode-toolbox 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +197 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -38315,6 +38315,72 @@ Shows success/total metrics to highlight failures. Use to check if toolbox is wo
38315
38315
  var PERF_DESC = `Get detailed performance metrics for the toolbox plugin.
38316
38316
 
38317
38317
  Shows initialization times, search latencies, execution stats, and per-server metrics.`;
38318
+ var TEST_DESC = `Test all toolbox tools with minimal predefined prompts.
38319
+
38320
+ Executes every registered tool with super simple inputs to verify they work. Returns pass/fail for each tool.`;
38321
+ var TEST_PROMPTS = {
38322
+ time_get_current_time: {},
38323
+ time_convert_time: { source_timezone: "UTC", time: "12:00", target_timezone: "America/New_York" },
38324
+ brave_brave_web_search: { query: "test", count: 1 },
38325
+ brave_brave_local_search: { query: "coffee", count: 1 },
38326
+ brave_brave_video_search: { query: "test", count: 1 },
38327
+ brave_brave_image_search: { query: "test", count: 1 },
38328
+ brave_brave_news_search: { query: "test", count: 1 },
38329
+ brave_brave_summarizer: { key: "test" },
38330
+ brightdata_search_engine: { query: "hello", engine: "google", count: 1 },
38331
+ brightdata_search_engine_batch: { queries: [{ query: "test", engine: "google", count: 1 }] },
38332
+ brightdata_scrape_as_markdown: { url: "https://example.com" },
38333
+ brightdata_scrape_as_html: { url: "https://example.com" },
38334
+ brightdata_scrape_batch: { urls: ["https://example.com"] },
38335
+ brightdata_extract: { url: "https://example.com" },
38336
+ brightdata_session_stats: {},
38337
+ brightdata_web_data_reuter_news: { url: "https://www.reuters.com/technology/" },
38338
+ brightdata_web_data_github_repository_file: { url: "https://github.com/octocat/Hello-World/blob/master/README" },
38339
+ "tavily_tavily-search": { query: "test", maxResults: 1 },
38340
+ "tavily_tavily-extract": { urls: ["https://example.com"] },
38341
+ "tavily_tavily-map": { url: "https://example.com" },
38342
+ "context7_resolve-library-id": { libraryName: "react" },
38343
+ octocode_githubSearchRepositories: { query: "test", maxResults: 1 },
38344
+ octocode_githubSearchCode: { query: "function test", maxResults: 1 },
38345
+ octocode_githubViewRepoStructure: { owner: "octocat", repo: "Hello-World" },
38346
+ perplexity_perplexity_ask: { query: "What is 1+1?" },
38347
+ perplexity_perplexity_search: { query: "test", maxResults: 1 }
38348
+ };
38349
+ function generateMinimalArgs(schema2) {
38350
+ const args = {};
38351
+ if (schema2.type !== "object" || !schema2.properties) {
38352
+ return args;
38353
+ }
38354
+ const properties = schema2.properties;
38355
+ const required3 = schema2.required || [];
38356
+ for (const propName of required3) {
38357
+ const prop = properties[propName];
38358
+ if (!prop)
38359
+ continue;
38360
+ const enumValues = prop.enum;
38361
+ switch (prop.type) {
38362
+ case "string":
38363
+ args[propName] = prop.default ?? enumValues?.[0] ?? "test";
38364
+ break;
38365
+ case "number":
38366
+ case "integer":
38367
+ args[propName] = prop.default ?? prop.minimum ?? 1;
38368
+ break;
38369
+ case "boolean":
38370
+ args[propName] = prop.default ?? false;
38371
+ break;
38372
+ case "array":
38373
+ args[propName] = prop.default ?? [];
38374
+ break;
38375
+ case "object":
38376
+ args[propName] = prop.default ?? {};
38377
+ break;
38378
+ default:
38379
+ args[propName] = prop.default ?? null;
38380
+ }
38381
+ }
38382
+ return args;
38383
+ }
38318
38384
  var isTestEnv = !!process.env.BUN_TEST;
38319
38385
  function log(level, message, extra) {
38320
38386
  if (isTestEnv)
@@ -38344,25 +38410,14 @@ You have access to an extended toolbox with additional capabilities (web search,
38344
38410
  ## Workflow
38345
38411
  1. Search: toolbox_search_bm25({ text: "what you need" }) or toolbox_search_regex({ pattern: "prefix_.*" })
38346
38412
  2. Execute: toolbox_execute({ name: "tool_name", arguments: '{"key": "value"}' })`;
38347
- function generateSystemPrompt(mcpManager) {
38348
- const servers = mcpManager.getAllServers();
38349
- if (servers.length === 0) {
38350
- return SYSTEM_PROMPT_BASE;
38351
- }
38352
- const toolboxSchema = {};
38353
- for (const server of servers) {
38354
- if (server.status === "connected" && server.tools.length > 0) {
38355
- toolboxSchema[server.name] = server.tools.map((t) => t.idString);
38356
- }
38357
- }
38358
- if (Object.keys(toolboxSchema).length === 0) {
38413
+ function generateSystemPrompt(configuredServers) {
38414
+ if (configuredServers.length === 0) {
38359
38415
  return SYSTEM_PROMPT_BASE;
38360
38416
  }
38361
38417
  return `${SYSTEM_PROMPT_BASE}
38362
38418
 
38363
38419
  ## Registered MCP Servers
38364
- ${Object.entries(toolboxSchema).map(([server, tools]) => `- ${server}: ${tools.map((t) => t.split("_").slice(1).join("_")).join(", ")}`).join(`
38365
- `)}`;
38420
+ - ${configuredServers.join(", ")}`;
38366
38421
  }
38367
38422
  var ToolboxPlugin = async (ctx) => {
38368
38423
  const pluginLoadStart = performance.now();
@@ -38663,15 +38718,137 @@ var ToolboxPlugin = async (ctx) => {
38663
38718
  }
38664
38719
  }, null, 2);
38665
38720
  }
38721
+ }),
38722
+ toolbox_test: tool({
38723
+ description: TEST_DESC,
38724
+ args: {
38725
+ timeout: tool.schema.number().optional().describe("Timeout per tool in ms (default: 10000)")
38726
+ },
38727
+ async execute(args) {
38728
+ const startTime = performance.now();
38729
+ const output = [];
38730
+ output.push("=".repeat(80));
38731
+ output.push("TOOLBOX TEST - Full Execution Log");
38732
+ output.push("=".repeat(80));
38733
+ output.push("");
38734
+ try {
38735
+ await ensureInitialized();
38736
+ } catch (error92) {
38737
+ output.push(`[FATAL] Failed to initialize: ${error92 instanceof Error ? error92.message : String(error92)}`);
38738
+ return output.join(`
38739
+ `);
38740
+ }
38741
+ const allTools = mcpManager.getAllCatalogTools();
38742
+ const timeout = args.timeout || 1e4;
38743
+ output.push(`[INFO] Found ${allTools.length} tools to test`);
38744
+ output.push(`[INFO] Timeout per tool: ${timeout}ms`);
38745
+ output.push(`[INFO] Started at: ${new Date().toISOString()}`);
38746
+ output.push("");
38747
+ let passed = 0;
38748
+ let failed = 0;
38749
+ let timedOut = 0;
38750
+ let skipped = 0;
38751
+ for (let i = 0;i < allTools.length; i++) {
38752
+ const catalogTool = allTools[i];
38753
+ const toolId = catalogTool.idString;
38754
+ const testNum = i + 1;
38755
+ output.push("-".repeat(80));
38756
+ output.push(`[TEST ${testNum}/${allTools.length}] ${toolId}`);
38757
+ output.push("-".repeat(80));
38758
+ const parsed = parseToolName(toolId);
38759
+ if (!parsed) {
38760
+ output.push(`[SKIP] Invalid tool name format`);
38761
+ output.push("");
38762
+ skipped++;
38763
+ continue;
38764
+ }
38765
+ output.push(`[INFO] Server: ${parsed.serverName}`);
38766
+ output.push(`[INFO] Tool: ${parsed.toolName}`);
38767
+ output.push(`[INFO] Description: ${catalogTool.description || "(no description)"}`);
38768
+ output.push("");
38769
+ let testArgs;
38770
+ let argsSource;
38771
+ const predefinedArgs = TEST_PROMPTS[toolId];
38772
+ if (predefinedArgs !== undefined) {
38773
+ testArgs = predefinedArgs;
38774
+ argsSource = "PREDEFINED";
38775
+ } else {
38776
+ testArgs = generateMinimalArgs(catalogTool.inputSchema);
38777
+ argsSource = Object.keys(testArgs).length > 0 ? "GENERATED" : "EMPTY";
38778
+ }
38779
+ output.push(`[INPUT] Arguments source: ${argsSource}`);
38780
+ output.push(`[INPUT] Request payload:`);
38781
+ output.push(JSON.stringify(testArgs, null, 2).split(`
38782
+ `).map((line) => " " + line).join(`
38783
+ `));
38784
+ output.push("");
38785
+ const toolStart = performance.now();
38786
+ try {
38787
+ const timeoutPromise = new Promise((_, reject) => {
38788
+ setTimeout(() => reject(new Error("TIMEOUT")), timeout);
38789
+ });
38790
+ const execPromise = mcpManager.callTool(parsed.serverName, parsed.toolName, testArgs);
38791
+ const result = await Promise.race([execPromise, timeoutPromise]);
38792
+ const duration5 = Math.round(performance.now() - toolStart);
38793
+ output.push(`[OUTPUT] Response received in ${duration5}ms:`);
38794
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
38795
+ output.push(resultStr.split(`
38796
+ `).map((line) => " " + line).join(`
38797
+ `));
38798
+ output.push("");
38799
+ output.push(`[PASS] \u2713 Test passed in ${duration5}ms`);
38800
+ passed++;
38801
+ } catch (error92) {
38802
+ const duration5 = Math.round(performance.now() - toolStart);
38803
+ const errorMsg = error92 instanceof Error ? error92.message : String(error92);
38804
+ if (errorMsg === "TIMEOUT") {
38805
+ output.push(`[OUTPUT] No response - timed out after ${timeout}ms`);
38806
+ output.push("");
38807
+ output.push(`[TIMEOUT] \u2717 Test timed out after ${duration5}ms`);
38808
+ timedOut++;
38809
+ } else {
38810
+ output.push(`[OUTPUT] Error response:`);
38811
+ output.push(` ${errorMsg}`);
38812
+ output.push("");
38813
+ output.push(`[FAIL] \u2717 Test failed in ${duration5}ms`);
38814
+ output.push(`[FAIL] Error: ${errorMsg}`);
38815
+ failed++;
38816
+ }
38817
+ }
38818
+ output.push("");
38819
+ }
38820
+ const totalDuration = Math.round(performance.now() - startTime);
38821
+ const total = allTools.length;
38822
+ const successRate = total > 0 ? Math.round(passed / total * 100) : 0;
38823
+ output.push("=".repeat(80));
38824
+ output.push("TEST SUMMARY");
38825
+ output.push("=".repeat(80));
38826
+ output.push("");
38827
+ output.push(`Total tests: ${total}`);
38828
+ output.push(`Passed: ${passed} \u2713`);
38829
+ output.push(`Failed: ${failed} \u2717`);
38830
+ output.push(`Timed out: ${timedOut} \u23F1`);
38831
+ output.push(`Skipped: ${skipped} \u2298`);
38832
+ output.push("");
38833
+ output.push(`Success rate: ${successRate}%`);
38834
+ output.push(`Total duration: ${totalDuration}ms`);
38835
+ output.push(`Finished at: ${new Date().toISOString()}`);
38836
+ output.push("");
38837
+ output.push("=".repeat(80));
38838
+ log("info", `Toolbox test completed: ${passed}/${total} passed in ${totalDuration}ms`, {
38839
+ passed,
38840
+ failed,
38841
+ timedOut,
38842
+ skipped,
38843
+ total
38844
+ });
38845
+ return output.join(`
38846
+ `);
38847
+ }
38666
38848
  })
38667
38849
  },
38668
38850
  "experimental.chat.system.transform": async (_input, output) => {
38669
- if (!mcpManager.isReady() && initMode === "eager") {
38670
- try {
38671
- await mcpManager.waitForPartial();
38672
- } catch {}
38673
- }
38674
- output.system.push(generateSystemPrompt(mcpManager));
38851
+ output.system.push(generateSystemPrompt(serverNames));
38675
38852
  }
38676
38853
  };
38677
38854
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-toolbox",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Tool Search Tool Plugin for OpenCode - search and execute tools from MCP servers on-demand",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",