Skip to content

Commit 15b3667

Browse files
waydelyleclaude
andcommitted
feat: implement v0.2 — reputation, quality, tribunal, portfolios, audit, rate limiting
Add all spec-defined features that were missing from the MVP: Schema: 5 new tables (agent_reputation, portfolio_items, audit_log, transactions, disputes upgraded) and 15+ new columns across existing tables. Ratings migrated from integer 1-5 to float 0-1 scale. Services: reputation engine with weighted scoring and anti-gaming, deterministic quality verification, 3-judge tribunal dispute system, hash-chained audit log, Redis client (optional), rate limiting middleware. Routes: ratings trigger reputation/trust updates and audit log, admin gets tribunal endpoint and split resolution, payments query transactions table, tasks run quality checks on approval, agents get portfolio CRUD and store agentCard JSONB. Worker: task expiry (60s), agent dormancy (5min), auto-match (10s) loops. Dashboard: leaderboard, admin stats/revenue, admin transactions pages. SDK: SwarmDockAgent class with onTask/onTaskAvailable event-driven mode, portfolio management, reputation endpoint. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 90e130f commit 15b3667

30 files changed

Lines changed: 3375 additions & 95 deletions
Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
-- Migration: 0000_initial_schema
2+
-- Description: Initial schema for SwarmDock database
3+
-- Generated manually due to drizzle-kit BigInt serialization bug (v0.30.6)
4+
5+
-- Enable pgvector extension
6+
CREATE EXTENSION IF NOT EXISTS vector;
7+
8+
-- ============================================
9+
-- AGENTS
10+
-- ============================================
11+
12+
CREATE TABLE IF NOT EXISTS "agents" (
13+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
14+
"did" text UNIQUE NOT NULL,
15+
"public_key" text NOT NULL,
16+
"display_name" text NOT NULL,
17+
"description" text,
18+
"avatar_url" text,
19+
"owner_did" text,
20+
"framework" text,
21+
"framework_version" text,
22+
"model_provider" text,
23+
"model_name" text,
24+
"agent_card" jsonb,
25+
"wallet_address" text NOT NULL,
26+
"trust_level" integer DEFAULT 0 NOT NULL,
27+
"daily_spending_limit" bigint,
28+
"earning_total" bigint DEFAULT 0,
29+
"agent_card_url" text,
30+
"status" text DEFAULT 'pending' NOT NULL,
31+
"verified_at" timestamp with time zone,
32+
"last_heartbeat" timestamp with time zone,
33+
"last_active_at" timestamp with time zone,
34+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
35+
"description_embedding" vector(768),
36+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
37+
);
38+
39+
-- ============================================
40+
-- AGENT SKILLS
41+
-- ============================================
42+
43+
CREATE TABLE IF NOT EXISTS "agent_skills" (
44+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
45+
"agent_id" uuid NOT NULL REFERENCES "agents"("id") ON DELETE CASCADE,
46+
"skill_id" text NOT NULL,
47+
"skill_name" text NOT NULL,
48+
"description" text NOT NULL,
49+
"category" text NOT NULL,
50+
"tags" text[] DEFAULT '{}' NOT NULL,
51+
"input_modes" text[] DEFAULT '{text}' NOT NULL,
52+
"output_modes" text[] DEFAULT '{text}' NOT NULL,
53+
"pricing_model" text DEFAULT 'per-task' NOT NULL,
54+
"base_price" bigint NOT NULL,
55+
"currency" text DEFAULT 'USDC' NOT NULL,
56+
"example_prompts" text[] DEFAULT '{}' NOT NULL,
57+
"benchmark_scores" jsonb,
58+
"sample_outputs" jsonb,
59+
"skill_embedding" vector(768),
60+
"tasks_completed" integer DEFAULT 0 NOT NULL,
61+
"avg_completion_time" text,
62+
"avg_quality_score" real,
63+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
64+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
65+
);
66+
67+
CREATE UNIQUE INDEX IF NOT EXISTS "agent_skill_unique" ON "agent_skills" ("agent_id", "skill_id");
68+
69+
-- ============================================
70+
-- TASKS
71+
-- ============================================
72+
73+
CREATE TABLE IF NOT EXISTS "tasks" (
74+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
75+
"requester_id" uuid NOT NULL REFERENCES "agents"("id"),
76+
"assignee_id" uuid REFERENCES "agents"("id"),
77+
"title" text NOT NULL,
78+
"description" text NOT NULL,
79+
"skill_requirements" text[] NOT NULL,
80+
"input_data" jsonb,
81+
"input_files" text[],
82+
"matching_mode" text DEFAULT 'open' NOT NULL,
83+
"budget_min" bigint,
84+
"budget_max" bigint NOT NULL,
85+
"currency" text DEFAULT 'USDC' NOT NULL,
86+
"final_price" bigint,
87+
"platform_fee" bigint,
88+
"payment_tx_id" text,
89+
"status" text DEFAULT 'open' NOT NULL,
90+
"deadline" timestamp with time zone,
91+
"started_at" timestamp with time zone,
92+
"submitted_at" timestamp with time zone,
93+
"completed_at" timestamp with time zone,
94+
"result_artifacts" jsonb,
95+
"result_files" text[],
96+
"description_embedding" vector(768),
97+
"quality_score" real,
98+
"quality_details" jsonb,
99+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
100+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
101+
);
102+
103+
-- ============================================
104+
-- TASK BIDS
105+
-- ============================================
106+
107+
CREATE TABLE IF NOT EXISTS "task_bids" (
108+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
109+
"task_id" uuid NOT NULL REFERENCES "tasks"("id") ON DELETE CASCADE,
110+
"bidder_id" uuid NOT NULL REFERENCES "agents"("id"),
111+
"proposed_price" bigint NOT NULL,
112+
"confidence_score" real,
113+
"estimated_duration" text,
114+
"proposal" text,
115+
"portfolio_refs" text[],
116+
"status" text DEFAULT 'pending' NOT NULL,
117+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
118+
);
119+
120+
CREATE UNIQUE INDEX IF NOT EXISTS "task_bid_unique" ON "task_bids" ("task_id", "bidder_id");
121+
122+
-- ============================================
123+
-- ESCROW TRANSACTIONS
124+
-- ============================================
125+
126+
CREATE TABLE IF NOT EXISTS "escrow_transactions" (
127+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
128+
"task_id" uuid NOT NULL REFERENCES "tasks"("id"),
129+
"payer_id" uuid NOT NULL REFERENCES "agents"("id"),
130+
"payee_id" uuid REFERENCES "agents"("id"),
131+
"amount" bigint NOT NULL,
132+
"platform_fee" bigint,
133+
"status" text DEFAULT 'pending' NOT NULL,
134+
"escrow_tx_hash" text,
135+
"release_tx_hash" text,
136+
"network" text DEFAULT 'base-sepolia' NOT NULL,
137+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
138+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
139+
);
140+
141+
-- ============================================
142+
-- AGENT RATINGS
143+
-- ============================================
144+
145+
CREATE TABLE IF NOT EXISTS "agent_ratings" (
146+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
147+
"task_id" uuid NOT NULL REFERENCES "tasks"("id"),
148+
"rater_id" uuid NOT NULL REFERENCES "agents"("id"),
149+
"ratee_id" uuid NOT NULL REFERENCES "agents"("id"),
150+
"quality_score" real NOT NULL,
151+
"speed_score" real,
152+
"communication_score" real,
153+
"reliability_score" real,
154+
"value_score" real,
155+
"overall_score" real NOT NULL,
156+
"evidence" jsonb,
157+
"comment" text,
158+
"rater_reputation_at_time" real,
159+
"weight" real DEFAULT 1.0,
160+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
161+
);
162+
163+
CREATE UNIQUE INDEX IF NOT EXISTS "rating_unique" ON "agent_ratings" ("task_id", "rater_id");
164+
165+
-- ============================================
166+
-- AGENT REPUTATION
167+
-- ============================================
168+
169+
CREATE TABLE IF NOT EXISTS "agent_reputation" (
170+
"agent_id" uuid NOT NULL REFERENCES "agents"("id") ON DELETE CASCADE,
171+
"dimension" text NOT NULL,
172+
"score" real DEFAULT 0.5 NOT NULL,
173+
"confidence" real DEFAULT 0 NOT NULL,
174+
"total_ratings" integer DEFAULT 0 NOT NULL,
175+
"recent_trend" real DEFAULT 0,
176+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
177+
);
178+
179+
CREATE UNIQUE INDEX IF NOT EXISTS "agent_reputation_pk" ON "agent_reputation" ("agent_id", "dimension");
180+
181+
-- ============================================
182+
-- PORTFOLIO ITEMS
183+
-- ============================================
184+
185+
CREATE TABLE IF NOT EXISTS "portfolio_items" (
186+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
187+
"agent_id" uuid NOT NULL REFERENCES "agents"("id") ON DELETE CASCADE,
188+
"task_id" uuid REFERENCES "tasks"("id"),
189+
"title" text NOT NULL,
190+
"description" text,
191+
"category" text NOT NULL,
192+
"artifacts" jsonb,
193+
"files" text[],
194+
"quality_score" real,
195+
"completion_time" text,
196+
"requester_rating" real,
197+
"is_pinned" boolean DEFAULT false NOT NULL,
198+
"display_order" integer DEFAULT 0 NOT NULL,
199+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
200+
);
201+
202+
-- ============================================
203+
-- AUDIT LOG
204+
-- ============================================
205+
206+
CREATE TABLE IF NOT EXISTS "audit_log" (
207+
"id" serial PRIMARY KEY,
208+
"timestamp" timestamp with time zone DEFAULT now() NOT NULL,
209+
"event_type" text NOT NULL,
210+
"actor_id" uuid,
211+
"target_id" uuid,
212+
"target_type" text,
213+
"payload" jsonb NOT NULL,
214+
"hash" text NOT NULL,
215+
"previous_hash" text
216+
);
217+
218+
CREATE INDEX IF NOT EXISTS "idx_audit_timestamp" ON "audit_log" ("timestamp");
219+
CREATE INDEX IF NOT EXISTS "idx_audit_event_type" ON "audit_log" ("event_type");
220+
CREATE INDEX IF NOT EXISTS "idx_audit_actor" ON "audit_log" ("actor_id");
221+
222+
-- ============================================
223+
-- TRANSACTIONS
224+
-- ============================================
225+
226+
CREATE TABLE IF NOT EXISTS "transactions" (
227+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
228+
"task_id" uuid REFERENCES "tasks"("id"),
229+
"type" text NOT NULL,
230+
"from_agent_id" uuid REFERENCES "agents"("id"),
231+
"to_agent_id" uuid REFERENCES "agents"("id"),
232+
"amount" bigint NOT NULL,
233+
"currency" text DEFAULT 'USDC' NOT NULL,
234+
"tx_hash" text,
235+
"block_number" bigint,
236+
"network" text DEFAULT 'base-sepolia',
237+
"status" text DEFAULT 'pending' NOT NULL,
238+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
239+
"confirmed_at" timestamp with time zone
240+
);
241+
242+
CREATE INDEX IF NOT EXISTS "idx_transactions_task" ON "transactions" ("task_id");
243+
CREATE INDEX IF NOT EXISTS "idx_transactions_type" ON "transactions" ("type");
244+
CREATE INDEX IF NOT EXISTS "idx_transactions_from" ON "transactions" ("from_agent_id");
245+
CREATE INDEX IF NOT EXISTS "idx_transactions_to" ON "transactions" ("to_agent_id");
246+
CREATE INDEX IF NOT EXISTS "idx_transactions_status" ON "transactions" ("status");
247+
248+
-- ============================================
249+
-- DISPUTES
250+
-- ============================================
251+
252+
CREATE TABLE IF NOT EXISTS "disputes" (
253+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
254+
"task_id" uuid NOT NULL REFERENCES "tasks"("id") ON DELETE CASCADE,
255+
"raised_by_agent_id" uuid NOT NULL REFERENCES "agents"("id"),
256+
"against_agent_id" uuid REFERENCES "agents"("id"),
257+
"reason" text NOT NULL,
258+
"evidence" jsonb,
259+
"status" text DEFAULT 'open' NOT NULL,
260+
"resolution" text,
261+
"resolution_notes" text,
262+
"tribunal_agents" text[],
263+
"tribunal_votes" jsonb,
264+
"verdict" text,
265+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
266+
"resolved_at" timestamp with time zone,
267+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
268+
);
269+
270+
-- ============================================
271+
-- EVENT OUTBOX
272+
-- ============================================
273+
274+
CREATE TABLE IF NOT EXISTS "event_outbox" (
275+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
276+
"subject" text NOT NULL,
277+
"target" text NOT NULL,
278+
"agent_id" uuid REFERENCES "agents"("id"),
279+
"event_type" text NOT NULL,
280+
"payload" jsonb NOT NULL,
281+
"status" text DEFAULT 'pending' NOT NULL,
282+
"attempts" integer DEFAULT 0 NOT NULL,
283+
"last_error" text,
284+
"published_at" timestamp with time zone,
285+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
286+
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
287+
);
288+
289+
-- ============================================
290+
-- CHALLENGES
291+
-- ============================================
292+
293+
CREATE TABLE IF NOT EXISTS "challenges" (
294+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
295+
"public_key" text NOT NULL,
296+
"challenge" text NOT NULL,
297+
"expires_at" timestamp with time zone NOT NULL,
298+
"used" boolean DEFAULT false NOT NULL,
299+
"created_at" timestamp with time zone DEFAULT now() NOT NULL
300+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"version": "7",
3+
"dialect": "postgresql",
4+
"entries": [
5+
{
6+
"idx": 0,
7+
"version": "7",
8+
"when": 1743292800000,
9+
"tag": "0000_initial_schema",
10+
"breakpoints": true
11+
}
12+
]
13+
}

0 commit comments

Comments
 (0)