@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.
- package/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +164 -0
- package/cjs/index.cjs +2519 -0
- package/cjs/index.cjs.map +1 -0
- package/esm/contracts/http.type.d.mts +96 -0
- package/esm/contracts/http.type.d.mts.map +1 -0
- package/esm/contracts/index.d.mts +4 -0
- package/esm/contracts/mcp.type.d.mts +216 -0
- package/esm/contracts/mcp.type.d.mts.map +1 -0
- package/esm/contracts/utility.type.d.mts +96 -0
- package/esm/contracts/utility.type.d.mts.map +1 -0
- package/esm/contracts/web.type.d.mts +136 -0
- package/esm/contracts/web.type.d.mts.map +1 -0
- package/esm/errors.d.mts +225 -0
- package/esm/errors.d.mts.map +1 -0
- package/esm/errors.mjs +136 -0
- package/esm/errors.mjs.map +1 -0
- package/esm/http/http-request.d.mts +57 -0
- package/esm/http/http-request.d.mts.map +1 -0
- package/esm/http/http-request.mjs +221 -0
- package/esm/http/http-request.mjs.map +1 -0
- package/esm/index.d.mts +19 -0
- package/esm/index.mjs +15 -0
- package/esm/mcp/client.mjs +199 -0
- package/esm/mcp/client.mjs.map +1 -0
- package/esm/mcp/index.d.mts +43 -0
- package/esm/mcp/index.d.mts.map +1 -0
- package/esm/mcp/index.mjs +19 -0
- package/esm/mcp/index.mjs.map +1 -0
- package/esm/mcp/json-schema-to-standard.d.mts +34 -0
- package/esm/mcp/json-schema-to-standard.d.mts.map +1 -0
- package/esm/mcp/json-schema-to-standard.mjs +147 -0
- package/esm/mcp/json-schema-to-standard.mjs.map +1 -0
- package/esm/mcp/serve.d.mts +46 -0
- package/esm/mcp/serve.d.mts.map +1 -0
- package/esm/mcp/serve.mjs +264 -0
- package/esm/mcp/serve.mjs.map +1 -0
- package/esm/mcp/transport.d.mts +48 -0
- package/esm/mcp/transport.d.mts.map +1 -0
- package/esm/mcp/transport.mjs +381 -0
- package/esm/mcp/transport.mjs.map +1 -0
- package/esm/mcp/transport.type.d.mts +51 -0
- package/esm/mcp/transport.type.d.mts.map +1 -0
- package/esm/node_modules/@standard-schema/spec/dist/index.d.mts +80 -0
- package/esm/node_modules/@standard-schema/spec/dist/index.d.mts.map +1 -0
- package/esm/register.d.mts +55 -0
- package/esm/register.d.mts.map +1 -0
- package/esm/register.mjs +21 -0
- package/esm/register.mjs.map +1 -0
- package/esm/schema.mjs +127 -0
- package/esm/schema.mjs.map +1 -0
- package/esm/utility/calculator.d.mts +35 -0
- package/esm/utility/calculator.d.mts.map +1 -0
- package/esm/utility/calculator.mjs +272 -0
- package/esm/utility/calculator.mjs.map +1 -0
- package/esm/utility/date-time.d.mts +57 -0
- package/esm/utility/date-time.d.mts.map +1 -0
- package/esm/utility/date-time.mjs +193 -0
- package/esm/utility/date-time.mjs.map +1 -0
- package/esm/utility/index.d.mts +2 -0
- package/esm/utility/index.mjs +4 -0
- package/esm/utility/schema.mjs +114 -0
- package/esm/utility/schema.mjs.map +1 -0
- package/esm/web/fetch-url.d.mts +39 -0
- package/esm/web/fetch-url.d.mts.map +1 -0
- package/esm/web/fetch-url.mjs +228 -0
- package/esm/web/fetch-url.mjs.map +1 -0
- package/esm/web/index.d.mts +2 -0
- package/esm/web/index.mjs +4 -0
- package/esm/web/schema.mjs +86 -0
- package/esm/web/schema.mjs.map +1 -0
- package/esm/web/web-search.d.mts +38 -0
- package/esm/web/web-search.d.mts.map +1 -0
- package/esm/web/web-search.mjs +167 -0
- package/esm/web/web-search.mjs.map +1 -0
- package/llms-full.txt +326 -0
- package/llms.txt +11 -0
- package/package.json +45 -0
- package/skills/README.md +17 -0
- package/skills/connect-mcp-server/SKILL.md +98 -0
- package/skills/expose-as-mcp-server/SKILL.md +85 -0
- 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
|