diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 5b37c85..cb1fd5c 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -33,8 +33,10 @@ export default defineConfig({ text: 'Introduction', items: [ { text: 'What is GemStack?', link: '/guide/' }, + { text: 'When to Use GemStack', link: '/guide/when-to-use' }, { text: 'Installation', link: '/guide/installation' }, { text: 'Your First Agent', link: '/guide/first-agent' }, + { text: 'Build a Multi-Agent App', link: '/guide/tutorial' }, ], }, { @@ -48,6 +50,12 @@ export default defineConfig({ { text: 'mcp', link: '/packages/mcp' }, ], }, + { + text: 'Project', + items: [ + { text: 'Contributing & Graduation', link: '/guide/contributing' }, + ], + }, ], '/packages/': [ diff --git a/docs/guide/contributing.md b/docs/guide/contributing.md new file mode 100644 index 0000000..c87a6f0 --- /dev/null +++ b/docs/guide/contributing.md @@ -0,0 +1,37 @@ +# Contributing & Graduation + +GemStack is shared, community-governed infrastructure built in the open with the [Vike](https://vike.dev) team. This page explains how the project grows and how to get involved. + +## The graduation model + +GemStack does not grow by bulk-moving a framework's package set in. Packages join one at a time, by **graduating**: a package earns a place under the `@gemstack/` scope when it proves framework-agnostic value, not when it is merely useful to one framework. + +In practice a package graduates when it is: + +- **Framework-agnostic.** It runs in any `fetch`-capable Node runtime and does not depend on a specific web framework, ORM, or UI library. Anything framework-specific stays in that framework's own binding. +- **Neutral about infrastructure.** Persistence, caching, and storage are expressed as contracts the caller implements, with in-memory defaults for getting started. The package does not bundle a database or a queue. +- **Well-tested and documented.** It ships a real test suite and a guide here. +- **Composable.** It works on its own and composes cleanly with the rest of the family through the shared primitives (one `toolDefinition()` shape, one `Agent` base, one provider config). + +The AI engine is the worked example: it was spun out of Rudder's `@rudderjs/ai`, decoupled from every framework binding, and re-versioned as [`@gemstack/ai-sdk`](/packages/ai-sdk/). The framework-specific pieces (an ORM-backed store set, a service provider, CLI scaffolders) stayed behind in the Rudder binding, which now re-exports the engine. + +## Bindings vs the engine + +A recurring shape in GemStack is **engine + binding**. The engine is the framework-agnostic core that lives here. A binding is a thin, framework-specific package that re-exports the engine and wires it into one framework's conventions (its container, config, ORM, and CLI). + +If you maintain a framework, the path is: depend on the GemStack engine, implement its neutral contracts against your framework's infrastructure, and ship that as your own binding. Your users keep importing from your package; the engine stays shared. + +## Ways to contribute + +- **File issues.** Bugs, missing capabilities, and rough edges in any package. Reproductions and a clear "expected vs actual" make these actionable fast. +- **Improve the docs.** These guides live in the repo under `docs/`. Fixes and clarifications are welcome; run `pnpm --filter @gemstack/docs docs:build` before opening a PR to catch dead links. +- **Propose a graduation.** If you have a framework-agnostic package that fits the bar above, open an issue describing what it does and why it belongs in GemStack rather than in a single framework. +- **Build a binding.** Wire the engine into your framework and let us link it from here. + +The repository, issues, and discussions live at [github.com/gemstack-land/gemstack](https://github.com/gemstack-land/gemstack). + +## Next + +- [What is GemStack?](/guide/) - the family and the design principles. +- [When to Use GemStack](/guide/when-to-use) - where it fits. +- [Packages overview](/packages/) - every package and how they compose. diff --git a/docs/guide/first-agent.md b/docs/guide/first-agent.md index a3ed8d8..39f9fb9 100644 --- a/docs/guide/first-agent.md +++ b/docs/guide/first-agent.md @@ -78,10 +78,13 @@ The agent decides when to call the tool, validates the arguments against `inputS | You want to… | Read | |---|---| +| Compose tools, skills, and a multi-agent supervisor into one app | [Build a Multi-Agent App](/guide/tutorial) | | Understand the agent loop, sub-agents, multi-step runs | [Agents](/packages/ai-sdk/agents) | | Go deeper on tools, scoped tools, client tools, approval gates | [Tools](/packages/ai-sdk/tools) | +| Add more model providers | [Providers](/packages/ai-sdk/providers) | | Stream tokens and tool progress to a UI | [Streaming](/packages/ai-sdk/streaming) | | Get typed objects back instead of text | [Structured Output](/packages/ai-sdk/structured-output) | | Persist conversations and give the agent memory | [Memory & Persistence](/packages/ai-sdk/memory) | | Retrieval-augmented generation over your documents | [Vector Stores & RAG](/packages/ai-sdk/rag) | | Test agents without hitting a real model | [Testing & Evals](/packages/ai-sdk/testing) | +| See the whole family and how the pieces fit | [Packages overview](/packages/) | diff --git a/docs/guide/index.md b/docs/guide/index.md index 3f516f1..8476aa3 100644 --- a/docs/guide/index.md +++ b/docs/guide/index.md @@ -33,7 +33,7 @@ mcp standalone MCP server framework agent-agnostic, not - **Framework-agnostic core.** Every package runs in any `fetch`-capable JS runtime - Node, the browser, Electron, React Native. The agent runtime has zero static `node:*` imports in its main entry, and its only required runtime dependency is `zod`. - **Neutral contracts, not bundled infrastructure.** Persistence (conversation history, user memory, budgets, suspended runs, generated-file storage) is defined as interfaces you implement against your own database, cache, or object store. In-memory defaults ship for getting started. -- **One way to do a thing.** A single `tool()` shape, a single `Agent` base, a single provider config object - shared across the whole family. +- **One way to do a thing.** A single `toolDefinition()` shape, a single `Agent` base, a single provider config object - shared across the whole family. - **Graduated, not dumped.** GemStack grows by promoting packages that earn framework-agnostic standing, with the API settling toward `1.0` in the open. ## Where these came from diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 9848355..a8faddd 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -6,7 +6,7 @@ The agent runtime lives in [`@gemstack/ai-sdk`](/packages/ai-sdk/). Install it p pnpm add @gemstack/ai-sdk pnpm add @anthropic-ai/sdk # Anthropic (Claude) -pnpm add openai # OpenAI (also OpenRouter / Mistral / DeepSeek / Groq / xAI / Ollama) +pnpm add openai # OpenAI (also Azure / OpenRouter / Mistral / DeepSeek / Groq / xAI / Ollama) pnpm add @google/genai # Google (Gemini) pnpm add cohere-ai # Cohere (reranking + embeddings) pnpm add @aws-sdk/client-bedrock-runtime # AWS Bedrock @@ -24,7 +24,7 @@ import { AiRegistry, AnthropicProvider, OpenAIProvider, OllamaProvider } from '@ AiRegistry.register(new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY! })) AiRegistry.register(new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! })) -AiRegistry.register(new OllamaProvider({ baseUrl: 'http://localhost:11434' })) +AiRegistry.register(new OllamaProvider({ baseUrl: 'http://localhost:11434/v1' })) AiRegistry.setDefault('anthropic/claude-sonnet-4-6') ``` diff --git a/docs/guide/tutorial.md b/docs/guide/tutorial.md new file mode 100644 index 0000000..ec0f2e2 --- /dev/null +++ b/docs/guide/tutorial.md @@ -0,0 +1,181 @@ +# Build a Multi-Agent App + +[Your First Agent](/guide/first-agent) ended with a single agent answering one prompt. Real work rarely fits one prompt: a research question fans out into several lines of inquiry that each want their own tools, a shared house style, and someone to plan the work and stitch the findings back together. + +This tutorial builds that app, a small research assistant, by composing three GemStack packages: + +- [`@gemstack/ai-sdk`](/packages/ai-sdk/agents) for tools and the agent loop, +- [`@gemstack/ai-skills`](/packages/ai-skills) to load a portable `SKILL.md` skill onto a worker, +- [`@gemstack/ai-autopilot`](/packages/ai-autopilot) to plan a task into subtasks, dispatch them to workers, and synthesize the result. + +By the end you will have a `Supervisor` that breaks a research question into subtasks, runs each on a skill-equipped worker agent, and combines the answers. We finish with a short note on exposing the whole thing over MCP. + +If you have not registered a provider yet, do that first (see [Installation](/guide/installation)). + +## Register a provider + +Every example assumes a default provider registered once at startup: + +```ts +import { AiRegistry, AnthropicProvider } from '@gemstack/ai-sdk' + +AiRegistry.register(new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY! })) +AiRegistry.setDefault('anthropic/claude-sonnet-4-6') +``` + +With a default model set, agents do not need to declare one. + +## Step 1: two tools the worker can call + +A research worker needs to reach the web. We give it two tools with `toolDefinition(...)`: one to search, one to fetch a page. Each declares its input with Zod and attaches a `.server()` handler that the agent calls (see [Tools](/packages/ai-sdk/tools)). Swap the stubbed bodies for a real search API and HTTP client. + +```ts +import { toolDefinition } from '@gemstack/ai-sdk' +import { z } from 'zod' + +export const searchWeb = toolDefinition({ + name: 'search_web', + description: 'Search the web and return the top matching result snippets', + inputSchema: z.object({ + query: z.string().describe('The search query'), + limit: z.number().int().min(1).max(10).default(5), + }), +}).server(async ({ query, limit }) => { + // Call your real search provider here. + return await search(query, limit) // -> [{ title, url, snippet }, ...] +}) + +export const fetchPage = toolDefinition({ + name: 'fetch_page', + description: 'Fetch a URL and return its readable text content', + inputSchema: z.object({ url: z.string().url() }), +}).server(async ({ url }) => { + const res = await fetch(url) + return await res.text() +}) +``` + +The agent decides when to call each tool, validates the arguments against `inputSchema` before your handler runs, and feeds the result back to the model on the next step. + +## Step 2: a skill for house style + +Every worker should cite its sources the same way, and that convention should travel with the agent rather than being copy-pasted into each system prompt. That is exactly what a skill is: a portable folder of instructions (and optionally tools and resources) you compose onto an agent on demand. + +Create `skills/citations/SKILL.md`. The YAML frontmatter is the manifest; the markdown body becomes extra system-prompt text: + +```markdown +--- +name: citations +description: Cite every claim with a source URL and never invent sources +trigger: answering a research question that draws on web sources +--- + +# Citations + +When you state a fact drawn from a source, cite it inline with the page URL in +parentheses, like (https://example.com/article). Only cite pages you actually +fetched with `fetch_page`. If you could not verify a claim, say so plainly +instead of guessing. End your answer with a "Sources" list of the URLs you used. +``` + +This skill is instructions-only, so there is no build step to worry about. (A skill that ships tools co-locates them in a `tools.ts` that the loader imports from its compiled output; see the [compiled-output caveat](/packages/ai-skills) when you go that far.) + +Load it once at module init, since loading is async and the agent hooks are synchronous: + +```ts +import { loadSkill } from '@gemstack/ai-skills' + +const citations = await loadSkill('./skills/citations') +``` + +## Step 3: the worker agent + +The worker is a `SkillfulAgent`. You declare your own identity in `baseInstructions()` and your own tools in `baseTools()`; the skills listed in `skills()` are merged in, with your own declarations winning on any name collision. Because research is multi-step (search, fetch, read, repeat), we give it a stop condition with `stepCountIs(...)`. + +```ts +import { SkillfulAgent } from '@gemstack/ai-skills' +import { stepCountIs } from '@gemstack/ai-sdk' + +class ResearchWorker extends SkillfulAgent { + baseInstructions() { + return 'You research a focused question using the web tools, then answer concisely.' + } + skills() { return [citations] } // adds the citation house style + baseTools() { return [searchWeb, fetchPage] } + stopWhen() { return stepCountIs(6) } // up to 6 tool-calling rounds +} +``` + +Override the `base*` hooks, not `instructions()` / `tools()`: those are sealed on `SkillfulAgent` and do the merge for you. Overriding them directly would drop the skill composition. + +You can run this worker on its own to sanity-check it before wiring up the supervisor: + +```ts +const probe = await new ResearchWorker().prompt( + 'What problem did the original Transformer paper set out to solve?', +) +console.log(probe.text) // answer, with a Sources list, thanks to the skill +``` + +## Step 4: plan, dispatch, synthesize + +Now the orchestration. A `Supervisor` takes three stages: a `plan` that decomposes the task into subtasks, the `workers` that run them, and a `synthesize` that combines the results. The planner and synthesizer are themselves ai-sdk agents, adapted with `agentPlanner(...)` and `agentSynthesizer(...)`. + +```ts +import { Supervisor, agentPlanner, agentSynthesizer } from '@gemstack/ai-autopilot' +import { agent } from '@gemstack/ai-sdk' + +const planner = agent( + 'You break a research question into a few independent sub-questions that can be researched in parallel.', +) + +const editor = agent( + 'You combine several researched answers into one coherent, well-cited brief. Preserve every source URL.', +) + +const supervisor = new Supervisor({ + plan: agentPlanner(planner), // LLM decomposition into subtasks + workers: new ResearchWorker(), // every subtask runs on this worker + synthesize: agentSynthesizer(editor), // LLM synthesis of the results + concurrency: 3, // up to 3 workers in flight at once + maxSubtasks: 5, // hard cap; a longer plan is trimmed + budget: { maxTotalTokens: 200_000 }, // stop dispatching past this spend + onEvent: (e) => console.log(e.type), // 'plan', 'dispatch-start', ... +}) +``` + +`workers` here is a single agent, so each subtask runs on a fresh `ResearchWorker` prompt. When you want different subtasks handled by different specialists, pass a `Record` instead and let the planner set each `subtask.worker` to route between them. + +## Step 5: run it + +```ts +const run = await supervisor.run( + 'How did the Transformer architecture change machine translation, and what came after it?', +) + +console.log(run.text) // the synthesized, cited brief +console.log(run.plan) // the subtasks that were executed +console.log(run.results) // one result per subtask: { text, ok, error?, usage } +console.log(run.usage) // aggregate token usage across dispatched subtasks +console.log(run.stoppedEarly) // true if a guardrail trimmed or halted the work +``` + +`run()` resolves to a `SupervisorRun`. A few properties worth leaning on: + +- **`run.results`** is one entry per dispatched subtask, in plan order. A worker that throws becomes an `ok: false` result; its siblings still run, so one failed line of inquiry does not sink the whole report. +- **`run.usage`** aggregates token usage across the dispatched workers. (Planning and synthesis spend are not counted: those contracts return data, not usage.) +- **`run.stoppedEarly`** tells you a guardrail (the `maxSubtasks` cap or the token `budget`) cut the work short, so you can flag a partial answer. + +That is the whole app: tools give a worker hands, a skill gives it a house style, and the supervisor plans the work, fans it out, and reassembles it. + +## Optional: expose it over MCP + +Once the supervisor works, you can publish it as a Model Context Protocol server so other agents and MCP-aware clients can call it as a tool. Wrap the run in a server tool and serve it with [`@gemstack/ai-mcp`](/packages/ai-mcp); the worker's own tools stay internal, and callers see one `research` capability. See [/packages/ai-mcp](/packages/ai-mcp) for the server surface and transport options. + +## See also + +- [Tools](/packages/ai-sdk/tools) - `toolDefinition(...).server(...)`, streaming, approval, and scoped tools. +- [Running agents](/packages/ai-sdk/agents) - the agent loop, stop conditions, sub-agents, and suspend/resume. +- [`@gemstack/ai-skills`](/packages/ai-skills) - authoring, loading, and composing `SKILL.md` skills. +- [`@gemstack/ai-autopilot`](/packages/ai-autopilot) - the `Supervisor` topology and its guardrails. +- [`@gemstack/ai-mcp`](/packages/ai-mcp) - expose agents and tools over the Model Context Protocol. diff --git a/docs/guide/when-to-use.md b/docs/guide/when-to-use.md new file mode 100644 index 0000000..ec662a6 --- /dev/null +++ b/docs/guide/when-to-use.md @@ -0,0 +1,36 @@ +# When to Use GemStack + +GemStack is a set of standalone, framework-agnostic packages for building AI applications in Node. This page is about fit: what GemStack is good at, where it deliberately stops, and how it differs from the tools you might reach for instead. + +## Reach for GemStack when + +- **You want a provider-agnostic agent runtime, not a provider SDK.** Define an agent once and swap Anthropic, OpenAI, Google, Ollama, and others by changing one model string. The tool loop, streaming, structured output, middleware, and a test fake come with it. +- **You are building on the server, in any stack.** GemStack is UI-agnostic and framework-agnostic. It runs in any `fetch`-capable runtime and ships no React/Vue/Svelte coupling, so it drops into an existing Express, Hono, Fastify, Nitro, or Rudder app without taking it over. +- **You need production concerns as first-class APIs.** Conversation persistence, cross-conversation user memory, token/cost budgets, prompt caching, sub-agent streaming with mid-run suspend, and an eval harness are part of the runtime, behind neutral contracts you implement against your own infrastructure. +- **You care about testing.** A full fake (`AiFake`) lets you assert on prompts, tool calls, and every modality without hitting a real model or spending a token. +- **You are working with MCP from either side.** Bridge an agent to remote MCP servers, expose an agent as a server, or author a standalone MCP server, all with first-party packages. + +## Look elsewhere when + +- **You want a batteries-included frontend chat UI.** GemStack is a server runtime. It speaks the Vercel AI protocol (`toVercelResponse()`), so a frontend chat library can consume its stream, but it ships no `useChat`-style hooks of its own. +- **You only ever call one provider and want its native SDK.** If you are committed to a single vendor and want every bleeding-edge feature the day it ships, that vendor's own SDK will always be a release ahead of any abstraction. +- **You want a hosted platform.** GemStack is libraries you run, not a managed service with a dashboard and billing. + +## How it differs from the usual suspects + +| | GemStack | A provider SDK (e.g. one vendor's client) | A heavyweight agent framework | +|---|---|---|---| +| **Scope** | Agent runtime + skills + orchestration + MCP, as separate packages | One provider's API surface | Large, opinionated, many abstractions | +| **Providers** | Many, swap by model string | One | Many, via adapters | +| **Coupling** | Framework-agnostic, server-side, `zod` is the only hard dependency | None, but vendor-locked | Often heavy dependency graph | +| **Persistence** | Neutral contracts you implement (BYO database / cache / store) | None | Often bundled and opinionated | +| **Adopt incrementally** | Yes, take one package | N/A | Usually all-or-nothing | + +The point is not that GemStack does the most. It is that each package does one thing, stays framework-agnostic, and composes with the others, so you can adopt a single piece without buying into a platform. + +## Next + +- [Installation](/guide/installation) - get the runtime and a provider running. +- [Your First Agent](/guide/first-agent) - the smallest end-to-end example. +- [Build a Multi-Agent App](/guide/tutorial) - compose tools, skills, and a supervisor. +- [Packages overview](/packages/) - the whole family and how the pieces fit. diff --git a/docs/packages/ai-autopilot.md b/docs/packages/ai-autopilot.md index dac1677..e3b696d 100644 --- a/docs/packages/ai-autopilot.md +++ b/docs/packages/ai-autopilot.md @@ -2,7 +2,7 @@ Orchestration for [`@gemstack/ai-sdk`](/packages/ai-sdk/) agents: the "director" layer that runs **many** agent runs under a control policy. -`ai-sdk` owns the single-agent loop and the handoff / subagent primitives. `ai-autopilot` owns orchestrating multiple runs: which agents run, in what order, how their results combine, and when to stop. If a feature is just calling an `ai-sdk` primitive, it belongs in `ai-sdk`; autopilot earns its keep only as the topology and control-policy layer. +`ai-sdk` owns the single-agent loop and the handoff / subagent primitives. `ai-autopilot` owns orchestrating multiple runs: which agents run, in what order, how their results combine, and when to stop. Anything that is just a call to an `ai-sdk` primitive belongs in `ai-sdk`; this package adds value as the topology and control-policy layer on top. ```bash pnpm add @gemstack/ai-autopilot @gemstack/ai-sdk @@ -10,7 +10,7 @@ pnpm add @gemstack/ai-autopilot @gemstack/ai-sdk ## Supervisor (plan, dispatch, synthesize) -The first slice is the supervisor/worker topology, the smallest thing clearly more than the primitives: +The supervisor/worker topology is the first orchestration shape this package ships: 1. **Plan** - a planner decomposes the task into subtasks. 2. **Dispatch** - each subtask runs on a worker agent, with bounded concurrency, an optional token budget, and per-subtask error isolation. @@ -77,8 +77,9 @@ Progress is reported through `onEvent` as typed `SupervisorEvent`s (`plan`, `pla ## Scope (what's deferred) -The seed dispatches **autonomous** workers via `agent.prompt()`. A worker that pauses for a client-tool or approval round-trip is reported as a failed subtask. Durable pause/resume across a supervised run (building on `ai-sdk`'s `SubAgentRunStore` and resume primitives) is a deferred adapter, as are other topologies (pipelines, debate) and queue-backed long-running execution. Those land on demand, behind optional seams, not in the core. +The supervisor dispatches **autonomous** workers via `agent.prompt()`. A worker that pauses for a client-tool or approval round-trip is reported as a failed subtask. Durable pause/resume across a supervised run (building on `ai-sdk`'s `SubAgentRunStore` and resume primitives) is a deferred adapter, as are other topologies (pipelines, debate) and queue-backed long-running execution. Those land on demand, behind optional seams, not in the core. -## License +## See also -MIT +- [Agents](/packages/ai-sdk/agents) - the single-agent loop the supervisor dispatches to. +- [Build a Multi-Agent App](/guide/tutorial) - the Supervisor wired up end to end. diff --git a/docs/packages/ai-mcp.md b/docs/packages/ai-mcp.md index ec104cd..41f5e7e 100644 --- a/docs/packages/ai-mcp.md +++ b/docs/packages/ai-mcp.md @@ -98,6 +98,7 @@ Via `opts.expose`: Other options: `name` / `version` (server identity; `name` defaults to `${AgentClass.name}Server`), `instructions` (advertised server instructions, defaulting to the agent's `instructions()`), and `agentToolName` (the prompt-tool's name in `'agent'` / `'both'` mode, defaulting to the agent class name). -## License +## See also -MIT +- [mcp](/packages/mcp) - author a standalone MCP server (the other MCP axis). +- [Agents](/packages/ai-sdk/agents) - the agents this package bridges to MCP. diff --git a/docs/packages/ai-sdk/agents.md b/docs/packages/ai-sdk/agents.md index 3fbaefb..a80a54c 100644 --- a/docs/packages/ai-sdk/agents.md +++ b/docs/packages/ai-sdk/agents.md @@ -348,3 +348,9 @@ await agent({ instructions: 'You are helpful.', middleware: [logging] }).prompt( - **Streaming `response` not resolving.** `await response` only resolves after the `stream` iterator has been fully consumed. Always iterate the stream first, even if you only care about the final result. - **Bare model names.** `model: 'claude-sonnet-4-6'` throws; it must be `provider/model`. - **Suspend needs a run store and streaming.** `suspendable` requires `streaming` on `asTool`, and the cache-backed stores require a `CacheAdapter` you supply. + +## See also + +- [Tools](/packages/ai-sdk/tools) - define what the agent can call. +- [Streaming](/packages/ai-sdk/streaming) - stream tokens and sub-agent progress to a UI. +- [Build a Multi-Agent App](/guide/tutorial) - drive many agents under a supervisor. diff --git a/docs/packages/ai-sdk/memory.md b/docs/packages/ai-sdk/memory.md index 52b5db3..54d5f53 100644 --- a/docs/packages/ai-sdk/memory.md +++ b/docs/packages/ai-sdk/memory.md @@ -269,3 +269,8 @@ The two middleware are also exported standalone - `withMemoryInject(spec, opts?) - **`remembers()` is a no-op without a store.** Auto-inject and auto-extract resolve the registered `UserMemory` - call `setUserMemory(...)` (or wire your own implementation) first, or nothing is recalled or written. - **In-memory defaults lose everything on restart.** `MemoryConversationStore` and `MemoryUserMemory` are in-process. Anything you need to survive a restart or share across web processes and workers needs a real backend behind the contract. - **External vector store cascade.** If a custom `UserMemory` writes vectors to an external store (Pinecone, Weaviate, pgvector), `forget()` / `forgetAll()` only delete the rows you delete - you must implement the cascade to the second store yourself. + +## See also + +- [Agents](/packages/ai-sdk/agents) - where conversation threads and memory plug in. +- [Vector Stores & RAG](/packages/ai-sdk/rag) - embeddings and retrieval for semantic recall. diff --git a/docs/packages/ai-sdk/providers.md b/docs/packages/ai-sdk/providers.md index b6bbd47..5989f59 100644 --- a/docs/packages/ai-sdk/providers.md +++ b/docs/packages/ai-sdk/providers.md @@ -255,3 +255,9 @@ class AcmeGatewayAdapter extends HttpGatewayAdapter { ``` The subpath also exports `GatewayAdapterConfig`, `GatewayRequestContext`, and `parseSseStream` (with its `SseEvent` type) for decoding a custom event stream. Wrap your adapter in a small `ProviderFactory` and register it like any other provider. + +## See also + +- [Installation](/guide/installation) - register providers and set the default model. +- [Vector Stores & RAG](/packages/ai-sdk/rag) - embeddings and reranking capabilities by provider. +- [Testing & Evals](/packages/ai-sdk/testing) - run agents against a fake instead of a real provider. diff --git a/docs/packages/ai-sdk/rag.md b/docs/packages/ai-sdk/rag.md index 761b403..b8f0666 100644 --- a/docs/packages/ai-sdk/rag.md +++ b/docs/packages/ai-sdk/rag.md @@ -179,3 +179,8 @@ await files.delete(uploaded.id) ## Provider support at a glance Hosted file search, embeddings, and reranking are each provider-specific capabilities. Rather than duplicate the matrix here, see [/packages/ai-sdk/providers](/packages/ai-sdk/providers) for which providers implement embeddings, reranking, and hosted vector stores. The portable pattern is: keep the agent's `tools()` and prompt identical, and switch capability by changing the registered provider and model string. + +## See also + +- [Providers](/packages/ai-sdk/providers) - which providers implement embeddings, reranking, and hosted stores. +- [Memory & Persistence](/packages/ai-sdk/memory) - semantic user memory built on embeddings. diff --git a/docs/packages/ai-sdk/streaming.md b/docs/packages/ai-sdk/streaming.md index 9240036..c7cab78 100644 --- a/docs/packages/ai-sdk/streaming.md +++ b/docs/packages/ai-sdk/streaming.md @@ -155,5 +155,5 @@ The same `signal` option works on `stream(...)`: aborting rejects the `response` ## See also - [Agents](/packages/ai-sdk/agents) for `prompt()`, tools, and multi-step loops. -- [Structured Output & Attachments](/packages/ai-sdk/structured-output) for typed results and multi-modal input. +- [Structured Output](/packages/ai-sdk/structured-output) for typed results and multi-modal input. - [Testing](/packages/ai-sdk/testing) for driving streams against the fake. diff --git a/docs/packages/ai-sdk/tools.md b/docs/packages/ai-sdk/tools.md index 0a6af6e..094a2b1 100644 --- a/docs/packages/ai-sdk/tools.md +++ b/docs/packages/ai-sdk/tools.md @@ -127,3 +127,9 @@ The generated schema is a single object: the discriminator (`sub_tool: 'web' | ' - **Tool handlers throwing.** The agent gets the error message back as the tool result. Catch known errors inside the handler and return a structured failure shape instead of throwing. - **Non-idempotent parallel tools.** Handlers in one step run concurrently by default. Set `parallelTools: false` when they share mutable state. - **Client tools need a resume path.** A tool with no `.server()` pauses the loop; the run only completes once the caller returns its result. See [Running agents](/packages/ai-sdk/agents). + +## See also + +- [Agents](/packages/ai-sdk/agents) - the loop that decides when to call your tools. +- [Structured Output](/packages/ai-sdk/structured-output) - typed results and attachments. +- [ai-skills](/packages/ai-skills) - ship tools as composable capability bundles. diff --git a/docs/packages/ai-skills.md b/docs/packages/ai-skills.md index 8f0b7e4..91d1e17 100644 --- a/docs/packages/ai-skills.md +++ b/docs/packages/ai-skills.md @@ -13,7 +13,7 @@ A skill is a directory with one required file and two optional pieces: ``` my-skill/ SKILL.md # YAML frontmatter (name, description, trigger, ...) + markdown instructions - tools.ts # optional: exports @gemstack/ai-sdk tool() objects (loaded compiled, see caveat) + tools.ts # optional: exports @gemstack/ai-sdk toolDefinition() objects (loaded compiled, see caveat) resources/ # optional: reference files ``` @@ -21,7 +21,7 @@ The skill's instructions become extra system-prompt text, its tools become extra ## The skill manifest -`SKILL.md` is markdown with a YAML frontmatter block, the same convention `@gemstack/ai-sdk` ships in `boost/skills`: +`SKILL.md` is markdown with a YAML frontmatter block, the same shape as an Anthropic Agent Skill: ```markdown --- @@ -54,7 +54,7 @@ The frontmatter is validated into a `SkillManifest`: ## Authoring `tools.ts` -A co-located `tools.ts` exports the skill's tools as plain `@gemstack/ai-sdk` `tool()` objects, so there is one tool API across the framework (see [tools](/packages/ai-sdk/tools)): +A co-located `tools.ts` exports the skill's tools as plain `@gemstack/ai-sdk` `toolDefinition()` objects, so there is one tool API across the family (see [Tools](/packages/ai-sdk/tools)): ```ts import { toolDefinition } from '@gemstack/ai-sdk' @@ -129,7 +129,7 @@ import { loadSkill } from '@gemstack/ai-skills' const refunds = await loadSkill('./skills/refunds') refunds.instructions // markdown body (string) -refunds.tools // ai-sdk tool() objects +refunds.tools // ai-sdk toolDefinition() objects refunds.resources // [{ name, path }, ...] ``` @@ -161,6 +161,8 @@ A skill is code you install or author, like a Vite or ESLint plugin: **loading i If you need real isolation, run the app under OS or container isolation, and only load skills from sources you trust. -## License +## See also -MIT +- [Tools](/packages/ai-sdk/tools) - the `toolDefinition()` API a skill's `tools.ts` exports. +- [Agents](/packages/ai-sdk/agents) - the `Agent` base that `SkillfulAgent` extends. +- [Build a Multi-Agent App](/guide/tutorial) - skills composed with a supervisor, end to end. diff --git a/docs/packages/mcp.md b/docs/packages/mcp.md index 0539a28..4d2f632 100644 --- a/docs/packages/mcp.md +++ b/docs/packages/mcp.md @@ -6,7 +6,7 @@ Once you author an MCP server, an external AI agent (Claude Code, Cursor, Windsu It is standalone and dependency-light: its only runtime dependencies are `@modelcontextprotocol/sdk`, `zod`, and `reflect-metadata`. (It graduated from the mature `@rudderjs/mcp` server framework, re-versioned under the GemStack umbrella.) -## Which MCP package do I want? +## Which MCP package do I use? There are two MCP packages in GemStack, on opposite axes; don't conflate them: @@ -327,6 +327,7 @@ const unsubscribe = mcpObservers.subscribe((event) => { For custom inspectors or tooling built on the core, the main entry also exports two pure helpers: `zodToJsonSchema(schema)` converts a Zod object to the JSON Schema MCP advertises, and `matchUriTemplate(template, uri)` matches a URI against a `resource://{template}` pattern. -## License +## See also -MIT +- [ai-mcp](/packages/ai-mcp) - bridge an agent to MCP (consume a server's tools, or expose an agent). +- [Packages overview](/packages/) - the whole GemStack family.