Skip to content

Commit e9d263b

Browse files
docs: async polling guide and SDK 0.6.0 examples (#3)
* docs: add async polling guide and update examples for SDK 0.6.0 - Add new async-polling.mdx page explaining the job-based API model - Update quickstart to show 202 responses and polling pattern - Update authentication to explain idempotency key's role in polling - Update concepts to note all graph generation is async - Add SDK SupermodelClient usage examples with polling configuration Closes supermodeltools/supermodel-public-api#336 * fix: correct timeout comment and add AbortController to example - Fix comment: 600000ms is 10 minutes, not 5 - Define AbortController before referencing controller.signal * fix: match docs examples to actual production responses - Initial status is "pending" (not "processing") - retryAfter is 10 in production - Sequence diagram shows pending → processing → completed flow * fix: consistent retryAfter value across all examples
1 parent 4b5b838 commit e9d263b

File tree

5 files changed

+241
-28
lines changed

5 files changed

+241
-28
lines changed

async-polling.mdx

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
---
2+
title: 'Async Polling'
3+
description: 'How graph generation jobs work and how to poll for results'
4+
icon: 'arrows-rotate'
5+
---
6+
7+
All graph generation endpoints are **asynchronous**. When you submit a request, the API creates a background job and returns immediately with a job status. You then poll for results by re-submitting the same request with the same `Idempotency-Key`.
8+
9+
## How It Works
10+
11+
```mermaid
12+
sequenceDiagram
13+
participant Client
14+
participant API
15+
16+
Client->>API: POST /v1/graphs/dependency (file + Idempotency-Key)
17+
API-->>Client: 202 Accepted {status: "pending", retryAfter: 10}
18+
Note over Client: Wait retryAfter seconds
19+
Client->>API: POST /v1/graphs/dependency (same file + same key)
20+
API-->>Client: 202 Accepted {status: "processing", retryAfter: 10}
21+
Note over Client: Wait retryAfter seconds
22+
Client->>API: POST /v1/graphs/dependency (same file + same key)
23+
API-->>Client: 200 OK {status: "completed", result: {graph: {...}}}
24+
```
25+
26+
## Job Statuses
27+
28+
| Status | HTTP Code | Description |
29+
|--------|-----------|-------------|
30+
| `pending` | 202 | Job is queued, waiting to be processed |
31+
| `processing` | 202 | Job is actively being analyzed |
32+
| `completed` | 200 | Job finished successfully, `result` field contains the graph |
33+
| `failed` | 200 | Job encountered an error, `error` field contains the message |
34+
35+
## Response Envelope
36+
37+
All graph endpoints return a consistent envelope:
38+
39+
```json
40+
{
41+
"status": "pending | processing | completed | failed",
42+
"jobId": "unique-job-identifier",
43+
"retryAfter": 10,
44+
"result": { ... },
45+
"error": "error message if failed"
46+
}
47+
```
48+
49+
- **`status`** - Current job state
50+
- **`jobId`** - Unique identifier for the job
51+
- **`retryAfter`** - Recommended seconds to wait before the next poll (only present for pending/processing)
52+
- **`result`** - The graph data (only present when completed)
53+
- **`error`** - Error description (only present when failed)
54+
55+
## Polling with cURL
56+
57+
Store the `Idempotency-Key` in a variable and re-use it for polling:
58+
59+
```bash
60+
IDEMPOTENCY_KEY=$(uuidgen)
61+
62+
# Submit the job
63+
curl --request POST \
64+
--url https://api.supermodeltools.com/v1/graphs/dependency \
65+
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
66+
--header 'X-Api-Key: <your-api-key>' \
67+
--header 'Content-Type: multipart/form-data' \
68+
--form file='@repo.zip'
69+
70+
# Poll until completed (re-submit the same request)
71+
curl --request POST \
72+
--url https://api.supermodeltools.com/v1/graphs/dependency \
73+
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
74+
--header 'X-Api-Key: <your-api-key>' \
75+
--header 'Content-Type: multipart/form-data' \
76+
--form file='@repo.zip'
77+
```
78+
79+
<Tip>
80+
The server uses the `Idempotency-Key` to identify your existing job. Re-submitting the file does not create a duplicate job.
81+
</Tip>
82+
83+
## Using the SDK
84+
85+
The `@supermodeltools/sdk` package handles polling automatically. Install it with:
86+
87+
```bash
88+
npm install @supermodeltools/sdk
89+
```
90+
91+
### Basic Usage
92+
93+
```typescript
94+
import { Configuration, DefaultApi, SupermodelClient } from '@supermodeltools/sdk';
95+
import * as fs from 'fs';
96+
97+
const config = new Configuration({
98+
basePath: 'https://api.supermodeltools.com',
99+
apiKey: 'smsk_live_...',
100+
});
101+
102+
const api = new DefaultApi(config);
103+
const client = new SupermodelClient(api);
104+
105+
// Read your zip file
106+
const zipBuffer = fs.readFileSync('repo.zip');
107+
const file = new Blob([zipBuffer], { type: 'application/zip' });
108+
109+
// This handles polling internally and returns the completed result
110+
const result = await client.generateDependencyGraph(file);
111+
console.log(result.graph.nodes);
112+
```
113+
114+
### Configuring Polling Behavior
115+
116+
```typescript
117+
const controller = new AbortController();
118+
119+
const client = new SupermodelClient(api, {
120+
timeoutMs: 600000, // Max wait time: 10 minutes (default: 5 minutes)
121+
defaultRetryIntervalMs: 3000, // Poll interval if server doesn't specify (default: 5s)
122+
maxPollingAttempts: 120, // Max number of polls (default: 60)
123+
onPollingProgress: (progress) => {
124+
console.log(`Attempt ${progress.attempt}/${progress.maxAttempts} - ${progress.status}`);
125+
},
126+
signal: controller.signal, // AbortSignal for cancellation
127+
});
128+
129+
// To cancel polling at any point:
130+
// controller.abort();
131+
```
132+
133+
### Available Methods
134+
135+
| Method | Endpoint |
136+
|--------|----------|
137+
| `client.generateDependencyGraph(file)` | `/v1/graphs/dependency` |
138+
| `client.generateCallGraph(file)` | `/v1/graphs/call` |
139+
| `client.generateDomainGraph(file)` | `/v1/graphs/domain` |
140+
| `client.generateParseGraph(file)` | `/v1/graphs/parse` |
141+
| `client.generateSupermodelGraph(file)` | `/v1/graphs/supermodel` |
142+
143+
## Error Handling
144+
145+
If a job fails, the response will have `status: "failed"` with an `error` message:
146+
147+
```json
148+
{
149+
"status": "failed",
150+
"jobId": "550e8400-e29b-41d4-a716-446655440000",
151+
"error": "Nested archives are not supported"
152+
}
153+
```
154+
155+
Common failure reasons:
156+
157+
| Error | Resolution |
158+
|-------|------------|
159+
| Nested archives | Exclude `.zip`/`.tar` files from your archive using `.gitattributes` with `export-ignore` |
160+
| File exceeds size limits | Exclude large binary files from the archive |
161+
| Blob expired | Job waited too long in the queue; retry with a new idempotency key |
162+
163+
<Warning>
164+
Jobs have a limited processing window. If a job stays in `pending` status too long, the uploaded file may expire and the job will be marked as `failed`.
165+
</Warning>
166+
167+
## Idempotency Key Behavior
168+
169+
The `Idempotency-Key` scopes a job to your API key. Key behaviors:
170+
171+
- **Same key, same user**: Returns the existing job (no duplicate processing)
172+
- **Same key, different user**: Creates independent jobs (no conflict)
173+
- **New key, same file**: Creates a new job (useful for re-analysis after code changes)
174+
175+
<Info>
176+
Completed jobs are retained for 24 hours. After that, submitting the same idempotency key will create a new job.
177+
</Info>

authentication.mdx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ X-Api-Key: smsk_live_...
2020

2121
## Idempotency Key
2222

23-
All API requests require an `Idempotency-Key` header. This is a unique value (such as a UUID) that you generate for each request. It serves two purposes:
23+
All API requests require an `Idempotency-Key` header. This is a unique value (such as a UUID) that you generate for each request. It serves three purposes:
2424

25-
1. **Safe retries**: If a request fails due to a network issue, you can safely retry it with the same idempotency key without risking duplicate operations.
26-
2. **Request tracing**: The key is echoed back in the `X-Request-Id` response header for debugging and support purposes.
25+
1. **Job identity**: The key identifies your graph generation job. Re-submitting the same key returns the existing job status rather than creating a duplicate.
26+
2. **Polling**: You poll for results by re-submitting the same request with the same idempotency key. See [Async Polling](/async-polling) for details.
27+
3. **Request tracing**: The key is echoed back in the `X-Request-Id` response header for debugging and support purposes.
2728

2829
```bash
2930
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

concepts.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ icon: 'layer-group'
66

77
Supermodel provides different "lenses" to view your codebase through. Each API endpoint generates a specific type of graph suited for different analysis tasks.
88

9+
All graph generation is **asynchronous** — the API accepts your request, processes it in the background, and you poll for results. See [Async Polling](/async-polling) for details.
10+
911
## Dependency Graph
1012

1113
**Endpoint:** `/v1/graphs/dependency`

docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"index",
3131
"quickstart",
3232
"authentication",
33+
"async-polling",
3334
"concepts"
3435
]
3536
}

quickstart.mdx

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,53 +21,85 @@ The Supermodel API accepts code as a zipped archive. Navigate to your project fo
2121
zip -r repo.zip . -x ".*" -x "**/.*" -x "node_modules/*"
2222
```
2323

24-
## Step 2: Generate a graph
24+
## Step 2: Submit a graph generation job
2525

26-
Use the `dependency` endpoint to generate a graph of file-level dependencies. Replace `<your-api-key>` with your actual key. The `Idempotency-Key` should be a unique value (like a UUID) for each request.
26+
Use the `dependency` endpoint to submit a graph generation job. Replace `<your-api-key>` with your actual key. The `Idempotency-Key` should be a unique value (like a UUID) for each request.
2727

2828
```bash
29+
IDEMPOTENCY_KEY=$(uuidgen)
30+
2931
curl --request POST \
3032
--url https://api.supermodeltools.com/v1/graphs/dependency \
31-
--header "Idempotency-Key: $(uuidgen)" \
33+
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
3234
--header 'X-Api-Key: <your-api-key>' \
3335
--header 'Content-Type: multipart/form-data' \
3436
--form file='@repo.zip'
3537
```
3638

39+
The API returns an **HTTP 202 Accepted** response with the job status:
40+
41+
```json
42+
{
43+
"status": "pending",
44+
"jobId": "550e8400-e29b-41d4-a716-446655440000",
45+
"retryAfter": 10
46+
}
47+
```
48+
3749
<Tip>
3850
The `$(uuidgen)` command generates a unique ID automatically on macOS and Linux. On Windows, you can use `[guid]::NewGuid()` in PowerShell.
3951
</Tip>
4052

41-
## Step 3: Interpret the response
53+
## Step 3: Poll for results
4254

43-
You will receive a JSON response containing the graph nodes (files) and relationships (imports).
55+
Graph generation is asynchronous. Poll by re-submitting the same request with the **same Idempotency-Key** until the job completes:
56+
57+
```bash
58+
# Re-submit the same request to check job status
59+
curl --request POST \
60+
--url https://api.supermodeltools.com/v1/graphs/dependency \
61+
--header "Idempotency-Key: $IDEMPOTENCY_KEY" \
62+
--header 'X-Api-Key: <your-api-key>' \
63+
--header 'Content-Type: multipart/form-data' \
64+
--form file='@repo.zip'
65+
```
66+
67+
When the job completes, you receive an **HTTP 200** response with the graph inside the `result` field:
4468

4569
```json
4670
{
47-
"graph": {
48-
"nodes": [
49-
{
50-
"id": "src/main.ts",
51-
"labels": ["File"],
52-
"properties": { "name": "main.ts" }
53-
},
54-
{
55-
"id": "src/utils.ts",
56-
"labels": ["File"],
57-
"properties": { "name": "utils.ts" }
58-
}
59-
],
60-
"relationships": [
61-
{
62-
"type": "imports",
63-
"startNode": "src/main.ts",
64-
"endNode": "src/utils.ts"
65-
}
66-
]
71+
"status": "completed",
72+
"jobId": "550e8400-e29b-41d4-a716-446655440000",
73+
"result": {
74+
"graph": {
75+
"nodes": [
76+
{
77+
"id": "src/main.ts",
78+
"labels": ["File"],
79+
"properties": { "name": "main.ts" }
80+
},
81+
{
82+
"id": "src/utils.ts",
83+
"labels": ["File"],
84+
"properties": { "name": "utils.ts" }
85+
}
86+
],
87+
"relationships": [
88+
{
89+
"type": "imports",
90+
"startNode": "src/main.ts",
91+
"endNode": "src/utils.ts"
92+
}
93+
]
94+
}
6795
}
6896
}
6997
```
7098

99+
<Info>
100+
**Using the SDK?** The `@supermodeltools/sdk` package handles polling automatically. See the [Async Polling](/async-polling) guide for details.
101+
</Info>
102+
71103
## Next Steps
72104

73105
Explore other graph types to get different insights into your code:

0 commit comments

Comments
 (0)