@dench.com/cli 2.1.1 → 2.1.3
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/agent-config.ts +3 -126
- package/browser.ts +507 -0
- package/chat.ts +1 -1
- package/crm.ts +209 -0
- package/dench.ts +173 -49
- package/fs-daemon.ts +201 -2
- package/lib/api-schemas.ts +1095 -0
- package/lib/command-registry.ts +1816 -0
- package/lib/enrichment-gateway.ts +23 -12
- package/lib/organizationSelector.ts +58 -0
- package/linkedin.ts +210 -0
- package/package.json +6 -2
|
@@ -0,0 +1,1095 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep per-operation request/response schemas for the Dench API v1.
|
|
3
|
+
*
|
|
4
|
+
* These are the source of truth for:
|
|
5
|
+
* - OpenAPI generation (scripts/generate-openapi.ts) -> interactive
|
|
6
|
+
* Mintlify playground parameters, request bodies, and responses.
|
|
7
|
+
* - Runtime validation in the API v1 dispatcher.
|
|
8
|
+
* - The generated curl guide (public/references/API.md).
|
|
9
|
+
*
|
|
10
|
+
* Auth args (`sessionToken` / `apiKey` / `runId`) are intentionally
|
|
11
|
+
* omitted here: the dispatcher injects them from the bearer token and
|
|
12
|
+
* `x-dench-run-id` header. Path-parameter fields (e.g. `objectName`,
|
|
13
|
+
* `entryId`) ARE included so they validate and reach the backend; any
|
|
14
|
+
* decorative path segment a backend function does not accept is left out
|
|
15
|
+
* so strict parsing drops it before the Convex call.
|
|
16
|
+
*
|
|
17
|
+
* Schemas mirror the real Convex `args` validators and gateway request
|
|
18
|
+
* shapes. They avoid `.refine()`/`.transform()` so `z.toJSONSchema`
|
|
19
|
+
* stays lossless for the playground.
|
|
20
|
+
*/
|
|
21
|
+
import { type ZodTypeAny, z } from "zod";
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Shared enums + fragments (mirror convex validators)
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
export const FIELD_TYPES = [
|
|
28
|
+
"text",
|
|
29
|
+
"email",
|
|
30
|
+
"phone",
|
|
31
|
+
"url",
|
|
32
|
+
"number",
|
|
33
|
+
"boolean",
|
|
34
|
+
"date",
|
|
35
|
+
"richtext",
|
|
36
|
+
"file",
|
|
37
|
+
"user",
|
|
38
|
+
"enum",
|
|
39
|
+
"relation",
|
|
40
|
+
"tags",
|
|
41
|
+
"action",
|
|
42
|
+
] as const;
|
|
43
|
+
|
|
44
|
+
const fieldType = z
|
|
45
|
+
.enum(FIELD_TYPES)
|
|
46
|
+
.describe(
|
|
47
|
+
"Field data type. `relation` needs relatedObjectName + relationshipType; `enum` uses enumValues/enumColors; `user` cells store a member userId; long prose belongs in the protected `Notes` richtext field.",
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const viewKind = z
|
|
51
|
+
.enum(["table", "kanban", "calendar", "timeline", "gallery", "list"])
|
|
52
|
+
.describe("Default view rendered for the object.");
|
|
53
|
+
|
|
54
|
+
const relationshipType = z
|
|
55
|
+
.enum(["many_to_one", "many_to_many"])
|
|
56
|
+
.describe("Relation cardinality for a `relation` field.");
|
|
57
|
+
|
|
58
|
+
const memoryKind = z
|
|
59
|
+
.enum([
|
|
60
|
+
"fact",
|
|
61
|
+
"decision",
|
|
62
|
+
"preference",
|
|
63
|
+
"goal",
|
|
64
|
+
"tool_note",
|
|
65
|
+
"other",
|
|
66
|
+
"convention",
|
|
67
|
+
"project_context",
|
|
68
|
+
"agent_lesson",
|
|
69
|
+
"docs_knowledge",
|
|
70
|
+
"open_goal",
|
|
71
|
+
])
|
|
72
|
+
.describe("Memory classification.");
|
|
73
|
+
|
|
74
|
+
const memorySensitivity = z
|
|
75
|
+
.enum(["normal", "broad", "sensitive"])
|
|
76
|
+
.describe("Sensitivity tier; `sensitive` memories land in needs-review.");
|
|
77
|
+
|
|
78
|
+
const memoryVisibility = z
|
|
79
|
+
.enum(["user", "org"])
|
|
80
|
+
.describe("Who can see the memory. Defaults to `user`.");
|
|
81
|
+
|
|
82
|
+
const riskLevel = z.enum(["low", "medium", "high"]).describe("Risk level.");
|
|
83
|
+
|
|
84
|
+
const approvalDecision = z
|
|
85
|
+
.enum(["approved", "rejected"])
|
|
86
|
+
.describe("Human decision for an approval request.");
|
|
87
|
+
|
|
88
|
+
const signInIntent = z
|
|
89
|
+
.enum(["join_existing", "create_workspace"])
|
|
90
|
+
.describe("Whether to join an existing workspace or create a new one.");
|
|
91
|
+
|
|
92
|
+
const reportType = z
|
|
93
|
+
.enum(["pie", "bar", "line", "table"])
|
|
94
|
+
.describe("Chart type for the generated report.");
|
|
95
|
+
|
|
96
|
+
const reportMetric = z
|
|
97
|
+
.enum(["count", "sum", "avg", "min", "max"])
|
|
98
|
+
.describe("Aggregation metric. Defaults to `count`.");
|
|
99
|
+
|
|
100
|
+
const overlapPolicy = z
|
|
101
|
+
.enum(["skip", "queue", "kill_old"])
|
|
102
|
+
.describe(
|
|
103
|
+
"What to do when a previous run is still active. Defaults to `skip`.",
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const cronTarget = z.literal("chat_turn").describe("Routine run target.");
|
|
107
|
+
|
|
108
|
+
const scheduleSpec = z
|
|
109
|
+
.union([
|
|
110
|
+
z.object({
|
|
111
|
+
kind: z.literal("every"),
|
|
112
|
+
everyMs: z
|
|
113
|
+
.number()
|
|
114
|
+
.int()
|
|
115
|
+
.positive()
|
|
116
|
+
.describe("Interval in milliseconds (1s to 365d)."),
|
|
117
|
+
anchorMs: z
|
|
118
|
+
.number()
|
|
119
|
+
.int()
|
|
120
|
+
.optional()
|
|
121
|
+
.describe("Optional anchor timestamp for the recurring fire."),
|
|
122
|
+
}),
|
|
123
|
+
z.object({
|
|
124
|
+
kind: z.literal("cron"),
|
|
125
|
+
expr: z.string().describe("5-field POSIX cron expression."),
|
|
126
|
+
tz: z
|
|
127
|
+
.string()
|
|
128
|
+
.optional()
|
|
129
|
+
.describe("IANA timezone, e.g. America/New_York."),
|
|
130
|
+
}),
|
|
131
|
+
z.object({
|
|
132
|
+
kind: z.literal("at"),
|
|
133
|
+
at: z.string().describe("ISO 8601 timestamp for a one-shot run."),
|
|
134
|
+
}),
|
|
135
|
+
])
|
|
136
|
+
.describe(
|
|
137
|
+
"Schedule: recurring (`every`), cron expression, or one-shot (`at`).",
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const dataMap = z
|
|
141
|
+
.record(z.string(), z.unknown())
|
|
142
|
+
.describe("Field-name -> value map. Use member userIds for `user` fields.");
|
|
143
|
+
|
|
144
|
+
const cellValue = z
|
|
145
|
+
.unknown()
|
|
146
|
+
.describe(
|
|
147
|
+
"Cell value. Enum=option string, tags=string array, user=member userId, relation=related entry id, boolean=true/false.",
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const enrichmentConfig = z
|
|
151
|
+
.object({
|
|
152
|
+
category: z.enum(["people", "company"]),
|
|
153
|
+
key: z.string(),
|
|
154
|
+
apolloPath: z.string(),
|
|
155
|
+
inputFieldName: z.string().optional(),
|
|
156
|
+
})
|
|
157
|
+
.describe(
|
|
158
|
+
"Enrichment binding that lets the field auto-fill from a provider.",
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const crmOp = z
|
|
162
|
+
.union([
|
|
163
|
+
z.object({
|
|
164
|
+
type: z.literal("entries.create"),
|
|
165
|
+
objectName: z.string(),
|
|
166
|
+
data: dataMap,
|
|
167
|
+
}),
|
|
168
|
+
z.object({
|
|
169
|
+
type: z.literal("entries.update"),
|
|
170
|
+
entryId: z.string(),
|
|
171
|
+
data: dataMap,
|
|
172
|
+
}),
|
|
173
|
+
z.object({
|
|
174
|
+
type: z.literal("entries.delete"),
|
|
175
|
+
entryId: z.string(),
|
|
176
|
+
}),
|
|
177
|
+
])
|
|
178
|
+
.describe("A single CRM batch/transaction operation.");
|
|
179
|
+
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Response fragments (representative; not exhaustive)
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
const okResponse = z.object({ ok: z.boolean() });
|
|
185
|
+
|
|
186
|
+
const crmObjectShape = z
|
|
187
|
+
.object({
|
|
188
|
+
id: z.string(),
|
|
189
|
+
name: z.string(),
|
|
190
|
+
description: z.string().nullable().optional(),
|
|
191
|
+
icon: z.string().nullable().optional(),
|
|
192
|
+
immutable: z.boolean().optional(),
|
|
193
|
+
})
|
|
194
|
+
.describe("A CRM object (table).");
|
|
195
|
+
|
|
196
|
+
const crmFieldShape = z
|
|
197
|
+
.object({
|
|
198
|
+
id: z.string(),
|
|
199
|
+
name: z.string(),
|
|
200
|
+
type: z.enum(FIELD_TYPES),
|
|
201
|
+
required: z.boolean().optional(),
|
|
202
|
+
enum_values: z.array(z.string()).nullable().optional(),
|
|
203
|
+
enum_colors: z.array(z.string()).nullable().optional(),
|
|
204
|
+
indexed: z.boolean().optional(),
|
|
205
|
+
})
|
|
206
|
+
.describe("A CRM field (column).");
|
|
207
|
+
|
|
208
|
+
const crmEntryShape = z
|
|
209
|
+
.object({
|
|
210
|
+
id: z.string(),
|
|
211
|
+
fields: dataMap,
|
|
212
|
+
createdAt: z.number().nullable().optional(),
|
|
213
|
+
updatedAt: z.number().nullable().optional(),
|
|
214
|
+
})
|
|
215
|
+
.describe("A materialized CRM entry (row).");
|
|
216
|
+
|
|
217
|
+
const memberShape = z.object({
|
|
218
|
+
userId: z.string(),
|
|
219
|
+
name: z.string().nullable().optional(),
|
|
220
|
+
email: z.string().nullable().optional(),
|
|
221
|
+
image: z.string().nullable().optional(),
|
|
222
|
+
role: z.string().optional(),
|
|
223
|
+
joinedAt: z.number().optional(),
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// Gateway request shapes (re-declared without refine/transform)
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
const exaSearch = z.object({
|
|
231
|
+
query: z.string().describe("Search query."),
|
|
232
|
+
type: z
|
|
233
|
+
.enum(["auto", "neural", "fast", "deep", "deep-reasoning", "instant"])
|
|
234
|
+
.optional(),
|
|
235
|
+
numResults: z.number().int().min(1).max(100).optional(),
|
|
236
|
+
category: z
|
|
237
|
+
.enum([
|
|
238
|
+
"company",
|
|
239
|
+
"research paper",
|
|
240
|
+
"news",
|
|
241
|
+
"personal site",
|
|
242
|
+
"financial report",
|
|
243
|
+
"people",
|
|
244
|
+
])
|
|
245
|
+
.optional(),
|
|
246
|
+
includeDomains: z.array(z.string()).optional(),
|
|
247
|
+
excludeDomains: z.array(z.string()).optional(),
|
|
248
|
+
startPublishedDate: z.string().optional(),
|
|
249
|
+
endPublishedDate: z.string().optional(),
|
|
250
|
+
includeText: z.array(z.string()).optional(),
|
|
251
|
+
excludeText: z.array(z.string()).optional(),
|
|
252
|
+
userLocation: z.string().optional(),
|
|
253
|
+
moderation: z.boolean().optional(),
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const exaContents = z.object({
|
|
257
|
+
urls: z.array(z.string()).describe("URLs to fetch (max 10)."),
|
|
258
|
+
text: z.boolean().optional(),
|
|
259
|
+
summary: z
|
|
260
|
+
.object({ query: z.string().optional() })
|
|
261
|
+
.optional()
|
|
262
|
+
.describe("Optional per-URL summary."),
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const exaAnswer = z.object({
|
|
266
|
+
query: z.string().describe("Question to answer with web search."),
|
|
267
|
+
text: z.boolean().optional(),
|
|
268
|
+
stream: z.boolean().optional(),
|
|
269
|
+
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const imageGenerate = z.object({
|
|
273
|
+
prompt: z.string().min(1).max(32_000).describe("Image prompt."),
|
|
274
|
+
size: z.string().optional().describe("e.g. 1024x1024, 1536x1024, auto."),
|
|
275
|
+
quality: z.enum(["auto", "low", "medium", "high"]).optional(),
|
|
276
|
+
format: z.enum(["png", "jpeg", "webp"]).optional(),
|
|
277
|
+
output_compression: z.number().int().min(0).max(100).optional(),
|
|
278
|
+
background: z.enum(["auto", "opaque", "transparent"]).optional(),
|
|
279
|
+
savePath: z
|
|
280
|
+
.string()
|
|
281
|
+
.optional()
|
|
282
|
+
.describe("Workspace path to write the image."),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const imageEdit = imageGenerate.extend({
|
|
286
|
+
input_images_base64: z
|
|
287
|
+
.array(z.string())
|
|
288
|
+
.min(1)
|
|
289
|
+
.max(8)
|
|
290
|
+
.describe("Base64-encoded source images (1-8)."),
|
|
291
|
+
mask_base64: z.string().optional().describe("Optional base64 mask image."),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const composioConnect = z.object({
|
|
295
|
+
toolkit: z
|
|
296
|
+
.string()
|
|
297
|
+
.min(1)
|
|
298
|
+
.describe("Toolkit slug, e.g. github, gmail, stripe."),
|
|
299
|
+
callback_url: z.string().optional().describe("Optional OAuth callback URL."),
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
const composioToolSearch = z.object({
|
|
303
|
+
queries: z
|
|
304
|
+
.array(
|
|
305
|
+
z.object({
|
|
306
|
+
use_case: z.string().min(1).describe("Natural-language use case."),
|
|
307
|
+
known_fields: z.string().optional(),
|
|
308
|
+
}),
|
|
309
|
+
)
|
|
310
|
+
.min(1)
|
|
311
|
+
.max(7),
|
|
312
|
+
session: z
|
|
313
|
+
.object({ id: z.string().optional(), generate_id: z.boolean().optional() })
|
|
314
|
+
.optional(),
|
|
315
|
+
account: z.string().optional(),
|
|
316
|
+
model: z.string().optional(),
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const composioToolRun = z.object({
|
|
320
|
+
execution_ref: z
|
|
321
|
+
.string()
|
|
322
|
+
.optional()
|
|
323
|
+
.describe(
|
|
324
|
+
"Execution ref from a prior search, OR pass session_id+tool_slug.",
|
|
325
|
+
),
|
|
326
|
+
session_id: z.string().optional(),
|
|
327
|
+
tool_slug: z
|
|
328
|
+
.string()
|
|
329
|
+
.optional()
|
|
330
|
+
.describe("Composio tool slug, e.g. GMAIL_FETCH_EMAILS."),
|
|
331
|
+
arguments: z
|
|
332
|
+
.record(z.string(), z.unknown())
|
|
333
|
+
.optional()
|
|
334
|
+
.describe("Tool arguments object."),
|
|
335
|
+
account: z.string().optional(),
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
const peopleSearch = z.object({
|
|
339
|
+
linkedinUrl: z.string().optional(),
|
|
340
|
+
fullName: z.string().optional(),
|
|
341
|
+
firstName: z.string().optional(),
|
|
342
|
+
lastName: z.string().optional(),
|
|
343
|
+
keywords: z.string().optional(),
|
|
344
|
+
companyDomain: z.string().optional(),
|
|
345
|
+
companyName: z.string().optional(),
|
|
346
|
+
titles: z.array(z.string()).max(50).optional(),
|
|
347
|
+
seniorities: z.array(z.string()).max(20).optional(),
|
|
348
|
+
jobFunctions: z.array(z.string()).max(20).optional(),
|
|
349
|
+
industries: z.array(z.string()).max(50).optional(),
|
|
350
|
+
locations: z.array(z.string()).max(50).optional(),
|
|
351
|
+
headcountRanges: z.array(z.string()).max(20).optional(),
|
|
352
|
+
exactMatch: z.boolean().optional(),
|
|
353
|
+
limit: z.number().int().positive().max(100).optional(),
|
|
354
|
+
offset: z.number().int().nonnegative().optional(),
|
|
355
|
+
preferCache: z.boolean().optional(),
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
const companySearch = z.object({
|
|
359
|
+
domain: z.string().optional(),
|
|
360
|
+
name: z.string().optional(),
|
|
361
|
+
linkedinUrl: z.string().optional(),
|
|
362
|
+
exactMatch: z.boolean().optional(),
|
|
363
|
+
limit: z.number().int().positive().max(100).optional(),
|
|
364
|
+
offset: z.number().int().nonnegative().optional(),
|
|
365
|
+
preferCache: z.boolean().optional(),
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// ---------------------------------------------------------------------------
|
|
369
|
+
// Request schemas keyed by operation id
|
|
370
|
+
// ---------------------------------------------------------------------------
|
|
371
|
+
|
|
372
|
+
export const requestSchemas: Record<string, ZodTypeAny> = {
|
|
373
|
+
// Auth
|
|
374
|
+
"auth.signin.create": z.object({
|
|
375
|
+
codeHash: z.string(),
|
|
376
|
+
sessionTokenHash: z.string(),
|
|
377
|
+
agentName: z.string(),
|
|
378
|
+
agentKind: z.string().describe("Agent kind, normalized to snake_case."),
|
|
379
|
+
intent: signInIntent,
|
|
380
|
+
proposedOrganizationName: z
|
|
381
|
+
.string()
|
|
382
|
+
.optional()
|
|
383
|
+
.describe("Required when intent is create_workspace."),
|
|
384
|
+
requestedOrganizationSelector: z.string().optional(),
|
|
385
|
+
userAgent: z.string().optional(),
|
|
386
|
+
}),
|
|
387
|
+
"auth.signin.poll": z.object({
|
|
388
|
+
codeHash: z.string(),
|
|
389
|
+
sessionTokenHash: z.string(),
|
|
390
|
+
}),
|
|
391
|
+
"auth.otp.start": z.object({
|
|
392
|
+
email: z.string().describe("Email to send the code to."),
|
|
393
|
+
}),
|
|
394
|
+
"auth.otp.verify": z.object({
|
|
395
|
+
email: z.string(),
|
|
396
|
+
code: z.string().describe("6+ digit code from the email."),
|
|
397
|
+
agentName: z.string(),
|
|
398
|
+
agentKind: z.string(),
|
|
399
|
+
sessionTokenHash: z
|
|
400
|
+
.string()
|
|
401
|
+
.describe("sha256 hex of the local session token."),
|
|
402
|
+
intent: signInIntent,
|
|
403
|
+
proposedOrganizationName: z.string().optional(),
|
|
404
|
+
organizationSelector: z.string().optional(),
|
|
405
|
+
userAgent: z.string().optional(),
|
|
406
|
+
}),
|
|
407
|
+
"auth.otp.finalize": z.object({
|
|
408
|
+
authToken: z.string(),
|
|
409
|
+
organizationId: z
|
|
410
|
+
.string()
|
|
411
|
+
.optional()
|
|
412
|
+
.describe("Provide this OR newOrganizationName."),
|
|
413
|
+
newOrganizationName: z.string().optional(),
|
|
414
|
+
}),
|
|
415
|
+
|
|
416
|
+
// Workspace
|
|
417
|
+
"workspace.artifacts.list": z.object({
|
|
418
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
419
|
+
}),
|
|
420
|
+
"workspace.suggestedWork.list": z.object({
|
|
421
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
422
|
+
}),
|
|
423
|
+
|
|
424
|
+
// Memory
|
|
425
|
+
"memory.search": z.object({
|
|
426
|
+
query: z.string().describe("Full-text query."),
|
|
427
|
+
limit: z.coerce.number().int().min(1).max(20).optional(),
|
|
428
|
+
}),
|
|
429
|
+
"memory.save": z.object({
|
|
430
|
+
key: z.string().describe("Stable memory key."),
|
|
431
|
+
kind: memoryKind,
|
|
432
|
+
text: z.string().describe("Memory body. No secrets or scratch notes."),
|
|
433
|
+
tags: z.array(z.string()).optional(),
|
|
434
|
+
sensitivity: memorySensitivity.optional(),
|
|
435
|
+
visibility: memoryVisibility.optional(),
|
|
436
|
+
projectId: z.string().optional(),
|
|
437
|
+
sourceQuote: z.string().optional(),
|
|
438
|
+
confidence: z.number().optional(),
|
|
439
|
+
importance: z.number().optional(),
|
|
440
|
+
}),
|
|
441
|
+
|
|
442
|
+
// Approvals
|
|
443
|
+
"approval.request": z.object({
|
|
444
|
+
title: z.string().describe("What needs human approval."),
|
|
445
|
+
reason: z.string().optional(),
|
|
446
|
+
risk: riskLevel,
|
|
447
|
+
}),
|
|
448
|
+
"approval.decide": z.object({
|
|
449
|
+
approvalId: z.string(),
|
|
450
|
+
decision: approvalDecision,
|
|
451
|
+
evidence: z
|
|
452
|
+
.string()
|
|
453
|
+
.optional()
|
|
454
|
+
.describe("Required when the requesting agent records its own decision."),
|
|
455
|
+
}),
|
|
456
|
+
|
|
457
|
+
// Billing
|
|
458
|
+
"billing.topup": z.object({
|
|
459
|
+
requestId: z
|
|
460
|
+
.string()
|
|
461
|
+
.describe("Idempotency key (1-200 of [A-Za-z0-9:_-])."),
|
|
462
|
+
amountUsd: z.number().describe("USD amount, $5 to $1000."),
|
|
463
|
+
}),
|
|
464
|
+
"billing.upgrade": z.object({
|
|
465
|
+
tier: z.enum(["pro", "max", "cloud", "desktop", "api"]).optional(),
|
|
466
|
+
billingCycle: z.enum(["monthly", "yearly"]).optional(),
|
|
467
|
+
requestId: z.string().optional(),
|
|
468
|
+
returnPath: z
|
|
469
|
+
.string()
|
|
470
|
+
.optional()
|
|
471
|
+
.describe("Internal return path beginning with /."),
|
|
472
|
+
}),
|
|
473
|
+
|
|
474
|
+
// Chat
|
|
475
|
+
"chat.list": z.object({
|
|
476
|
+
titleQuery: z.string().optional(),
|
|
477
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
478
|
+
includeArchived: z.coerce.boolean().optional(),
|
|
479
|
+
includeAutomated: z.coerce.boolean().optional(),
|
|
480
|
+
}),
|
|
481
|
+
"chat.search": z.object({
|
|
482
|
+
query: z.string().describe("Full-text query across past messages."),
|
|
483
|
+
limit: z.coerce.number().int().min(1).max(50).optional(),
|
|
484
|
+
excludeThreadId: z.string().optional(),
|
|
485
|
+
includeAutomated: z.coerce.boolean().optional(),
|
|
486
|
+
}),
|
|
487
|
+
"chat.read": z.object({
|
|
488
|
+
threadId: z.string(),
|
|
489
|
+
limit: z.coerce.number().int().min(1).max(200).optional(),
|
|
490
|
+
}),
|
|
491
|
+
"chat.tree": z.object({
|
|
492
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
493
|
+
}),
|
|
494
|
+
"chat.rename": z.object({
|
|
495
|
+
items: z
|
|
496
|
+
.array(z.object({ threadId: z.string(), title: z.string() }))
|
|
497
|
+
.min(1)
|
|
498
|
+
.max(50),
|
|
499
|
+
}),
|
|
500
|
+
"chat.delete": z.object({
|
|
501
|
+
threadIds: z.array(z.string()).min(1).max(25),
|
|
502
|
+
includeAutomated: z.boolean().optional(),
|
|
503
|
+
}),
|
|
504
|
+
"chat.new": z.object({
|
|
505
|
+
prompt: z.string().describe("The user message that starts the turn."),
|
|
506
|
+
model: z.string().optional(),
|
|
507
|
+
fileContextPath: z.string().optional(),
|
|
508
|
+
visibility: z.enum(["private", "shared"]).optional(),
|
|
509
|
+
yolo: z
|
|
510
|
+
.boolean()
|
|
511
|
+
.optional()
|
|
512
|
+
.describe("Bypass approval gates for this turn."),
|
|
513
|
+
title: z.string().optional(),
|
|
514
|
+
}),
|
|
515
|
+
"chat.send": z.object({
|
|
516
|
+
threadId: z.string(),
|
|
517
|
+
prompt: z.string().describe("The message to append."),
|
|
518
|
+
model: z.string().optional(),
|
|
519
|
+
yolo: z.boolean().optional(),
|
|
520
|
+
}),
|
|
521
|
+
"chat.follow": z.object({ threadId: z.string() }),
|
|
522
|
+
|
|
523
|
+
// CRM objects
|
|
524
|
+
"crm.objects.get": z.object({ name: z.string() }),
|
|
525
|
+
"crm.objects.create": z.object({
|
|
526
|
+
name: z.string().describe("Object name (lowercased, singular)."),
|
|
527
|
+
description: z.string().optional(),
|
|
528
|
+
defaultView: viewKind.optional(),
|
|
529
|
+
icon: z
|
|
530
|
+
.string()
|
|
531
|
+
.optional()
|
|
532
|
+
.describe("Lucide icon name, e.g. users, target."),
|
|
533
|
+
}),
|
|
534
|
+
"crm.objects.update": z.object({
|
|
535
|
+
name: z.string(),
|
|
536
|
+
description: z.string().optional(),
|
|
537
|
+
defaultView: viewKind.optional(),
|
|
538
|
+
icon: z.string().optional(),
|
|
539
|
+
viewSettings: z.record(z.string(), z.unknown()).optional(),
|
|
540
|
+
savedViews: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
541
|
+
}),
|
|
542
|
+
"crm.objects.rename": z.object({
|
|
543
|
+
from: z.string().describe("Current object name (path)."),
|
|
544
|
+
to: z.string().describe("New object name."),
|
|
545
|
+
}),
|
|
546
|
+
"crm.objects.delete": z.object({ name: z.string() }),
|
|
547
|
+
|
|
548
|
+
// CRM fields
|
|
549
|
+
"crm.fields.list": z.object({ objectName: z.string() }),
|
|
550
|
+
"crm.fields.create": z.object({
|
|
551
|
+
objectName: z.string(),
|
|
552
|
+
name: z.string(),
|
|
553
|
+
type: fieldType,
|
|
554
|
+
required: z.boolean().optional(),
|
|
555
|
+
defaultValue: z.string().optional(),
|
|
556
|
+
relatedObjectName: z
|
|
557
|
+
.string()
|
|
558
|
+
.optional()
|
|
559
|
+
.describe("Target object for `relation` fields."),
|
|
560
|
+
relationshipType: relationshipType.optional(),
|
|
561
|
+
enumValues: z
|
|
562
|
+
.array(z.string())
|
|
563
|
+
.optional()
|
|
564
|
+
.describe("Options for `enum` fields."),
|
|
565
|
+
enumColors: z
|
|
566
|
+
.array(z.string())
|
|
567
|
+
.optional()
|
|
568
|
+
.describe("Hex colors aligned to enumValues."),
|
|
569
|
+
enumMultiple: z.boolean().optional().describe("Allow multi-select enum."),
|
|
570
|
+
description: z.string().optional(),
|
|
571
|
+
indexed: z.boolean().optional().describe("Index for filter/search/sort."),
|
|
572
|
+
enrichment: enrichmentConfig.optional(),
|
|
573
|
+
}),
|
|
574
|
+
"crm.fields.update": z.object({
|
|
575
|
+
objectName: z.string(),
|
|
576
|
+
fieldName: z.string(),
|
|
577
|
+
name: z.string().optional().describe("Rename the field."),
|
|
578
|
+
description: z.string().optional(),
|
|
579
|
+
required: z.boolean().optional(),
|
|
580
|
+
enumValues: z
|
|
581
|
+
.array(z.string())
|
|
582
|
+
.optional()
|
|
583
|
+
.describe("Full replacement of options."),
|
|
584
|
+
enumColors: z.array(z.string()).optional(),
|
|
585
|
+
enumMultiple: z.boolean().optional(),
|
|
586
|
+
indexed: z.boolean().optional(),
|
|
587
|
+
enrichment: enrichmentConfig.optional(),
|
|
588
|
+
clearEnrichment: z.boolean().optional(),
|
|
589
|
+
}),
|
|
590
|
+
"crm.fields.delete": z.object({
|
|
591
|
+
objectName: z.string(),
|
|
592
|
+
fieldName: z.string(),
|
|
593
|
+
}),
|
|
594
|
+
"crm.fields.reorder": z.object({
|
|
595
|
+
objectName: z.string(),
|
|
596
|
+
orderedFieldNames: z
|
|
597
|
+
.array(z.string())
|
|
598
|
+
.describe("Field names in desired order."),
|
|
599
|
+
}),
|
|
600
|
+
"crm.fields.enum.reorder": z.object({
|
|
601
|
+
objectName: z.string(),
|
|
602
|
+
fieldName: z.string(),
|
|
603
|
+
orderedValues: z
|
|
604
|
+
.array(z.string())
|
|
605
|
+
.describe("Exact permutation of existing options."),
|
|
606
|
+
}),
|
|
607
|
+
"crm.fields.enum.add": z.object({
|
|
608
|
+
objectName: z.string(),
|
|
609
|
+
fieldName: z.string(),
|
|
610
|
+
value: z.string().describe("Option value to add."),
|
|
611
|
+
color: z.string().optional().describe("Hex color for the option."),
|
|
612
|
+
position: z
|
|
613
|
+
.number()
|
|
614
|
+
.int()
|
|
615
|
+
.optional()
|
|
616
|
+
.describe("0-based insert index; defaults to append."),
|
|
617
|
+
}),
|
|
618
|
+
"crm.fields.enum.remove": z.object({
|
|
619
|
+
objectName: z.string(),
|
|
620
|
+
fieldName: z.string(),
|
|
621
|
+
value: z.string(),
|
|
622
|
+
}),
|
|
623
|
+
"crm.fields.enum.rename": z.object({
|
|
624
|
+
objectName: z.string(),
|
|
625
|
+
fieldName: z.string(),
|
|
626
|
+
oldValue: z.string().describe("Existing option value (path)."),
|
|
627
|
+
newValue: z
|
|
628
|
+
.string()
|
|
629
|
+
.describe("New option value; migrates entries + statuses."),
|
|
630
|
+
}),
|
|
631
|
+
"crm.fields.enum.color": z.object({
|
|
632
|
+
objectName: z.string(),
|
|
633
|
+
fieldName: z.string(),
|
|
634
|
+
value: z.string(),
|
|
635
|
+
color: z.string().describe("Hex color, e.g. #22c55e."),
|
|
636
|
+
}),
|
|
637
|
+
|
|
638
|
+
// CRM entries
|
|
639
|
+
"crm.entries.list": z.object({
|
|
640
|
+
objectName: z.string(),
|
|
641
|
+
limit: z.coerce.number().int().min(1).max(1000).optional(),
|
|
642
|
+
}),
|
|
643
|
+
"crm.entries.get": z.object({
|
|
644
|
+
objectName: z.string(),
|
|
645
|
+
entryId: z.string(),
|
|
646
|
+
}),
|
|
647
|
+
"crm.entries.create": z.object({
|
|
648
|
+
objectName: z.string(),
|
|
649
|
+
data: dataMap,
|
|
650
|
+
}),
|
|
651
|
+
"crm.entries.createMany": z.object({
|
|
652
|
+
objectName: z.string(),
|
|
653
|
+
entries: z.array(dataMap).max(200).describe("Up to 200 field maps."),
|
|
654
|
+
}),
|
|
655
|
+
"crm.entries.update": z.object({
|
|
656
|
+
objectName: z.string(),
|
|
657
|
+
entryId: z.string(),
|
|
658
|
+
data: dataMap,
|
|
659
|
+
}),
|
|
660
|
+
"crm.entries.updateMany": z.object({
|
|
661
|
+
objectName: z.string().describe("Object the entries belong to."),
|
|
662
|
+
updates: z
|
|
663
|
+
.array(
|
|
664
|
+
z
|
|
665
|
+
.object({
|
|
666
|
+
entryId: z.string().optional(),
|
|
667
|
+
id: z.string().optional(),
|
|
668
|
+
data: dataMap,
|
|
669
|
+
})
|
|
670
|
+
.refine((u) => u.entryId || u.id, {
|
|
671
|
+
message: "Each update must include entryId or id",
|
|
672
|
+
}),
|
|
673
|
+
)
|
|
674
|
+
.max(200)
|
|
675
|
+
.describe("Per-entry partial updates (entryId or id + data)."),
|
|
676
|
+
}),
|
|
677
|
+
"crm.entries.delete": z.object({ entryId: z.string() }),
|
|
678
|
+
"crm.entries.bulkDelete": z.object({
|
|
679
|
+
entryIds: z.array(z.string()).max(200),
|
|
680
|
+
}),
|
|
681
|
+
|
|
682
|
+
// CRM cells
|
|
683
|
+
"crm.cells.get": z.object({
|
|
684
|
+
objectName: z.string(),
|
|
685
|
+
entryId: z.string(),
|
|
686
|
+
fieldName: z.string(),
|
|
687
|
+
}),
|
|
688
|
+
"crm.cells.set": z.object({
|
|
689
|
+
objectName: z.string(),
|
|
690
|
+
entryId: z.string(),
|
|
691
|
+
fieldName: z.string(),
|
|
692
|
+
value: cellValue,
|
|
693
|
+
}),
|
|
694
|
+
"crm.cells.setMany": z.object({
|
|
695
|
+
cells: z
|
|
696
|
+
.array(
|
|
697
|
+
z.object({
|
|
698
|
+
objectName: z.string(),
|
|
699
|
+
entryId: z.string(),
|
|
700
|
+
fieldName: z.string(),
|
|
701
|
+
value: cellValue,
|
|
702
|
+
}),
|
|
703
|
+
)
|
|
704
|
+
.max(200),
|
|
705
|
+
}),
|
|
706
|
+
"crm.cells.append": z.object({
|
|
707
|
+
objectName: z.string(),
|
|
708
|
+
entryId: z.string(),
|
|
709
|
+
fieldName: z.string(),
|
|
710
|
+
value: cellValue,
|
|
711
|
+
}),
|
|
712
|
+
|
|
713
|
+
// CRM query
|
|
714
|
+
"crm.query": z.object({
|
|
715
|
+
objectName: z.string(),
|
|
716
|
+
dsl: z
|
|
717
|
+
.object({
|
|
718
|
+
filter: z.record(z.string(), z.unknown()).optional(),
|
|
719
|
+
select: z.array(z.string()).optional(),
|
|
720
|
+
sort: z.string().optional().describe("e.g. -Score,Name (- = desc)."),
|
|
721
|
+
limit: z.number().int().optional(),
|
|
722
|
+
})
|
|
723
|
+
.optional()
|
|
724
|
+
.describe("Query DSL. Bare equality only; use dslJson for $-operators."),
|
|
725
|
+
dslJson: z
|
|
726
|
+
.string()
|
|
727
|
+
.optional()
|
|
728
|
+
.describe(
|
|
729
|
+
"JSON string of the DSL when filters use operators like $gt/$in/$contains/$and/$or.",
|
|
730
|
+
),
|
|
731
|
+
}),
|
|
732
|
+
"crm.sql": z.object({
|
|
733
|
+
objectName: z.string(),
|
|
734
|
+
dsl: z.record(z.string(), z.unknown()).optional(),
|
|
735
|
+
dslJson: z.string().optional(),
|
|
736
|
+
}),
|
|
737
|
+
"crm.aggregate": z.object({
|
|
738
|
+
objectName: z.string(),
|
|
739
|
+
fieldName: z.string().describe("Field to bucket by."),
|
|
740
|
+
}),
|
|
741
|
+
"crm.search": z.object({
|
|
742
|
+
text: z.string().describe("Full-text query."),
|
|
743
|
+
objectName: z.string().optional().describe("Omit to search org-wide."),
|
|
744
|
+
limit: z.coerce.number().int().min(1).max(100).optional(),
|
|
745
|
+
}),
|
|
746
|
+
|
|
747
|
+
// CRM statuses
|
|
748
|
+
"crm.statuses.list": z.object({ objectName: z.string() }),
|
|
749
|
+
"crm.statuses.set": z.object({
|
|
750
|
+
objectName: z.string(),
|
|
751
|
+
statuses: z.array(
|
|
752
|
+
z.object({
|
|
753
|
+
name: z.string(),
|
|
754
|
+
color: z.string().describe("Hex color."),
|
|
755
|
+
sortOrder: z.number().optional(),
|
|
756
|
+
isDefault: z.boolean().optional(),
|
|
757
|
+
}),
|
|
758
|
+
),
|
|
759
|
+
}),
|
|
760
|
+
|
|
761
|
+
// CRM batch + transactions
|
|
762
|
+
"crm.batch": z.object({
|
|
763
|
+
ops: z.array(crmOp).max(200),
|
|
764
|
+
idempotencyKey: z.string().optional(),
|
|
765
|
+
}),
|
|
766
|
+
"crm.transaction.begin": z.object({}),
|
|
767
|
+
"crm.transaction.add": z.object({ txnId: z.string(), op: crmOp }),
|
|
768
|
+
"crm.transaction.commit": z.object({ txnId: z.string() }),
|
|
769
|
+
"crm.transaction.abort": z.object({ txnId: z.string() }),
|
|
770
|
+
"crm.transaction.inspect": z.object({ txnId: z.string() }),
|
|
771
|
+
|
|
772
|
+
// CRM docs / actions / reports / enrich / members
|
|
773
|
+
"crm.docs.create": z.object({
|
|
774
|
+
title: z.string(),
|
|
775
|
+
filePath: z.string(),
|
|
776
|
+
icon: z.string().optional(),
|
|
777
|
+
coverImage: z.string().optional(),
|
|
778
|
+
parentId: z.string().optional(),
|
|
779
|
+
parentObjectName: z.string().optional(),
|
|
780
|
+
entryId: z.string().optional(),
|
|
781
|
+
}),
|
|
782
|
+
"crm.docs.link": z.object({
|
|
783
|
+
filePath: z.string(),
|
|
784
|
+
objectName: z.string().optional(),
|
|
785
|
+
entryId: z.string().optional(),
|
|
786
|
+
}),
|
|
787
|
+
"crm.actions.list": z.object({ entryId: z.string() }),
|
|
788
|
+
"crm.actions.run": z.object({
|
|
789
|
+
actionId: z.string(),
|
|
790
|
+
fieldId: z.string(),
|
|
791
|
+
entryId: z.string(),
|
|
792
|
+
}),
|
|
793
|
+
"crm.reports.generate": z.object({
|
|
794
|
+
objectName: z.string(),
|
|
795
|
+
type: reportType,
|
|
796
|
+
groupByField: z.string(),
|
|
797
|
+
metric: reportMetric.optional(),
|
|
798
|
+
metricField: z.string().optional(),
|
|
799
|
+
}),
|
|
800
|
+
"crm.enrich.cell": z.object({
|
|
801
|
+
objectName: z.string(),
|
|
802
|
+
entryId: z.string(),
|
|
803
|
+
fieldName: z.string(),
|
|
804
|
+
provider: z.string().optional().describe("Defaults to auto."),
|
|
805
|
+
}),
|
|
806
|
+
"crm.enrich.object": z.object({
|
|
807
|
+
objectName: z.string(),
|
|
808
|
+
fieldName: z.string(),
|
|
809
|
+
provider: z.string().optional(),
|
|
810
|
+
missingOnly: z
|
|
811
|
+
.boolean()
|
|
812
|
+
.optional()
|
|
813
|
+
.describe("Only enrich empty cells. Defaults true."),
|
|
814
|
+
}),
|
|
815
|
+
"crm.people.search": peopleSearch,
|
|
816
|
+
"crm.companies.search": companySearch,
|
|
817
|
+
|
|
818
|
+
// Routines
|
|
819
|
+
"cron.list": z.object({ enabledOnly: z.coerce.boolean().optional() }),
|
|
820
|
+
"cron.history": z.object({
|
|
821
|
+
limit: z.coerce.number().int().min(1).max(200).optional(),
|
|
822
|
+
}),
|
|
823
|
+
"cron.get": z.object({ jobId: z.string() }),
|
|
824
|
+
"cron.create": z.object({
|
|
825
|
+
name: z.string(),
|
|
826
|
+
prompt: z.string().describe("Agent goal/message for each run."),
|
|
827
|
+
schedule: scheduleSpec,
|
|
828
|
+
description: z.string().optional(),
|
|
829
|
+
overlapPolicy: overlapPolicy.optional(),
|
|
830
|
+
enabled: z.boolean().optional(),
|
|
831
|
+
deleteAfterRun: z.boolean().optional(),
|
|
832
|
+
target: cronTarget.optional(),
|
|
833
|
+
}),
|
|
834
|
+
"cron.update": z.object({
|
|
835
|
+
jobId: z.string(),
|
|
836
|
+
name: z.string().optional(),
|
|
837
|
+
prompt: z.string().optional(),
|
|
838
|
+
schedule: scheduleSpec.optional(),
|
|
839
|
+
description: z.string().optional(),
|
|
840
|
+
overlapPolicy: overlapPolicy.optional(),
|
|
841
|
+
enabled: z.boolean().optional(),
|
|
842
|
+
deleteAfterRun: z.boolean().optional(),
|
|
843
|
+
target: cronTarget.optional(),
|
|
844
|
+
}),
|
|
845
|
+
"cron.delete": z.object({ jobId: z.string() }),
|
|
846
|
+
"cron.enable": z.object({ jobId: z.string() }),
|
|
847
|
+
"cron.disable": z.object({ jobId: z.string() }),
|
|
848
|
+
"cron.run": z.object({ jobId: z.string() }),
|
|
849
|
+
"cron.runs": z.object({
|
|
850
|
+
jobId: z.string(),
|
|
851
|
+
limit: z.coerce.number().int().min(1).max(200).optional(),
|
|
852
|
+
}),
|
|
853
|
+
|
|
854
|
+
// Files
|
|
855
|
+
"files.list": z.object({
|
|
856
|
+
prefix: z.string().optional().describe("Directory path, defaults to /."),
|
|
857
|
+
slug: z.string().optional(),
|
|
858
|
+
}),
|
|
859
|
+
"files.downloadUrl": z.object({ path: z.string() }),
|
|
860
|
+
"files.delete": z.object({ path: z.string() }),
|
|
861
|
+
"files.move": z.object({
|
|
862
|
+
from: z.string().describe("Source workspace path."),
|
|
863
|
+
to: z.string().describe("Destination workspace path."),
|
|
864
|
+
}),
|
|
865
|
+
"files.stage": z.object({
|
|
866
|
+
files: z
|
|
867
|
+
.array(
|
|
868
|
+
z.object({
|
|
869
|
+
path: z.string(),
|
|
870
|
+
text: z.string().optional(),
|
|
871
|
+
base64: z.string().optional(),
|
|
872
|
+
}),
|
|
873
|
+
)
|
|
874
|
+
.optional()
|
|
875
|
+
.describe("Files to write. Each needs text or base64."),
|
|
876
|
+
path: z.string().optional().describe("Single-file shortcut."),
|
|
877
|
+
text: z.string().optional(),
|
|
878
|
+
base64: z.string().optional(),
|
|
879
|
+
lastModifiedBy: z.string().optional(),
|
|
880
|
+
}),
|
|
881
|
+
|
|
882
|
+
// Agent config
|
|
883
|
+
"agentConfig.identity.edit": z.object({ content: z.string() }),
|
|
884
|
+
"agentConfig.organisation.edit": z.object({ content: z.string() }),
|
|
885
|
+
"agentConfig.user.edit": z.object({ content: z.string() }),
|
|
886
|
+
"agentConfig.tools.edit": z.object({ content: z.string() }),
|
|
887
|
+
"agentConfig.mem.edit": z.object({
|
|
888
|
+
content: z.string(),
|
|
889
|
+
append: z.boolean().optional(),
|
|
890
|
+
}),
|
|
891
|
+
"agentConfig.bootstrap.complete": z.object({
|
|
892
|
+
completed: z.boolean().optional(),
|
|
893
|
+
}),
|
|
894
|
+
"agentConfig.bootstrap.template": z.object({ content: z.string() }),
|
|
895
|
+
"agentConfig.model.default": z.object({
|
|
896
|
+
modelId: z.string().nullable().describe("Model id, or null to clear."),
|
|
897
|
+
}),
|
|
898
|
+
"agentConfig.model.thread": z.object({
|
|
899
|
+
threadId: z.string(),
|
|
900
|
+
modelId: z.string().nullable(),
|
|
901
|
+
}),
|
|
902
|
+
"agentConfig.daily.show": z.object({
|
|
903
|
+
date: z.string().describe("YYYY-MM-DD."),
|
|
904
|
+
}),
|
|
905
|
+
|
|
906
|
+
// Gateway: search + images + tools
|
|
907
|
+
"search.web": exaSearch,
|
|
908
|
+
"search.contents": exaContents,
|
|
909
|
+
"search.answer": exaAnswer,
|
|
910
|
+
"image.generate": imageGenerate,
|
|
911
|
+
"image.edit": imageEdit,
|
|
912
|
+
"tool.connect": composioConnect,
|
|
913
|
+
"tool.search": composioToolSearch,
|
|
914
|
+
"tool.run": composioToolRun,
|
|
915
|
+
"tool.disconnect": z.object({ connectionId: z.string() }),
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
// ---------------------------------------------------------------------------
|
|
919
|
+
// Response schemas keyed by operation id (representative subset)
|
|
920
|
+
// ---------------------------------------------------------------------------
|
|
921
|
+
|
|
922
|
+
export const responseSchemas: Record<string, ZodTypeAny> = {
|
|
923
|
+
"crm.objects.list": z.array(crmObjectShape),
|
|
924
|
+
"crm.objects.get": crmObjectShape.nullable(),
|
|
925
|
+
"crm.objects.create": z.object({ id: z.string() }),
|
|
926
|
+
"crm.objects.update": okResponse,
|
|
927
|
+
"crm.objects.rename": okResponse,
|
|
928
|
+
"crm.objects.delete": okResponse,
|
|
929
|
+
"crm.fields.list": z.array(crmFieldShape),
|
|
930
|
+
"crm.fields.create": z.object({ id: z.string() }),
|
|
931
|
+
"crm.fields.enum.add": z.object({
|
|
932
|
+
ok: z.boolean(),
|
|
933
|
+
enumValues: z.array(z.string()),
|
|
934
|
+
enumColors: z.array(z.string()),
|
|
935
|
+
inserted: z.boolean(),
|
|
936
|
+
}),
|
|
937
|
+
"crm.fields.enum.color": z.object({
|
|
938
|
+
ok: z.boolean(),
|
|
939
|
+
enumColors: z.array(z.string()),
|
|
940
|
+
}),
|
|
941
|
+
"crm.entries.list": z.array(crmEntryShape),
|
|
942
|
+
"crm.entries.get": crmEntryShape.nullable(),
|
|
943
|
+
"crm.entries.create": z.object({ entryId: z.string() }),
|
|
944
|
+
"crm.entries.createMany": z.object({
|
|
945
|
+
results: z.array(z.object({ entryId: z.string() })),
|
|
946
|
+
count: z.number(),
|
|
947
|
+
}),
|
|
948
|
+
"crm.cells.get": cellValue,
|
|
949
|
+
"crm.aggregate": z.array(
|
|
950
|
+
z.object({
|
|
951
|
+
key: z.string(),
|
|
952
|
+
count: z.number(),
|
|
953
|
+
sumNumber: z.number().optional(),
|
|
954
|
+
}),
|
|
955
|
+
),
|
|
956
|
+
"crm.members.list": z.object({
|
|
957
|
+
members: z.array(memberShape),
|
|
958
|
+
organizationId: z.string(),
|
|
959
|
+
organizationSlug: z.string(),
|
|
960
|
+
organizationName: z.string(),
|
|
961
|
+
}),
|
|
962
|
+
"billing.status": z.object({
|
|
963
|
+
availableCreditsCents: z.number(),
|
|
964
|
+
billedCents: z.number().optional(),
|
|
965
|
+
subscriptionStatus: z.string().optional(),
|
|
966
|
+
}),
|
|
967
|
+
"approval.request": z.object({ ok: z.boolean(), approvalId: z.string() }),
|
|
968
|
+
"memory.save": z.object({
|
|
969
|
+
ok: z.boolean(),
|
|
970
|
+
memoryId: z.string(),
|
|
971
|
+
status: z.enum(["active", "needs_review"]),
|
|
972
|
+
}),
|
|
973
|
+
"cron.create": z.object({
|
|
974
|
+
jobId: z.string(),
|
|
975
|
+
nextFireAt: z.number().optional(),
|
|
976
|
+
}),
|
|
977
|
+
};
|
|
978
|
+
|
|
979
|
+
// ---------------------------------------------------------------------------
|
|
980
|
+
// Convex backend extras (fixedArgs / transformArgs) keyed by operation id
|
|
981
|
+
// ---------------------------------------------------------------------------
|
|
982
|
+
|
|
983
|
+
export type ConvexExtras = {
|
|
984
|
+
fixedArgs?: Record<string, unknown>;
|
|
985
|
+
transformArgs?: (input: Record<string, unknown>) => Record<string, unknown>;
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
export const convexExtras: Record<string, ConvexExtras> = {
|
|
989
|
+
"cron.enable": { fixedArgs: { enabled: true } },
|
|
990
|
+
"cron.disable": { fixedArgs: { enabled: false } },
|
|
991
|
+
"crm.entries.updateMany": {
|
|
992
|
+
transformArgs: (input) => {
|
|
993
|
+
const updates = Array.isArray(input.updates) ? input.updates : [];
|
|
994
|
+
return {
|
|
995
|
+
ops: updates.map((raw) => {
|
|
996
|
+
const update = (raw ?? {}) as {
|
|
997
|
+
entryId?: unknown;
|
|
998
|
+
id?: unknown;
|
|
999
|
+
data?: unknown;
|
|
1000
|
+
};
|
|
1001
|
+
return {
|
|
1002
|
+
type: "entries.update",
|
|
1003
|
+
entryId: String(update.entryId ?? update.id ?? ""),
|
|
1004
|
+
data: update.data ?? {},
|
|
1005
|
+
};
|
|
1006
|
+
}),
|
|
1007
|
+
};
|
|
1008
|
+
},
|
|
1009
|
+
},
|
|
1010
|
+
};
|
|
1011
|
+
|
|
1012
|
+
// ---------------------------------------------------------------------------
|
|
1013
|
+
// Curated request examples keyed by operation id (for playground + curl)
|
|
1014
|
+
// ---------------------------------------------------------------------------
|
|
1015
|
+
|
|
1016
|
+
export const requestExamples: Record<string, unknown> = {
|
|
1017
|
+
"crm.objects.create": {
|
|
1018
|
+
name: "lead",
|
|
1019
|
+
description: "Sales leads",
|
|
1020
|
+
defaultView: "kanban",
|
|
1021
|
+
icon: "target",
|
|
1022
|
+
},
|
|
1023
|
+
"crm.fields.create": {
|
|
1024
|
+
name: "Status",
|
|
1025
|
+
type: "enum",
|
|
1026
|
+
enumValues: ["New", "Working", "Qualified", "Lost"],
|
|
1027
|
+
enumColors: ["#94a3b8", "#3b82f6", "#22c55e", "#ef4444"],
|
|
1028
|
+
indexed: true,
|
|
1029
|
+
},
|
|
1030
|
+
"crm.fields.enum.color": { color: "#22c55e" },
|
|
1031
|
+
"crm.fields.enum.add": { value: "Nurturing", color: "#eab308", position: 2 },
|
|
1032
|
+
"crm.entries.create": {
|
|
1033
|
+
data: { Name: "Ada Lovelace", Email: "ada@example.com", Status: "New" },
|
|
1034
|
+
},
|
|
1035
|
+
"crm.entries.createMany": {
|
|
1036
|
+
entries: [
|
|
1037
|
+
{ Name: "Jane", Email: "jane@example.com" },
|
|
1038
|
+
{ Name: "Bob", Email: "bob@example.com" },
|
|
1039
|
+
],
|
|
1040
|
+
},
|
|
1041
|
+
"crm.cells.set": { value: "In progress" },
|
|
1042
|
+
"crm.query": {
|
|
1043
|
+
dslJson:
|
|
1044
|
+
'{"filter":{"Status":"Qualified","Score":{"$gt":50}},"sort":"-Score","limit":50}',
|
|
1045
|
+
},
|
|
1046
|
+
"crm.statuses.set": {
|
|
1047
|
+
statuses: [
|
|
1048
|
+
{ name: "New", color: "#94a3b8" },
|
|
1049
|
+
{ name: "Working", color: "#3b82f6" },
|
|
1050
|
+
{ name: "Qualified", color: "#22c55e", isDefault: true },
|
|
1051
|
+
],
|
|
1052
|
+
},
|
|
1053
|
+
"crm.batch": {
|
|
1054
|
+
ops: [
|
|
1055
|
+
{ type: "entries.create", objectName: "people", data: { Name: "Jane" } },
|
|
1056
|
+
],
|
|
1057
|
+
idempotencyKey: "import-2026-06-01",
|
|
1058
|
+
},
|
|
1059
|
+
"memory.save": {
|
|
1060
|
+
key: "deployment-policy",
|
|
1061
|
+
kind: "decision",
|
|
1062
|
+
text: "Never deploy without human approval.",
|
|
1063
|
+
tags: ["deployment", "policy"],
|
|
1064
|
+
},
|
|
1065
|
+
"approval.request": {
|
|
1066
|
+
title: "Deploy the new API branch?",
|
|
1067
|
+
reason: "Production deploy changes public behavior.",
|
|
1068
|
+
risk: "high",
|
|
1069
|
+
},
|
|
1070
|
+
"approval.decide": {
|
|
1071
|
+
decision: "approved",
|
|
1072
|
+
evidence: "User said yes in chat",
|
|
1073
|
+
},
|
|
1074
|
+
"chat.new": { prompt: "Summarize the latest CRM changes." },
|
|
1075
|
+
"cron.create": {
|
|
1076
|
+
name: "Daily digest",
|
|
1077
|
+
prompt: "Summarize open CRM tasks.",
|
|
1078
|
+
schedule: { kind: "every", everyMs: 86_400_000 },
|
|
1079
|
+
},
|
|
1080
|
+
"search.web": { query: "latest AI CRM workflows", numResults: 5 },
|
|
1081
|
+
"image.generate": {
|
|
1082
|
+
prompt: "A minimal flat-vector app icon",
|
|
1083
|
+
size: "1024x1024",
|
|
1084
|
+
},
|
|
1085
|
+
"tool.run": {
|
|
1086
|
+
tool_slug: "GMAIL_FETCH_EMAILS",
|
|
1087
|
+
arguments: { max_results: 10 },
|
|
1088
|
+
},
|
|
1089
|
+
"crm.people.search": {
|
|
1090
|
+
titles: ["Head of Sales"],
|
|
1091
|
+
industries: ["SaaS"],
|
|
1092
|
+
limit: 10,
|
|
1093
|
+
},
|
|
1094
|
+
"crm.companies.search": { domain: "example.com" },
|
|
1095
|
+
};
|