@warlock.js/ai-tools 4.5.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 (83) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +164 -0
  4. package/cjs/index.cjs +2519 -0
  5. package/cjs/index.cjs.map +1 -0
  6. package/esm/contracts/http.type.d.mts +96 -0
  7. package/esm/contracts/http.type.d.mts.map +1 -0
  8. package/esm/contracts/index.d.mts +4 -0
  9. package/esm/contracts/mcp.type.d.mts +216 -0
  10. package/esm/contracts/mcp.type.d.mts.map +1 -0
  11. package/esm/contracts/utility.type.d.mts +96 -0
  12. package/esm/contracts/utility.type.d.mts.map +1 -0
  13. package/esm/contracts/web.type.d.mts +136 -0
  14. package/esm/contracts/web.type.d.mts.map +1 -0
  15. package/esm/errors.d.mts +225 -0
  16. package/esm/errors.d.mts.map +1 -0
  17. package/esm/errors.mjs +136 -0
  18. package/esm/errors.mjs.map +1 -0
  19. package/esm/http/http-request.d.mts +57 -0
  20. package/esm/http/http-request.d.mts.map +1 -0
  21. package/esm/http/http-request.mjs +221 -0
  22. package/esm/http/http-request.mjs.map +1 -0
  23. package/esm/index.d.mts +19 -0
  24. package/esm/index.mjs +15 -0
  25. package/esm/mcp/client.mjs +199 -0
  26. package/esm/mcp/client.mjs.map +1 -0
  27. package/esm/mcp/index.d.mts +43 -0
  28. package/esm/mcp/index.d.mts.map +1 -0
  29. package/esm/mcp/index.mjs +19 -0
  30. package/esm/mcp/index.mjs.map +1 -0
  31. package/esm/mcp/json-schema-to-standard.d.mts +34 -0
  32. package/esm/mcp/json-schema-to-standard.d.mts.map +1 -0
  33. package/esm/mcp/json-schema-to-standard.mjs +147 -0
  34. package/esm/mcp/json-schema-to-standard.mjs.map +1 -0
  35. package/esm/mcp/serve.d.mts +46 -0
  36. package/esm/mcp/serve.d.mts.map +1 -0
  37. package/esm/mcp/serve.mjs +264 -0
  38. package/esm/mcp/serve.mjs.map +1 -0
  39. package/esm/mcp/transport.d.mts +48 -0
  40. package/esm/mcp/transport.d.mts.map +1 -0
  41. package/esm/mcp/transport.mjs +381 -0
  42. package/esm/mcp/transport.mjs.map +1 -0
  43. package/esm/mcp/transport.type.d.mts +51 -0
  44. package/esm/mcp/transport.type.d.mts.map +1 -0
  45. package/esm/node_modules/@standard-schema/spec/dist/index.d.mts +80 -0
  46. package/esm/node_modules/@standard-schema/spec/dist/index.d.mts.map +1 -0
  47. package/esm/register.d.mts +55 -0
  48. package/esm/register.d.mts.map +1 -0
  49. package/esm/register.mjs +21 -0
  50. package/esm/register.mjs.map +1 -0
  51. package/esm/schema.mjs +127 -0
  52. package/esm/schema.mjs.map +1 -0
  53. package/esm/utility/calculator.d.mts +35 -0
  54. package/esm/utility/calculator.d.mts.map +1 -0
  55. package/esm/utility/calculator.mjs +272 -0
  56. package/esm/utility/calculator.mjs.map +1 -0
  57. package/esm/utility/date-time.d.mts +57 -0
  58. package/esm/utility/date-time.d.mts.map +1 -0
  59. package/esm/utility/date-time.mjs +193 -0
  60. package/esm/utility/date-time.mjs.map +1 -0
  61. package/esm/utility/index.d.mts +2 -0
  62. package/esm/utility/index.mjs +4 -0
  63. package/esm/utility/schema.mjs +114 -0
  64. package/esm/utility/schema.mjs.map +1 -0
  65. package/esm/web/fetch-url.d.mts +39 -0
  66. package/esm/web/fetch-url.d.mts.map +1 -0
  67. package/esm/web/fetch-url.mjs +228 -0
  68. package/esm/web/fetch-url.mjs.map +1 -0
  69. package/esm/web/index.d.mts +2 -0
  70. package/esm/web/index.mjs +4 -0
  71. package/esm/web/schema.mjs +86 -0
  72. package/esm/web/schema.mjs.map +1 -0
  73. package/esm/web/web-search.d.mts +38 -0
  74. package/esm/web/web-search.d.mts.map +1 -0
  75. package/esm/web/web-search.mjs +167 -0
  76. package/esm/web/web-search.mjs.map +1 -0
  77. package/llms-full.txt +326 -0
  78. package/llms.txt +11 -0
  79. package/package.json +45 -0
  80. package/skills/README.md +17 -0
  81. package/skills/connect-mcp-server/SKILL.md +98 -0
  82. package/skills/expose-as-mcp-server/SKILL.md +85 -0
  83. package/skills/use-web-and-http-tools/SKILL.md +125 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # Changelog — @warlock.js/ai-tools
2
+
3
+ All notable changes to `@warlock.js/ai-tools` are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
+
7
+ ## 4.5.0 - 2026-07-01
8
+
9
+ Initial release — a batteries-included tool belt + a Model Context Protocol client and server for `@warlock.js/ai`, built entirely on the framework's vendor-neutral `ai.tool()` seam.
10
+
11
+ ### Added
12
+
13
+ - **Five ready-made agent tools, attached to the shared `ai` object under `ai.tools.*`** via a `declare module "@warlock.js/ai"` augmentation, so a bare `import "@warlock.js/ai-tools"` makes them available and statically typed. Each returns a `ToolContract` that drops straight into `ai.agent({ tools: [...] })`:
14
+ - **`ai.tools.webSearch(options)`** (`web_search`) — web search via a chosen provider (`tavily` / `brave` / `serpapi`) over the global `fetch`; the API key falls back to `TAVILY_API_KEY` / `BRAVE_API_KEY` / `SERPAPI_API_KEY`; `maxResults` is clamped per call.
15
+ - **`ai.tools.fetchUrl(options?)`** (`fetch_url`) — fetch a URL and return its content as readability-extracted `text` (default), raw `html`, or `markdown`, with a host allowlist (SSRF guardrail), a byte cap (`truncated` flag), and a request timeout.
16
+ - **`ai.tools.http(options?)`** (`http_request`) — a guarded HTTP/REST client: method + host allowlists enforced before the network call, optional `baseUrl` join, static-header merge, byte cap, and timeout; JSON-parses a JSON response body.
17
+ - **`ai.tools.calculator(options?)`** (`calculator`) — a SAFE arithmetic evaluator (`+ - * / % ^`, unary signs, parentheses, decimal/scientific literals) implemented with a shunting-yard pass — it never calls `eval`/`Function`.
18
+ - **`ai.tools.dateTime(options?)`** (`date_time`) — clock/calendar operations: `now` / `add` / `diff` / `format` over ISO-8601 instants, with millisecond-based units and IANA time-zone rendering. `diff` accepts `from` as an alias for the start instant (`iso` wins when both are set).
19
+ - **MCP client — `ai.mcp(server, options?)` (Direction A).** Connects to an external MCP server over a stdio (`node:child_process` + `node:readline`, no dependency) or Streamable HTTP transport, runs the `initialize` handshake + `tools/list`, and adapts each remote tool into a native `ToolContract` (its JSON Schema wrapped as a Standard Schema, `tools/call` as `execute`). Supports `namePrefix`, `filter`, and a per-call `timeoutMs`; an `isError` result surfaces as `{ error }` data.
20
+ - **MCP server — `ai.mcp.serve(source, options)` (Direction B).** Exposes a built agent / supervisor / orchestrator (or a raw `ToolContract[]`) AS an MCP server: `tools/list` emits each tool's `inputSchema` via `extractJsonSchema` at the configured `schemaTarget` (default `draft-2020-12`), and `tools/call` routes to `contract.invoke()`, mapping `data` to a text content block and `error` to an `isError: true` result. The stdio transport is auto-pumped over `process.stdin` / `process.stdout`; the pure protocol core is also exported as `createServeHandler` for a host's own HTTP wiring.
21
+ - **Typed error classes** — `WebToolError`, `HttpPolicyError`, `CalculatorError`, `DateTimeError`, and `McpTransportError`, each extending the `@warlock.js/ai` `AIError` base with a `type` discriminator. Every tool follows the errors-as-data contract: failures are thrown inside `execute`, wrapped by `tool()`, and reach the model as `{ error }` so the agent self-corrects instead of crashing the run.
22
+ - **Optional peers, lazily imported.** Heavy dependencies — a search provider (`@tavily/core`), the readability scraper (`@mozilla/readability` + `jsdom`), the MCP SDK (`@modelcontextprotocol/sdk`), and the JSON-Schema validator (`ajv`) — are optional peers, `import()`ed only when the relevant path runs, surfacing a curated `npm install` string when absent rather than crashing at import time. The only required runtime peer is `@warlock.js/ai`; everything else is Node built-ins + the global `fetch` (Node 18+).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Hassan Zohdy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,164 @@
1
+ # @warlock.js/ai-tools
2
+
3
+ > Ready-made agent tools (web search, fetch, HTTP, calculator, date-time) + an MCP client/server for `@warlock.js/ai`.
4
+
5
+ A batteries-included **tool belt** for [`@warlock.js/ai`](https://github.com/warlockjs) agents plus a
6
+ Model Context Protocol (MCP) client and server — built entirely on the framework's vendor-neutral
7
+ `ai.tool()` seam, so every tool returns a `ToolContract` that drops straight into
8
+ `ai.agent({ tools: [...] })`. Importing the package registers the tools on the shared `ai` object,
9
+ so they are reached as `ai.tools.*` and `ai.mcp` per the `ai.`-namespace convention.
10
+
11
+ ## What's in the belt
12
+
13
+ All five tools attach onto the shared `ai` object at import time under the `ai.tools.*` namespace
14
+ (via a `declare module "@warlock.js/ai"` augmentation), so a bare `import "@warlock.js/ai-tools"`
15
+ makes them available and statically typed.
16
+
17
+ | Tool | LLM-visible name | What it does |
18
+ |---|---|---|
19
+ | `ai.tools.webSearch(options)` | `web_search` | Web search via a chosen provider (`tavily` / `brave` / `serpapi`) — ranked title/URL/snippet hits. |
20
+ | `ai.tools.fetchUrl(options?)` | `fetch_url` | Fetch a URL → readability `text` (default), raw `html`, or `markdown`; host allowlist + byte cap. |
21
+ | `ai.tools.http(options?)` | `http_request` | A guarded HTTP/REST client — method + host allowlists, `baseUrl` join, byte/timeout caps. |
22
+ | `ai.tools.calculator(options?)` | `calculator` | A SAFE arithmetic evaluator (shunting-yard; never `eval`/`Function`). |
23
+ | `ai.tools.dateTime(options?)` | `date_time` | `now` / `add` / `diff` / `format` over ISO-8601 instants, IANA time zones. |
24
+
25
+ ## MCP — both directions
26
+
27
+ - **`ai.mcp(server, options?)`** — connect to an external MCP server and adapt each of its tools into
28
+ a native `ToolContract` (Direction A: server → agent tools).
29
+ - **`ai.mcp.serve(source, options)`** — expose a warlock agent / supervisor / orchestrator (or a raw
30
+ `ToolContract[]`) **as** an MCP server other clients consume (Direction B: primitive → server).
31
+
32
+ > There is **no SQL tool.** An LLM-driven SQL surface is sensitive and must be audited per app, so it
33
+ > is deliberately not part of this belt.
34
+
35
+ ## Install
36
+
37
+ ```bash
38
+ npm install @warlock.js/ai-tools
39
+ ```
40
+
41
+ `@warlock.js/ai` is the only required runtime peer. Everything heavy — a search provider, the
42
+ readability scraper, the MCP SDK, and a JSON-Schema validator — is an **optional peer**, lazily
43
+ `import()`ed only when the relevant path runs; a missing one surfaces a curated `npm install` string
44
+ rather than crashing at import time. Beyond `@warlock.js/ai` the package uses only Node built-ins and
45
+ the global `fetch` (Node 18+). Import the package once for its side effect so the surface is
46
+ registered:
47
+
48
+ ```ts
49
+ import "@warlock.js/ai-tools";
50
+ ```
51
+
52
+ ## Usage
53
+
54
+ ### 1. An agent with web search + HTTP
55
+
56
+ Hand an agent the web tools and let it research, then hit an API — both bounded by a host allowlist.
57
+ A failing tool call comes back as `{ error }` *data*, so the agent self-corrects instead of crashing.
58
+
59
+ ```ts
60
+ import "@warlock.js/ai-tools"; // registers ai.tools.* + ai.mcp on import
61
+ import { ai } from "@warlock.js/ai";
62
+
63
+ const agent = ai.agent({
64
+ model: ai.openai.model({ name: "gpt-4o" }),
65
+ systemPrompt: "Research with web_search, then call the API with http_request.",
66
+ tools: [
67
+ ai.tools.webSearch({ provider: "tavily" }), // TAVILY_API_KEY from env, or pass { apiKey }
68
+ ai.tools.http({
69
+ baseUrl: "https://api.github.com",
70
+ allowHosts: ["api.github.com"],
71
+ allowMethods: ["GET"],
72
+ headers: { "user-agent": "warlock-agent" },
73
+ }),
74
+ ],
75
+ maxTrips: 12,
76
+ });
77
+
78
+ await agent.execute("Find the latest @warlock.js release and summarize its notes.");
79
+ ```
80
+
81
+ ### 2. Consume an external MCP server
82
+
83
+ `ai.mcp(server)` connects to any MCP server, lists its tools, and adapts each into a `ToolContract`.
84
+ `await client.tools()` runs the handshake once and is cached; spread the result into `tools: [...]`.
85
+
86
+ ```ts
87
+ import "@warlock.js/ai-tools";
88
+ import { ai } from "@warlock.js/ai";
89
+
90
+ const github = ai.mcp(
91
+ { type: "stdio", command: "npx", args: ["-y", "@modelcontextprotocol/server-github"] },
92
+ { namePrefix: "github." }, // avoid colliding with local tool names
93
+ );
94
+
95
+ const dev = ai.agent({
96
+ model: ai.openai.model({ name: "gpt-4o" }),
97
+ systemPrompt: "Use the GitHub tools to triage issues.",
98
+ tools: [...(await github.tools())],
99
+ maxTrips: 20,
100
+ });
101
+
102
+ await dev.execute("List the open issues labeled 'bug' and propose a fix for the oldest.");
103
+
104
+ // On teardown:
105
+ await github.close();
106
+ ```
107
+
108
+ ### 3. Expose an agent's tools AS an MCP server
109
+
110
+ `ai.mcp.serve(source, options)` turns a local `ToolContract[]` (or anything with a `tools()` method)
111
+ into an MCP server. The default `stdio` transport is auto-pumped over `process.stdin`/`process.stdout`,
112
+ so Cursor / Claude Desktop / any MCP client can call these tools.
113
+
114
+ ```ts
115
+ import "@warlock.js/ai-tools";
116
+
117
+ const server = ai.mcp.serve(
118
+ [ai.tools.calculator(), ai.tools.dateTime()],
119
+ { name: "warlock-utils", transport: { type: "stdio" } },
120
+ );
121
+
122
+ await server.start();
123
+ // ...later:
124
+ await server.stop();
125
+ ```
126
+
127
+ ## Errors flow as data, not throws
128
+
129
+ Every tool follows the framework's errors-as-data contract: a guardrail rejection or a failed call is
130
+ thrown inside the tool handler, caught by `tool()`, and surfaced in the returned `{ error }` field —
131
+ `invoke()` never throws. Each error class extends the `@warlock.js/ai` `AIError` base and carries a
132
+ `type` discriminator you can branch on:
133
+
134
+ ```ts
135
+ import { HttpPolicyError } from "@warlock.js/ai-tools";
136
+
137
+ const http = ai.tools.http({ allowHosts: ["api.github.com"] });
138
+ const { error } = await http.invoke({ url: "https://evil.test" });
139
+
140
+ if (error instanceof HttpPolicyError && error.type === "host-not-allowed") {
141
+ // rejected before any network call — an SSRF guardrail
142
+ }
143
+ ```
144
+
145
+ - `WebToolError.type`: `"missing-peer"` | `"missing-key"` | `"denied-host"` | `"invalid-url"` | `"request-failed"`
146
+ - `HttpPolicyError.type`: `"method-not-allowed"` | `"host-not-allowed"` | `"invalid-url"`
147
+ - `CalculatorError.type`: `"syntax"` | `"divide-by-zero"` | `"overflow"`
148
+ - `DateTimeError.type`: `"invalid-input"` | `"invalid-unit"` | `"invalid-time-zone"` | `"unsupported-op"`
149
+ - `McpTransportError.type`: `"connect"` | `"protocol"` | `"timeout"` | `"closed"`
150
+
151
+ ## Skills
152
+
153
+ Progressive-disclosure, per-task docs live under [`skills/`](./skills/README.md):
154
+
155
+ - [`use-web-and-http-tools/`](./skills/use-web-and-http-tools/SKILL.md) — wire `web_search`, `fetch_url`,
156
+ `http_request`, `calculator`, and `date_time` into an agent under their guardrails.
157
+ - [`connect-mcp-server/`](./skills/connect-mcp-server/SKILL.md) — adapt an external MCP server's tools
158
+ with `ai.mcp(server)` (Direction A).
159
+ - [`expose-as-mcp-server/`](./skills/expose-as-mcp-server/SKILL.md) — publish a local primitive AS an
160
+ MCP server with `ai.mcp.serve(source)` (Direction B).
161
+
162
+ ## License
163
+
164
+ MIT © Hassan Zohdy