catelog 1.0.0 → 1.0.2
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/DECISION.md +183 -183
- package/README.md +98 -74
- package/USAGE.md +958 -0
- package/dist/adapters.d.ts +84 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +267 -0
- package/dist/adapters.js.map +1 -0
- package/dist/agent.d.ts +73 -13
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +373 -154
- package/dist/agent.js.map +1 -1
- package/dist/banner.d.ts +6 -3
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js +29 -18
- package/dist/banner.js.map +1 -1
- package/dist/context.d.ts +18 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +82 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -6
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +4 -4
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +46 -20
- package/dist/schema.js.map +1 -1
- package/dist/security.d.ts +25 -16
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +132 -55
- package/dist/security.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -3
- package/dist/server.js.map +1 -1
- package/dist/sse.d.ts +31 -7
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +94 -26
- package/dist/sse.js.map +1 -1
- package/dist/telemetry.d.ts +41 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +93 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +115 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/package.json +5 -2
package/DECISION.md
CHANGED
|
@@ -1,250 +1,250 @@
|
|
|
1
|
-
# Architecture & Design Decisions
|
|
1
|
+
# Catelog TypeScript SDK — Architecture & Design Decisions
|
|
2
2
|
|
|
3
|
-
> **
|
|
4
|
-
>
|
|
3
|
+
> **From Team ROX:**
|
|
4
|
+
> *"Welcome to the agent economy, where humans and agents rent out intelligence."*
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## What Is Catelog?
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
`catelog` is the official TypeScript SDK for the **Catelog Marketplace**. It solves one problem cleanly: turning any AI agent — regardless of the framework, model, or runtime — into a production-ready, marketplace-compliant microservice in **under 20 lines of code**.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
- Raw HTTP server routing and CORS handling.
|
|
14
|
-
- Cryptographic request signing and anti-replay defense.
|
|
15
|
-
- Server-Sent Events (SSE) streaming with heartbeat keep-alives.
|
|
16
|
-
- JSON Schema generation from TypeScript types.
|
|
17
|
-
- Client disconnect / cancellation propagation.
|
|
12
|
+
You bring your agent logic. The SDK handles everything else:
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
- HTTP routing, CORS, and error handling
|
|
15
|
+
- Authentication (Bearer token, HMAC-SHA256, or permissive dev mode)
|
|
16
|
+
- Real-time SSE streaming with heartbeat keep-alives
|
|
17
|
+
- Task lifecycle state management (working → completed / failed / canceled / input-required)
|
|
18
|
+
- Schema validation and manifest generation
|
|
19
|
+
- Background telemetry reporting
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## Guiding Principle: Progressive Disclosure
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
* **Context:** The marketplace requires standardized communication contracts between the Gateway and BYOS agent servers.
|
|
27
|
-
* **Decision:** `catelog` strictly implements the **Marketplace Agent Protocol Specification (MAPS v1.0.0)**.
|
|
28
|
-
* **Endpoints Exposed:**
|
|
29
|
-
1. `GET /health`: Instantaneous liveness and uptime probe ($< 10\text{ms}$).
|
|
30
|
-
2. `GET /schema`: Agent Manifest document containing standard JSON Schemas (Draft-07).
|
|
31
|
-
3. `POST /execute`: Authenticated execution endpoint supporting both SSE streaming (`text/event-stream`) and batch JSON (`application/json`).
|
|
25
|
+
Senior engineers should never struggle with the SDK. The design follows a **progressive disclosure** model:
|
|
32
26
|
|
|
33
|
-
|
|
27
|
+
```
|
|
28
|
+
Level 1 — Zero friction (5 lines, no config)
|
|
29
|
+
Level 2 — Add schemas for validation and marketplace forms
|
|
30
|
+
Level 3 — Add keys for production auth
|
|
31
|
+
Level 4 — Add mode, telemetry, and framework adapters
|
|
32
|
+
```
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
* **Context:** Open-network agent servers are targets for denial-of-service, spoofed executions, and credential burn. Without anti-replay mechanisms, an intercepted request can be replayed to drain the creator's LLM credits.
|
|
37
|
-
* **Decision:**
|
|
38
|
-
- **Canonical HMAC-SHA256 Signing:** All `/execute` calls require a signature calculated over normalized components:
|
|
39
|
-
$$\text{BodyHash} = \text{HEX}(\text{SHA256}(\text{RawRequestBodyBytes}))$$
|
|
40
|
-
$$\text{CanonicalString} = \text{METHOD} + "\backslash\text{n}" + \text{PATH} + "\backslash\text{n}" + \text{TIMESTAMP} + "\backslash\text{n}" + \text{NONCE} + "\backslash\text{n}" + \text{RUN\_ID} + "\backslash\text{n}" + \text{BodyHash}$$
|
|
41
|
-
$$\text{Signature} = \text{HEX}(\text{HMAC-SHA256}(\text{Secret}, \text{CanonicalString}))$$
|
|
42
|
-
- **5-Minute Clock Drift Enforcement:** Requests with $|\text{CurrentTime} - \text{Timestamp}| > 300{,}000\text{ms}$ are rejected immediately (`AUTH_TIMESTAMP_OUT_OF_BOUNDS`).
|
|
43
|
-
- **Sliding Nonce Cache:** In-memory LRU cache with 5-minute TTL. Any repeated nonce within the drift window is blocked (`AUTH_REPLAY_DETECTED`).
|
|
44
|
-
- **Run ID Idempotency:** Duplicate active or completed run IDs cannot be re-executed.
|
|
45
|
-
- **Constant-Time Comparison:** Uses `crypto.timingSafeEqual` to eliminate side-channel timing attacks.
|
|
34
|
+
At every level, the SDK adds features without breaking the previous level.
|
|
46
35
|
|
|
47
36
|
---
|
|
48
37
|
|
|
49
|
-
|
|
50
|
-
* **Context:** Forcing developers into a specific LLM library creates friction.
|
|
51
|
-
* **Decision:** `catelog` uses the **Adapter Pattern**. The SDK is completely decoupled from agent orchestration frameworks:
|
|
52
|
-
- Works with **LangGraph / LangChain**.
|
|
53
|
-
- Works with **OpenAI SDK** (`client.responses.create`).
|
|
54
|
-
- Works with **LlamaIndex**, **Vercel AI SDK**, or vanilla TypeScript loops.
|
|
55
|
-
Developers simply pass an `execute({ input, stream, signal })` async function.
|
|
38
|
+
## Core Architectural Decisions
|
|
56
39
|
|
|
57
|
-
|
|
40
|
+
### Decision 1: Inferred Task Lifecycle (No Manual State Management)
|
|
58
41
|
|
|
59
|
-
|
|
60
|
-
* **Context:** The marketplace UI and gateway validation engine require explicit JSON Schemas to generate input forms and enforce pre-execution contracts.
|
|
61
|
-
* **Decision:** Developers can define schemas using standard [Zod](https://zod.dev) or raw JSON Schema objects. `catelog` automatically converts Zod objects into standard JSON Schema Draft-07 for the `GET /schema` endpoint while providing runtime type safety for incoming buyer payloads.
|
|
42
|
+
**Problem:** If developers must manually call `task.setStatus("working")`, `task.setStatus("completed")`, etc., they will forget — leaving tasks stuck in a "working" state forever on unhandled exceptions.
|
|
62
43
|
|
|
63
|
-
|
|
44
|
+
**Decision:** The SDK infers the full task state machine from standard async function semantics:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
execute() starts → SDK emits task.status = "working"
|
|
48
|
+
stream.delta(...) → SDK emits task.delta (task stays "working")
|
|
49
|
+
stream.progress(...) → SDK emits task.progress (task stays "working")
|
|
50
|
+
return value → SDK emits task.completed automatically
|
|
51
|
+
throw error → SDK emits task.failed automatically
|
|
52
|
+
client disconnects → SDK emits task.canceled automatically
|
|
53
|
+
ctx.needInput(...) → SDK emits task.input_required (HITL suspension)
|
|
54
|
+
```
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
* **Context:** Long-running deep research or multi-agent loops (e.g. 30–120 seconds) frequently get terminated prematurely by intermediate proxies (Cloudflare Error 524, AWS ALB 504 Gateway Timeout).
|
|
67
|
-
* **Decision:**
|
|
68
|
-
- **Automatic 15s Heartbeats:** The SDK spawns an internal timer emitting `{ event: "heartbeat", timestamp: ... }` every 15 seconds during active runs.
|
|
69
|
-
- **Clean Disconnect Handling:** If a buyer or gateway closes the socket, the SDK catches the event and trips an `AbortSignal`, allowing developers to abort downstream LLM calls immediately and prevent wasted API costs.
|
|
56
|
+
The developer only writes normal `async/await` code. Task state is never their concern.
|
|
70
57
|
|
|
71
58
|
---
|
|
72
59
|
|
|
73
|
-
### Decision
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
### Decision 2: Dual-Mode Authentication (Not Strict HMAC-Only)
|
|
61
|
+
|
|
62
|
+
**Problem:** Requiring full HMAC-SHA256 headers for every request means a senior engineer can't test with `curl` or Postman without writing a custom signing script. This kills developer experience.
|
|
63
|
+
|
|
64
|
+
**Decision:** The SDK detects the best available authentication method from the request:
|
|
65
|
+
|
|
66
|
+
| Priority | Method | How It's Detected | When Used |
|
|
67
|
+
| :---: | :--- | :--- | :--- |
|
|
68
|
+
| 1 | **HMAC-SHA256** | `X-Marketplace-Signature` header present | Marketplace Gateway → Agent |
|
|
69
|
+
| 2 | **Bearer secret** | `Authorization: Bearer cat_sec_live_...` | curl, Postman, internal services |
|
|
70
|
+
| 3 | **Bearer public** | `Authorization: Bearer cat_pub_live_...` | Frontend, schema/health calls |
|
|
71
|
+
| 4 | **Dev mode** | No auth, `NODE_ENV !== "production"` | Local development |
|
|
72
|
+
| 5 | **Rejected** | No auth in production | Security enforcement |
|
|
73
|
+
|
|
74
|
+
Keys are auto-discovered from environment variables (`CATELOG_SECRET_KEY`, `CATELOG_PUBLIC_KEY`). The developer never needs to pass them manually if `.env` is configured.
|
|
76
75
|
|
|
77
76
|
---
|
|
78
77
|
|
|
79
|
-
|
|
78
|
+
### Decision 3: Three Execution Modes
|
|
79
|
+
|
|
80
|
+
**Problem:** Agents have fundamentally different execution profiles. A web search agent finishes in 2 seconds. A deep research graph may take 4 minutes. A document assistant may need to ask a clarifying question mid-run.
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
**Decision:** Three first-class execution modes, selectable with a single config field:
|
|
82
83
|
|
|
83
84
|
```
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
├── README.md # Comprehensive developer documentation
|
|
88
|
-
├── DECISION.md # This architectural decision document
|
|
89
|
-
├── scripts/
|
|
90
|
-
│ └── postinstall.js # Zero-dependency install splash for npm/pnpm/yarn/bun
|
|
91
|
-
├── src/
|
|
92
|
-
│ ├── index.ts # Clean root exports
|
|
93
|
-
│ ├── types.ts # Protocol interfaces, event contracts & error codes
|
|
94
|
-
│ ├── security.ts # SecurityManager (HMAC-SHA256, nonce cache, replay guard)
|
|
95
|
-
│ ├── sse.ts # SSEWriter (heartbeat timer, stream formatting, abort signal)
|
|
96
|
-
│ ├── schema.ts # Zod-to-JSON-Schema converter & runtime validator
|
|
97
|
-
│ ├── agent.ts # MarketplaceAgent class & createMarketplaceAgent() factory
|
|
98
|
-
│ ├── server.ts # Lightweight native HTTP server runner (.serve(port))
|
|
99
|
-
│ └── banner.ts # Rich ANSI terminal diagnostics and startup splash
|
|
100
|
-
└── test/
|
|
101
|
-
└── index.test.ts # Automated verification test suite
|
|
85
|
+
"sync" → Direct HTTP/SSE connection, resolves in same request
|
|
86
|
+
"async" → Returns 202 Accepted + jobId, polled via GET /tasks/:id
|
|
87
|
+
"conversational" → Supports ctx.needInput() for HITL suspension and resume
|
|
102
88
|
```
|
|
103
89
|
|
|
104
|
-
|
|
90
|
+
The developer sets `mode: "async"` and writes normal async code. The SDK handles the 202 response, background execution, job store, and polling endpoint automatically.
|
|
105
91
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Decision 4: Optional Schemas (Not Required)
|
|
95
|
+
|
|
96
|
+
**Problem:** Forcing `inputSchema` and `outputSchema` as required fields blocks rapid prototyping. A developer testing locally shouldn't need to write a Zod schema just to get a server running.
|
|
97
|
+
|
|
98
|
+
**Decision:** Both `inputSchema` and `outputSchema` are optional:
|
|
99
|
+
|
|
100
|
+
- If provided, the SDK validates inputs at the gateway and generates marketplace forms from the schema
|
|
101
|
+
- If omitted, the SDK accepts any valid JSON payload and returns an open `{ type: "object" }` schema
|
|
102
|
+
|
|
103
|
+
Zod v3, Zod v4, and raw JSON Schema Draft-07 objects are all supported natively.
|
|
114
104
|
|
|
115
105
|
---
|
|
116
106
|
|
|
117
|
-
|
|
107
|
+
### Decision 5: Two-Layer Non-Blocking Telemetry
|
|
118
108
|
|
|
119
|
-
|
|
120
|
-
`catelog` is universally compatible with all package managers:
|
|
109
|
+
**Problem:** Telemetry is valuable but must never break or slow down agent execution. If a telemetry endpoint is unreachable, the buyer's run must still complete normally.
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
# pnpm
|
|
124
|
-
pnpm add catelog zod
|
|
111
|
+
**Decision:** Two independent telemetry layers:
|
|
125
112
|
|
|
126
|
-
|
|
127
|
-
|
|
113
|
+
**Layer 1 — Universal Base (automatic, zero developer effort):**
|
|
114
|
+
Collected for every agent regardless of framework: execution duration, input/output byte sizes, chunks streamed, task final state, error codes.
|
|
128
115
|
|
|
129
|
-
|
|
130
|
-
|
|
116
|
+
**Layer 2 — Framework-Specific Enrichment (progressive, graceful):**
|
|
117
|
+
When using OpenAI, Vercel AI SDK, or LangGraph adapters, the SDK extracts token counts, tool call counts, and graph node transitions. If extraction fails, it silently falls back to Layer 1.
|
|
131
118
|
|
|
132
|
-
|
|
133
|
-
bun add catelog zod
|
|
134
|
-
```
|
|
119
|
+
**Background reporting** is fire-and-forget with a 3-second timeout. Network failures are silently discarded. The agent response is never blocked.
|
|
135
120
|
|
|
136
121
|
---
|
|
137
122
|
|
|
138
|
-
###
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
summary: z.string(),
|
|
155
|
-
sources: z.array(z.string()),
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// 2. Wrap the agent
|
|
159
|
-
export const agent = createMarketplaceAgent({
|
|
160
|
-
name: "B2B Market Research Agent",
|
|
161
|
-
version: "1.0.0",
|
|
162
|
-
description: "Autonomous research agent using OpenAI web search",
|
|
163
|
-
secret: process.env.MARKETPLACE_SECRET, // Provided by the marketplace
|
|
164
|
-
inputSchema: InputSchema,
|
|
165
|
-
outputSchema: OutputSchema,
|
|
166
|
-
|
|
167
|
-
async execute({ input, stream, signal }) {
|
|
168
|
-
// Report progress steps live to the buyer UI
|
|
169
|
-
stream.step("Initiating web discovery...");
|
|
170
|
-
|
|
171
|
-
const response = await client.responses.create({
|
|
172
|
-
model: "gpt-6-luna",
|
|
173
|
-
input: input.query,
|
|
174
|
-
tools: [{ type: "web_search" }],
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
stream.step("Formatting structured report...");
|
|
178
|
-
|
|
179
|
-
return {
|
|
180
|
-
output: {
|
|
181
|
-
summary: response.output_text || "",
|
|
182
|
-
sources: ["https://example.com/source1"],
|
|
183
|
-
},
|
|
184
|
-
telemetry: {
|
|
185
|
-
model_used: "gpt-6-luna",
|
|
186
|
-
llm_tokens: {
|
|
187
|
-
total: response.usage?.total_tokens || 350,
|
|
188
|
-
},
|
|
189
|
-
cost_usd: 0.002,
|
|
190
|
-
},
|
|
191
|
-
};
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// 3. Start the server (prints the signature CATELOG banner)
|
|
196
|
-
agent.serve(4000);
|
|
123
|
+
### Decision 6: Framework Adapters (One-Line Integration)
|
|
124
|
+
|
|
125
|
+
**Problem:** Developers using OpenAI streams, LangGraph runnables, or Vercel AI SDK results must manually loop over chunks and call `stream.delta()` for every piece. This is repetitive glue code.
|
|
126
|
+
|
|
127
|
+
**Decision:** Native adapter functions that pipe framework-specific outputs directly into Catelog's task event stream:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
// Before (verbose glue):
|
|
131
|
+
for await (const chunk of openaiStream) {
|
|
132
|
+
if (chunk.choices[0].delta.content) {
|
|
133
|
+
stream.delta(chunk.choices[0].delta.content);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// After (one line):
|
|
138
|
+
return pipeOpenAiStream(openaiStream, stream);
|
|
197
139
|
```
|
|
198
140
|
|
|
141
|
+
Adapters handle streaming, telemetry extraction, tool call events, and graceful error recovery — all in a single call.
|
|
142
|
+
|
|
199
143
|
---
|
|
200
144
|
|
|
201
|
-
###
|
|
145
|
+
### Decision 7: Health Check as Registration Probe
|
|
146
|
+
|
|
147
|
+
**Problem:** When a creator registers their agent server on the marketplace, the platform needs to verify the server is reachable, running the right protocol version, and capable of the declared features — before accepting the listing.
|
|
148
|
+
|
|
149
|
+
**Decision:** `GET /health` returns a rich response with capabilities, used for one-click registration verification:
|
|
202
150
|
|
|
203
|
-
#### Test Ping / Liveness:
|
|
204
|
-
```bash
|
|
205
|
-
curl http://localhost:4000/health
|
|
206
|
-
```
|
|
207
151
|
```json
|
|
208
152
|
{
|
|
209
153
|
"status": "ready",
|
|
210
154
|
"protocol_version": "1.0.0",
|
|
211
|
-
"uptime_seconds":
|
|
212
|
-
"environment_ready": true
|
|
155
|
+
"uptime_seconds": 1284,
|
|
156
|
+
"environment_ready": true,
|
|
157
|
+
"capabilities": {
|
|
158
|
+
"streaming": true,
|
|
159
|
+
"delta_stream": true,
|
|
160
|
+
"execution_modes": ["async"]
|
|
161
|
+
}
|
|
213
162
|
}
|
|
214
163
|
```
|
|
215
164
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
165
|
+
The marketplace fires `/health` then `/schema` in sequence. The creator sees their agent's name, input fields, and capabilities auto-populated on the listing page — no manual configuration.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Source File Map
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
sdk/ts-sdk/src/
|
|
173
|
+
├── index.ts Clean root exports for everything below
|
|
174
|
+
├── types.ts Protocol types, task states, SSE events, error codes
|
|
175
|
+
├── agent.ts CatelogAgent class — the core engine
|
|
176
|
+
├── security.ts Dual-mode auth: Bearer, HMAC-SHA256, public key, dev
|
|
177
|
+
├── sse.ts SSEWriter — task lifecycle events, heartbeat, disconnect
|
|
178
|
+
├── context.ts AgentExecutionContext — session, needInput(), log, metric
|
|
179
|
+
├── telemetry.ts 2-layer telemetry collector + background reporter
|
|
180
|
+
├── adapters.ts Framework adapters: OpenAI, Vercel AI SDK, LangGraph
|
|
181
|
+
├── schema.ts Zod-to-JSON-Schema + runtime input validation
|
|
182
|
+
├── server.ts Lightweight native Node.js HTTP server
|
|
183
|
+
└── banner.ts ANSI terminal startup splash
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| File | Responsibility |
|
|
187
|
+
| :--- | :--- |
|
|
188
|
+
| `agent.ts` | Routes `/health`, `/schema`, `/execute`, `/tasks/:id`. Dispatches execution modes. Normalizes results and errors. |
|
|
189
|
+
| `security.ts` | Detects auth method, verifies Bearer tokens, validates HMAC-SHA256 signatures, manages nonce replay cache. |
|
|
190
|
+
| `sse.ts` | Writes canonical SSE frames, emits 8 task lifecycle event types, manages heartbeat timer and client disconnect detection. |
|
|
191
|
+
| `context.ts` | Builds the `ctx` object passed to `execute()`. Manages session store for conversational agents. |
|
|
192
|
+
| `telemetry.ts` | Collects base metrics, provides structured logger, fires background telemetry reports with silent failure. |
|
|
193
|
+
| `adapters.ts` | Translates OpenAI, Vercel AI SDK, LangGraph, and generic async iterable outputs into Catelog stream events. |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## The SSE Event Protocol (What the Marketplace Receives)
|
|
198
|
+
|
|
199
|
+
Every streaming execution produces this sequence of events:
|
|
200
|
+
|
|
219
201
|
```
|
|
220
|
-
|
|
202
|
+
event: task.status
|
|
203
|
+
data: {"event":"task.status","run_id":"run_abc","status":"working","timestamp":1729410000000}
|
|
204
|
+
|
|
205
|
+
event: task.progress ← from stream.progress(40, "Searching...")
|
|
206
|
+
data: {"event":"task.progress","run_id":"run_abc","percent":40,"message":"Searching...","step":1}
|
|
221
207
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
- `X-Marketplace-Protocol: 1.0.0`
|
|
225
|
-
- `X-Marketplace-Timestamp: <timestamp>`
|
|
226
|
-
- `X-Marketplace-Nonce: <uuid>`
|
|
227
|
-
- `X-Marketplace-Run-Id: <run_id>`
|
|
228
|
-
- `X-Marketplace-Signature: <hex_hmac>`
|
|
208
|
+
event: task.delta ← from stream.delta("Found 3 results...")
|
|
209
|
+
data: {"event":"task.delta","run_id":"run_abc","index":0,"delta_type":"text","content":"Found 3 results..."}
|
|
229
210
|
|
|
230
|
-
|
|
211
|
+
event: task.activity ← from stream.activity("tool_call", {...})
|
|
212
|
+
data: {"event":"task.activity","run_id":"run_abc","activity_type":"tool_call","data":{...}}
|
|
213
|
+
|
|
214
|
+
event: heartbeat ← automatic every 15 seconds
|
|
215
|
+
data: {"event":"heartbeat","timestamp":1729410015000}
|
|
216
|
+
|
|
217
|
+
event: task.completed ← from return result
|
|
218
|
+
data: {"event":"task.completed","run_id":"run_abc","duration_ms":3412,"output":{...},"telemetry":{...}}
|
|
231
219
|
```
|
|
232
|
-
event: run.started
|
|
233
|
-
data: {"event":"run.started","run_id":"run_123","timestamp":1729410000000}
|
|
234
220
|
|
|
235
|
-
|
|
236
|
-
|
|
221
|
+
For `input-required` agents:
|
|
222
|
+
```
|
|
223
|
+
event: task.input_required ← from ctx.needInput({...})
|
|
224
|
+
data: {"event":"task.input_required","run_id":"run_abc","prompt":"...","resume_token":"resume_abc123","input_schema":{...}}
|
|
225
|
+
```
|
|
237
226
|
|
|
238
|
-
|
|
239
|
-
|
|
227
|
+
For failed agents:
|
|
228
|
+
```
|
|
229
|
+
event: task.failed ← from throw new Error(...)
|
|
230
|
+
data: {"event":"task.failed","run_id":"run_abc","duration_ms":812,"error":{"code":"INTERNAL_CRASH","message":"...","retryable":false}}
|
|
240
231
|
```
|
|
241
232
|
|
|
242
233
|
---
|
|
243
234
|
|
|
244
|
-
##
|
|
235
|
+
## API Keys: Public vs Secret
|
|
236
|
+
|
|
237
|
+
| Key | Format | Where It Lives | Used For |
|
|
238
|
+
| :--- | :--- | :--- | :--- |
|
|
239
|
+
| **Publishable** | `cat_pub_live_...` | Frontend, client apps | `/health`, `/schema` calls, analytics |
|
|
240
|
+
| **Secret** | `cat_sec_live_...` | Server `.env` only | `/execute` auth, agent registration, webhooks |
|
|
245
241
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
242
|
+
The secret key is revealed **once** at creation. It is stored in the database as a SHA-256 hash. The preview characters shown in the UI (`cat_sec_live_...xxxx`) are for identification only.
|
|
243
|
+
|
|
244
|
+
On the agent server, set the secret key in `.env`:
|
|
245
|
+
```
|
|
246
|
+
CATELOG_SECRET_KEY=cat_sec_live_your_key_here
|
|
247
|
+
CATELOG_PUBLIC_KEY=cat_pub_live_your_key_here
|
|
248
|
+
```
|
|
250
249
|
|
|
250
|
+
The SDK auto-reads both from `process.env`. No manual passing required.
|
package/README.md
CHANGED
|
@@ -9,110 +9,134 @@
|
|
|
9
9
|
╚██████╗██║ ██║ ██║ ███████╗███████╗╚██████╔╝╚██████╔╝
|
|
10
10
|
╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝
|
|
11
11
|
────────────────────────────────────────────────────────────────────
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
NOTE FROM TEAM ROX
|
|
13
|
+
"Welcome to the agent economy, where humans and agents rent out intelligence."
|
|
14
14
|
════════════════════════════════════════════════════════════════════
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
The official TypeScript SDK for the **
|
|
18
|
-
Wrap any AI agent
|
|
17
|
+
The official TypeScript SDK for the **Catelog Agent Marketplace**.
|
|
18
|
+
Wrap any AI agent — LangGraph, OpenAI, Vercel AI SDK, CrewAI, or vanilla TypeScript — into a production-ready, protocol-compliant marketplace microservice in under 20 lines of code.
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## Documentation
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
| Document | Purpose |
|
|
25
|
+
| :--- | :--- |
|
|
26
|
+
| **[USAGE.md](./USAGE.md)** | Complete developer guide — agent types, framework integrations, schemas, keys, telemetry, testing |
|
|
27
|
+
| **[DECISION.md](./DECISION.md)** | Architecture decisions — why things work the way they do |
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pnpm add catelog zod
|
|
29
|
-
```
|
|
29
|
+
---
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm install catelog zod
|
|
34
|
-
```
|
|
31
|
+
## Installation
|
|
35
32
|
|
|
36
|
-
### **yarn**
|
|
37
33
|
```bash
|
|
38
|
-
|
|
34
|
+
pnpm add catelog zod # or npm / yarn / bun
|
|
39
35
|
```
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
bun add catelog zod
|
|
44
|
-
```
|
|
37
|
+
> `zod` is optional — only needed if you want typed schema validation and auto-generated marketplace input forms.
|
|
45
38
|
|
|
46
39
|
---
|
|
47
40
|
|
|
48
|
-
##
|
|
41
|
+
## Quickstart (5 lines)
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
- ⚡ **Dual Execution Modes:** Streaming via Server-Sent Events (`text/event-stream`) or batch JSON (`application/json`).
|
|
53
|
-
- 💓 **Auto Heartbeats:** Emits automatic 15s heartbeats to prevent Cloudflare/ALB gateway timeouts.
|
|
54
|
-
- 📐 **Schema Flexibility:** Native support for [Zod](https://zod.dev) schemas or standard JSON Schema Draft-07.
|
|
55
|
-
- 📡 **Ping / Liveness Check:** Instant `GET /health` verification probe for reachability and uptime.
|
|
56
|
-
- 🎨 **Rich Terminal Aesthetics:** Modern shadcn-style terminal splash on install and server boot.
|
|
43
|
+
```ts
|
|
44
|
+
import { createAgent } from "catelog";
|
|
57
45
|
|
|
58
|
-
|
|
46
|
+
const agent = createAgent({
|
|
47
|
+
name: "Hello Agent",
|
|
48
|
+
async execute({ input }) {
|
|
49
|
+
return { message: `Hello, ${(input as any).name ?? "world"}!` };
|
|
50
|
+
},
|
|
51
|
+
});
|
|
59
52
|
|
|
60
|
-
|
|
53
|
+
agent.listen(3000);
|
|
54
|
+
```
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
import { createMarketplaceAgent } from "catelog";
|
|
64
|
-
import { z } from "zod";
|
|
56
|
+
That's all. You get `/health`, `/schema`, and `/execute` — with streaming, heartbeats, and dev-mode auth — for free.
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## What You Can Build
|
|
61
|
+
|
|
62
|
+
### Sync Agent — Fast responses (default)
|
|
63
|
+
```ts
|
|
64
|
+
createAgent({
|
|
65
|
+
name: "Summarizer",
|
|
66
|
+
async execute({ input, stream }) {
|
|
67
|
+
stream.progress(20, "Analyzing...");
|
|
68
|
+
stream.delta("Here is your summary...\n");
|
|
69
|
+
return { output: { summary: "..." } };
|
|
70
|
+
},
|
|
70
71
|
});
|
|
72
|
+
```
|
|
71
73
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
### Async Agent — Long-running jobs (minutes)
|
|
75
|
+
```ts
|
|
76
|
+
createAgent({
|
|
77
|
+
name: "Deep Researcher",
|
|
78
|
+
mode: "async",
|
|
79
|
+
async execute({ input, log }) {
|
|
80
|
+
log.info("Starting deep research", { topic: input.topic });
|
|
81
|
+
const report = await longRunningResearch(input.topic);
|
|
82
|
+
return { output: { report } };
|
|
83
|
+
},
|
|
75
84
|
});
|
|
85
|
+
// Returns 202 immediately. Marketplace polls GET /tasks/:id until done.
|
|
86
|
+
```
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Call your LLM, LangGraph workflow, or custom code here:
|
|
92
|
-
const summary = `Comprehensive report on ${input.topic}`;
|
|
93
|
-
const citations = ["https://example.com/source1"];
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
output: { summary, citations },
|
|
97
|
-
telemetry: {
|
|
98
|
-
model_used: "gpt-4o-mini",
|
|
99
|
-
llm_tokens: { prompt: 250, completion: 400, total: 650 },
|
|
100
|
-
cost_usd: 0.0012,
|
|
101
|
-
},
|
|
102
|
-
};
|
|
88
|
+
### Conversational Agent — Ask clarifying questions
|
|
89
|
+
```ts
|
|
90
|
+
createAgent({
|
|
91
|
+
name: "SQL Assistant",
|
|
92
|
+
mode: "conversational",
|
|
93
|
+
async execute({ input, ctx }) {
|
|
94
|
+
if (!input.table) {
|
|
95
|
+
return ctx.needInput({
|
|
96
|
+
prompt: "Which table would you like to query?",
|
|
97
|
+
schema: { type: "string", enum: await getTables() },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return { output: { rows: await query(input.table) } };
|
|
103
101
|
},
|
|
104
102
|
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Framework Adapters
|
|
108
|
+
|
|
109
|
+
One-line integrations for popular AI frameworks:
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
```ts
|
|
112
|
+
// OpenAI SDK
|
|
113
|
+
return pipeOpenAiStream(openaiStream, stream);
|
|
114
|
+
|
|
115
|
+
// Vercel AI SDK (streamText, generateText)
|
|
116
|
+
return pipeAiSdkStream(result, stream);
|
|
117
|
+
|
|
118
|
+
// LangGraph compiled graph
|
|
119
|
+
return pipeLangGraphStream(graph, { input }, stream, { signal });
|
|
120
|
+
|
|
121
|
+
// Any AsyncIterable<string> — CrewAI, LlamaIndex, custom generators
|
|
122
|
+
return pipeAsyncIterableStream(myStream, stream);
|
|
108
123
|
```
|
|
109
124
|
|
|
110
125
|
---
|
|
111
126
|
|
|
112
|
-
##
|
|
127
|
+
## Endpoints Provided
|
|
128
|
+
|
|
129
|
+
| Endpoint | Method | Purpose |
|
|
130
|
+
| :--- | :--- | :--- |
|
|
131
|
+
| `/health` | `GET` | Liveness probe — used by marketplace during registration |
|
|
132
|
+
| `/schema` | `GET` | Agent manifest with input/output JSON Schemas |
|
|
133
|
+
| `/execute` | `POST` | Authenticated execution — SSE streaming or JSON batch |
|
|
134
|
+
| `/tasks/:id` | `GET` | Poll async job status *(async mode only)* |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Requirements
|
|
113
139
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
| `/schema` | `GET` | `application/json` | Agent manifest with input/output JSON Schemas |
|
|
118
|
-
| `/execute` | `POST` | `text/event-stream` / `application/json` | Secure HMAC-authenticated execution with streaming |
|
|
140
|
+
- **Node.js** 18+
|
|
141
|
+
- **TypeScript** 5+ (optional but strongly recommended)
|
|
142
|
+
- **ESM** (`"type": "module"` in `package.json`)
|