From 97fb4a1c16d0274166c58e5cbc24c1c66a633bf9 Mon Sep 17 00:00:00 2001 From: chrisjleal <184772742+chrisjleal@users.noreply.github.com> Date: Sun, 1 Nov 2026 14:14:48 -0600 Subject: [PATCH] Talk to your agent from any app: one call, inside its limits, with citations A new guide shows the one call that reaches a hosted agent from any app, server or runtime: the SDK's agentChat and the HTTP turn it wraps, what runs on each turn, the final event with its citations, the refusals, what a turn costs and how to read your spend. The Agents page lists it with the other ways in, and the API reference carries the turn and the usage read. Co-Authored-By: Claude Opus 5.5 --- agents/index.mdx | 2 + agents/talk-to-an-agent.mdx | 102 ++++++++++++++++ docs.json | 2 +- openapi/public-api.json | 232 ++++++++++++++++++++++++++++++++++++ 4 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 agents/talk-to-an-agent.mdx diff --git a/agents/index.mdx b/agents/index.mdx index 70222a3..a2ea583 100644 --- a/agents/index.mdx +++ b/agents/index.mdx @@ -34,6 +34,7 @@ The agent lives on your signed-in profile by default. Ask for a dedicated spend ## Use it where you work - **Chat and jobs on Proofable.** Chat now, or start a [job](/jobs) for background and scheduled work. +- **Any app or runtime.** Talk to it with one call from your app, your server, or another runtime. Nothing to deploy. [Talk from any app](/agents/talk-to-an-agent) - **Any MCP client.** Load the same agent with `npx -y @proofable/sdk mount --apply cursor`. - **Your servers.** Point the runtime at the same endpoint with an [access key](/deployment/access-keys), or deploy to a [private cloud](/deployment/private-cloud). - **Other apps and marketplaces.** Each agent has a public card that others can check before they trust it. [Discover agents](/agents/named-agent-card) @@ -45,6 +46,7 @@ Keep your model, runtime, and enterprise sign-in such as Okta. Proofable keeps t | Where the agent runs | What Proofable provides | |---|---| | Chat and jobs on Proofable | Enforces permissions, tool access, and proof checks | +| Your app, calling the agent | Runs the turn as the agent and checks every tool call against its permission | | MCP clients | Loads the agent's rules and context. Start a new session after you mount. | | Your workers and backends | Returns the permission bundle for your code to enforce | diff --git a/agents/talk-to-an-agent.mdx b/agents/talk-to-an-agent.mdx new file mode 100644 index 0000000..76ea5f7 --- /dev/null +++ b/agents/talk-to-an-agent.mdx @@ -0,0 +1,102 @@ +--- +title: Talk to your agent from any app +sidebarTitle: Talk from any app +description: Your agent runs on Proofable. Any app, server, or runtime talks to it with one call, inside the limits you signed, and every answer cites the records it read. +icon: comments +--- + +Your agent runs on Proofable, so there is nothing to deploy and no machine to keep. Any app, server, or runtime talks to it with one call. It answers as itself, inside the limits you signed, and cites the records it read. + +## One call + +```javascript +import { ProofableClient } from '@proofable/sdk'; + +const client = new ProofableClient({ apiKey: process.env.PROOFABLE_ACCESS_KEY }); + +const turn = await client.agentChat({ + agentId: 'my-agent', + messages: [{ role: 'user', content: 'Summarize this week for the client.' }], + onEvent: (type, data) => { + if (type === 'answer.delta') process.stdout.write(data.text); + }, +}); + +turn.answer; // the agent's answer +turn.citations; // the records it read +turn.credits; // what the turn spent +``` + +Sign the client in with an [access key](/deployment/access-keys) on a server, or with the signed-in person's session in a browser. Never ship an access key in browser code. + +## What happens on each turn + +1. Proofable finds the [permission](/agents/agent-delegation) you signed for the agent. No active permission from your account, no turn. +2. The turn runs as the agent: its own instructions and skills from its [identity](/agents/agent-identity), and the connected apps you bound to it. +3. Every tool call is checked against the permission before it runs, read again for each call. Revoke the permission and the next call stops, in every app that talks to the agent. +4. The answer comes back with the records the agent read. Each one opens at `proofable.me/proof/`, so anyone you share it with can check where the answer came from. + +## Over HTTP + +`POST https://api.proofable.me/api/v1/agent/chat/turn` with `Authorization: Bearer ` streams the turn as Server-Sent Events. + +```bash +curl -N https://api.proofable.me/api/v1/agent/chat/turn \ + -H "Authorization: Bearer $PROOFABLE_ACCESS_KEY" \ + -H "Content-Type: application/json" \ + -d '{"agentId":"my-agent","messages":[{"role":"user","content":"What changed today?"}]}' +``` + +| Field | What it does | +|---|---| +| `agentId` | Run the turn as this agent. Omit it to run as yourself. | +| `agentWallet` | The agent's account, when two of your agents share an id | +| `messages` | The conversation, `user` and `assistant` turns, ending with the user | +| `systemPrompt` | Context from your app. The agent reads it as data, after its own instructions. | +| `model` | `default` or `advanced`. With `provider`, that provider's model id. | +| `provider`, `providerSecretProofQHash` | Run on your own model key from the vault instead of hosted inference | + +The stream sends `turn.start`, `answer.delta` as the answer arrives, `tool.start` and `tool.result` for each call, and ends with one `final` event: + +```json +{ + "outcome": "succeeded", + "answer": "…", + "citations": [{ "qHash": "0x…", "title": "Chapter 1", "facet": "memory", "visibility": "public" }], + "agent": { "agentId": "my-agent", "agentWallet": "0x…", "identityQHash": "0x…", "delegationQHash": "0x…" }, + "credits": { "spent": 2 } +} +``` + +A request Proofable refuses never opens the stream. It answers JSON with the reason: + +| Status | Code | Why | +|---|---|---| +| 401 | `AUTH_REQUIRED` | No session, OAuth token, or access key | +| 402 | `INSUFFICIENT_CREDITS` | Not enough credits for a hosted turn | +| 403 | `AGENT_DELEGATION_REQUIRED` | No active permission from your account to this agent | +| 403 | `ADVANCED_REQUIRES_PRO` | Advanced runs on paid plans | + +## What it costs + +A hosted turn spends credits from the account that calls it, by the tokens it used and the model that served them, the same rate as a [job](/jobs) step. A turn on your own model key spends no platform credits. See [pricing](/pricing). + +Read your balance and spend at any time, by line and by day: + +```javascript +const { credits, usage } = await client.getUsage({ from: '2026-11-01', to: '2026-11-30' }); +usage.summary.debitedByDay; // { '2026-11-01': 14, … } +``` + +Over HTTP it is `GET /api/v1/profile/usage?from=YYYY-MM-DD&to=YYYY-MM-DD` with the same token. In an MCP client, `proofable_context` carries the balance. + +## Other ways to reach the same agent + +- **In an MCP client.** `npx -y @proofable/sdk mount my-agent --apply claude` loads the agent into Claude, Cursor, Codex, Hermes, OpenClaw, or OpenCode. [Connect agent context](/agents/runtime-mount) +- **As background work.** Start a [job](/jobs) for scheduled or long work, on an isolated computer when it needs one. + +## Related + +- [Agent permissions](/agents/agent-delegation) +- [Agent identity](/agents/agent-identity) +- [Import an agent](/agents/import) diff --git a/docs.json b/docs.json index c941c3b..aaabce9 100644 --- a/docs.json +++ b/docs.json @@ -114,7 +114,7 @@ "pages": [ { "group": "Agents", - "pages": ["mcp/guarded-action", "agents/agent-delegation", "agents/agent-identity", "agents/import", "agents/named-agent-card", "agents/team-agents", "agents/runtime-mount"] + "pages": ["mcp/guarded-action", "agents/talk-to-an-agent", "agents/agent-delegation", "agents/agent-identity", "agents/import", "agents/named-agent-card", "agents/team-agents", "agents/runtime-mount"] }, { "group": "Proofs", diff --git a/openapi/public-api.json b/openapi/public-api.json index 987fa9f..f3aaf46 100644 --- a/openapi/public-api.json +++ b/openapi/public-api.json @@ -3971,6 +3971,108 @@ } } }, + "/api/v1/profile/usage": { + "get": { + "operationId": "getProfileUsage", + "summary": "Read your credits and spend, by line and by day", + "tags": [ + "Profile" + ], + "parameters": [ + { + "name": "from", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date" + }, + "description": "First UTC day of the period (YYYY-MM-DD)." + }, + { + "name": "to", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date" + }, + "description": "Last UTC day of the period (YYYY-MM-DD)." + }, + { + "name": "appId", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "Only spend recorded under this app or namespace." + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 500 + }, + "description": "Most events returned, newest first (default 500)." + } + ], + "responses": { + "200": { + "description": "Balance, events and summary" + }, + "400": { + "description": "Invalid period" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "429": { + "description": "Rate limited", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, "/api/v1/profile/gates/discoverable": { "get": { "operationId": "listDiscoverableGates", @@ -4731,6 +4833,136 @@ } } } + }, + "/api/v1/agent/chat/turn": { + "post": { + "operationId": "streamAgentChatTurn", + "summary": "Talk to an agent: run one chat turn as it, streamed as Server-Sent Events", + "description": "Runs one turn on the hosted agent runtime. With agentId the turn runs as that agent: its instructions and skills, under the delegation you signed, every tool call checked against it. The final event carries the answer, the records it read as citations, and the credits it spent. Nothing to deploy: call it from any app or runtime with a session, an OAuth token or a profile access key.", + "tags": [ + "Agents" + ], + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "messages" + ], + "properties": { + "agentId": { + "type": "string", + "description": "Run the turn as this agent, under the delegation the caller signed for it." + }, + "agentWallet": { + "type": "string", + "description": "The agent's account, when two of the caller's agents share an agentId." + }, + "messages": { + "type": "array", + "description": "The visible conversation; the last message is from the user.", + "items": { + "type": "object", + "required": [ + "role", + "content" + ], + "properties": { + "role": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "content": { + "type": "string" + } + } + } + }, + "model": { + "type": "string", + "description": "A hosted tier (\"default\", \"advanced\") or, with a provider, that provider's model id. Defaults to \"default\"." + }, + "provider": { + "type": "string", + "description": "Omit for hosted inference; name a provider to run on your own key." + }, + "providerSecretProofQHash": { + "type": "string", + "description": "The vault secret holding your provider key." + }, + "systemPrompt": { + "type": "string", + "description": "Context from your app. With agentId it follows the agent's own instructions, as data." + }, + "responseMode": { + "type": "string", + "enum": [ + "agent", + "plan" + ] + }, + "turnId": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "text/event-stream in the agent-turn-events/1 contract" + }, + "400": { + "description": "Invalid turn request" + }, + "401": { + "description": "Authentication required" + }, + "402": { + "description": "Not enough credits for a hosted turn" + }, + "403": { + "description": "No active delegation for this agent, or Advanced without a paid plan" + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "429": { + "description": "Rate limited", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } } } } \ No newline at end of file