@samrahimi/smol-js 0.7.0 → 0.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samrahimi/smol-js",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "A TypeScript agentic framework - CodeAgent and ToolUseAgent with YAML orchestration, built-in tools, and Exa.ai integration",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -17,6 +17,7 @@
17
17
  },
18
18
  "files": [
19
19
  "dist",
20
+ "toolHarness.ts",
20
21
  "README.md"
21
22
  ],
22
23
  "scripts": {
package/toolHarness.ts ADDED
@@ -0,0 +1,73 @@
1
+ /**
2
+ * toolHarness.ts — Transport adapter for standalone custom tools.
3
+ *
4
+ * This is the ONLY file that knows about the stdout protocol. It is invoked
5
+ * by ProxyTool as:
6
+ *
7
+ * bun run toolHarness.ts <toolPath> <argsJson>
8
+ *
9
+ * It dynamically imports the tool file, calls its exported `execute` function,
10
+ * and writes the result using the protocol. The tool itself has zero knowledge
11
+ * of how it is being called — it simply exports a function.
12
+ *
13
+ * A tool file must export:
14
+ * - TOOL_METADATA: { name, description, inputs, outputType }
15
+ * - execute(args: Record<string, unknown>): Promise<unknown>
16
+ *
17
+ * Any console.log calls made inside execute() will flow through stdout
18
+ * naturally and be captured as streaming output by the ProxyTool on the
19
+ * other end — no special handling needed by the tool author.
20
+ */
21
+
22
+ async function main(): Promise<void> {
23
+ const toolPath = process.argv[2];
24
+ const argsJson = process.argv[3] ?? '{}';
25
+
26
+ if (!toolPath) {
27
+ process.stderr.write('toolHarness: no tool path provided (argv[2])\n');
28
+ process.exit(1);
29
+ }
30
+
31
+ // Deserialize arguments
32
+ let args: Record<string, unknown>;
33
+ try {
34
+ args = JSON.parse(argsJson);
35
+ } catch (err) {
36
+ process.stderr.write(`toolHarness: invalid JSON arguments: ${(err as Error).message}\n`);
37
+ process.exit(1);
38
+ }
39
+
40
+ // Dynamically import the tool module — Bun handles .ts natively
41
+ let toolModule: Record<string, unknown>;
42
+ try {
43
+ toolModule = await import(toolPath) as Record<string, unknown>;
44
+ } catch (err) {
45
+ process.stderr.write(`toolHarness: failed to import tool at "${toolPath}": ${(err as Error).message}\n`);
46
+ process.exit(1);
47
+ }
48
+
49
+ // Extract and validate the execute export
50
+ const execute = toolModule.execute;
51
+ if (typeof execute !== 'function') {
52
+ const exported = Object.keys(toolModule).filter(k => k !== '__esModule').join(', ');
53
+ process.stderr.write(
54
+ `toolHarness: tool at "${toolPath}" does not export an 'execute' function.\n` +
55
+ ` Exported keys: [${exported}]\n` +
56
+ ` A custom tool must: export async function execute(args) { ... }\n`
57
+ );
58
+ process.exit(1);
59
+ }
60
+
61
+ // Invoke the tool's execute function
62
+ const result = await (execute as (args: Record<string, unknown>) => Promise<unknown>)(args);
63
+
64
+ // Write the return value on the protocol line — this is the only place
65
+ // the protocol is spoken. The tool never sees it.
66
+ process.stdout.write(`[TOOL_RESULT]${JSON.stringify(result)}\n`);
67
+ }
68
+
69
+ main().catch((err: Error) => {
70
+ // Protocol error line — tool threw or something went wrong
71
+ process.stdout.write(`[TOOL_ERROR]${err.message}\n`);
72
+ process.exit(1);
73
+ });