Skip to content

Commit fae9801

Browse files
committed
feat(sdk): add searchAllFeedback, listAllFeedbacks, configurable cache TTL
- searchAllFeedback() merges results across FeedbackV1 + FeedbackPublicV1 - listAllFeedbacks() async generator for bulk pagination across schemas - feedbackCacheTtlMs option on SATIClientOptions (default 30s, 0 to disable) - Remove @coral-xyz/anchor from peer dependencies - Dashboard: default network to mainnet, OG meta tags for agent pages - Docs: collecting-feedback guide, REST API reference
1 parent e2d64fd commit fae9801

11 files changed

Lines changed: 462 additions & 248 deletions

File tree

apps/dashboard/src/react-app/lib/network.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export type SolanaChain = "solana:mainnet" | "solana:devnet" | "solana:testnet"
1919
export type { Network };
2020

2121
const STORAGE_KEY = "sati-network";
22-
const DEFAULT_CHAIN: SolanaChain = "solana:devnet";
22+
const DEFAULT_CHAIN: SolanaChain = "solana:mainnet";
2323

2424
/**
2525
* Map from Wallet Standard chain to SDK network type

apps/dashboard/src/worker/index.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,50 @@ function createApp(bindings: WorkerBindings) {
160160

161161
app.use("/*", cors());
162162

163+
// OG meta tags for agent pages (social sharing previews)
164+
app.get("/agent/:mint", async (c, next) => {
165+
const mint = c.req.param("mint");
166+
if (!isAddress(mint)) return next();
167+
168+
// Only inject OG tags for social crawlers and link previews
169+
const ua = c.req.header("user-agent") ?? "";
170+
const isCrawler = /bot|crawl|spider|preview|slack|discord|telegram|twitter|facebook|whatsapp|linkedin|embed/i.test(
171+
ua,
172+
);
173+
if (!isCrawler) return next();
174+
175+
try {
176+
const network = "mainnet";
177+
const sati = createSatiClient(network, env);
178+
const agent = await sati.loadAgent(mint as Address);
179+
if (!agent) return next();
180+
181+
const title = `${agent.name} - SATI Agent`;
182+
const description = `On-chain AI agent #${agent.memberNumber} on Solana. View reputation, feedback, and services.`;
183+
const url = `https://sati.cascade.fyi/agent/${mint}`;
184+
185+
const html = `<!doctype html>
186+
<html lang="en"><head>
187+
<meta charset="UTF-8"/>
188+
<title>${title}</title>
189+
<meta name="description" content="${description}"/>
190+
<meta property="og:type" content="profile"/>
191+
<meta property="og:url" content="${url}"/>
192+
<meta property="og:title" content="${title}"/>
193+
<meta property="og:description" content="${description}"/>
194+
<meta name="twitter:card" content="summary"/>
195+
<meta name="twitter:site" content="@cascade_fyi"/>
196+
<meta name="twitter:title" content="${title}"/>
197+
<meta name="twitter:description" content="${description}"/>
198+
<meta http-equiv="refresh" content="0;url=${url}"/>
199+
</head><body>Redirecting to <a href="${url}">${title}</a></body></html>`;
200+
201+
return c.html(html);
202+
} catch {
203+
return next();
204+
}
205+
});
206+
163207
// Health check
164208
app.get("/api/health", (c) => c.json({ ok: true, timestamp: Date.now() }));
165209

docs/.vitepress/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default defineConfig({
4747
{ text: 'Agent Marketplace', link: '/guides/agent-marketplace' },
4848
{ text: 'x402 Payment Feedback', link: '/guides/x402-feedback' },
4949
{ text: 'Register an MCP Agent', link: '/guides/mcp-agent' },
50+
{ text: 'Collecting Feedback', link: '/guides/collecting-feedback' },
5051
{ text: 'Query Reputation', link: '/guides/query-reputation' },
5152
{ text: 'Browser Wallet Flow', link: '/guides/browser-wallet' },
5253
]
@@ -57,6 +58,7 @@ export default defineConfig({
5758
{ text: 'Overview', link: '/reference/' },
5859
{ text: 'sati-agent0-sdk', link: '/reference/sati-agent0-sdk' },
5960
{ text: 'sati-sdk', link: '/reference/sati-sdk' },
61+
{ text: 'REST API', link: '/reference/rest-api' },
6062
]
6163
},
6264
{

docs/guides/collecting-feedback.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Collecting Feedback
2+
3+
You registered your agent. Now what? This guide covers how users actually leave feedback and how to integrate feedback collection into your workflow.
4+
5+
## How feedback reaches your agent
6+
7+
There are three paths for feedback to reach your registered agent:
8+
9+
### 1. SATI Dashboard (zero integration)
10+
11+
Share your agent's dashboard link:
12+
13+
```
14+
https://sati.cascade.fyi/agent/<YOUR_MINT>
15+
```
16+
17+
The dashboard has a "Give Feedback" button. Users connect a Solana wallet and submit feedback directly. No code changes on your side.
18+
19+
**Best for:** standalone agents (MCP servers, A2A endpoints) where you don't control the client.
20+
21+
### 2. CLI (for operators and monitoring)
22+
23+
```bash
24+
npx create-sati-agent give-feedback \
25+
--agent <MINT> --tag1 starred --value 85 --network mainnet
26+
```
27+
28+
**Best for:** automated health checks, uptime monitoring, internal QA.
29+
30+
### 3. SDK (programmatic, for platforms)
31+
32+
```typescript
33+
import { Sati, Outcome, address } from "@cascade-fyi/sati-sdk";
34+
35+
const sati = new Sati({ network: "mainnet" });
36+
37+
// Server-side: your platform pays, user just rates
38+
const { signature } = await sati.giveFeedback({
39+
payer, // Platform's funded keypair
40+
agentMint: address("Agent..."),
41+
outcome: Outcome.Positive,
42+
value: 87,
43+
tag1: "starred",
44+
message: "Fast response",
45+
});
46+
```
47+
48+
**Best for:** marketplaces, facilitators, and platforms that want to embed feedback into their UX.
49+
50+
## Choosing the right feedback schema
51+
52+
SATI has two feedback schemas with different trust properties:
53+
54+
| Schema | Mode | Who signs | Use when |
55+
|--------|------|-----------|----------|
56+
| **FeedbackPublicV1** | CounterpartySigned | Reviewer only | Public reviews, marketplace ratings, health checks |
57+
| **FeedbackV1** | DualSignature | Agent + Reviewer | Proof-of-participation, x402 payments, high-trust scenarios |
58+
59+
`giveFeedback()` uses FeedbackPublicV1 (simple, one signer). For blind feedback with DualSignature, use the lower-level `createFeedback()` - see the [x402 feedback guide](/guides/x402-feedback).
60+
61+
## For standalone agent operators
62+
63+
If you run an MCP server or API and want users to leave feedback:
64+
65+
1. **Add your dashboard link to your README/docs:**
66+
```
67+
Reputation: https://sati.cascade.fyi/agent/<YOUR_MINT>
68+
```
69+
70+
2. **Include your mint address in your MCP server's metadata** (the `agent-registration.json` already has it in `registrations[]` after publishing).
71+
72+
3. **Use the REST API to show reputation in your docs:**
73+
```bash
74+
curl https://sati.cascade.fyi/api/reputation/<MINT>?network=mainnet
75+
# {"count": 42, "summaryValue": 85, "summaryValueDecimals": 0}
76+
```
77+
78+
4. **Monitor incoming feedback:**
79+
```typescript
80+
// Poll for new feedback (check periodically)
81+
const feedbacks = await sati.searchFeedback({
82+
agentMint: address("YourMint..."),
83+
});
84+
console.log(`${feedbacks.length} reviews`);
85+
```
86+
87+
## For platforms and marketplaces
88+
89+
If you run a platform where multiple agents operate:
90+
91+
1. **Register agents programmatically** when they join your platform:
92+
```typescript
93+
const result = await sati.registerAgent({
94+
payer: platformKeypair,
95+
name: agentName,
96+
uri: registrationFileUri,
97+
});
98+
```
99+
100+
2. **Collect feedback after each interaction** on behalf of users:
101+
```typescript
102+
await sati.giveFeedback({
103+
payer: platformKeypair, // Platform pays ~0.00001 SOL
104+
agentMint: address(agentMint),
105+
value: userRating,
106+
tag1: "starred",
107+
});
108+
```
109+
110+
3. **Display reputation** using the SDK or REST API:
111+
```typescript
112+
const summary = await sati.getReputationSummary(address(agentMint));
113+
// { count: 42, averageValue: 85.3 }
114+
```
115+
116+
4. **Query across all schemas** for complete data:
117+
```typescript
118+
// Includes both FeedbackPublicV1 and FeedbackV1 (blind)
119+
const allFeedback = await sati.searchAllFeedback({
120+
agentMint: address(agentMint),
121+
});
122+
```
123+
124+
## Tag conventions
125+
126+
Use consistent tags so reputation aggregates meaningfully:
127+
128+
| tag1 | value range | meaning |
129+
|------|-------------|---------|
130+
| `starred` | 0-100 | Overall rating |
131+
| `reachable` | 0 or 1 | Health check |
132+
| `uptime` | 0-100 | Uptime percentage |
133+
| `responseTime` | ms | Latency in milliseconds |
134+
| `successRate` | 0-100 | Success percentage |
135+
136+
## Cost
137+
138+
Each feedback attestation costs ~0.00001 SOL (compressed via ZK Compression). At $200 SOL, that's $0.002 per review. Devnet is free.

docs/reference/rest-api.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# REST API
2+
3+
The SATI dashboard exposes a public REST API at `https://sati.cascade.fyi`. Use it to query agents, feedback, and reputation without pulling in the full SDK.
4+
5+
**Base URL:** `https://sati.cascade.fyi`
6+
7+
All endpoints accept a `?network=mainnet|devnet` query parameter (defaults to mainnet).
8+
9+
## Endpoints
10+
11+
### List agents
12+
13+
```
14+
GET /api/agents?network=mainnet&limit=20&name=search&owner=ADDRESS
15+
```
16+
17+
| Param | Type | Description |
18+
|-------|------|-------------|
19+
| `network` | `mainnet` \| `devnet` | Network to query |
20+
| `limit` | number | Max results (1-50, default 20) |
21+
| `name` | string | Filter by name (case-insensitive substring) |
22+
| `owner` | string | Filter by owner address |
23+
24+
**Response:**
25+
26+
```json
27+
{
28+
"agents": [
29+
{
30+
"mint": "AgentMint...",
31+
"agentId": "solana:5eykt4...:AgentMint...",
32+
"owner": "Owner...",
33+
"name": "MyAgent",
34+
"description": "AI assistant",
35+
"image": "https://...",
36+
"uri": "ipfs://Qm...",
37+
"memberNumber": 1,
38+
"active": true,
39+
"services": [{"name": "MCP", "endpoint": "https://..."}],
40+
"supportedTrust": ["reputation"],
41+
"x402Support": false
42+
}
43+
],
44+
"count": 1
45+
}
46+
```
47+
48+
### Get agent
49+
50+
```
51+
GET /api/agents/:mint?network=mainnet
52+
```
53+
54+
Returns a single agent with reputation summary.
55+
56+
**Response:** Same as list item, plus:
57+
58+
```json
59+
{
60+
"registrations": [{"agentId": "...", "agentRegistry": "..."}],
61+
"reputation": {
62+
"count": 42,
63+
"summaryValue": 85,
64+
"summaryValueDecimals": 0
65+
}
66+
}
67+
```
68+
69+
### Get reputation
70+
71+
```
72+
GET /api/reputation/:mint?network=mainnet&tag1=starred&tag2=chat&clientAddresses=ADDR1,ADDR2
73+
```
74+
75+
| Param | Type | Description |
76+
|-------|------|-------------|
77+
| `tag1` | string | Filter by primary tag |
78+
| `tag2` | string | Filter by secondary tag |
79+
| `clientAddresses` | string | Comma-separated reviewer addresses |
80+
81+
**Response:**
82+
83+
```json
84+
{
85+
"count": 42,
86+
"summaryValue": 85,
87+
"summaryValueDecimals": 0
88+
}
89+
```
90+
91+
### List feedback
92+
93+
```
94+
GET /api/feedback/:mint?network=mainnet&clientAddress=ADDR&tag1=starred&tag2=chat
95+
```
96+
97+
**Response:**
98+
99+
```json
100+
{
101+
"feedbacks": [
102+
{
103+
"clientAddress": "Reviewer...",
104+
"feedbackIndex": 0,
105+
"value": 87,
106+
"valueDecimals": 0,
107+
"tag1": "starred",
108+
"tag2": "chat",
109+
"endpoint": "https://...",
110+
"reviewer": "",
111+
"outcome": 2,
112+
"isRevoked": false
113+
}
114+
],
115+
"count": 1
116+
}
117+
```
118+
119+
### Submit feedback
120+
121+
```
122+
POST /api/feedback
123+
Content-Type: application/json
124+
125+
{
126+
"network": "mainnet",
127+
"agentMint": "AgentMint...",
128+
"value": 85,
129+
"valueDecimals": 0,
130+
"tag1": "starred",
131+
"endpoint": "https://..."
132+
}
133+
```
134+
135+
Server acts as counterparty and pays transaction fees. Rate limited per IP.
136+
137+
## Rate limits
138+
139+
- Read endpoints: best-effort per-IP rate limiting (Cloudflare Worker isolate-level)
140+
- Photon proxy (`/api/photon/:network`): ~120 requests/min per IP
141+
- For production workloads, use the SDK with your own Helius/Triton RPC
142+
143+
## Notes
144+
145+
- Queries both FeedbackV1 and FeedbackPublicV1 schemas automatically
146+
- Reputation is computed by averaging all feedback values (no weighting)
147+
- `outcome` values: 0 = Negative, 1 = Neutral, 2 = Positive
148+
- Agent IDs follow CAIP-2 format: `solana:{genesis_hash}:{mint_address}`

packages/sdk/CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.13.0] - 2026-03-05
9+
10+
### Added
11+
12+
- **`searchAllFeedback()`** - search feedback across all deployed schemas (FeedbackV1 + FeedbackPublicV1), merging results
13+
- **`listAllFeedbacks()`** - async generator for bulk feedback pagination across all schemas
14+
- **`feedbackCacheTtlMs` option** - configurable feedback cache TTL on `SATIClientOptions` (default 30s, 0 to disable)
15+
16+
### Changed
17+
18+
- Removed `@coral-xyz/anchor` from peer dependencies (not needed by SDK consumers)
19+
- Extracted shared feedback search logic into `_searchFeedbackForSchema()` internal helper
20+
821
## [0.12.0] - 2026-02-21
922

1023
### Added
@@ -228,6 +241,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
228241
- Compressed attestation storage via Light Protocol
229242
- Basic querying via Photon RPC
230243

244+
[0.13.0]: https://github.com/cascade-protocol/sati/compare/@cascade-fyi/sati-sdk@0.12.0...@cascade-fyi/sati-sdk@0.13.0
231245
[0.12.0]: https://github.com/cascade-protocol/sati/compare/@cascade-fyi/sati-sdk@0.11.0...@cascade-fyi/sati-sdk@0.12.0
232246
[0.11.0]: https://github.com/cascade-protocol/sati/compare/@cascade-fyi/sati-sdk@0.10.1...@cascade-fyi/sati-sdk@0.11.0
233247
[0.10.1]: https://github.com/cascade-protocol/sati/compare/@cascade-fyi/sati-sdk@0.10.0...@cascade-fyi/sati-sdk@0.10.1

0 commit comments

Comments
 (0)