Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: build

on:
pull_request:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run types:check
- run: npm run check
- run: npm run build
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ yarn-error.log*
# others
.env*.local
.vercel
next-env.d.ts
next-env.d.ts
# local issue tracker (wayfinder map, never published)
.scratch/
84 changes: 55 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,71 @@
# docs
# Solrouter docs

This is a Next.js application generated with
[Create Fumadocs](https://github.com/fuma-nama/fumadocs).
Source for [docs.solrouter.com](https://docs.solrouter.com). Built with [Fumadocs](https://fumadocs.dev) on Next.js.

Run development server:
This repository is the source of truth for the public docs. Changes land through pull requests into `main`, and `main` deploys automatically. `scripts/publish-mirror.sh` is retired: it force-pushes a copy from the product monorepo and would erase merged pull requests.

## Run it

```bash
npm run dev
# or
pnpm dev
# or
yarn dev
npm ci
npm run dev # http://localhost:3000
npm run build # production build
npm run types:check # MDX collection, route types, tsc
npm run check # prose, status, and diagram-fallback checks
```

## Layout

```
content/docs/ hand-written pages (MDX) and meta.json sidebars
content/docs/api-reference/agent-privacy/
generated from openapi/agent-privacy.json, do not edit by hand
openapi/agent-privacy.json snapshot of https://api.solrouter.com/agents/v1/openapi.json
scripts/generate-openapi.mjs regenerates the Agent Privacy API pages from the snapshot
scripts/check-docs.mjs the checks behind `npm run check`
src/components/diagrams/ static, theme-aware diagrams (React + Tailwind)
src/components/verify/ client widgets that call the live API
src/lib/status.ts the status sentence shown under every page title
```

Open http://localhost:3000 with your browser to see the result.
The docs have two tiers. Start here, Products, and Account are written for readers with no technical background. Under the hood and Reference are written for engineers and auditors and cite the code that backs each claim.

## Status policy

Every hand-written page declares three frontmatter fields:

```yaml
status: live # live | soon | archived | mixed
checked: "2026-08-26"
statusNote: "Optional one-sentence reason for soon, archived, or mixed."
```

## Explore
- Live: the code path exists and the surface answered on api.solrouter.com, npm, or solrouter.com on the `checked` date.
- Soon: the code exists, but the surface is not published, not deployed, or not confirmed end to end.
- Archived: removed or disabled. The page stays to explain the change.
- Mixed: the page holds a table with a Status column. Read the rows.

In the project, you can see:
A feature nobody has confirmed ships as Soon, never as Live. The `checked` date changes only when someone re-checks the page against code or a live endpoint.

- `lib/source.ts`: Code for content source adapter, [`loader()`](https://fumadocs.dev/docs/headless/source-api) provides the interface to access your content.
- `lib/layout.shared.tsx`: Shared options for layouts, optional but preferred to keep.
## Truth rule

| Route | Description |
| ------------------------- | ------------------------------------------------------ |
| `app/(home)` | The route group for your landing page and other pages. |
| `app/docs` | The documentation layout and pages. |
| `app/api/search/route.ts` | The Route Handler for search. |
Every product claim in a pull request cites a file path in the product code or a live response in the PR body. No number, name, date, or benchmark goes in without a source.

### Fumadocs MDX
## Diagrams

A `source.config.ts` config file has been included, you can customise different options like frontmatter schema.
Add a diagram as a React component under `src/components/diagrams/`. Give the root element `role="img"` and an `aria-label` that describes the whole picture in one sentence. In the MDX, follow the component with a short Markdown list titled **In words**. That list is what screen readers, `llms.txt`, and the `.md` routes see, because component markup carries no meaning there. `npm run check` fails when the list is missing.

Read the [Introduction](https://fumadocs.dev/docs/mdx) for further details.
## Writing rules

## Learn More
- Short sentences, about 20 words or fewer. One idea per sentence. Active voice.
- No em dashes or en dashes. Use a period, a comma, a colon, or parentheses.
- No filler vocabulary. `npm run check` lists the banned words.
- Define a term in plain words before you use its acronym, or link to the glossary.

To learn more about Next.js and Fumadocs, take a look at the following
resources:
## Pull request checklist

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js
features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
- [Fumadocs](https://fumadocs.dev) - learn about Fumadocs
1. `npm run types:check`, `npm run check`, and `npm run build` pass.
2. Every changed factual sentence cites a file path or a live response in the PR body.
3. Touched pages have no horizontal scroll at 375 px. Wrap wide tables in a scroll container.
4. Moved or renamed pages have a redirect row in `next.config.mjs`.
5. No `Co-Authored-By` trailer in commits.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Provision a managed Umbra wallet (Mode A)
description: >-
Create a Solrouter-custodied Umbra wallet. The keypair is generated
server-side and envelope-encrypted (AES-256-GCM) — the agent never holds
server-side and envelope-encrypted (AES-256-GCM), so the agent never holds
private keys. Fund the returned `umbraAddress`, then run swaps and
encrypted-balance operations against the wallet id.
full: true
Expand All @@ -15,7 +15,7 @@ _openapi:
contents:
- content: >-
Create a Solrouter-custodied Umbra wallet. The keypair is generated
server-side and envelope-encrypted (AES-256-GCM) — the agent never
server-side and envelope-encrypted (AES-256-GCM), so the agent never
holds private keys. Fund the returned `umbraAddress`, then run swaps
and encrypted-balance operations against the wallet id.
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Shield + unlink — mixer round-trip to a fresh address
title: 'Shield + unlink: mixer round-trip to a fresh address'
description: >-
Four txs, ~60s. Public balance enters the Umbra mixer, a claim breaks the
on-chain link, then withdraw + transfer delivers to a FRESH destination.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Pool depth for a denomination bucket
description: >-
Inspect the anonymity set for a standard denomination bucket before swapping —
Inspect the anonymity set for a standard denomination bucket before swapping:
how many recent deposits share that bucket. A deeper pool means a larger crowd
to hide in.
full: true
Expand All @@ -14,7 +14,7 @@ _openapi:
contents:
- content: >-
Inspect the anonymity set for a standard denomination bucket before
swapping — how many recent deposits share that bucket. A deeper pool
swapping: how many recent deposits share that bucket. A deeper pool
means a larger crowd to hide in.
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Quote a private swap
description: >-
Price a private swap before executing it. Returns the expected output after
Solrouter's spread plus anonymity-set guidance — whether the amount snaps to a
Solrouter's spread plus anonymity-set guidance: whether the amount snaps to a
standard denomination bucket (strong privacy) or is an off-bucket amount with
a unique on-chain fingerprint.
full: true
Expand All @@ -15,7 +15,7 @@ _openapi:
contents:
- content: >-
Price a private swap before executing it. Returns the expected output
after Solrouter's spread plus anonymity-set guidance — whether the
after Solrouter's spread plus anonymity-set guidance: whether the
amount snaps to a standard denomination bucket (strong privacy) or is
an off-bucket amount with a unique on-chain fingerprint.
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: Begin a one-shot ephemeral-wallet private swap (Mode B)
description: >-
Start a private swap that runs through a throwaway ephemeral wallet — no
Start a private swap that runs through a throwaway ephemeral wallet, with no
managed custody. Solrouter returns an unsigned `fundingTx`; the agent signs
and broadcasts it, then calls `POST /swaps/oneshot/{id}/execute` to kick off
the swap orchestrator.
Expand All @@ -14,9 +14,9 @@ _openapi:
headings: []
contents:
- content: >-
Start a private swap that runs through a throwaway ephemeral wallet —
no managed custody. Solrouter returns an unsigned `fundingTx`; the
agent signs and broadcasts it, then calls `POST
Start a private swap that runs through a throwaway ephemeral wallet,
with no managed custody. Solrouter returns an unsigned `fundingTx`;
the agent signs and broadcasts it, then calls `POST
/swaps/oneshot/{id}/execute` to kick off the swap orchestrator.
---

Expand Down
112 changes: 89 additions & 23 deletions content/docs/api-reference/agent.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
---
title: "POST /agent"
icon: Webhook
description: "The /agent endpoint runs your prompt through SERV guided reasoning with access to web search, on-chain data, DEX quotes, and Solana tools."
description: "The /agent endpoint runs your prompt through a tool loop with web search, on-chain data, DEX quotes, and Solana tools. Optional guided reasoning (BRAID) and encrypted mode."
status: live
checked: "2026-08-26"
---

import { Callout } from 'fumadocs-ui/components/callout';

The `/agent` endpoint runs your prompt through Solrouter's full SERV-guided agent pipeline. Unlike a direct chat completion, the agent has access to a suite of built-in tools — web search, on-chain data, DEX quotes, token prices, and more — and uses SERV (Structured Execution via Reasoning Virtualization) to walk a deterministic reasoning graph rather than letting the model make freeform structural decisions. The result is faster, cheaper, and more reliable than a standard agent loop, while still producing synthesis-quality answers for complex multi-step queries.
The `/agent` endpoint runs your prompt through Solrouter's agent pipeline. Unlike a direct chat completion, the agent can call built-in tools: web search, on-chain data, DEX quotes, token prices, and more.

The request body selects one of three paths.

- Default: a standard tool loop with up to 8 model calls (`MAX_ITERATIONS = 8`).
- `reasoning: 'braid'`: guided reasoning (BRAID). A fixed Guided Reasoning Diagram (GRD) collects data, then one synthesis call writes the reply. Older material calls this SERV.
- `encryptedPrompt`: encrypted mode. The tool loop runs inside the CVM (a confidential virtual machine, which is a TEE, trusted execution environment) with a 5-tool allowlist.

## Endpoint

Expand All @@ -18,11 +26,15 @@ POST https://api.solrouter.com/agent

| Field | Type | Description |
| --- | --- | --- |
| `prompt` | string (required) | The question or task you want the agent to work on. You can ask for research, comparisons, on-chain analysis, swap quotes, or any other task covered by the built-in tools. |
| `model` | string | The model used for synthesis at the end of the reasoning pipeline. All models run on Solrouter's self-hosted Nosana GPU network — no third-party APIs. `gpt-oss:20b` (default) — Apache-2.0 open weights, 20B parameters. `qwen3:8b` — open weights, 8B parameters. |
| `useTools` | boolean | Enable or disable tool calls during agent execution. When `true`, the agent can call any of its built-in tools to gather data before synthesising a final answer. Set to `false` to run the prompt through guided reasoning without external data retrieval. Defaults to `true`. |
| `prompt` | string (required) | The question or task. Research, comparisons, on-chain analysis, swap quotes, or any task the built-in tools cover. |
| `model` | string | The model that runs the loop and writes the reply. Models run on Nosana GPU nodes. `gpt-oss:20b` (default) is Live. `qwen3.8:27b` is Live. `gemma4:31b` is Soon. `qwen3:8b` is retired (Archived). A model with no configured Nosana endpoint returns 501 `nosana_not_configured`. |
| `useTools` | boolean | Defaults to `true`. When `true`, the model can call any built-in tool before it writes the reply. Set `false` to run one plain completion with no tools. This field does not select guided reasoning. |
| `chatId` | string | Optional conversation id. When present, the backend stores the turn in that chat's history and sends prior turns as context. When absent, the call is stateless. |
| `reasoning` | string | Set `'braid'` to run guided reasoning instead of the tool loop. |
| `braidOptions` | object | BRAID only. `includeTrace: true` adds `braidTrace` to the response. `forceGrdId` picks a GRD by id instead of intent detection. |
| `encryptedPrompt` | string (JSON) | Encrypted mode. The prompt is encrypted client-side to the enclave public key and packaged as a JSON string with `ciphertext`, `nonce`, `publicKey`, `algorithm`, and `version`. The backend forwards it to the CVM without reading it. Status: Live for REST callers who send `encryptedPrompt`. Soon for the SDK. Not used by the chat app, whose agent mode runs the plaintext tool loop. |

## Example Request
## Example request

```bash
curl -X POST "https://api.solrouter.com/agent" \
Expand All @@ -35,39 +47,93 @@ curl -X POST "https://api.solrouter.com/agent" \
}'
```

## Example Response
## Example response (default path)

```json
{
"success": true,
"reply": "## Marginfi vs Kamino Lending Comparison\n\n...",
"toolCalls": [
{ "tool": "web_search", "args": { "query": "Marginfi vs Kamino lending Solana" } },
{ "tool": "token_price", "args": { "token": "MNDE" } }
{ "tool": "web_search", "args": { "query": "Marginfi vs Kamino lending Solana" }, "result": { "...": "..." } },
{ "tool": "token_price", "args": { "token": "MNDE" }, "result": { "...": "..." } }
],
"usage": { "promptTokens": 0, "completionTokens": 0, "totalTokens": 0 },
"iterations": 4,
"skillGraph": {
"nodesTraversed": ["defi-analysis", "liquidity-risk", "comparative-analysis"],
"relevanceScore": 0.72
}
"model": "gpt-oss:20b",
"provider": "nosana",
"billing": null,
"freeMessagesRemaining": 0
}
```

## Response Fields
## Response fields (default path)

| Field | Type | Description |
| --- | --- | --- |
| `success` | boolean | Whether the request completed successfully. `true` on success; `false` if an error occurred. |
| `reply` | string | The agent's final synthesised answer in Markdown. This is produced by the LLM synthesis step after SERV has collected all relevant data through tool calls. |
| `toolCalls` | array | The list of tools the agent called during execution, in order. Each entry contains a `tool` name and an `args` object with the parameters that were passed to that tool. |
| `iterations` | number | The number of reasoning iterations the SERV pipeline executed before producing the final answer. |
| `skillGraph.nodesTraversed` | array | The skill graph nodes that were activated for this query. Nodes represent structured domain knowledge (e.g. `defi-analysis`, `liquidity-risk`, `comparative-analysis`) that was injected into the synthesis context. Simple queries may return an empty array if skill-graph traversal was skipped. |
| `skillGraph.relevanceScore` | number | A score between 0 and 1 indicating how relevant the activated domain knowledge was to the query. Higher scores mean the skill graph contributed meaningfully to the final answer. |
| `success` | boolean | `true` when the request completed. A caller with no free messages and no USDC balance gets HTTP 200 with `success: false`, `requiresDeposit: true`, and `reason: "free_trial_exhausted"`. |
| `reply` | string | The final reply in Markdown. |
| `toolCalls` | array | Every tool the agent called, in order. Each entry has `tool`, `args`, and `result`. |
| `usage` | object | `promptTokens`, `completionTokens`, and `totalTokens`, summed over every model call in the loop. |
| `iterations` | number | The number of model calls the loop made. At most 8. |
| `model` | string | The model id that ran. |
| `provider` | string | Always `"nosana"`. |
| `billing` | object or null | The result of the billing step. `null` when billing failed or did not run. |
| `freeMessagesRemaining` | number | Free messages left on the account after this call. |

The response has no `skillGraph` field. The skill graph shapes the system prompt only.

## Example response (BRAID path)

```json
{
"success": true,
"reply": "## Marginfi vs Kamino Lending Comparison\n\n...",
"reasoning": "braid",
"braidTrace": {
"grdId": "comparison",
"intent": "comparison",
"nodes": [
{ "nodeId": "...", "label": "...", "type": "action", "status": "completed" }
],
"totalDurationMs": 0,
"totalTokens": 0
},
"usage": { "promptTokens": 0, "completionTokens": 0, "totalTokens": 0 },
"iterations": 1,
"model": "gpt-oss:20b",
"provider": "nosana",
"cost": "FREE",
"freeMessagesRemaining": 0
}
```

`braidTrace` is present only when `braidOptions.includeTrace` is `true`. On this path `iterations` counts GRD nodes, not model calls. If BRAID fails, the route falls back to the default tool loop.

## Example response (encrypted mode)

```json
{
"success": true,
"encrypted": true,
"encryptedResponse": { "...": "..." },
"toolCallsCount": 2,
"attestation": { "...": "..." },
"privacyGuarantee": {
"backendSawPlaintext": false,
"toolsExecutedInTEE": true
},
"freeMessagesRemaining": 0
}
```

The reply is encrypted to the `publicKey` inside `encryptedPrompt`. Any enclave error returns HTTP 500. The route does not fall back to a plaintext path.

## Available tools

## Available Tools
The default path registers 18 tools. They are listed on the [Agent Framework](/docs/how-it-works/agent-reasoning) page: `web_search`, `scrape_url`, `crawl_url`, `solana_balance`, `token_price`, `swap_quote`, `trending_tokens`, `deepwiki`, `colosseum_search`, `colosseum_archives`, `paysh_search_apis`, `paysh_call_api`, `github_list_repos`, `github_issues`, `github_read_file`, `notion_search`, `notion_get_page`, and `notion_query_database`. The model picks the tools at each step of the loop.

The agent has access to all built-in tools listed on the [Agents Overview](/docs/concepts/agent-framework) page, including `web_search`, `scrape_url`, `crawl_url`, `solana_balance`, `token_price`, `swap_quote`, `trending_tokens`, and `deepwiki`. Tool selection is handled automatically by the SERV reasoning pipeline — you don't need to specify which tools to use.
Encrypted mode allows 5 tools inside the CVM: `web_search` (SearXNG inside the CVM), `token_price`, `trending_tokens`, `swap_quote`, and `solana_balance`.

<Callout title="Tip">
If you are using the `@solrouter/sdk`, you can reach the same SERV-guided agent pipeline by passing `reasoning: 'braid'` to `client.chat()`. This routes your request through `/agent` automatically and returns the same structured response, with the added benefit of client-side encryption if `encrypted: true` is set.
With `@solrouter/sdk` 1.1.0, `client.chat(prompt, { reasoning: 'braid' })` sends the request to `/agent`. The SDK sends the prompt in plaintext on this path and returns `encrypted: false`. The SDK does not send `encryptedPrompt` to `/agent`. Encrypted agent mode is Live over REST and Soon in the SDK.
</Callout>
Loading
Loading