@nordsym/apiclaw 1.3.12 → 1.4.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.
Files changed (52) hide show
  1. package/PRD-API-CHAINING.md +483 -0
  2. package/PRD-HARDEN-SHELL.md +278 -0
  3. package/README.md +72 -0
  4. package/convex/_generated/api.d.ts +4 -0
  5. package/convex/chains.ts +1095 -0
  6. package/convex/crons.ts +11 -0
  7. package/convex/logs.ts +107 -0
  8. package/convex/schema.ts +107 -0
  9. package/convex/spendAlerts.ts +442 -0
  10. package/convex/workspaces.ts +26 -0
  11. package/dist/chain-types.d.ts +187 -0
  12. package/dist/chain-types.d.ts.map +1 -0
  13. package/dist/chain-types.js +33 -0
  14. package/dist/chain-types.js.map +1 -0
  15. package/dist/chainExecutor.d.ts +122 -0
  16. package/dist/chainExecutor.d.ts.map +1 -0
  17. package/dist/chainExecutor.js +454 -0
  18. package/dist/chainExecutor.js.map +1 -0
  19. package/dist/chainResolver.d.ts +100 -0
  20. package/dist/chainResolver.d.ts.map +1 -0
  21. package/dist/chainResolver.js +519 -0
  22. package/dist/chainResolver.js.map +1 -0
  23. package/dist/chainResolver.test.d.ts +5 -0
  24. package/dist/chainResolver.test.d.ts.map +1 -0
  25. package/dist/chainResolver.test.js +201 -0
  26. package/dist/chainResolver.test.js.map +1 -0
  27. package/dist/execute.d.ts +5 -1
  28. package/dist/execute.d.ts.map +1 -1
  29. package/dist/execute.js +207 -118
  30. package/dist/execute.js.map +1 -1
  31. package/dist/index.js +382 -2
  32. package/dist/index.js.map +1 -1
  33. package/landing/package-lock.json +29 -5
  34. package/landing/package.json +2 -1
  35. package/landing/public/logos/chattgpt.svg +1 -0
  36. package/landing/public/logos/claude.svg +1 -0
  37. package/landing/public/logos/gemini.svg +1 -0
  38. package/landing/public/logos/grok.svg +1 -0
  39. package/landing/src/app/page.tsx +11 -0
  40. package/landing/src/app/security/page.tsx +381 -0
  41. package/landing/src/app/workspace/chains/page.tsx +520 -0
  42. package/landing/src/components/AITestimonials.tsx +195 -0
  43. package/landing/src/components/ChainStepDetail.tsx +310 -0
  44. package/landing/src/components/ChainTrace.tsx +261 -0
  45. package/landing/src/lib/stats.json +1 -1
  46. package/package.json +1 -1
  47. package/src/chain-types.ts +270 -0
  48. package/src/chainExecutor.ts +730 -0
  49. package/src/chainResolver.test.ts +246 -0
  50. package/src/chainResolver.ts +658 -0
  51. package/src/execute.ts +273 -114
  52. package/src/index.ts +423 -2
@@ -0,0 +1,483 @@
1
+ # APIClaw: Orchestration Layer
2
+
3
+ **Status:** SPEC
4
+ **Philosophy:** Agents don't call APIs. They express intent. APIClaw executes.
5
+
6
+ ---
7
+
8
+ ## Core Truth
9
+
10
+ An agent that needs to:
11
+ 1. Generate an image
12
+ 2. Upload it somewhere
13
+ 3. Email the link to someone
14
+
15
+ Should not think about this as three separate operations. It's one intent: *"Create and deliver an image."*
16
+
17
+ APIClaw is the layer that translates intent into execution.
18
+
19
+ ---
20
+
21
+ ## The Interface
22
+
23
+ ```typescript
24
+ call_api({
25
+ intent: "generate_and_deliver_image",
26
+
27
+ // Or explicit chain:
28
+ chain: [
29
+ {
30
+ id: "generate",
31
+ provider: "replicate",
32
+ action: "run",
33
+ params: {
34
+ model: "stability-ai/sdxl",
35
+ prompt: "A sunset over mountains"
36
+ }
37
+ },
38
+ {
39
+ id: "upload",
40
+ provider: "cloudinary",
41
+ action: "upload",
42
+ params: {
43
+ url: "$generate.url"
44
+ }
45
+ },
46
+ {
47
+ id: "notify",
48
+ provider: "resend",
49
+ action: "send",
50
+ params: {
51
+ to: "client@example.com",
52
+ subject: "Your image",
53
+ html: "<img src='$upload.secure_url' />"
54
+ }
55
+ }
56
+ ],
57
+
58
+ // Execution modifiers
59
+ parallel: ["generate_alt_1", "generate_alt_2"], // Run these in parallel
60
+ continueOnError: false, // Stop on first failure
61
+ timeout: 30000, // Max execution time
62
+ retry: { maxAttempts: 3, backoff: "exponential" } // Retry policy
63
+ })
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Reference System
69
+
70
+ Steps reference each other by ID. Full JSONPath support.
71
+
72
+ ```typescript
73
+ // Direct reference
74
+ "$stepId.property"
75
+
76
+ // Nested access
77
+ "$generate.output.images[0].url"
78
+
79
+ // Previous step shorthand
80
+ "$prev.url"
81
+
82
+ // Array from parallel execution
83
+ "$parallel[0].url"
84
+
85
+ // Conditional reference
86
+ "$generate.success ? $generate.url : $fallback.url"
87
+ ```
88
+
89
+ ### Built-in Variables
90
+
91
+ ```typescript
92
+ "$chain.startedAt" // ISO timestamp
93
+ "$chain.workspace" // Workspace ID
94
+ "$chain.index" // Current step index
95
+ "$env.CUSTOM_VAR" // Workspace environment variables
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Execution Modes
101
+
102
+ ### Sequential (Default)
103
+ ```typescript
104
+ chain: [A, B, C] // A → B → C
105
+ ```
106
+
107
+ ### Parallel
108
+ ```typescript
109
+ chain: [
110
+ {
111
+ parallel: [
112
+ { id: "img1", provider: "replicate", ... },
113
+ { id: "img2", provider: "replicate", ... },
114
+ { id: "img3", provider: "replicate", ... }
115
+ ]
116
+ },
117
+ {
118
+ id: "combine",
119
+ provider: "cloudinary",
120
+ action: "create_collage",
121
+ params: {
122
+ images: ["$img1.url", "$img2.url", "$img3.url"]
123
+ }
124
+ }
125
+ ]
126
+ ```
127
+
128
+ ### Conditional
129
+ ```typescript
130
+ chain: [
131
+ { id: "analyze", provider: "openrouter", action: "chat", ... },
132
+ {
133
+ if: "$analyze.intent === 'image'",
134
+ then: { id: "gen", provider: "replicate", ... },
135
+ else: { id: "search", provider: "brave", ... }
136
+ },
137
+ { id: "deliver", provider: "resend", params: { content: "$prev.result" } }
138
+ ]
139
+ ```
140
+
141
+ ### Loop
142
+ ```typescript
143
+ chain: [
144
+ { id: "get_urls", provider: "brave", action: "search", ... },
145
+ {
146
+ forEach: "$get_urls.results",
147
+ as: "result",
148
+ do: {
149
+ id: "scrape_$index",
150
+ provider: "firecrawl",
151
+ action: "scrape",
152
+ params: { url: "$result.url" }
153
+ }
154
+ },
155
+ {
156
+ id: "summarize",
157
+ provider: "openrouter",
158
+ action: "chat",
159
+ params: { content: "$forEach.results" }
160
+ }
161
+ ]
162
+ ```
163
+
164
+ ### Map-Reduce
165
+ ```typescript
166
+ chain: [
167
+ {
168
+ map: {
169
+ input: "$urls",
170
+ fn: { provider: "firecrawl", action: "scrape", params: { url: "$item" } }
171
+ }
172
+ },
173
+ {
174
+ reduce: {
175
+ input: "$map.results",
176
+ fn: { provider: "openrouter", action: "chat", params: { summarize: "$items" } }
177
+ }
178
+ }
179
+ ]
180
+ ```
181
+
182
+ ---
183
+
184
+ ## Error Handling
185
+
186
+ ### Per-Step Configuration
187
+ ```typescript
188
+ {
189
+ id: "critical_step",
190
+ provider: "stripe",
191
+ action: "charge",
192
+ params: { ... },
193
+
194
+ onError: {
195
+ retry: { attempts: 3, backoff: [1000, 2000, 4000] },
196
+ fallback: { id: "fallback_step", ... },
197
+ abort: false // Continue chain even if this fails
198
+ }
199
+ }
200
+ ```
201
+
202
+ ### Chain-Level Policies
203
+ ```typescript
204
+ chain: [...],
205
+ errorPolicy: {
206
+ mode: "fail-fast" | "best-effort" | "transactional",
207
+
208
+ // Transactional mode: rollback on failure
209
+ rollback: [
210
+ { if: "stripe.charge.success", do: { provider: "stripe", action: "refund", ... } }
211
+ ]
212
+ }
213
+ ```
214
+
215
+ ### Error Response
216
+ ```typescript
217
+ {
218
+ success: false,
219
+ completedSteps: ["generate", "upload"],
220
+ failedStep: {
221
+ id: "notify",
222
+ error: "Rate limited",
223
+ code: "RATE_LIMITED",
224
+ retryAfter: 30
225
+ },
226
+ partialResults: {
227
+ generate: { url: "https://..." },
228
+ upload: { secure_url: "https://..." }
229
+ },
230
+ canResume: true,
231
+ resumeToken: "chain_abc123_step_3"
232
+ }
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Resumable Chains
238
+
239
+ Long-running or failed chains can be resumed:
240
+
241
+ ```typescript
242
+ call_api({
243
+ resume: "chain_abc123_step_3",
244
+ // Optional: override params for the failed step
245
+ overrides: {
246
+ notify: { to: "different@email.com" }
247
+ }
248
+ })
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Stored Chains (Templates)
254
+
255
+ Save chains as reusable templates:
256
+
257
+ ```typescript
258
+ // Define once
259
+ call_api({
260
+ defineChain: {
261
+ name: "content_pipeline",
262
+ description: "Generate, optimize, publish, notify",
263
+ inputs: {
264
+ prompt: { type: "string", required: true },
265
+ email: { type: "string", required: true }
266
+ },
267
+ chain: [
268
+ { provider: "replicate", params: { prompt: "$inputs.prompt" } },
269
+ { provider: "cloudinary", params: { url: "$prev.url" } },
270
+ { provider: "ghost", params: { image: "$prev.secure_url" } },
271
+ { provider: "resend", params: { to: "$inputs.email", content: "$prev.url" } }
272
+ ]
273
+ }
274
+ })
275
+
276
+ // Use anywhere
277
+ call_api({
278
+ useChain: "content_pipeline",
279
+ inputs: {
280
+ prompt: "A cyberpunk cityscape",
281
+ email: "client@example.com"
282
+ }
283
+ })
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Webhooks & Async
289
+
290
+ For long-running chains:
291
+
292
+ ```typescript
293
+ call_api({
294
+ chain: [...],
295
+ async: true,
296
+ webhook: "https://your-server.com/chain-complete",
297
+ // Or poll:
298
+ pollInterval: 5000
299
+ })
300
+
301
+ // Response:
302
+ {
303
+ chainId: "chain_xyz",
304
+ status: "running",
305
+ estimatedCompletion: "2026-03-02T01:15:00Z",
306
+ statusUrl: "https://apiclaw.com/api/chain/chain_xyz/status"
307
+ }
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Observability
313
+
314
+ Every chain execution is fully traced:
315
+
316
+ ```typescript
317
+ {
318
+ chainId: "chain_xyz",
319
+ trace: [
320
+ {
321
+ stepId: "generate",
322
+ startedAt: "...",
323
+ completedAt: "...",
324
+ latencyMs: 2340,
325
+ provider: "replicate",
326
+ cost: { cents: 2 },
327
+ input: { ... },
328
+ output: { ... }
329
+ },
330
+ // ...
331
+ ],
332
+ totalLatencyMs: 4521,
333
+ totalCost: { cents: 5 },
334
+ tokensSaved: 1600 // vs discrete calls
335
+ }
336
+ ```
337
+
338
+ Dashboard shows:
339
+ - Chain execution timeline (Gantt-style)
340
+ - Cost breakdown per step
341
+ - Error rates per provider
342
+ - Most-used chain templates
343
+
344
+ ---
345
+
346
+ ## Security
347
+
348
+ ### Credential Isolation
349
+ Each step runs with only the credentials it needs. Step B cannot access Step A's provider credentials.
350
+
351
+ ### Input Validation
352
+ References are validated before execution:
353
+ - `$nonexistent.url` → Error before any step runs
354
+ - Type mismatches caught early
355
+
356
+ ### Rate Limiting
357
+ Chain-level rate limits prevent runaway execution:
358
+ ```typescript
359
+ chain: [...],
360
+ limits: {
361
+ maxSteps: 20,
362
+ maxParallel: 5,
363
+ maxCost: { cents: 100 }
364
+ }
365
+ ```
366
+
367
+ ---
368
+
369
+ ## Pricing
370
+
371
+ **Chain execution = sum of step costs.**
372
+
373
+ No orchestration fee. Chaining is a feature, not a product.
374
+
375
+ Why: Chains reduce our compute overhead (1 request vs N). We pass savings to users.
376
+
377
+ ---
378
+
379
+ ## The Complete Picture
380
+
381
+ ```
382
+ ┌─────────────────────────────────────────────────────────────────┐
383
+ │ AGENT │
384
+ │ │
385
+ │ "Generate 3 variations, pick the best, publish, notify team" │
386
+ │ │
387
+ └─────────────────────────┬───────────────────────────────────────┘
388
+
389
+
390
+ ┌─────────────────────────────────────────────────────────────────┐
391
+ │ call_api({ chain: [...] }) │
392
+ └─────────────────────────┬───────────────────────────────────────┘
393
+
394
+
395
+ ┌─────────────────────────────────────────────────────────────────┐
396
+ │ APICLAW ORCHESTRATOR │
397
+ │ │
398
+ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
399
+ │ │ Parse │→ │Validate │→ │ Plan │ │
400
+ │ │ Chain │ │ Refs │ │ Exec │ │
401
+ │ └─────────┘ └─────────┘ └─────────┘ │
402
+ │ │ │
403
+ │ ▼ │
404
+ │ ┌──────────────────────────────────────────────────────────┐ │
405
+ │ │ EXECUTION ENGINE │ │
406
+ │ │ │ │
407
+ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
408
+ │ │ │ A │───→│ B │───→│ C │ Sequential │ │
409
+ │ │ └─────┘ └─────┘ └─────┘ │ │
410
+ │ │ │ │
411
+ │ │ ┌─────┐ │ │
412
+ │ │ │ A │─┐ │ │
413
+ │ │ └─────┘ │ ┌─────┐ │ │
414
+ │ │ ┌─────┐ ├─→│ D │ Parallel + Join │ │
415
+ │ │ │ B │─┤ └─────┘ │ │
416
+ │ │ └─────┘ │ │ │
417
+ │ │ ┌─────┐ │ │ │
418
+ │ │ │ C │─┘ │ │
419
+ │ │ └─────┘ │ │
420
+ │ │ │ │
421
+ │ │ ┌─────┐ ┌─────┐ │ │
422
+ │ │ │ A │───→│ B? │───→ B₁ or B₂ Conditional │ │
423
+ │ │ └─────┘ └─────┘ │ │
424
+ │ │ │ │
425
+ │ └──────────────────────────────────────────────────────────┘ │
426
+ │ │ │
427
+ │ ▼ │
428
+ │ ┌──────────────────────────────────────────────────────────┐ │
429
+ │ │ Replicate │ Cloudinary │ Resend │ Stripe │ ... 18 more │ │
430
+ │ └──────────────────────────────────────────────────────────┘ │
431
+ │ │
432
+ └─────────────────────────────────────────────────────────────────┘
433
+
434
+
435
+ ┌─────────────────────────────────────────────────────────────────┐
436
+ │ AGENT │
437
+ │ │
438
+ │ { success: true, finalResult: { publishedUrl: "..." } } │
439
+ │ │
440
+ └─────────────────────────────────────────────────────────────────┘
441
+ ```
442
+
443
+ ---
444
+
445
+ ## What This Enables
446
+
447
+ ### Self-Orchestrating Agents
448
+ Agent receives a complex task → breaks it into chain → executes atomically → reports result.
449
+
450
+ No human writing glue code. No n8n. No Zapier. The agent IS the orchestrator, APIClaw is the executor.
451
+
452
+ ### Compound Actions
453
+ "Research this company and draft an outreach email" becomes one chain:
454
+ ```
455
+ Brave → Firecrawl (×3) → OpenRouter (analyze) → OpenRouter (draft) → Resend (preview)
456
+ ```
457
+
458
+ ### Agent-to-Agent Workflows
459
+ Agent A triggers a chain that includes calling Agent B's endpoint, which triggers its own chain.
460
+
461
+ Recursive. Distributed. Autonomous.
462
+
463
+ ---
464
+
465
+ ## The Positioning
466
+
467
+ > "APIClaw is not an API aggregator. It's the execution layer for autonomous AI."
468
+
469
+ > "Agents don't integrate APIs. They declare intent. APIClaw handles the rest."
470
+
471
+ > "From tool-calling to orchestration. From 10 round-trips to 1."
472
+
473
+ ---
474
+
475
+ *"A chain of three call_api calls with no context switching."*
476
+
477
+ *Three? Try thirty. Try three hundred.*
478
+
479
+ *No switching. No waiting. No glue code.*
480
+
481
+ *Just execution.*
482
+
483
+ 🦞