@oneie/sdk 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +2 -0
- package/dist/auth.js.map +1 -1
- package/dist/billing.d.ts +49 -0
- package/dist/billing.d.ts.map +1 -0
- package/dist/billing.js +49 -0
- package/dist/billing.js.map +1 -0
- package/dist/brain.d.ts +36 -0
- package/dist/brain.d.ts.map +1 -0
- package/dist/brain.js +99 -0
- package/dist/brain.js.map +1 -0
- package/dist/broadcast.d.ts +37 -0
- package/dist/broadcast.d.ts.map +1 -0
- package/dist/broadcast.js +7 -0
- package/dist/broadcast.js.map +1 -0
- package/dist/client.d.ts +28 -34
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +36 -26
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/market.d.ts +63 -0
- package/dist/market.d.ts.map +1 -0
- package/dist/market.js +92 -0
- package/dist/market.js.map +1 -0
- package/dist/meta.d.ts +45 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +44 -0
- package/dist/meta.js.map +1 -0
- package/dist/openapi.d.ts +27 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +62 -0
- package/dist/openapi.js.map +1 -0
- package/dist/receivers.d.ts +1497 -0
- package/dist/receivers.d.ts.map +1 -0
- package/dist/receivers.js +1441 -0
- package/dist/receivers.js.map +1 -0
- package/dist/schemas.d.ts +52 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +40 -0
- package/dist/schemas.js.map +1 -1
- package/dist/soul.d.ts +10 -0
- package/dist/soul.d.ts.map +1 -0
- package/dist/soul.js +31 -0
- package/dist/soul.js.map +1 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/types.d.ts +18 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +26 -1
|
@@ -0,0 +1,1441 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AgentActionResponseSchema, AgentStatusResponseSchema, CapabilityItemSchema, PayResponseSchema, RegisterResponseSchema, StatsSchema, StepKind, WorkflowDiffSchema, } from "./schemas.js";
|
|
3
|
+
/**
|
|
4
|
+
* Declare a receiver contract. Identity at runtime — its only job is to pin the
|
|
5
|
+
* `Req`/`Res` generics so the catalog infers payload + outcome types.
|
|
6
|
+
*/
|
|
7
|
+
export function receiver(r) {
|
|
8
|
+
return r;
|
|
9
|
+
}
|
|
10
|
+
const ok = z.object({ ok: z.boolean() });
|
|
11
|
+
/**
|
|
12
|
+
* The receiver catalog — one source of truth for capability. Object-literal keys
|
|
13
|
+
* are always literal, so `keyof typeof RECEIVERS` yields the declared receiver
|
|
14
|
+
* names and `ask<R>` infers payload + outcome by inference (no codegen).
|
|
15
|
+
*
|
|
16
|
+
* Populated incrementally: C2 = spine + 21 `world:*` + `grant-capability`;
|
|
17
|
+
* C4 = remaining families with metadata; C5 = the `meta:` family.
|
|
18
|
+
*/
|
|
19
|
+
export const RECEIVERS = {
|
|
20
|
+
// ── Spine (non-world) — contracts only this cycle; route-wiring lands in C4 ──
|
|
21
|
+
"agent:enroll": receiver({
|
|
22
|
+
receiver: "agent:enroll",
|
|
23
|
+
summary: "Self-enroll as an agent — mint identity + API key with no prior session",
|
|
24
|
+
request: z.object({ name: z.string(), capabilities: z.array(z.string()).optional() }),
|
|
25
|
+
response: z.object({ ok: z.literal(true), actorId: z.string(), slug: z.string(), apiKey: z.string(), credits: z.number() }),
|
|
26
|
+
effect: "ask", auth: "public", reversible: false, idempotent: false,
|
|
27
|
+
}),
|
|
28
|
+
"auth:agent": receiver({
|
|
29
|
+
receiver: "auth:agent",
|
|
30
|
+
summary: "Become an actor — mint a uid, wallet, and scoped API key",
|
|
31
|
+
request: z.object({ name: z.string().optional(), uid: z.string().optional(), kind: z.string().optional() }),
|
|
32
|
+
response: z.object({
|
|
33
|
+
uid: z.string(), name: z.string(), kind: z.string(),
|
|
34
|
+
wallet: z.string().nullable(), apiKey: z.string(), keyId: z.string(), returning: z.boolean(),
|
|
35
|
+
}),
|
|
36
|
+
effect: "ask",
|
|
37
|
+
reversible: false,
|
|
38
|
+
idempotent: true,
|
|
39
|
+
}),
|
|
40
|
+
"agents:sync": receiver({
|
|
41
|
+
receiver: "agents:sync",
|
|
42
|
+
summary: "Declare capability — sync agent definitions, skills, and memberships",
|
|
43
|
+
// Accepts a single markdown body or a structured multi-agent world payload.
|
|
44
|
+
request: z.union([
|
|
45
|
+
z.object({ markdown: z.string() }),
|
|
46
|
+
z.object({
|
|
47
|
+
agents: z.array(z.object({ name: z.string().optional(), content: z.string() })),
|
|
48
|
+
world: z.string().optional(),
|
|
49
|
+
description: z.unknown().optional(),
|
|
50
|
+
}),
|
|
51
|
+
]),
|
|
52
|
+
response: z.object({
|
|
53
|
+
ok: z.boolean(), agent: z.string().optional(), uid: z.string().optional(),
|
|
54
|
+
wallet: z.string().nullable().optional(), suiObjectId: z.string().nullable().optional(),
|
|
55
|
+
skills: z.array(z.string()).optional(), world: z.string().optional(),
|
|
56
|
+
}).passthrough(),
|
|
57
|
+
effect: "ask",
|
|
58
|
+
}),
|
|
59
|
+
// ── world:* — workspace / actor / thing / key / path / learning mutations ──
|
|
60
|
+
"world:create-workspace": receiver({
|
|
61
|
+
receiver: "world:create-workspace",
|
|
62
|
+
summary: "Create a workspace; optionally provision a full billing-aware client (parent + credits + brand + starter agents) in one atomic call",
|
|
63
|
+
request: z.object({
|
|
64
|
+
name: z.string(),
|
|
65
|
+
slug: z.string(),
|
|
66
|
+
ownerEmail: z.string().email().optional(),
|
|
67
|
+
// Extended atomic client provision (optional — omit for a bare workspace).
|
|
68
|
+
parent: z.string().optional(),
|
|
69
|
+
plan: z.enum(["free", "pro", "studio", "agency", "enterprise"]).optional(),
|
|
70
|
+
credit: z.number().int().nonnegative().optional(),
|
|
71
|
+
markup: z.number().int().min(0).max(100).optional(),
|
|
72
|
+
cap: z.number().int().nonnegative().nullable().optional(),
|
|
73
|
+
brand: z.boolean().optional(),
|
|
74
|
+
agents: z.array(z.string()).optional(),
|
|
75
|
+
}),
|
|
76
|
+
response: z.object({ wsid: z.string(), slug: z.string() }),
|
|
77
|
+
effect: "ask", auth: "manage_workspace", reversible: false,
|
|
78
|
+
examples: [
|
|
79
|
+
{ name: "Acme", slug: "acme", ownerEmail: "owner@acme.com" },
|
|
80
|
+
{ name: "Acme", slug: "acme", parent: "donal", plan: "studio", credit: 50000, markup: 20, cap: 50000, brand: true, agents: ["sales", "support"] },
|
|
81
|
+
],
|
|
82
|
+
}),
|
|
83
|
+
"world:invite-client": receiver({
|
|
84
|
+
receiver: "world:invite-client",
|
|
85
|
+
summary: "Agency mints a scoped invite; on accept the invitee owns a new workspace parented under the agency",
|
|
86
|
+
request: z.object({
|
|
87
|
+
slug: z.string(),
|
|
88
|
+
name: z.string().optional(),
|
|
89
|
+
email: z.string().email().optional(),
|
|
90
|
+
plan: z.enum(["free", "pro", "studio", "agency", "enterprise"]).optional(),
|
|
91
|
+
credits: z.number().int().nonnegative().optional(),
|
|
92
|
+
markup: z.number().int().min(0).max(100).optional(),
|
|
93
|
+
cap: z.number().int().nonnegative().nullable().optional(),
|
|
94
|
+
brand: z.boolean().optional(),
|
|
95
|
+
agents: z.array(z.string()).optional(),
|
|
96
|
+
}),
|
|
97
|
+
response: z.object({ token: z.string(), id: z.string(), child: z.string(), expiresAt: z.number() }),
|
|
98
|
+
effect: "ask", auth: "manage_clients", reversible: false,
|
|
99
|
+
examples: [{ slug: "beta", email: "owner@beta.com", plan: "studio", credits: 50000, markup: 20 }],
|
|
100
|
+
}),
|
|
101
|
+
"world:accept-client-invite": receiver({
|
|
102
|
+
receiver: "world:accept-client-invite",
|
|
103
|
+
summary: "Redeem a client invite — creates the workspace owned by the invitee (single-use, replay-protected)",
|
|
104
|
+
request: z.object({ token: z.string(), email: z.string().email().optional(), name: z.string().optional() }),
|
|
105
|
+
response: z.object({ wsid: z.string(), slug: z.string(), owner: z.string(), parent: z.string() }),
|
|
106
|
+
effect: "ask", reversible: false, idempotent: false,
|
|
107
|
+
}),
|
|
108
|
+
"world:invite-member": receiver({
|
|
109
|
+
receiver: "world:invite-member",
|
|
110
|
+
summary: "Invite a human member to a workspace",
|
|
111
|
+
request: z.object({ workspace: z.string(), email: z.string().email(), role: z.string().optional() }),
|
|
112
|
+
response: z.object({ ok: z.boolean(), uid: z.string() }),
|
|
113
|
+
effect: "ask", auth: "manage_members",
|
|
114
|
+
}),
|
|
115
|
+
"world:remove-member": receiver({
|
|
116
|
+
receiver: "world:remove-member",
|
|
117
|
+
summary: "Remove a member from a workspace",
|
|
118
|
+
request: z.object({ workspace: z.string(), aid: z.string() }),
|
|
119
|
+
response: ok, effect: "ask", auth: "manage_members", reversible: false,
|
|
120
|
+
}),
|
|
121
|
+
"world:suspend-workspace": receiver({
|
|
122
|
+
receiver: "world:suspend-workspace",
|
|
123
|
+
summary: "Suspend a workspace",
|
|
124
|
+
request: z.object({ workspace: z.string() }),
|
|
125
|
+
response: ok, effect: "ask", auth: "manage_workspace",
|
|
126
|
+
}),
|
|
127
|
+
"world:create-group": receiver({
|
|
128
|
+
receiver: "world:create-group",
|
|
129
|
+
summary: "Create a group in the caller's workspace",
|
|
130
|
+
request: z.object({ name: z.string(), type: z.string(), tags: z.array(z.string()).optional() }),
|
|
131
|
+
response: z.object({ gid: z.string() }), effect: "ask", auth: "manage_groups",
|
|
132
|
+
}),
|
|
133
|
+
"world:update-group": receiver({
|
|
134
|
+
receiver: "world:update-group",
|
|
135
|
+
summary: "Update a group's name, tags, or meta",
|
|
136
|
+
request: z.object({ gid: z.string(), name: z.string().optional(), tags: z.array(z.string()).optional(), meta: z.unknown().optional() }),
|
|
137
|
+
response: ok, effect: "ask", auth: "manage_groups",
|
|
138
|
+
}),
|
|
139
|
+
"world:remove-group": receiver({
|
|
140
|
+
receiver: "world:remove-group",
|
|
141
|
+
summary: "Delete a group",
|
|
142
|
+
request: z.object({ gid: z.string() }), response: ok, effect: "ask", auth: "manage_groups", reversible: false,
|
|
143
|
+
}),
|
|
144
|
+
"world:create-actor": receiver({
|
|
145
|
+
receiver: "world:create-actor",
|
|
146
|
+
summary: "Create an actor (agent or human) in the world",
|
|
147
|
+
request: z.object({
|
|
148
|
+
name: z.string(), type: z.string(), group: z.string().optional(),
|
|
149
|
+
tags: z.array(z.string()).optional(), model: z.string().optional(), prompt: z.string().optional(),
|
|
150
|
+
}),
|
|
151
|
+
response: z.object({ aid: z.string() }), effect: "ask", auth: "manage_actors",
|
|
152
|
+
examples: [{ name: "scout", type: "agent" }],
|
|
153
|
+
}),
|
|
154
|
+
"world:update-actor": receiver({
|
|
155
|
+
receiver: "world:update-actor",
|
|
156
|
+
summary: "Update an actor's name, tags, prompt, or model",
|
|
157
|
+
request: z.object({ aid: z.string(), name: z.string().optional(), tags: z.array(z.string()).optional(), prompt: z.string().optional(), model: z.string().optional() }),
|
|
158
|
+
response: ok, effect: "ask", auth: "manage_actors",
|
|
159
|
+
}),
|
|
160
|
+
"world:update-contact": receiver({
|
|
161
|
+
receiver: "world:update-contact",
|
|
162
|
+
summary: "Update an actor's contact/profile attributes — identity, contact details, professional, personal, CRM metrics",
|
|
163
|
+
request: z.object({
|
|
164
|
+
aid: z.string(),
|
|
165
|
+
// identity
|
|
166
|
+
name: z.string().optional(),
|
|
167
|
+
firstName: z.string().optional(),
|
|
168
|
+
lastName: z.string().optional(),
|
|
169
|
+
nickname: z.string().optional(),
|
|
170
|
+
title: z.string().optional(),
|
|
171
|
+
avatar: z.string().optional(),
|
|
172
|
+
bio: z.string().optional(),
|
|
173
|
+
// contact
|
|
174
|
+
email: z.string().optional(),
|
|
175
|
+
phone: z.string().optional(),
|
|
176
|
+
website: z.string().optional(),
|
|
177
|
+
// professional
|
|
178
|
+
jobTitle: z.string().optional(),
|
|
179
|
+
company: z.string().optional(),
|
|
180
|
+
department: z.string().optional(),
|
|
181
|
+
role: z.string().optional(),
|
|
182
|
+
// personal
|
|
183
|
+
birthday: z.string().optional(),
|
|
184
|
+
gender: z.string().optional(),
|
|
185
|
+
nationality: z.string().optional(),
|
|
186
|
+
timezone: z.string().optional(),
|
|
187
|
+
// address
|
|
188
|
+
street: z.string().optional(),
|
|
189
|
+
city: z.string().optional(),
|
|
190
|
+
region: z.string().optional(),
|
|
191
|
+
postcode: z.string().optional(),
|
|
192
|
+
country: z.string().optional(),
|
|
193
|
+
// crm
|
|
194
|
+
lifecycle: z.string().optional(),
|
|
195
|
+
source: z.string().optional(),
|
|
196
|
+
// numeric crm metrics
|
|
197
|
+
value: z.number().optional(),
|
|
198
|
+
fitScore: z.number().optional(),
|
|
199
|
+
nps: z.number().optional(),
|
|
200
|
+
csat: z.number().optional(),
|
|
201
|
+
}),
|
|
202
|
+
response: ok, effect: "ask", auth: "manage_actors",
|
|
203
|
+
}),
|
|
204
|
+
"world:remove-actor": receiver({
|
|
205
|
+
receiver: "world:remove-actor",
|
|
206
|
+
summary: "Delete an actor",
|
|
207
|
+
request: z.object({ aid: z.string() }), response: ok, effect: "ask", auth: "manage_actors", reversible: false,
|
|
208
|
+
}),
|
|
209
|
+
"world:create-key": receiver({
|
|
210
|
+
receiver: "world:create-key",
|
|
211
|
+
summary: "Mint a scoped API key (PAT) for an actor you own; scope is capped at the actor's role, optional expiresIn (seconds)",
|
|
212
|
+
request: z.object({
|
|
213
|
+
actor: z.string(),
|
|
214
|
+
scope: z.enum(["read", "write", "admin"]).optional(),
|
|
215
|
+
label: z.string().optional(),
|
|
216
|
+
expiresIn: z.number().int().positive().optional(),
|
|
217
|
+
}),
|
|
218
|
+
// Self-service: any authenticated member can mint a key for an actor they own
|
|
219
|
+
// (requireActorOwner is the gate). The scope ceiling prevents privilege escalation.
|
|
220
|
+
response: z.object({ key: z.string(), keyId: z.string(), scope: z.string() }),
|
|
221
|
+
effect: "ask", auth: "member", scope: "write", reversible: false,
|
|
222
|
+
examples: [{ actor: "01ABC", scope: "write", label: "cli" }],
|
|
223
|
+
}),
|
|
224
|
+
"world:list-keys": receiver({
|
|
225
|
+
receiver: "world:list-keys",
|
|
226
|
+
summary: "List active API keys (metadata only — never the secret) for an actor you own",
|
|
227
|
+
request: z.object({ actor: z.string() }),
|
|
228
|
+
response: z.object({
|
|
229
|
+
keys: z.array(z.object({
|
|
230
|
+
keyId: z.string(),
|
|
231
|
+
label: z.string().nullable(),
|
|
232
|
+
scope: z.string(),
|
|
233
|
+
createdAt: z.number(),
|
|
234
|
+
validTo: z.number().nullable(),
|
|
235
|
+
})),
|
|
236
|
+
}),
|
|
237
|
+
effect: "ask", auth: "member", scope: "read", cost: "free", idempotent: true,
|
|
238
|
+
}),
|
|
239
|
+
"world:revoke-key": receiver({
|
|
240
|
+
receiver: "world:revoke-key",
|
|
241
|
+
summary: "Revoke an API key",
|
|
242
|
+
request: z.object({ keyId: z.string() }), response: ok, effect: "ask", auth: "member", scope: "write", reversible: false,
|
|
243
|
+
}),
|
|
244
|
+
"world:create-thing": receiver({
|
|
245
|
+
receiver: "world:create-thing",
|
|
246
|
+
summary: "Create a thing (skill, token, product) in the world",
|
|
247
|
+
request: z.object({ name: z.string(), type: z.string(), group: z.string().optional(), tags: z.array(z.string()).optional(), price: z.number().optional() }),
|
|
248
|
+
response: z.object({ tid: z.string() }), effect: "ask", auth: "manage_things",
|
|
249
|
+
}),
|
|
250
|
+
"world:update-thing": receiver({
|
|
251
|
+
receiver: "world:update-thing",
|
|
252
|
+
summary: "Update a thing's name, tags, price, or meta",
|
|
253
|
+
request: z.object({ tid: z.string(), name: z.string().optional(), tags: z.array(z.string()).optional(), price: z.number().optional(), meta: z.unknown().optional() }),
|
|
254
|
+
response: ok, effect: "ask", auth: "manage_things",
|
|
255
|
+
}),
|
|
256
|
+
"world:remove-thing": receiver({
|
|
257
|
+
receiver: "world:remove-thing",
|
|
258
|
+
summary: "Delete a thing",
|
|
259
|
+
request: z.object({ tid: z.string() }), response: ok, effect: "ask", auth: "manage_things", reversible: false,
|
|
260
|
+
}),
|
|
261
|
+
"world:freeze-path": receiver({
|
|
262
|
+
receiver: "world:freeze-path",
|
|
263
|
+
summary: "Freeze a path so decay cannot weaken it",
|
|
264
|
+
request: z.object({ edge: z.string() }), response: ok, effect: "ask", auth: "manage_paths",
|
|
265
|
+
}),
|
|
266
|
+
"world:unfreeze-path": receiver({
|
|
267
|
+
receiver: "world:unfreeze-path",
|
|
268
|
+
summary: "Unfreeze a path",
|
|
269
|
+
request: z.object({ edge: z.string() }), response: ok, effect: "ask", auth: "manage_paths",
|
|
270
|
+
}),
|
|
271
|
+
"world:remove-path": receiver({
|
|
272
|
+
receiver: "world:remove-path",
|
|
273
|
+
summary: "Delete a path",
|
|
274
|
+
request: z.object({ edge: z.string() }), response: ok, effect: "ask", auth: "manage_paths", reversible: false,
|
|
275
|
+
}),
|
|
276
|
+
"world:create-hypothesis": receiver({
|
|
277
|
+
receiver: "world:create-hypothesis",
|
|
278
|
+
summary: "Record a hypothesis for later verification",
|
|
279
|
+
request: z.object({ claim: z.string(), tags: z.array(z.string()).optional(), confidence: z.number().optional() }),
|
|
280
|
+
response: z.object({ hid: z.string() }), effect: "ask", auth: "manage_learning",
|
|
281
|
+
}),
|
|
282
|
+
"world:promote-hypothesis": receiver({
|
|
283
|
+
receiver: "world:promote-hypothesis",
|
|
284
|
+
summary: "Promote a hypothesis to confirmed",
|
|
285
|
+
request: z.object({ hid: z.string() }), response: ok, effect: "ask", auth: "manage_learning",
|
|
286
|
+
}),
|
|
287
|
+
"world:reject-hypothesis": receiver({
|
|
288
|
+
receiver: "world:reject-hypothesis",
|
|
289
|
+
summary: "Reject a hypothesis with a reason",
|
|
290
|
+
request: z.object({ hid: z.string(), reason: z.string().optional() }), response: ok, effect: "ask", auth: "manage_learning",
|
|
291
|
+
}),
|
|
292
|
+
// ── grant-capability — capability grant (intercepted in signal/[receiver].ts) ──
|
|
293
|
+
"grant-capability": receiver({
|
|
294
|
+
receiver: "grant-capability",
|
|
295
|
+
summary: "Issue a scoped, time-boxed capability grant to a principal",
|
|
296
|
+
request: z.object({
|
|
297
|
+
grantee: z.string().min(1),
|
|
298
|
+
actions: z.array(z.string()).min(1),
|
|
299
|
+
scope: z.string().min(1),
|
|
300
|
+
valid_from: z.number(),
|
|
301
|
+
valid_to: z.number(),
|
|
302
|
+
}).refine((g) => g.valid_to > g.valid_from, { message: "valid_to must be after valid_from", path: ["valid_to"] }),
|
|
303
|
+
response: z.object({ outcome: z.literal("granted"), id: z.string(), grantee: z.string(), scope: z.string() }),
|
|
304
|
+
effect: "ask", auth: "mint_capability", reversible: false,
|
|
305
|
+
}),
|
|
306
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
307
|
+
// C4 — remaining families (sequenced by recipe: identity → groups → BUILD
|
|
308
|
+
// → TRADE → TRANSACT → reads). Request schemas mirror the exact client.ts
|
|
309
|
+
// call sites so a wrong payload is a compile error (the C3 mechanism).
|
|
310
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
311
|
+
// ── identity ──
|
|
312
|
+
"identity:address": receiver({
|
|
313
|
+
receiver: "identity:address",
|
|
314
|
+
summary: "Resolve an actor's wallet address",
|
|
315
|
+
request: z.object({ uid: z.string() }),
|
|
316
|
+
response: z.object({ uid: z.string(), address: z.string() }),
|
|
317
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
318
|
+
}),
|
|
319
|
+
// ── auth (human session) ──
|
|
320
|
+
// auth:sign-in killed (C7): Better Auth handles all human auth; signal/ask pipeline returns dissolved
|
|
321
|
+
"auth:sign-out": receiver({
|
|
322
|
+
receiver: "auth:sign-out",
|
|
323
|
+
summary: "End the current session",
|
|
324
|
+
request: z.object({}),
|
|
325
|
+
response: ok,
|
|
326
|
+
effect: "signal", idempotent: true,
|
|
327
|
+
}),
|
|
328
|
+
// board:join killed (C7): no resolver, no route, no caller
|
|
329
|
+
// agency:push:complete killed (C7): no resolver, no route, no caller
|
|
330
|
+
// agency:friction killed (C7): no resolver, no route, no caller
|
|
331
|
+
// ── groups ──
|
|
332
|
+
"groups:join": receiver({
|
|
333
|
+
receiver: "groups:join",
|
|
334
|
+
summary: "Join a group",
|
|
335
|
+
request: z.object({ gid: z.string() }),
|
|
336
|
+
response: z.object({ ok: z.boolean(), gid: z.string(), role: z.string() }),
|
|
337
|
+
effect: "signal", idempotent: true,
|
|
338
|
+
}),
|
|
339
|
+
"groups:leave": receiver({
|
|
340
|
+
receiver: "groups:leave",
|
|
341
|
+
summary: "Leave a group",
|
|
342
|
+
request: z.object({ gid: z.string() }),
|
|
343
|
+
response: ok,
|
|
344
|
+
effect: "signal", idempotent: true,
|
|
345
|
+
}),
|
|
346
|
+
"groups:invite": receiver({
|
|
347
|
+
receiver: "groups:invite",
|
|
348
|
+
summary: "Invite an actor to a group",
|
|
349
|
+
request: z.object({ gid: z.string(), uid: z.string(), role: z.string().optional() }),
|
|
350
|
+
response: ok,
|
|
351
|
+
effect: "signal", auth: "manage_members",
|
|
352
|
+
}),
|
|
353
|
+
"groups:members": receiver({
|
|
354
|
+
receiver: "groups:members",
|
|
355
|
+
summary: "List a group's members",
|
|
356
|
+
request: z.object({ gid: z.string() }),
|
|
357
|
+
response: z.object({
|
|
358
|
+
gid: z.string(),
|
|
359
|
+
members: z.array(z.object({ uid: z.string(), name: z.string().optional(), role: z.string() })),
|
|
360
|
+
}),
|
|
361
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
362
|
+
}),
|
|
363
|
+
"billing:clients": receiver({
|
|
364
|
+
receiver: "billing:clients",
|
|
365
|
+
summary: "Agency P&L — per-client funded · burned · margin · balance · cap (margin from the ledger)",
|
|
366
|
+
request: z.object({}).optional(),
|
|
367
|
+
response: z.object({
|
|
368
|
+
agency: z.object({ slug: z.string(), name: z.string().nullable(), markup_pct: z.number(), pool: z.number() }).nullable(),
|
|
369
|
+
clients: z.array(z.object({
|
|
370
|
+
slug: z.string(), name: z.string().nullable(), plan: z.string(),
|
|
371
|
+
funded: z.number(), burned: z.number(), margin: z.number(), balance: z.number(), cap: z.number().nullable(),
|
|
372
|
+
})),
|
|
373
|
+
}),
|
|
374
|
+
effect: "ask", auth: "manage_clients", cost: "free", idempotent: true,
|
|
375
|
+
}),
|
|
376
|
+
// paths:bridge killed (C7): no resolver, no route, no caller
|
|
377
|
+
// ── subscriptions ──
|
|
378
|
+
"subscriptions:register": receiver({
|
|
379
|
+
receiver: "subscriptions:register",
|
|
380
|
+
summary: "Subscribe to a receiver's events by tag",
|
|
381
|
+
request: z.object({
|
|
382
|
+
receiver: z.string(),
|
|
383
|
+
tags: z.array(z.string()),
|
|
384
|
+
scope: z.enum(["private", "public"]).optional(),
|
|
385
|
+
}),
|
|
386
|
+
response: ok,
|
|
387
|
+
effect: "signal", idempotent: true,
|
|
388
|
+
}),
|
|
389
|
+
// ── agents (TRADE / lifecycle) ──
|
|
390
|
+
"agents:register": receiver({
|
|
391
|
+
receiver: "agents:register",
|
|
392
|
+
summary: "Register an agent as a sellable actor with capabilities",
|
|
393
|
+
request: z.object({
|
|
394
|
+
uid: z.string(),
|
|
395
|
+
kind: z.string().optional(),
|
|
396
|
+
capabilities: z.array(z.object({ skill: z.string(), price: z.number().optional() })).optional(),
|
|
397
|
+
wallet: z.string().optional(),
|
|
398
|
+
chain: z.string().optional(),
|
|
399
|
+
}),
|
|
400
|
+
response: RegisterResponseSchema,
|
|
401
|
+
effect: "ask", idempotent: true,
|
|
402
|
+
}),
|
|
403
|
+
"agents:commend": receiver({
|
|
404
|
+
receiver: "agents:commend",
|
|
405
|
+
summary: "Commend an agent — strengthen its reputation path",
|
|
406
|
+
request: z.object({ uid: z.string() }),
|
|
407
|
+
response: AgentActionResponseSchema,
|
|
408
|
+
effect: "signal",
|
|
409
|
+
}),
|
|
410
|
+
"agents:flag": receiver({
|
|
411
|
+
receiver: "agents:flag",
|
|
412
|
+
summary: "Flag an agent — add resistance to its reputation path",
|
|
413
|
+
request: z.object({ uid: z.string() }),
|
|
414
|
+
response: AgentActionResponseSchema,
|
|
415
|
+
effect: "signal",
|
|
416
|
+
}),
|
|
417
|
+
"agents:status": receiver({
|
|
418
|
+
receiver: "agents:status",
|
|
419
|
+
summary: "Set an agent active or inactive",
|
|
420
|
+
request: z.object({ uid: z.string(), status: z.string() }),
|
|
421
|
+
response: AgentStatusResponseSchema,
|
|
422
|
+
effect: "signal", idempotent: true,
|
|
423
|
+
}),
|
|
424
|
+
"agents:capabilities": receiver({
|
|
425
|
+
receiver: "agents:capabilities",
|
|
426
|
+
summary: "List an agent's published capabilities",
|
|
427
|
+
request: z.object({ uid: z.string() }),
|
|
428
|
+
response: z.array(CapabilityItemSchema),
|
|
429
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
430
|
+
}),
|
|
431
|
+
// agents:deploy-on-behalf killed (C7): no resolver, no route, no caller
|
|
432
|
+
// ── pay (TRANSACT — onchain settlement) ──
|
|
433
|
+
"pay:weight": receiver({
|
|
434
|
+
receiver: "pay:weight",
|
|
435
|
+
summary: "Pay for a task by weighting the path between two actors",
|
|
436
|
+
request: z.object({ from: z.string(), to: z.string(), task: z.string(), amount: z.number() }),
|
|
437
|
+
response: PayResponseSchema,
|
|
438
|
+
effect: "ask", cost: "variable", settles: "onchain", reversible: false, simulatable: true,
|
|
439
|
+
}),
|
|
440
|
+
// ── market (A2A negotiation, C2) ──
|
|
441
|
+
"market:offer": receiver({
|
|
442
|
+
receiver: "market:offer",
|
|
443
|
+
summary: "Buyer creates a Deal at OFFER stage — initiates A2A negotiation",
|
|
444
|
+
request: z.object({
|
|
445
|
+
id: z.string().uuid().optional(),
|
|
446
|
+
seller: z.string().min(1),
|
|
447
|
+
skill: z.string().min(1),
|
|
448
|
+
price: z.number().nonnegative(),
|
|
449
|
+
currency: z.string().default("credits"),
|
|
450
|
+
deadline: z.string().datetime(),
|
|
451
|
+
}),
|
|
452
|
+
response: z.union([
|
|
453
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
454
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
455
|
+
]),
|
|
456
|
+
effect: "ask", auth: "required", reversible: true, idempotent: false,
|
|
457
|
+
}),
|
|
458
|
+
"market:counter": receiver({
|
|
459
|
+
receiver: "market:counter",
|
|
460
|
+
summary: "Seller revises deal terms — stays at OFFER, bumps version",
|
|
461
|
+
request: z.object({
|
|
462
|
+
dealId: z.string().min(1),
|
|
463
|
+
price: z.number().nonnegative().optional(),
|
|
464
|
+
deadline: z.string().datetime().optional(),
|
|
465
|
+
skill: z.string().optional(),
|
|
466
|
+
}),
|
|
467
|
+
response: z.union([
|
|
468
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
469
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
470
|
+
]),
|
|
471
|
+
effect: "ask", auth: "required", reversible: true, idempotent: false,
|
|
472
|
+
}),
|
|
473
|
+
"market:accept": receiver({
|
|
474
|
+
receiver: "market:accept",
|
|
475
|
+
summary: "Buyer accepts deal — OFFER → ESCROW",
|
|
476
|
+
request: z.object({ dealId: z.string().min(1) }),
|
|
477
|
+
response: z.union([
|
|
478
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
479
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
480
|
+
]),
|
|
481
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
482
|
+
}),
|
|
483
|
+
"market:reject": receiver({
|
|
484
|
+
receiver: "market:reject",
|
|
485
|
+
summary: "Buyer rejects deal — OFFER → FADE",
|
|
486
|
+
request: z.object({ dealId: z.string().min(1) }),
|
|
487
|
+
response: z.union([
|
|
488
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
489
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
490
|
+
]),
|
|
491
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
492
|
+
}),
|
|
493
|
+
"market:deliver": receiver({
|
|
494
|
+
receiver: "market:deliver",
|
|
495
|
+
summary: "Seller delivers work — EXECUTE → VERIFY",
|
|
496
|
+
request: z.object({ dealId: z.string().min(1), result: z.record(z.string(), z.unknown()).optional() }),
|
|
497
|
+
response: z.union([
|
|
498
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
499
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
500
|
+
]),
|
|
501
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
502
|
+
}),
|
|
503
|
+
"market:verify": receiver({
|
|
504
|
+
receiver: "market:verify",
|
|
505
|
+
summary: "Buyer scores delivered work — VERIFY → SETTLE (≥0.65) or DISPUTE (<0.65)",
|
|
506
|
+
request: z.object({
|
|
507
|
+
dealId: z.string().min(1),
|
|
508
|
+
fit: z.number().min(0).max(1),
|
|
509
|
+
form: z.number().min(0).max(1),
|
|
510
|
+
truth: z.number().min(0).max(1),
|
|
511
|
+
taste: z.number().min(0).max(1),
|
|
512
|
+
}),
|
|
513
|
+
response: z.union([
|
|
514
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }), scores: z.object({ fit: z.number(), form: z.number(), truth: z.number(), taste: z.number() }) }),
|
|
515
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
516
|
+
]),
|
|
517
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
518
|
+
}),
|
|
519
|
+
"market:settle": receiver({
|
|
520
|
+
receiver: "market:settle",
|
|
521
|
+
summary: "Release escrow payment — SETTLE → RECEIPT",
|
|
522
|
+
request: z.object({ dealId: z.string().min(1) }),
|
|
523
|
+
response: z.union([
|
|
524
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
525
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
526
|
+
]),
|
|
527
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
528
|
+
}),
|
|
529
|
+
"market:dispute": receiver({
|
|
530
|
+
receiver: "market:dispute",
|
|
531
|
+
summary: "Escalate an active deal to DISPUTE — either party may call",
|
|
532
|
+
request: z.object({ dealId: z.string().min(1) }),
|
|
533
|
+
response: z.union([
|
|
534
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }) }),
|
|
535
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
536
|
+
]),
|
|
537
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
538
|
+
}),
|
|
539
|
+
"market:escrow": receiver({
|
|
540
|
+
receiver: "market:escrow",
|
|
541
|
+
summary: "Buyer locks payment via pay.one.ie — ESCROW → EXECUTE on confirmed tx",
|
|
542
|
+
request: z.object({ dealId: z.string().min(1) }),
|
|
543
|
+
response: z.union([
|
|
544
|
+
z.object({ ok: z.literal(true), deal: z.object({ id: z.string(), stage: z.string(), version: z.number() }), escrowRef: z.string() }),
|
|
545
|
+
z.object({ ok: z.literal(false), error: z.string(), deal: z.object({ id: z.string(), stage: z.string() }).optional() }),
|
|
546
|
+
]),
|
|
547
|
+
effect: "ask", auth: "required", reversible: false, idempotent: false,
|
|
548
|
+
}),
|
|
549
|
+
// ── market (TRADE) ──
|
|
550
|
+
"market:hire": receiver({
|
|
551
|
+
receiver: "market:hire",
|
|
552
|
+
summary: "Hire an agent for a skill — opens a chat or returns an escrow template",
|
|
553
|
+
request: z.object({ providerUid: z.string(), skillId: z.string(), initialMessage: z.string().optional() }),
|
|
554
|
+
response: z.union([
|
|
555
|
+
z.object({ ok: z.literal(true), groupId: z.string(), chatUrl: z.string() }),
|
|
556
|
+
z.object({
|
|
557
|
+
status: z.literal(402), code: z.string(),
|
|
558
|
+
escrow_template: z.record(z.string(), z.unknown()), expires_at: z.string(),
|
|
559
|
+
}),
|
|
560
|
+
]),
|
|
561
|
+
effect: "ask", cost: "variable", settles: "onchain", reversible: false, simulatable: true,
|
|
562
|
+
}),
|
|
563
|
+
"market:bounty": receiver({
|
|
564
|
+
receiver: "market:bounty",
|
|
565
|
+
summary: "Post a bounty for a skill, backed by an escrow",
|
|
566
|
+
request: z.object({
|
|
567
|
+
skillId: z.string(), sellerUid: z.string(), posterUid: z.string(), price: z.number(),
|
|
568
|
+
tags: z.array(z.string()).optional(),
|
|
569
|
+
content: z.record(z.string(), z.unknown()).optional(),
|
|
570
|
+
rubric: z.object({
|
|
571
|
+
fit: z.number().optional(), form: z.number().optional(),
|
|
572
|
+
truth: z.number().optional(), taste: z.number().optional(),
|
|
573
|
+
}).optional(),
|
|
574
|
+
deadline: z.string().optional(),
|
|
575
|
+
posterUnitObjectId: z.string().optional(),
|
|
576
|
+
workerUnitObjectId: z.string().optional(),
|
|
577
|
+
pathObjectId: z.string().optional(),
|
|
578
|
+
}),
|
|
579
|
+
response: z.object({ id: z.string(), escrowId: z.string().optional(), data: z.record(z.string(), z.unknown()) }),
|
|
580
|
+
effect: "ask", cost: "variable", settles: "onchain", reversible: false, simulatable: true,
|
|
581
|
+
}),
|
|
582
|
+
"market:bounties": receiver({
|
|
583
|
+
receiver: "market:bounties",
|
|
584
|
+
summary: "List bounties, optionally filtered by seller or poster",
|
|
585
|
+
request: z.object({ seller: z.string().optional(), poster: z.string().optional() }),
|
|
586
|
+
response: z.array(z.object({
|
|
587
|
+
id: z.string(), skillId: z.string(), sellerUid: z.string(), posterUid: z.string(), price: z.number(),
|
|
588
|
+
tags: z.array(z.string()).optional(), deadline: z.string().optional(), status: z.string(),
|
|
589
|
+
})),
|
|
590
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
591
|
+
}),
|
|
592
|
+
"market:claim": receiver({
|
|
593
|
+
receiver: "market:claim",
|
|
594
|
+
summary: "Claim an open bounty — atomically marks it picked and binds the claimant",
|
|
595
|
+
request: z.object({ bountyId: z.string() }),
|
|
596
|
+
response: z.union([
|
|
597
|
+
z.object({ ok: z.literal(true), bountyId: z.string(), claimantUid: z.string() }),
|
|
598
|
+
z.object({ ok: z.literal(false), error: z.string() }),
|
|
599
|
+
]),
|
|
600
|
+
effect: "ask", cost: "free", reversible: false, idempotent: false,
|
|
601
|
+
}),
|
|
602
|
+
"market:list": receiver({
|
|
603
|
+
receiver: "market:list",
|
|
604
|
+
summary: "List the capability market",
|
|
605
|
+
request: z.object({ tag: z.string().optional(), maxPrice: z.number().optional() }),
|
|
606
|
+
response: z.object({ capabilities: z.array(z.unknown()) }),
|
|
607
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
608
|
+
}),
|
|
609
|
+
// ── capabilities ──
|
|
610
|
+
"capabilities:publish": receiver({
|
|
611
|
+
receiver: "capabilities:publish",
|
|
612
|
+
summary: "Publish a capability (skill listing) to the market",
|
|
613
|
+
request: z.object({
|
|
614
|
+
skillId: z.string(), name: z.string(), price: z.number(),
|
|
615
|
+
mode: z.string().optional(), visibility: z.string().optional(), scope: z.string().optional(),
|
|
616
|
+
tags: z.array(z.string()).optional(),
|
|
617
|
+
rubricThresholds: z.object({
|
|
618
|
+
fit: z.number().optional(), form: z.number().optional(),
|
|
619
|
+
truth: z.number().optional(), taste: z.number().optional(),
|
|
620
|
+
}).optional(),
|
|
621
|
+
}),
|
|
622
|
+
response: z.object({ ok: z.literal(true), sid: z.string(), scope: z.string() }),
|
|
623
|
+
effect: "ask",
|
|
624
|
+
}),
|
|
625
|
+
// loop:close killed (C7): no resolver, no route, no caller
|
|
626
|
+
// ── reads (free · idempotent) ──
|
|
627
|
+
"signals:list": receiver({
|
|
628
|
+
receiver: "signals:list",
|
|
629
|
+
summary: "List recent signals",
|
|
630
|
+
request: z.object({
|
|
631
|
+
limit: z.number().optional(), since: z.number().optional(),
|
|
632
|
+
from: z.number().optional(), to: z.number().optional(),
|
|
633
|
+
}),
|
|
634
|
+
response: z.array(z.object({
|
|
635
|
+
id: z.string(), from: z.string(), to: z.string(), skill: z.string().optional(),
|
|
636
|
+
outcome: z.enum(["success", "failure", "timeout"]), revenue: z.number(), ts: z.number(),
|
|
637
|
+
})),
|
|
638
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
639
|
+
}),
|
|
640
|
+
"stats:current": receiver({
|
|
641
|
+
receiver: "stats:current",
|
|
642
|
+
summary: "Current world stats — units, skills, highways, revenue, signals",
|
|
643
|
+
request: z.object({}),
|
|
644
|
+
response: StatsSchema,
|
|
645
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
646
|
+
}),
|
|
647
|
+
"dashboard:usage": receiver({
|
|
648
|
+
receiver: "dashboard:usage",
|
|
649
|
+
summary: "Caller's plan usage — calls, agents, limits",
|
|
650
|
+
request: z.object({}),
|
|
651
|
+
response: z.object({
|
|
652
|
+
tier: z.string(), calls_this_month: z.number(), agents_count: z.number(),
|
|
653
|
+
api_limit: z.number(), agent_limit: z.number(), loops: z.array(z.string()),
|
|
654
|
+
highways_count: z.number(), upgrade_url: z.string(),
|
|
655
|
+
}),
|
|
656
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
657
|
+
}),
|
|
658
|
+
"world:state": receiver({
|
|
659
|
+
receiver: "world:state",
|
|
660
|
+
summary: "Full world snapshot — units, edges, highways, tags, stats",
|
|
661
|
+
request: z.object({}),
|
|
662
|
+
response: z.object({}).passthrough(),
|
|
663
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
664
|
+
}),
|
|
665
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
666
|
+
// C5 — meta: the self-describing surface. Pure reads an agent uses to learn
|
|
667
|
+
// the catalog, a receiver's schema, and its own memory before acting. The
|
|
668
|
+
// catalog/schema handlers are pure projections over RECEIVERS (see meta.ts).
|
|
669
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
670
|
+
"meta:catalog": receiver({
|
|
671
|
+
receiver: "meta:catalog",
|
|
672
|
+
summary: "List every receiver the caller can use (with cost/reversibility/settlement), or a goal's recipe",
|
|
673
|
+
request: z.object({ goal: z.enum(["spine", "build", "trade", "transact"]).optional() }),
|
|
674
|
+
response: z.union([
|
|
675
|
+
z.array(z.object({
|
|
676
|
+
receiver: z.string(), summary: z.string(), effect: z.enum(["signal", "ask"]),
|
|
677
|
+
auth: z.string().optional(), reversible: z.boolean().optional(),
|
|
678
|
+
settles: z.enum(["none", "offchain", "onchain"]).optional(),
|
|
679
|
+
}).passthrough()),
|
|
680
|
+
z.object({ goal: z.string(), recipe: z.array(z.string()) }),
|
|
681
|
+
]),
|
|
682
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
683
|
+
}),
|
|
684
|
+
"meta:schema": receiver({
|
|
685
|
+
receiver: "meta:schema",
|
|
686
|
+
summary: "JSON Schema for one receiver's request + response — read it before you call",
|
|
687
|
+
request: z.object({ receiver: z.string() }),
|
|
688
|
+
response: z.object({
|
|
689
|
+
receiver: z.string(), summary: z.string(),
|
|
690
|
+
request: z.unknown(), response: z.unknown(),
|
|
691
|
+
}),
|
|
692
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
693
|
+
}),
|
|
694
|
+
"meta:recall": receiver({
|
|
695
|
+
receiver: "meta:recall",
|
|
696
|
+
summary: "Recall the caller's hypotheses (memory), optionally filtered by a search term",
|
|
697
|
+
request: z.object({ match: z.string().optional(), limit: z.number().optional() }),
|
|
698
|
+
response: z.object({
|
|
699
|
+
hypotheses: z.array(z.object({
|
|
700
|
+
hid: z.string(), claim: z.string(), status: z.string(), confidence: z.number().nullable(),
|
|
701
|
+
})),
|
|
702
|
+
}),
|
|
703
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
704
|
+
}),
|
|
705
|
+
// ── actor discovery + messaging ──────────────────────────────────────────
|
|
706
|
+
"actors:find": receiver({
|
|
707
|
+
receiver: "actors:find",
|
|
708
|
+
summary: "Find agents on the marketplace by name fragment or skill — marketplace discovery only",
|
|
709
|
+
request: z.object({
|
|
710
|
+
// human is excluded: personal names/emails are PII, not marketplace data.
|
|
711
|
+
type: z.enum(["agent", "world"]).optional(),
|
|
712
|
+
search: z.string().max(100).optional(),
|
|
713
|
+
skill: z.string().max(100).optional(),
|
|
714
|
+
limit: z.number().max(100).optional(),
|
|
715
|
+
}),
|
|
716
|
+
response: z.object({
|
|
717
|
+
actors: z.array(z.object({ uid: z.string(), name: z.string(), type: z.string() })),
|
|
718
|
+
total: z.number(),
|
|
719
|
+
}),
|
|
720
|
+
effect: "ask", cost: "free", idempotent: true,
|
|
721
|
+
}),
|
|
722
|
+
"peer:message": receiver({
|
|
723
|
+
receiver: "peer:message",
|
|
724
|
+
summary: "Send an async message to another agent's inbox — instant store, no LLM, no streaming",
|
|
725
|
+
request: z.object({ to: z.string(), content: z.string(), from: z.string().optional() }),
|
|
726
|
+
response: z.object({ ok: z.boolean(), id: z.string().optional(), ts: z.number().optional(), to: z.string().optional(), from: z.string().optional(), error: z.string().optional() }),
|
|
727
|
+
effect: "ask", idempotent: false,
|
|
728
|
+
}),
|
|
729
|
+
"chat:send": receiver({
|
|
730
|
+
receiver: "chat:send",
|
|
731
|
+
summary: "Send a message to a group the caller is a member of — sender is always the authenticated caller",
|
|
732
|
+
request: z.object({
|
|
733
|
+
group: z.string(),
|
|
734
|
+
text: z.string(),
|
|
735
|
+
// sender is NOT in the schema — derived server-side from the authenticated caller uid.
|
|
736
|
+
slug: z.string().optional(),
|
|
737
|
+
}),
|
|
738
|
+
response: z.object({ ok: z.boolean(), reply: z.string().optional(), error: z.string().optional() }),
|
|
739
|
+
effect: "ask", auth: "member",
|
|
740
|
+
}),
|
|
741
|
+
// ── booking — one calendar, two doors (text/booking-plan.md §5) ───────────────
|
|
742
|
+
// Both public-bookable: a customer with no account books a slot. The provider
|
|
743
|
+
// side (configure a service) is the separate, gated booking:configure.
|
|
744
|
+
"booking:list-slots": receiver({
|
|
745
|
+
receiver: "booking:list-slots",
|
|
746
|
+
summary: "List open slots for a workspace's service on a date (or next open days)",
|
|
747
|
+
request: z.object({
|
|
748
|
+
slug: z.string(), // provider workspace
|
|
749
|
+
service: z.string().optional(), // service_id; omitted → the workspace's first active
|
|
750
|
+
date: z.string().optional(), // 'YYYY-MM-DD'; omitted → next N open days
|
|
751
|
+
days: z.number().int().min(1).max(14).optional(), // window size when date omitted
|
|
752
|
+
}),
|
|
753
|
+
response: z.object({
|
|
754
|
+
service: z.object({
|
|
755
|
+
service_id: z.string(), name: z.string(), duration_min: z.number(),
|
|
756
|
+
price: z.number(), currency: z.string(),
|
|
757
|
+
}).nullable(),
|
|
758
|
+
slots: z.array(z.object({ date: z.string(), times: z.array(z.string()) })), // CalendarCard shape
|
|
759
|
+
error: z.string().optional(),
|
|
760
|
+
}),
|
|
761
|
+
effect: "ask", cost: "free", idempotent: true, simulatable: false,
|
|
762
|
+
examples: [{ slug: "clearwater", date: "2026-06-10" }],
|
|
763
|
+
}),
|
|
764
|
+
"booking:create": receiver({
|
|
765
|
+
receiver: "booking:create",
|
|
766
|
+
summary: "Hold a slot for a customer; returns a ref and a payment intent when price > 0",
|
|
767
|
+
request: z.object({
|
|
768
|
+
slug: z.string(),
|
|
769
|
+
service: z.string(),
|
|
770
|
+
slotDate: z.string(), // 'YYYY-MM-DD'
|
|
771
|
+
slotTime: z.string(), // 'HH:MM' 24h, slot start
|
|
772
|
+
customer: z.object({ name: z.string(), email: z.string().email().optional() }),
|
|
773
|
+
paymentRail: z.enum(["stripe", "sui"]).optional(), // resolver overrides by caller kind
|
|
774
|
+
}),
|
|
775
|
+
response: z.object({
|
|
776
|
+
ok: z.boolean(),
|
|
777
|
+
ref: z.string().optional(),
|
|
778
|
+
status: z.enum(["pending", "confirmed"]).optional(),
|
|
779
|
+
paymentRail: z.enum(["stripe", "sui"]).nullable().optional(),
|
|
780
|
+
paymentIntent: z.object({ clientSecret: z.string(), amount: z.number() }).optional(), // human, price>0
|
|
781
|
+
escrow: z.object({ escrowId: z.string(), bounty: z.number(), deadline: z.string() }).optional(), // agent
|
|
782
|
+
error: z.string().optional(), // 'slot_taken' | 'closed' | 'unknown_service'
|
|
783
|
+
}),
|
|
784
|
+
effect: "ask", cost: "variable", settles: "offchain", reversible: false,
|
|
785
|
+
simulatable: true, idempotent: true, // idempotencyKey dedupes a retried hold
|
|
786
|
+
examples: [{ slug: "clearwater", service: "svc_x", slotDate: "2026-06-10",
|
|
787
|
+
slotTime: "15:00", customer: { name: "Sarah", email: "s@ex.com" } }],
|
|
788
|
+
}),
|
|
789
|
+
// booking:configure — the ONE provider-gated booking receiver (§10). Unlike the
|
|
790
|
+
// two public-bookable receivers above, the resolver re-walks
|
|
791
|
+
// can(actor, group, "manage_clients") server-side and UPSERTs only the caller's
|
|
792
|
+
// own service rows. NOT public-bookable.
|
|
793
|
+
"booking:configure": receiver({
|
|
794
|
+
receiver: "booking:configure",
|
|
795
|
+
summary: "Provider-gated: create or update a bookable service (hours, slot length, price, currency, tz, active)",
|
|
796
|
+
request: z.object({
|
|
797
|
+
slug: z.string(), // the workspace; the write scope (re-walked)
|
|
798
|
+
actorId: z.string().optional(), // re-walk subject (gateway-forwarded)
|
|
799
|
+
service: z.string().optional(), // service_id to update; omitted → create
|
|
800
|
+
name: z.string(),
|
|
801
|
+
duration_min: z.number().int().positive(),
|
|
802
|
+
price: z.number().int().nonnegative().optional(),
|
|
803
|
+
currency: z.string().optional(),
|
|
804
|
+
hours_json: z.array(z.array(z.object({ start: z.string(), end: z.string() }))), // 7 entries, 0=Sun
|
|
805
|
+
tz: z.string().optional(),
|
|
806
|
+
active: z.boolean().optional(),
|
|
807
|
+
}),
|
|
808
|
+
response: z.object({ ok: z.boolean(), service_id: z.string().optional(), error: z.string().optional() }),
|
|
809
|
+
effect: "ask", cost: "free", idempotent: true, reversible: true, auth: "manage_clients",
|
|
810
|
+
examples: [{ slug: "clearwater", name: "Consultation", duration_min: 30, price: 4000, currency: "gbp",
|
|
811
|
+
hours_json: [[], [{ start: "09:00", end: "17:00" }], [], [], [], [], []] }],
|
|
812
|
+
}),
|
|
813
|
+
// booking:list-bookings — the provider's own appointment list for a month (§6
|
|
814
|
+
// web surface). Tenant-private read: the resolver scopes to the authenticated
|
|
815
|
+
// owner, never the body slug, so a caller only ever sees their own workspace.
|
|
816
|
+
"booking:list-bookings": receiver({
|
|
817
|
+
receiver: "booking:list-bookings",
|
|
818
|
+
summary: "Provider-gated: list a workspace's bookings for a month (customer, time, service, status)",
|
|
819
|
+
request: z.object({
|
|
820
|
+
slug: z.string(), // workspace (informational; gate re-scopes to caller)
|
|
821
|
+
month: z.string().optional(), // 'YYYY-MM'; omitted → current month
|
|
822
|
+
}),
|
|
823
|
+
response: z.object({
|
|
824
|
+
bookings: z.array(z.object({
|
|
825
|
+
id: z.string(), ref: z.string(), service_name: z.string(),
|
|
826
|
+
slot_date: z.string(), slot_time: z.string(),
|
|
827
|
+
customer_name: z.string(), status: z.string(),
|
|
828
|
+
})),
|
|
829
|
+
error: z.string().optional(),
|
|
830
|
+
}),
|
|
831
|
+
effect: "ask", cost: "free", idempotent: true, auth: "manage_clients",
|
|
832
|
+
examples: [{ slug: "clearwater", month: "2026-06" }],
|
|
833
|
+
}),
|
|
834
|
+
// booking:cancel — provider dissolves a booking by ref, releasing the slot
|
|
835
|
+
// immediately (the partial unique index drops dissolved rows from scope, §9).
|
|
836
|
+
// Tenant-private write: scoped to the authenticated owner. Idempotent.
|
|
837
|
+
"booking:cancel": receiver({
|
|
838
|
+
receiver: "booking:cancel",
|
|
839
|
+
summary: "Provider-gated: dissolve a booking by ref, releasing the slot",
|
|
840
|
+
request: z.object({
|
|
841
|
+
slug: z.string(),
|
|
842
|
+
ref: z.string(),
|
|
843
|
+
}),
|
|
844
|
+
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
845
|
+
effect: "ask", cost: "free", idempotent: true, reversible: false, auth: "manage_clients",
|
|
846
|
+
examples: [{ slug: "clearwater", ref: "CLE-2026-4821" }],
|
|
847
|
+
}),
|
|
848
|
+
// ── workflows — define an SOP, run it, watch it learn (text/workflows-plan.md) ──
|
|
849
|
+
// Every workflow op is a typed receiver. No new REST routes. apply-diff is
|
|
850
|
+
// simulatable: simulate=true validates the WorkflowDiff (incl. DAG acyclicity)
|
|
851
|
+
// and commits nothing — the chat-authoring preview path.
|
|
852
|
+
"workflow:list": receiver({
|
|
853
|
+
receiver: "workflow:list",
|
|
854
|
+
summary: "List a workspace's workflows (D1 mirror); pass templates=true for the public SOP catalog",
|
|
855
|
+
request: z.object({
|
|
856
|
+
slug: z.string().optional(),
|
|
857
|
+
templates: z.boolean().optional(),
|
|
858
|
+
}),
|
|
859
|
+
response: z.object({
|
|
860
|
+
workflows: z.array(z.object({
|
|
861
|
+
id: z.string(), name: z.string(), description: z.string().optional(), step_count: z.number(),
|
|
862
|
+
status: z.string(), last_run_status: z.string().nullable(),
|
|
863
|
+
})),
|
|
864
|
+
error: z.string().optional(),
|
|
865
|
+
}),
|
|
866
|
+
effect: "ask", cost: "free", idempotent: true, simulatable: false, auth: "view_workflows",
|
|
867
|
+
examples: [{ slug: "acme" }, { templates: true }],
|
|
868
|
+
}),
|
|
869
|
+
"workflow:get": receiver({
|
|
870
|
+
receiver: "workflow:get",
|
|
871
|
+
summary: "Fetch one workflow's full graph — steps (kind, config, position) and edges (with conditions)",
|
|
872
|
+
request: z.object({ workflowId: z.string() }),
|
|
873
|
+
response: z.object({
|
|
874
|
+
id: z.string(), name: z.string(), status: z.string(),
|
|
875
|
+
steps: z.array(z.object({
|
|
876
|
+
id: z.string(), kind: StepKind, name: z.string(),
|
|
877
|
+
config: z.string(), position: z.string().optional(),
|
|
878
|
+
})),
|
|
879
|
+
edges: z.array(z.object({
|
|
880
|
+
source: z.string(), target: z.string(),
|
|
881
|
+
strength: z.number(), resistance: z.number(),
|
|
882
|
+
condition: z.string().optional(),
|
|
883
|
+
})),
|
|
884
|
+
error: z.string().optional(),
|
|
885
|
+
}),
|
|
886
|
+
effect: "ask", cost: "free", idempotent: true, simulatable: false, auth: "view_workflows",
|
|
887
|
+
examples: [{ workflowId: "wf_abc" }],
|
|
888
|
+
}),
|
|
889
|
+
"workflow:runs": receiver({
|
|
890
|
+
receiver: "workflow:runs",
|
|
891
|
+
summary: "List recent runs of a workflow (D1 workflow_run) for the monitor + history surfaces",
|
|
892
|
+
request: z.object({ workflowId: z.string(), runId: z.string().optional(), limit: z.number().int().min(1).max(200).optional() }),
|
|
893
|
+
response: z.object({
|
|
894
|
+
runs: z.array(z.object({
|
|
895
|
+
id: z.string(), status: z.string(),
|
|
896
|
+
started_at: z.number(), finished_at: z.number().nullable(),
|
|
897
|
+
})),
|
|
898
|
+
events: z.array(z.object({
|
|
899
|
+
step_id: z.string(), kind: z.string(), status: z.string().nullable(),
|
|
900
|
+
latency_ms: z.number().nullable(), at: z.number(),
|
|
901
|
+
})).optional(),
|
|
902
|
+
error: z.string().optional(),
|
|
903
|
+
}),
|
|
904
|
+
effect: "ask", cost: "free", idempotent: true, simulatable: false, auth: "view_workflows",
|
|
905
|
+
examples: [{ workflowId: "wf_abc", limit: 20 }, { workflowId: "wf_abc", runId: "run_1" }],
|
|
906
|
+
}),
|
|
907
|
+
"workflow:create": receiver({
|
|
908
|
+
receiver: "workflow:create",
|
|
909
|
+
summary: "Create a blank workflow (group group-type=workflow) — optionally cloned from a template",
|
|
910
|
+
request: z.object({
|
|
911
|
+
slug: z.string().optional(),
|
|
912
|
+
name: z.string(),
|
|
913
|
+
description: z.string().optional(), // defaults from the cloned template
|
|
914
|
+
fromTemplate: z.string().optional(),
|
|
915
|
+
simulate: z.boolean().optional(),
|
|
916
|
+
}),
|
|
917
|
+
response: z.object({ id: z.string(), workflowId: z.string() }),
|
|
918
|
+
effect: "ask", cost: "free", reversible: true, idempotent: false, simulatable: true,
|
|
919
|
+
auth: "manage_workflows",
|
|
920
|
+
examples: [{ name: "Client Onboarding" }, { name: "demo", simulate: true }],
|
|
921
|
+
}),
|
|
922
|
+
"workflow:apply-diff": receiver({
|
|
923
|
+
receiver: "workflow:apply-diff",
|
|
924
|
+
summary: "Apply a WorkflowDiff (add/remove/connect/disconnect/update). simulate=true validates the DAG without persisting",
|
|
925
|
+
request: z.object({
|
|
926
|
+
workflowId: z.string(),
|
|
927
|
+
diff: WorkflowDiffSchema,
|
|
928
|
+
simulate: z.boolean().optional(),
|
|
929
|
+
version: z.number().int().optional(), // optimistic lock — stale → conflict
|
|
930
|
+
}),
|
|
931
|
+
response: z.object({
|
|
932
|
+
ok: z.boolean(),
|
|
933
|
+
stepCount: z.number().optional(),
|
|
934
|
+
idMap: z.record(z.string(), z.string()).optional(), // tempId → persisted id
|
|
935
|
+
error: z.string().optional(), // 'cycle_detected' | 'conflict' | 'invalid_diff'
|
|
936
|
+
}),
|
|
937
|
+
effect: "ask", cost: "free", reversible: true, idempotent: false, simulatable: true,
|
|
938
|
+
auth: "manage_workflows",
|
|
939
|
+
examples: [{ workflowId: "wf_abc", diff: { add: [{ tempId: "s1", kind: "trigger", name: "On signup", config: "{}" }] }, simulate: true }],
|
|
940
|
+
}),
|
|
941
|
+
"workflow:run": receiver({
|
|
942
|
+
receiver: "workflow:run",
|
|
943
|
+
summary: "Start a run — spawns the WorkflowRun DO, executes each step, marks path strength on traversed edges",
|
|
944
|
+
request: z.object({
|
|
945
|
+
workflowId: z.string(),
|
|
946
|
+
triggerPayload: z.record(z.string(), z.unknown()).optional(),
|
|
947
|
+
idempotencyKey: z.string().optional(),
|
|
948
|
+
}),
|
|
949
|
+
response: z.object({ runId: z.string(), status: z.string(), error: z.string().optional() }),
|
|
950
|
+
effect: "ask", cost: "variable", reversible: false, idempotent: true, simulatable: false, settles: "none",
|
|
951
|
+
auth: "manage_workflows",
|
|
952
|
+
examples: [{ workflowId: "wf_abc" }],
|
|
953
|
+
}),
|
|
954
|
+
"human:resolve": receiver({
|
|
955
|
+
receiver: "human:resolve",
|
|
956
|
+
summary: "Resolve a suspended human step — carries { runId, stepId, decision | formPayload } to the run DO",
|
|
957
|
+
request: z.object({
|
|
958
|
+
runId: z.string(),
|
|
959
|
+
stepId: z.string(),
|
|
960
|
+
decision: z.enum(["approved", "rejected"]).optional(),
|
|
961
|
+
formPayload: z.record(z.string(), z.unknown()).optional(),
|
|
962
|
+
// System callers (a Telegram/Discord button via channels) attest the
|
|
963
|
+
// workspace; an authenticated session's slug always wins over this. The
|
|
964
|
+
// `slug` is trusted ONLY with a valid `attestation` — HMAC(IDENTITY_SECRET,
|
|
965
|
+
// "human:resolve:<runId>:<stepId>:<slug>") that only channels can mint after
|
|
966
|
+
// it re-walks the tapper's authority. Without it, slug is ignored.
|
|
967
|
+
slug: z.string().optional(),
|
|
968
|
+
attestation: z.string().optional(),
|
|
969
|
+
}),
|
|
970
|
+
response: z.object({ ok: z.boolean(), status: z.string().optional(), error: z.string().optional() }),
|
|
971
|
+
effect: "ask", cost: "free", idempotent: true, simulatable: false, auth: "manage_workflows",
|
|
972
|
+
examples: [{ runId: "run_1", stepId: "s2", decision: "approved" }],
|
|
973
|
+
}),
|
|
974
|
+
"checkout:create": receiver({
|
|
975
|
+
receiver: "checkout:create",
|
|
976
|
+
summary: "The `sell` step's binding — mint a Connect checkout session for the buyer, stamping { runId, stepId } into session metadata so checkout:resume can wake the run",
|
|
977
|
+
request: z.object({
|
|
978
|
+
workspace: z.string(),
|
|
979
|
+
ppid: z.string(),
|
|
980
|
+
// Set by the executor when a `sell` step dispatches this — the run's resume coordinates.
|
|
981
|
+
runId: z.string().optional(),
|
|
982
|
+
stepId: z.string().optional(),
|
|
983
|
+
}),
|
|
984
|
+
response: z.object({
|
|
985
|
+
clientSecret: z.string().nullable().optional(),
|
|
986
|
+
sessionId: z.string().optional(),
|
|
987
|
+
applicationFeeAmount: z.number().optional(),
|
|
988
|
+
stripeAccount: z.string().optional(),
|
|
989
|
+
error: z.string().optional(),
|
|
990
|
+
}),
|
|
991
|
+
effect: "ask", cost: "variable", reversible: false, idempotent: false, simulatable: false, settles: "offchain",
|
|
992
|
+
auth: "manage_workflows",
|
|
993
|
+
examples: [{ workspace: "acme", ppid: "pr_1" }],
|
|
994
|
+
}),
|
|
995
|
+
"checkout:resume": receiver({
|
|
996
|
+
receiver: "checkout:resume",
|
|
997
|
+
summary: "Wake a run suspended at a `sell` step — the storefront webhook fires this on checkout.session.completed with the (runId, stepId) it stamped at create. Sibling of human:resolve.",
|
|
998
|
+
request: z.object({
|
|
999
|
+
runId: z.string(),
|
|
1000
|
+
stepId: z.string(),
|
|
1001
|
+
// The run's own workspace (from the session metadata the webhook reads); the
|
|
1002
|
+
// runId is the resume capability, re-validated against the parked run server-side.
|
|
1003
|
+
slug: z.string().optional(),
|
|
1004
|
+
}),
|
|
1005
|
+
response: z.object({ ok: z.boolean(), status: z.string().optional(), error: z.string().optional() }),
|
|
1006
|
+
effect: "signal", cost: "free", idempotent: true, simulatable: false, auth: "manage_workflows",
|
|
1007
|
+
examples: [{ runId: "run_1", stepId: "s2", slug: "acme" }],
|
|
1008
|
+
}),
|
|
1009
|
+
"human:notify": receiver({
|
|
1010
|
+
receiver: "human:notify",
|
|
1011
|
+
summary: "Post a channel-shaped approval into a run's conversation when it suspends at a human step — web card · Telegram inline keys · Discord components. Sibling of chat:send.",
|
|
1012
|
+
request: z.object({
|
|
1013
|
+
runId: z.string(),
|
|
1014
|
+
stepId: z.string(),
|
|
1015
|
+
stepName: z.string().optional(),
|
|
1016
|
+
workflowName: z.string().optional(),
|
|
1017
|
+
group: z.string().optional(), // conversation group; falls back to the run's started_by
|
|
1018
|
+
}),
|
|
1019
|
+
response: z.object({ ok: z.boolean(), group: z.string().optional(), error: z.string().optional() }),
|
|
1020
|
+
effect: "signal", cost: "free", idempotent: true, simulatable: false, auth: "manage_workflows",
|
|
1021
|
+
examples: [{ runId: "run_1", stepId: "s2", stepName: "Approve contract" }],
|
|
1022
|
+
}),
|
|
1023
|
+
"workflow:stop": receiver({
|
|
1024
|
+
receiver: "workflow:stop",
|
|
1025
|
+
summary: "Park a live run at its current step (status → paused); preserves the resume cursor so human:resolve or a re-run continues it",
|
|
1026
|
+
request: z.object({ runId: z.string() }),
|
|
1027
|
+
response: z.object({ ok: z.boolean(), status: z.string().optional(), error: z.string().optional() }),
|
|
1028
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, simulatable: false, auth: "manage_workflows",
|
|
1029
|
+
examples: [{ runId: "run_1" }],
|
|
1030
|
+
}),
|
|
1031
|
+
"workflow:trigger": receiver({
|
|
1032
|
+
receiver: "workflow:trigger",
|
|
1033
|
+
summary: "Fire every workspace workflow whose trigger step matches a channel source (e.g. webhook:telegram)",
|
|
1034
|
+
request: z.object({
|
|
1035
|
+
source: z.string(),
|
|
1036
|
+
slug: z.string().optional(),
|
|
1037
|
+
triggerPayload: z.record(z.string(), z.unknown()).optional(),
|
|
1038
|
+
}),
|
|
1039
|
+
response: z.object({ ok: z.boolean(), started: z.number(), runIds: z.array(z.string()) }),
|
|
1040
|
+
effect: "signal", cost: "variable", reversible: false, idempotent: false, simulatable: false, auth: "manage_workflows",
|
|
1041
|
+
examples: [{ source: "webhook:telegram", slug: "acme" }],
|
|
1042
|
+
}),
|
|
1043
|
+
"workflow:delete": receiver({
|
|
1044
|
+
receiver: "workflow:delete",
|
|
1045
|
+
summary: "Delete a workflow and all its runs, steps, and edges",
|
|
1046
|
+
request: z.object({ workflowId: z.string() }),
|
|
1047
|
+
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
1048
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "manage_workflows",
|
|
1049
|
+
examples: [{ workflowId: "wf_abc" }],
|
|
1050
|
+
}),
|
|
1051
|
+
"workflow:update": receiver({
|
|
1052
|
+
receiver: "workflow:update",
|
|
1053
|
+
summary: "Rename a workflow or change its status (draft|active|paused)",
|
|
1054
|
+
request: z.object({ workflowId: z.string(), name: z.string().optional(), status: z.enum(["draft", "active", "paused"]).optional() }),
|
|
1055
|
+
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
1056
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, auth: "manage_workflows",
|
|
1057
|
+
examples: [{ workflowId: "wf_abc", name: "Renamed Workflow" }, { workflowId: "wf_abc", status: "paused" }],
|
|
1058
|
+
}),
|
|
1059
|
+
// ── The autonomy ladder's leaf runners — a workflow skill/agent step compiles
|
|
1060
|
+
// to one of these (workflow-executor.ts stepBinding). Both proxy to the
|
|
1061
|
+
// channels runtime; web owns the catalog + tenant authority (workflows-lock C2/C3).
|
|
1062
|
+
"skills:list": receiver({
|
|
1063
|
+
receiver: "skills:list",
|
|
1064
|
+
summary: "List the caller's workspace skill catalog (R2) — powers the canvas SkillPicker",
|
|
1065
|
+
request: z.object({}),
|
|
1066
|
+
response: z.object({
|
|
1067
|
+
skills: z.array(z.object({ name: z.string(), size: z.number() })),
|
|
1068
|
+
}),
|
|
1069
|
+
effect: "ask", cost: "free", idempotent: true, simulatable: false, auth: "view_workflows",
|
|
1070
|
+
examples: [{}],
|
|
1071
|
+
}),
|
|
1072
|
+
"skill:run": receiver({
|
|
1073
|
+
receiver: "skill:run",
|
|
1074
|
+
summary: "Run a workspace skill — loads its body from R2, runs one bounded turn via channels, returns { text }",
|
|
1075
|
+
request: z.object({ skill: z.string() }).catchall(z.unknown()), // extra keys = the skill's input
|
|
1076
|
+
response: z.object({ ok: z.boolean(), text: z.string().optional(), skill: z.string().optional(), error: z.string().optional() }),
|
|
1077
|
+
effect: "ask", cost: "variable", reversible: false, idempotent: false, simulatable: false, settles: "none", auth: "manage_workflows",
|
|
1078
|
+
examples: [{ skill: "copywriting", topic: "launch" }],
|
|
1079
|
+
}),
|
|
1080
|
+
"agent:run": receiver({
|
|
1081
|
+
receiver: "agent:run",
|
|
1082
|
+
summary: "Invoke a bound actor (optionally skill-constrained) for one bounded turn via channels; returns { text }",
|
|
1083
|
+
request: z.object({
|
|
1084
|
+
actorId: z.string(),
|
|
1085
|
+
skill: z.string().optional(),
|
|
1086
|
+
instructions: z.string().optional(),
|
|
1087
|
+
}).catchall(z.unknown()), // extra keys = the agent's input
|
|
1088
|
+
response: z.object({ ok: z.boolean(), text: z.string().optional(), actorId: z.string().optional(), error: z.string().optional() }),
|
|
1089
|
+
effect: "ask", cost: "variable", reversible: false, idempotent: false, simulatable: false, settles: "none", auth: "manage_workflows",
|
|
1090
|
+
examples: [{ actorId: "one:support", skill: "support", instructions: "Reply kindly." }],
|
|
1091
|
+
}),
|
|
1092
|
+
// ── video — room provisioning, sessions, invitations, recording (text/video-live-improve-plan.md) ──
|
|
1093
|
+
// Seven receivers already ship in receiver-resolvers.ts. These declarations expose
|
|
1094
|
+
// them to typed ask<R>/signal<R> callers, the MCP surface, and edge validation.
|
|
1095
|
+
// Four new receivers (quick-room, join-event, start-recording, start-stream) are
|
|
1096
|
+
// declared here and implemented in the same W1 batch.
|
|
1097
|
+
"video:create-room": receiver({
|
|
1098
|
+
receiver: "video:create-room",
|
|
1099
|
+
summary: "Create a 100ms video room for a workspace; returns the room slug and URL",
|
|
1100
|
+
request: z.object({
|
|
1101
|
+
workspace: z.string(),
|
|
1102
|
+
roomSlug: z.string(),
|
|
1103
|
+
name: z.string(),
|
|
1104
|
+
description: z.string().optional(),
|
|
1105
|
+
type: z.enum(["meeting", "classroom", "webinar"]).optional(),
|
|
1106
|
+
region: z.string().optional(),
|
|
1107
|
+
}),
|
|
1108
|
+
response: z.object({
|
|
1109
|
+
ok: z.boolean(),
|
|
1110
|
+
room: z.object({
|
|
1111
|
+
slug: z.string(), name: z.string(), description: z.string(),
|
|
1112
|
+
type: z.string(), hmsRoomId: z.string(), url: z.string(),
|
|
1113
|
+
}).optional(),
|
|
1114
|
+
error: z.string().optional(),
|
|
1115
|
+
}),
|
|
1116
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1117
|
+
examples: [{ workspace: "acme", roomSlug: "algebra-101", name: "Algebra 101", type: "classroom" }],
|
|
1118
|
+
}),
|
|
1119
|
+
"video:delete-room": receiver({
|
|
1120
|
+
receiver: "video:delete-room",
|
|
1121
|
+
summary: "Disable a video room and its 100ms counterpart; room is no longer joinable",
|
|
1122
|
+
request: z.object({ workspace: z.string(), roomSlug: z.string() }),
|
|
1123
|
+
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
1124
|
+
effect: "ask", cost: "free", idempotent: true, reversible: false, auth: "manage_clients",
|
|
1125
|
+
examples: [{ workspace: "acme", roomSlug: "algebra-101" }],
|
|
1126
|
+
}),
|
|
1127
|
+
"video:contact-call": receiver({
|
|
1128
|
+
receiver: "video:contact-call",
|
|
1129
|
+
summary: "Provision a one-to-one video room for a contact; links the room thread to the contact CRM record",
|
|
1130
|
+
request: z.object({
|
|
1131
|
+
workspace: z.string(),
|
|
1132
|
+
actorId: z.string(),
|
|
1133
|
+
name: z.string().optional(),
|
|
1134
|
+
}),
|
|
1135
|
+
response: z.object({
|
|
1136
|
+
ok: z.boolean(),
|
|
1137
|
+
roomSlug: z.string().optional(),
|
|
1138
|
+
threadId: z.string().nullable().optional(),
|
|
1139
|
+
guestJoinUrl: z.string().optional(),
|
|
1140
|
+
hostJoinUrl: z.string().optional(),
|
|
1141
|
+
error: z.string().optional(),
|
|
1142
|
+
}),
|
|
1143
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1144
|
+
examples: [{ workspace: "acme", actorId: "actor_123", name: "Call with Sarah" }],
|
|
1145
|
+
}),
|
|
1146
|
+
"video:invite": receiver({
|
|
1147
|
+
receiver: "video:invite",
|
|
1148
|
+
summary: "Generate a tracked /go/ join link for an actor into an existing room",
|
|
1149
|
+
request: z.object({
|
|
1150
|
+
workspace: z.string(),
|
|
1151
|
+
roomSlug: z.string(),
|
|
1152
|
+
actorId: z.string().optional(),
|
|
1153
|
+
}),
|
|
1154
|
+
response: z.object({
|
|
1155
|
+
ok: z.boolean(),
|
|
1156
|
+
goUrl: z.string().optional(),
|
|
1157
|
+
destination: z.string().optional(),
|
|
1158
|
+
error: z.string().optional(),
|
|
1159
|
+
}),
|
|
1160
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1161
|
+
examples: [{ workspace: "acme", roomSlug: "algebra-101", actorId: "actor_456" }],
|
|
1162
|
+
}),
|
|
1163
|
+
"video:schedule-webinar": receiver({
|
|
1164
|
+
receiver: "video:schedule-webinar",
|
|
1165
|
+
summary: "Create a webinar room and send tracked invite links to N contacts in one call",
|
|
1166
|
+
request: z.object({
|
|
1167
|
+
workspace: z.string(),
|
|
1168
|
+
name: z.string().optional(),
|
|
1169
|
+
actorIds: z.array(z.string()).min(1).max(500),
|
|
1170
|
+
}),
|
|
1171
|
+
response: z.object({
|
|
1172
|
+
ok: z.boolean(),
|
|
1173
|
+
roomUrl: z.string().optional(),
|
|
1174
|
+
invited: z.number().optional(),
|
|
1175
|
+
links: z.array(z.object({ actorId: z.string(), goUrl: z.string() })).optional(),
|
|
1176
|
+
error: z.string().optional(),
|
|
1177
|
+
}),
|
|
1178
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1179
|
+
examples: [{ workspace: "acme", name: "Product Launch", actorIds: ["actor_1", "actor_2"] }],
|
|
1180
|
+
}),
|
|
1181
|
+
"video:create-session": receiver({
|
|
1182
|
+
receiver: "video:create-session",
|
|
1183
|
+
summary: "Create a video session with host + guest tracked join links; optionally schedules the call",
|
|
1184
|
+
request: z.object({
|
|
1185
|
+
workspace: z.string(),
|
|
1186
|
+
roomSlug: z.string(),
|
|
1187
|
+
name: z.string(),
|
|
1188
|
+
type: z.enum(["meeting", "classroom", "webinar"]).optional(),
|
|
1189
|
+
region: z.string().optional(),
|
|
1190
|
+
guestActorId: z.string().optional(),
|
|
1191
|
+
scheduledAt: z.number().optional(),
|
|
1192
|
+
}),
|
|
1193
|
+
response: z.object({
|
|
1194
|
+
ok: z.boolean(),
|
|
1195
|
+
room: z.object({ slug: z.string(), hmsRoomId: z.string(), url: z.string() }).optional(),
|
|
1196
|
+
hostJoinUrl: z.string().optional(),
|
|
1197
|
+
guestJoinUrl: z.string().optional(),
|
|
1198
|
+
error: z.string().optional(),
|
|
1199
|
+
}),
|
|
1200
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1201
|
+
examples: [{ workspace: "acme", roomSlug: "consult-abc", name: "Consultation", guestActorId: "actor_789" }],
|
|
1202
|
+
}),
|
|
1203
|
+
"video:summary": receiver({
|
|
1204
|
+
receiver: "video:summary",
|
|
1205
|
+
summary: "Run an AI summary of a call transcript and append it as a system message on the room thread",
|
|
1206
|
+
request: z.object({
|
|
1207
|
+
threadId: z.string(),
|
|
1208
|
+
transcript: z.string(),
|
|
1209
|
+
}),
|
|
1210
|
+
response: z.object({
|
|
1211
|
+
ok: z.boolean(),
|
|
1212
|
+
threadId: z.string().optional(),
|
|
1213
|
+
skipped: z.string().optional(),
|
|
1214
|
+
error: z.string().optional(),
|
|
1215
|
+
}),
|
|
1216
|
+
effect: "ask", cost: "variable", idempotent: false, auth: "manage_clients",
|
|
1217
|
+
examples: [{ threadId: "thr_abc", transcript: "Host: Hello... Guest: Hi..." }],
|
|
1218
|
+
}),
|
|
1219
|
+
"video:quick-room": receiver({
|
|
1220
|
+
receiver: "video:quick-room",
|
|
1221
|
+
summary: "Ad-hoc video room from any chat thread — creates the room, sends the join link into the thread",
|
|
1222
|
+
request: z.object({
|
|
1223
|
+
workspace: z.string(),
|
|
1224
|
+
threadId: z.string().optional(),
|
|
1225
|
+
name: z.string().optional(),
|
|
1226
|
+
}),
|
|
1227
|
+
response: z.object({
|
|
1228
|
+
ok: z.boolean(),
|
|
1229
|
+
roomSlug: z.string().optional(),
|
|
1230
|
+
guestJoinUrl: z.string().optional(),
|
|
1231
|
+
hostJoinUrl: z.string().optional(),
|
|
1232
|
+
threadId: z.string().nullable().optional(),
|
|
1233
|
+
error: z.string().optional(),
|
|
1234
|
+
}),
|
|
1235
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1236
|
+
examples: [{ workspace: "acme", threadId: "thr_xyz", name: "Quick sync" }],
|
|
1237
|
+
}),
|
|
1238
|
+
"video:join-event": receiver({
|
|
1239
|
+
receiver: "video:join-event",
|
|
1240
|
+
summary: "Record a peer join event for tracking and lifecycle; public — called from the /go/ link handler",
|
|
1241
|
+
request: z.object({
|
|
1242
|
+
workspace: z.string(),
|
|
1243
|
+
roomSlug: z.string(),
|
|
1244
|
+
role: z.string().optional(),
|
|
1245
|
+
actorId: z.string().optional(),
|
|
1246
|
+
}),
|
|
1247
|
+
response: z.object({ ok: z.boolean(), error: z.string().optional() }),
|
|
1248
|
+
effect: "signal", cost: "free", idempotent: true,
|
|
1249
|
+
examples: [{ workspace: "acme", roomSlug: "consult-abc", role: "guest" }],
|
|
1250
|
+
}),
|
|
1251
|
+
"video:start-recording": receiver({
|
|
1252
|
+
receiver: "video:start-recording",
|
|
1253
|
+
summary: "Start cloud recording for an active room via 100ms REST; inserts a video_recordings row",
|
|
1254
|
+
request: z.object({ workspace: z.string(), roomSlug: z.string() }),
|
|
1255
|
+
response: z.object({
|
|
1256
|
+
ok: z.boolean(),
|
|
1257
|
+
recordingId: z.string().optional(),
|
|
1258
|
+
error: z.string().optional(),
|
|
1259
|
+
}),
|
|
1260
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1261
|
+
examples: [{ workspace: "acme", roomSlug: "algebra-101" }],
|
|
1262
|
+
}),
|
|
1263
|
+
"video:start-stream": receiver({
|
|
1264
|
+
receiver: "video:start-stream",
|
|
1265
|
+
summary: "Start an HLS live stream for a room; returns the playback URL when the stream is ready",
|
|
1266
|
+
request: z.object({
|
|
1267
|
+
workspace: z.string(),
|
|
1268
|
+
roomSlug: z.string(),
|
|
1269
|
+
hlsConfig: z.record(z.string(), z.unknown()).optional(),
|
|
1270
|
+
}),
|
|
1271
|
+
response: z.object({
|
|
1272
|
+
ok: z.boolean(),
|
|
1273
|
+
hlsUrl: z.string().optional(),
|
|
1274
|
+
error: z.string().optional(),
|
|
1275
|
+
}),
|
|
1276
|
+
effect: "ask", cost: "free", idempotent: false, auth: "manage_clients",
|
|
1277
|
+
examples: [{ workspace: "acme", roomSlug: "product-launch" }],
|
|
1278
|
+
}),
|
|
1279
|
+
// connect:channel — token-paste connect for a channel (Connect plan C7). The
|
|
1280
|
+
// typed contract over the shipped /api/connect/telegram route: the caller pastes
|
|
1281
|
+
// a channel credential, web verifies it (getMe), points the webhook, then hands
|
|
1282
|
+
// the raw secret to channels' /connect sink under the owner gate. SECURITY: the
|
|
1283
|
+
// token rides the REQUEST only; the response NEVER echoes it. effect:ask,
|
|
1284
|
+
// auth:manage_clients re-walked server-side off locals.slug (never body actorId).
|
|
1285
|
+
"connect:channel": receiver({
|
|
1286
|
+
receiver: "connect:channel",
|
|
1287
|
+
summary: "Connect a channel (e.g. telegram) by pasting its bot token; verifies, sets the webhook, seals the credential under the owner gate",
|
|
1288
|
+
request: z.object({
|
|
1289
|
+
channel: z.string(), // 'telegram' (token-paste path)
|
|
1290
|
+
token: z.string(), // the bot credential — request-only, never returned/logged
|
|
1291
|
+
slug: z.string().optional(), // workspace; gate re-scopes to the authenticated owner
|
|
1292
|
+
}),
|
|
1293
|
+
response: z.object({
|
|
1294
|
+
ok: z.boolean(),
|
|
1295
|
+
status: z.string().optional(), // 'active' | 'updated' from the channels sink
|
|
1296
|
+
account: z.string().optional(), // public handle (e.g. bot username) — never the token
|
|
1297
|
+
error: z.string().optional(), // 'invalid token' | 'unauthorized' | 'duplicate'
|
|
1298
|
+
}),
|
|
1299
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "manage_clients",
|
|
1300
|
+
examples: [{ channel: "telegram", token: "<bot-token>" }],
|
|
1301
|
+
}),
|
|
1302
|
+
// connect:status — list the workspace's connected channels (Connect plan C8).
|
|
1303
|
+
// Read-only contract over /api/connect/status: rows come from the `connection`
|
|
1304
|
+
// table scoped to the authenticated owner (locals.slug — never a body slug).
|
|
1305
|
+
// SECURITY: the response carries channel + public account id + status only;
|
|
1306
|
+
// cred_ref and webhook_secret never leave the server.
|
|
1307
|
+
"connect:status": receiver({
|
|
1308
|
+
receiver: "connect:status",
|
|
1309
|
+
summary: "List connected channels for the workspace — channel, account, status, runtime; never the credential",
|
|
1310
|
+
request: z.object({}),
|
|
1311
|
+
response: z.object({
|
|
1312
|
+
ok: z.boolean(),
|
|
1313
|
+
connections: z
|
|
1314
|
+
.array(z.object({
|
|
1315
|
+
channel: z.string(), // 'telegram' | 'slack' | 'discord' | 'email'
|
|
1316
|
+
account: z.string(), // external_account_id (bot id / team id / inbound address)
|
|
1317
|
+
status: z.string(), // 'active' | 'revoked'
|
|
1318
|
+
runtime: z.string(), // 'webhook' | 'socket'
|
|
1319
|
+
connected_at: z.number(), // unix epoch seconds
|
|
1320
|
+
}))
|
|
1321
|
+
.optional(),
|
|
1322
|
+
error: z.string().optional(),
|
|
1323
|
+
}),
|
|
1324
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, auth: "manage_clients",
|
|
1325
|
+
examples: [{}],
|
|
1326
|
+
}),
|
|
1327
|
+
// ── Broadcast (newsletter) ────────────────────────────────────────────────
|
|
1328
|
+
"broadcast:create": receiver({
|
|
1329
|
+
receiver: "broadcast:create",
|
|
1330
|
+
summary: "Create a broadcast draft — subject, body_md, audience_tag, channel",
|
|
1331
|
+
request: z.object({ workspace: z.string(), subject: z.string().optional(), body_md: z.string().optional(), audience_tag: z.string().optional(), channel: z.enum(["email", "sms", "whatsapp"]).optional() }),
|
|
1332
|
+
response: z.object({ broadcastId: z.string() }),
|
|
1333
|
+
effect: "ask", cost: "free", reversible: true, idempotent: false, auth: "write",
|
|
1334
|
+
}),
|
|
1335
|
+
"broadcast:update": receiver({
|
|
1336
|
+
receiver: "broadcast:update",
|
|
1337
|
+
summary: "Update a broadcast draft — subject, body, audience, schedule",
|
|
1338
|
+
request: z.object({ workspace: z.string(), broadcastId: z.string(), subject: z.string().optional(), body_md: z.string().optional(), audience_tag: z.string().optional(), scheduled_at: z.number().optional() }),
|
|
1339
|
+
response: z.object({ ok: z.boolean() }),
|
|
1340
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, auth: "write",
|
|
1341
|
+
}),
|
|
1342
|
+
"broadcast:list": receiver({
|
|
1343
|
+
receiver: "broadcast:list",
|
|
1344
|
+
summary: "List broadcasts for a workspace with status and sent_at",
|
|
1345
|
+
request: z.object({ workspace: z.string(), status: z.enum(["draft", "scheduled", "sending", "sent", "cancelled"]).optional(), limit: z.number().int().max(100).optional() }),
|
|
1346
|
+
response: z.object({ broadcasts: z.array(z.object({ id: z.string(), subject: z.string(), status: z.string(), sent_at: z.number().nullable(), audience_tag: z.string().nullable() })) }),
|
|
1347
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "read",
|
|
1348
|
+
}),
|
|
1349
|
+
"broadcast:get": receiver({
|
|
1350
|
+
receiver: "broadcast:get",
|
|
1351
|
+
summary: "Get a single broadcast with recipient counts",
|
|
1352
|
+
request: z.object({ workspace: z.string(), broadcastId: z.string() }),
|
|
1353
|
+
response: z.object({ broadcast: z.record(z.string(), z.unknown()) }),
|
|
1354
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "read",
|
|
1355
|
+
}),
|
|
1356
|
+
"broadcast:test": receiver({
|
|
1357
|
+
receiver: "broadcast:test",
|
|
1358
|
+
summary: "Send a test email for a broadcast to one address",
|
|
1359
|
+
request: z.object({ workspace: z.string(), broadcastId: z.string(), to: z.string().email() }),
|
|
1360
|
+
response: z.object({ ok: z.boolean() }),
|
|
1361
|
+
effect: "signal", cost: "variable", reversible: false, idempotent: false, auth: "write",
|
|
1362
|
+
}),
|
|
1363
|
+
"broadcast:send": receiver({
|
|
1364
|
+
receiver: "broadcast:send",
|
|
1365
|
+
summary: "Seed recipients from audience tag, apply suppression, enqueue the send batch",
|
|
1366
|
+
request: z.object({ workspace: z.string(), broadcastId: z.string() }),
|
|
1367
|
+
response: z.object({ enqueued: z.number() }),
|
|
1368
|
+
effect: "signal", cost: "variable", reversible: false, idempotent: false, auth: "write",
|
|
1369
|
+
}),
|
|
1370
|
+
"broadcast:schedule": receiver({
|
|
1371
|
+
receiver: "broadcast:schedule",
|
|
1372
|
+
summary: "Schedule a broadcast to send at a future unix timestamp",
|
|
1373
|
+
request: z.object({ workspace: z.string(), broadcastId: z.string(), scheduled_at: z.number().int() }),
|
|
1374
|
+
response: z.object({ ok: z.boolean() }),
|
|
1375
|
+
effect: "ask", cost: "free", reversible: true, idempotent: true, auth: "write",
|
|
1376
|
+
}),
|
|
1377
|
+
"broadcast:cancel": receiver({
|
|
1378
|
+
receiver: "broadcast:cancel",
|
|
1379
|
+
summary: "Cancel a scheduled or in-progress broadcast",
|
|
1380
|
+
request: z.object({ workspace: z.string(), broadcastId: z.string() }),
|
|
1381
|
+
response: z.object({ ok: z.boolean() }),
|
|
1382
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "write",
|
|
1383
|
+
}),
|
|
1384
|
+
// ── Audience (public subscribe/unsubscribe) ────────────────────────────────
|
|
1385
|
+
"audience:subscribe": receiver({
|
|
1386
|
+
receiver: "audience:subscribe",
|
|
1387
|
+
summary: "Begin double opt-in for a contact — writes consent:email:pending tag, sends confirm email",
|
|
1388
|
+
request: z.object({ workspace: z.string(), address: z.string().email(), list: z.string().optional(), ref: z.string().optional() }),
|
|
1389
|
+
response: z.object({ ok: z.boolean() }),
|
|
1390
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "public",
|
|
1391
|
+
}),
|
|
1392
|
+
"audience:unsubscribe": receiver({
|
|
1393
|
+
receiver: "audience:unsubscribe",
|
|
1394
|
+
summary: "One-click unsubscribe — writes suppression row and flips consent tag; RFC 8058 safe",
|
|
1395
|
+
request: z.object({ workspace: z.string(), channel: z.enum(["email", "sms", "whatsapp"]).optional(), address: z.string(), token: z.string() }),
|
|
1396
|
+
response: z.object({ ok: z.boolean() }),
|
|
1397
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "public",
|
|
1398
|
+
}),
|
|
1399
|
+
"audience:confirm": receiver({
|
|
1400
|
+
receiver: "audience:confirm",
|
|
1401
|
+
summary: "Confirm email subscription via opt-in token — flips consent tag to subscribed",
|
|
1402
|
+
request: z.object({ token: z.string() }),
|
|
1403
|
+
response: z.object({ ok: z.boolean() }),
|
|
1404
|
+
effect: "ask", cost: "free", reversible: false, idempotent: true, auth: "public",
|
|
1405
|
+
}),
|
|
1406
|
+
// ── Winback batch ─────────────────────────────────────────────────────────
|
|
1407
|
+
"audience:winback": receiver({
|
|
1408
|
+
receiver: "audience:winback",
|
|
1409
|
+
summary: "Re-engage dormant subscribers (batch winback sequence tool) — queries contacts with no send in `days` days, sends one re-engage email each through the suppression-checked send path",
|
|
1410
|
+
request: z.object({ days: z.number().optional(), campaign: z.string().optional() }),
|
|
1411
|
+
response: z.object({ ok: z.boolean(), sent: z.number(), scanned: z.number() }),
|
|
1412
|
+
effect: "signal", cost: "variable", reversible: false, idempotent: false, auth: "write",
|
|
1413
|
+
}),
|
|
1414
|
+
// ── Workflow tool — channel-neutral send ──────────────────────────────────
|
|
1415
|
+
"message:send": receiver({
|
|
1416
|
+
receiver: "message:send",
|
|
1417
|
+
summary: "Send a message to one address via channel — suppression-checked; sms/whatsapp dissolve until adapters ship",
|
|
1418
|
+
request: z.object({ workspace: z.string(), channel: z.enum(["email", "sms", "whatsapp"]), to: z.string(), subject: z.string().optional(), body: z.string(), campaign: z.string().optional() }),
|
|
1419
|
+
response: z.object({ ok: z.boolean() }),
|
|
1420
|
+
effect: "signal", cost: "variable", reversible: false, idempotent: false, auth: "write",
|
|
1421
|
+
}),
|
|
1422
|
+
};
|
|
1423
|
+
/**
|
|
1424
|
+
* RECIPES — the four agent journeys as typed, ordered receiver sequences (C6).
|
|
1425
|
+
* Each entry is `readonly ReceiverName[]`, so a typo or a renamed receiver is a
|
|
1426
|
+
* compile error. `meta:catalog?goal=` returns one of these; the MCP server
|
|
1427
|
+
* groups its tools by them. See `text/agent-first-spec-plan.md`.
|
|
1428
|
+
*/
|
|
1429
|
+
export const RECIPES = {
|
|
1430
|
+
/** Onboard: become an actor → mint a key → join a group → declare capability. */
|
|
1431
|
+
spine: ["auth:agent", "world:create-key", "groups:join", "agents:sync"],
|
|
1432
|
+
/** Build a world: workspace → group → actor → thing. */
|
|
1433
|
+
build: ["world:create-workspace", "world:create-group", "world:create-actor", "world:create-thing"],
|
|
1434
|
+
/** Trade: list a capability → browse the market → hire → pay. */
|
|
1435
|
+
trade: ["capabilities:publish", "market:list", "market:hire", "pay:weight"],
|
|
1436
|
+
/** Transact: post a bounty → settle it onchain. */
|
|
1437
|
+
transact: ["market:bounty", "pay:weight"],
|
|
1438
|
+
/** SOP: define a workflow → shape it with a diff → run it. */
|
|
1439
|
+
sop: ["workflow:create", "workflow:apply-diff", "workflow:run"],
|
|
1440
|
+
};
|
|
1441
|
+
//# sourceMappingURL=receivers.js.map
|