@harryy/ai-tools
v2.11.1
Published
Reusable AI tools with strict schemas and model-facing contracts. Define once; project to Node, edge, Mastra, AI SDK, TanStack AI, Cloudflare Workers AI, or MCP.
Readme
@harryy/ai-tools
Reusable AI tools with strict Zod schemas and model-facing contracts. Define once in the kernel; project to Mastra, Vercel AI SDK, TanStack AI, Cloudflare Workers AI, MCP, or call via class clients / runTool.
Docs: docs/README.md · Changelog: CHANGELOG.md · Release: docs/versioning.md
Why
- One authoring path —
defineTool/defineModuleonly; adapters never re-implement business logic. - Host-owned secrets — auth schemas +
withAuth; model inputs never carry API keys. - Two product roots —
modules/(our seams) vsvendors/(3rd-party packs); flat public imports. - Class clients + tools — host uses
new ResendClient(auth); agents use the same implementation via tools. - Subpath imports — tree-shake friendly; no root mega-barrel.
- Honest runtimes —
node|edge|both. - Stable tool ids — kebab-case, vendor- or capability-prefixed.
Install
bun add @harryy/ai-tools
# optional peers for adapters you use:
bun add @mastra/core
bun add ai
bun add @tanstack/ai
bun add @modelcontextprotocol/sdk # registerMcpTools onlyRequires Bun ≥ 1.3.14 or Node ≥ 24.
Quick start
import { withAuth } from '@harryy/ai-tools/core'
import { resendModule, ResendClient } from '@harryy/ai-tools/resend'
import { createMastraTools } from '@harryy/ai-tools/mastra'
// Host DX (class client)
const resend = new ResendClient({ api_key: process.env.RESEND_API_KEY! })
await resend.send({ to: '[email protected]', from: '[email protected]', subject: 'Hi', text: 'Hello' })
// Agent tools (same implementation)
const bound = withAuth(resendModule, { api_key: process.env.RESEND_API_KEY! })
export const tools = createMastraTools(bound)Multi-provider seam (host picks provider on auth):
import { withAuth } from '@harryy/ai-tools/core'
import { emailModule } from '@harryy/ai-tools/email'
const bound = withAuth(emailModule, {
provider: 'resend',
api_key: process.env.RESEND_API_KEY!,
sender: { email: '[email protected]', name: 'Product' },
})No-auth pure helpers:
import { emailMessageModule } from '@harryy/ai-tools/email-message'
import { createAiSdkTools } from '@harryy/ai-tools/ai-sdk'
export const tools = createAiSdkTools(emailMessageModule)Architecture
src/
core/ kernel (defineTool, withAuth, runTool, …)
transport/ HttpService / AwsService → @harryy/ai-tools/http
adapters/ mastra · ai-sdk · tanstack · cloudflare · mcp
modules/ our seams (email, messaging, files, …)
vendors/ 3rd-party packs (resend, telegram, s3, …)
+ vertical kits: _email · _storage · _messaging · _vector (not published)
shared/ bytes, batch, artifact, content-type, pagination| Root | Role |
| --- | --- |
| modules/ | Capability seams we own; usually multi-provider, with explicit product-locked host or single-provider seams |
| vendors/ | Full first-party API of one product; grow tools over time |
| vendors/_… | Vertical kits (codegen-skipped); shared by packs in that category |
Public imports are flat: @harryy/ai-tools/resend, not @harryy/ai-tools/vendors/resend.
defineTool / defineModule
│
├─► Host: Class client (new ResendClient(auth).send(…))
├─► Agent: withAuth(module) → tools → adapters
└─► Direct: runTool(tool, input, ctx)Subpaths
Brain
| Import | Role | Docs |
| --- | --- | --- |
| @harryy/ai-tools/core | Kernel, contracts, withAuth, runTool | core |
| @harryy/ai-tools/http | HttpService / AwsService | http transport |
| @harryy/ai-tools/mastra | Mastra projector | mastra |
| @harryy/ai-tools/ai-sdk | Vercel AI SDK projector | ai-sdk |
| @harryy/ai-tools/tanstack | TanStack AI projector | tanstack |
| @harryy/ai-tools/cloudflare | Workers AI tool defs | cloudflare |
| @harryy/ai-tools/mcp | MCP list/call + register | mcp |
Seams (modules/)
| Import | Kind | Tools (ids) | Docs |
| --- | --- | --- | --- |
| @harryy/ai-tools/email | multi-provider | email-send, email-send-batch | email |
| @harryy/ai-tools/messaging | multi-provider | messaging-send-text, edit, media, reactions, … (telegram/slack/teams/imessage) | messaging |
| @harryy/ai-tools/files | path root over nested S3 | files-* | files |
| @harryy/ai-tools/artifacts | object + host providers | artifacts-create, -read-range, -read-lines | artifacts |
| @harryy/ai-tools/vector-store | qdrant, pinecone, supabase, mastra | vector-store-* | vector-store |
| @harryy/ai-tools/rag | embed + nested vector-store | rag-* | rag |
| @harryy/ai-tools/document-extract | multi-provider | document-extract-text, -status, -text-batch | document-extract |
| @harryy/ai-tools/document-render | multi-provider | document-render-pdf, -screenshot, batches | document-render |
| @harryy/ai-tools/file-convert | gotenberg LO | file-convert (office-to-pdf), batch | file-convert |
| @harryy/ai-tools/document | core reader/builder/editor | read text/PDF/DOCX/XLSX/images; build text/DOCX/XLSX; edit text/DOCX/XLSX/CSV | document |
| @harryy/ai-tools/presentation | PPTX reader/builder/editor | read, build, and edit PPTX presentations; Node ESM only | presentation |
| @harryy/ai-tools/web-fetch | host policy | web-fetch-get, web-fetch-request | web-fetch |
| @harryy/ai-tools/email-message | pure (no auth) | email-message-parse, email-message-build | email-message |
| @harryy/ai-tools/content-type | pure (no auth) | content-type-get, -extension, -extensions | content-type |
| @harryy/ai-tools/skills | host-bound catalog | skills-list, skills-get, skills-search | skills |
| @harryy/ai-tools/tasks | host-backed definitions | tasks-create, -get, -list, -update, -delete | tasks |
| @harryy/ai-tools/scheduler | eventbridge provider | scheduler-create, -update, -get, -list, -delete | scheduler |
| @harryy/ai-tools/pdf | artifact utilities | inspect, merge, extract, split, rotate | pdf |
| @harryy/ai-tools/image | artifact transforms | metadata, resize, crop, thumbnail, convert | image |
| @harryy/ai-tools/crypto | Web Crypto | hash, HMAC sign/verify, random bytes | crypto |
| @harryy/ai-tools/calendar | pure iCalendar | build and parse ICS | calendar |
| @harryy/ai-tools/queue | sqs provider | enqueue, receive, acknowledge, extend visibility | queue |
| @harryy/ai-tools/browser | AgentCore + Cloudflare providers | start, get, stop | browser |
Vendors (vendors/)
| Import | Tools (ids) | Docs |
| --- | --- | --- |
| @harryy/ai-tools/resend | resend-send, resend-send-batch | resend |
| @harryy/ai-tools/cloudflare-email | cloudflare-email-send, -send-batch | cloudflare-email |
| @harryy/ai-tools/telegram | telegram-send-text, -edit-text, media, reactions, … | telegram |
| @harryy/ai-tools/slack | slack-send-text, edit, media, reactions, files, … | slack |
| @harryy/ai-tools/teams | teams-send-text, edit, media, Bot Framework activities | teams |
| @harryy/ai-tools/imessage | send/edit/react/unsend/read via Photon Advanced iMessage HTTP | imessage |
| @harryy/ai-tools/s3 | s3-* (+ signed URL, multipart) | s3 |
| @harryy/ai-tools/sqs | sqs-send, -receive, -delete, -change-visibility | sqs |
| @harryy/ai-tools/qdrant | qdrant-upsert, -query, -delete | qdrant |
| @harryy/ai-tools/pinecone | pinecone-upsert, -query, -delete | pinecone |
| @harryy/ai-tools/supabase-vector | supabase-vector-* (pgvector/PostgREST) | supabase-vector |
| @harryy/ai-tools/mastra-vector | mastra-vector-* (PgVector, node) | mastra-vector |
| @harryy/ai-tools/textract | textract-extract-text, -get-status, -extract-text-batch | textract |
| @harryy/ai-tools/eventbridge-scheduler | create/update/get/list/delete (task_ref) | eventbridge-scheduler |
| @harryy/ai-tools/bedrock-agentcore-code-interpreter | session + execute + files | bedrock-agentcore-code-interpreter |
| @harryy/ai-tools/bedrock-agentcore-browser | start/stop/get session + stream endpoints | bedrock-agentcore-browser |
| @harryy/ai-tools/gotenberg | render PDF/screenshot + office-to-pdf convert | gotenberg |
| @harryy/ai-tools/cloudflare-browser | sessions + PDF/screenshot quick actions | cloudflare-browser |
| @harryy/ai-tools/woocommerce | orders, notes, refunds, products, variations, customers, coupons, categories | woocommerce |
| @harryy/ai-tools/katana | sales/purchase/manufacturing orders, products, materials, customers, suppliers, inventory | katana |
| @harryy/ai-tools/amazon-sp-api | orders + items, FBA inventory, reports + documents, catalog search | amazon-sp-api |
Auth fields are snake_case (api_key, bot_token, access_key_id, …).
Guides
| Guide | Purpose |
| --- | --- |
| Getting started | Install, import map, first bind |
| Auth and binding | Host-owned secrets, withAuth |
| Adapters | Project kernel tools into frameworks |
| Authoring packs | modules vs vendors, layout, codegen |
| Errors | ToolError codes and retry |
| HTTP / AWS transport | HttpService / AwsService |
| Package surface | modules · vendors architecture |
| Provider seam | Multi-provider capability modules |
Develop
bun install
bun run hooks:install
oxfmt --write <touched-paths>
bun run check # format:check + lint + codegen:check + test
bun run codegen
bun run new-module <kebab-key> [--title …] [--description …] [--auth none|custom]
bun run buildCodegen owns package.json exports for packs under src/modules|vendors/<key>/ with index.ts. Underscore kits (_email, _storage, _messaging) are skipped.
Artifacts (extract · convert · render)
- Objects are S3 keys (
ArtifactRef), not base64 in the model. Spec: artifacts-extract-convert. - Read / build / edit: text, PDF, DOCX, spreadsheet, and image-metadata work lives in
document; PPTX work lives inpresentation. Product lock: document plane. - Extract: Amazon Textract (object must live in AWS S3 Textract can read).
- Convert (office→PDF): self-host Gotenberg LibreOffice (
file-convertpathoffice-to-pdf). - Render (HTML/URL): Gotenberg Chromium or Cloudflare Browser Rendering → storage
ArtifactRef.
Release
semantic-release on main from conventional commits. No manual version bump.
| Commit | Version |
| --- | --- |
| feat: | minor |
| fix: / perf: / refactor: | patch |
| BREAKING CHANGE / type!: | major |
Details: docs/versioning.md.
License
MIT © harryy
