@otisworks/batch-kit 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # batch-kit
2
+
3
+ An ergonomic CLI + library for the [Anthropic Message Batches API](https://platform.claude.com/docs/en/build-with-claude/batch-processing).
4
+
5
+ Process large volumes of documents with Claude at **50% off** the standard API cost — without hand-writing JSONL, tracking batch IDs, or reimplementing polling loops.
6
+
7
+ ```bash
8
+ batch add --dir ./reviews --prompt "Summarize this review:\n\n{content}"
9
+ batch send
10
+ # ...later...
11
+ batch fetch --latest --output summaries.json
12
+ ```
13
+
14
+ ---
15
+
16
+ ## Why
17
+
18
+ The Batch API is great for cost-effective bulk processing, but the raw developer experience is manual: you build the JSONL request shape yourself, poll for status, and track which batch is which. batch-kit wraps `@anthropic-ai/sdk` and handles all of that behind a familiar, git-like workflow.
19
+
20
+ ## Requirements
21
+
22
+ - Node.js **18+**
23
+ - An `ANTHROPIC_API_KEY`
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install @otisworks/batch-kit
29
+ ```
30
+
31
+ For the CLI globally:
32
+
33
+ ```bash
34
+ npm install -g @otisworks/batch-kit
35
+ ```
36
+
37
+ ## Setup
38
+
39
+ Set your API key via environment variable or a `.env` file in your working directory:
40
+
41
+ ```
42
+ ANTHROPIC_API_KEY=sk-ant-...
43
+ ```
44
+
45
+ The CLI automatically loads `.env` from the current directory.
46
+
47
+ ---
48
+
49
+ ## CLI
50
+
51
+ The CLI follows a git-like staged workflow: **add** documents, **review** them, **send** the batch, then **fetch** results.
52
+
53
+ ### `batch add`
54
+
55
+ Stage documents from a directory using a prompt template.
56
+
57
+ ```bash
58
+ batch add --dir ./documents --prompt "Summarize:\n\n{content}"
59
+ ```
60
+
61
+ | Option | Description |
62
+ |---|---|
63
+ | `-d, --dir <dir>` | Directory of documents (required) |
64
+ | `-p, --prompt <template>` | Prompt template (required) |
65
+ | `-m, --model <model>` | Model override |
66
+ | `--max-tokens <n>` | `max_tokens` override |
67
+ | `-e, --ext <list>` | Comma-separated extensions, e.g. `.txt,.md` |
68
+
69
+ **Template variables:** `{content}` (file contents), `{filename}`, `{index}`.
70
+
71
+ Supported file types: `.txt` and `.md` by default.
72
+
73
+ ### `batch review`
74
+
75
+ Preview what's currently staged.
76
+
77
+ ```bash
78
+ batch review
79
+ ```
80
+
81
+ ### `batch reset`
82
+
83
+ Discard the staging area.
84
+
85
+ ```bash
86
+ batch reset
87
+ ```
88
+
89
+ ### `batch send`
90
+
91
+ Submit staged documents as a single batch. Prints the batch ID and clears staging.
92
+
93
+ ```bash
94
+ batch send # submit and exit
95
+ batch send --wait # block until processing finishes
96
+ ```
97
+
98
+ ### `batch status`
99
+
100
+ Check a batch's processing status and per-request counts.
101
+
102
+ ```bash
103
+ batch status <batch-id>
104
+ batch status --latest # most recently submitted batch
105
+ ```
106
+
107
+ ### `batch fetch`
108
+
109
+ Retrieve results. Results are matched back to their source filenames.
110
+
111
+ ```bash
112
+ batch fetch <batch-id>
113
+ batch fetch --latest
114
+ batch fetch --latest --wait # wait for completion first
115
+ batch fetch --latest --output results.json # write JSON to a file
116
+ ```
117
+
118
+ | Option | Description |
119
+ |---|---|
120
+ | `-l, --latest` | Use the most recently submitted batch |
121
+ | `-o, --output <file>` | Write results as JSON |
122
+ | `-w, --wait` | Wait for completion before fetching |
123
+
124
+ ### `batch history`
125
+
126
+ Show the operation log (send / status / fetch events).
127
+
128
+ ```bash
129
+ batch history
130
+ ```
131
+
132
+ ### Global options
133
+
134
+ | Option | Description |
135
+ |---|---|
136
+ | `--state-dir <dir>` | State directory (default `./.batch-state`) |
137
+
138
+ ---
139
+
140
+ ## Example workflow
141
+
142
+ ```bash
143
+ # Stage 50 customer reviews for summarization
144
+ batch add --dir ./reviews --prompt "Summarize this review in 2 sentences:\n\n{content}"
145
+
146
+ batch review
147
+ # 50 document(s) staged: ...
148
+
149
+ batch send
150
+ # Batch submitted: msgbatch_01...
151
+
152
+ # (later — even from a fresh terminal)
153
+ batch status --latest
154
+ # status: ended counts: succeeded=50 ...
155
+
156
+ batch fetch --latest --output summaries.json
157
+ # Wrote 50 result(s) to summaries.json (50 succeeded).
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Library
163
+
164
+ ```typescript
165
+ import { BatchKit } from "@otisworks/batch-kit";
166
+
167
+ const kit = new BatchKit({
168
+ apiKey: process.env.ANTHROPIC_API_KEY, // optional; defaults to env var
169
+ stateDir: "./.batch-state", // optional
170
+ });
171
+
172
+ // Stage documents
173
+ await kit.add("./documents", {
174
+ prompt: "Extract keywords:\n\n{content}",
175
+ model: "claude-opus-4-8",
176
+ maxTokens: 1024,
177
+ });
178
+
179
+ // Preview
180
+ const { count, files } = await kit.review();
181
+
182
+ // Submit
183
+ const batchId = await kit.send();
184
+
185
+ // Wait for completion
186
+ await kit.wait(batchId, {
187
+ onPoll: ({ status, counts }) => console.log(status, counts),
188
+ });
189
+
190
+ // Stream results (matched back to files via customId)
191
+ for await (const result of kit.results(batchId)) {
192
+ if (result.type === "succeeded") {
193
+ console.log(result.customId, result.text);
194
+ }
195
+ }
196
+ ```
197
+
198
+ Batch-id methods (`status`, `wait`, `results`) also accept the string `"latest"`
199
+ to target the most recently submitted batch.
200
+
201
+ See [`examples/programmatic.mjs`](./examples/programmatic.mjs) for a runnable example.
202
+
203
+ ---
204
+
205
+ ## How state works
206
+
207
+ batch-kit persists job metadata to a local `.batch-state/` directory:
208
+
209
+ ```
210
+ .batch-state/
211
+ ├── jobs/<batch-id>.json # metadata + customId→filename map per batch
212
+ ├── staged.json # the current staging area
213
+ └── history.jsonl # append-only operation log
214
+ ```
215
+
216
+ This is what makes `--latest` and cross-session `fetch` work.
217
+
218
+ > **Note:** State is local to the machine and directory you run in (much like
219
+ > `.git/`). If you `send` on one machine, you'll need that machine's
220
+ > `.batch-state/` to resolve `--latest` later. The batch itself lives on
221
+ > Anthropic's servers regardless — you can always fetch by explicit batch ID.
222
+ >
223
+ > batch-kit assumes single-user, non-concurrent usage. Writes are atomic
224
+ > (temp file + rename) to avoid corruption on interruption.
225
+
226
+ ---
227
+
228
+ ## Development
229
+
230
+ ```bash
231
+ npm install
232
+ npm run build # compile TypeScript to dist/
233
+ npm test # run unit tests (no API calls)
234
+ npm run typecheck # type-check without emitting
235
+ ```
236
+
237
+ ## License
238
+
239
+ MIT
@@ -0,0 +1,66 @@
1
+ import { StateManager } from "./stateManager.js";
2
+ import type { AddOptions, BatchKitOptions, BatchResult, RequestCounts, ReviewSummary, StagedRequest } from "./types.js";
3
+ /** Options for {@link BatchKit.wait}. */
4
+ export interface WaitOptions {
5
+ /** Poll interval in ms. Default 5000. */
6
+ intervalMs?: number;
7
+ /** Give up after this many ms. Default 24h. */
8
+ timeoutMs?: number;
9
+ /** Called on each poll with the current counts + status. */
10
+ onPoll?: (info: {
11
+ status: string;
12
+ counts: RequestCounts;
13
+ }) => void;
14
+ }
15
+ /**
16
+ * Main entry point. Stage documents, send them as a batch, poll, and read
17
+ * results back.
18
+ *
19
+ * State persistence is intentionally not wired in yet — `add` stages
20
+ * in-memory for now. That layer comes next.
21
+ */
22
+ export declare class BatchKit {
23
+ private readonly client;
24
+ private readonly defaultModel;
25
+ private readonly defaultMaxTokens;
26
+ private readonly state;
27
+ constructor(options?: BatchKitOptions);
28
+ /** Access the underlying state store (job history, latest lookup). */
29
+ get store(): StateManager;
30
+ /**
31
+ * Resolve a batch id, supporting the special value `"latest"` which looks up
32
+ * the most recently submitted job from persisted state.
33
+ */
34
+ resolveBatchId(batchIdOrLatest: string): Promise<string>;
35
+ /**
36
+ * Read supported files from a directory, interpolate the prompt template,
37
+ * and stage them as requests. Returns the number of requests staged.
38
+ */
39
+ add(dir: string, options: AddOptions): Promise<number>;
40
+ /** Preview what's currently staged. */
41
+ review(): Promise<ReviewSummary>;
42
+ /** The currently staged requests. */
43
+ stagedRequests(): Promise<StagedRequest[]>;
44
+ /** Discard all staged requests. */
45
+ reset(): Promise<void>;
46
+ /**
47
+ * Submit all staged requests as a single batch. Returns the batch id.
48
+ * Clears the staging area on success.
49
+ */
50
+ send(): Promise<string>;
51
+ /** Fetch the current status + counts for a batch. Accepts `"latest"`. */
52
+ status(batchIdOrLatest: string): Promise<{
53
+ status: string;
54
+ counts: RequestCounts;
55
+ endedAt: string | null;
56
+ batchId: string;
57
+ }>;
58
+ /** Poll until the batch finishes processing (or timeout). Accepts `"latest"`. */
59
+ wait(batchIdOrLatest: string, options?: WaitOptions): Promise<void>;
60
+ /**
61
+ * Stream normalized results for a completed batch. Results may arrive out of
62
+ * order; use `customId` to match them back to source files.
63
+ */
64
+ results(batchIdOrLatest: string): AsyncGenerator<BatchResult>;
65
+ }
66
+ //# sourceMappingURL=BatchKit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BatchKit.d.ts","sourceRoot":"","sources":["../src/BatchKit.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EACV,UAAU,EACV,eAAe,EACf,WAAW,EAEX,aAAa,EACb,aAAa,EACb,aAAa,EACd,MAAM,YAAY,CAAC;AAMpB,yCAAyC;AACzC,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,KAAK,IAAI,CAAC;CACpE;AAED;;;;;;GAMG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;gBAEzB,OAAO,GAAE,eAAoB;IAazC,sEAAsE;IACtE,IAAI,KAAK,IAAI,YAAY,CAExB;IAED;;;OAGG;IACG,cAAc,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAS9D;;;OAGG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;IA8C5D,uCAAuC;IACjC,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC;IAQtC,qCAAqC;IAC/B,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAIhD,mCAAmC;IAC7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAqC7B,yEAAyE;IACnE,MAAM,CACV,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAa9F,iFAAiF;IAC3E,IAAI,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB7E;;;OAGG;IACI,OAAO,CAAC,eAAe,EAAE,MAAM,GAAG,cAAc,CAAC,WAAW,CAAC;CA6BrE"}
@@ -0,0 +1,205 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ import { readdir, readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { interpolate, toCustomId } from "./template.js";
5
+ import { StateManager } from "./stateManager.js";
6
+ const DEFAULT_MODEL = "claude-opus-4-8";
7
+ const DEFAULT_MAX_TOKENS = 1024;
8
+ const DEFAULT_EXTENSIONS = [".txt", ".md"];
9
+ /**
10
+ * Main entry point. Stage documents, send them as a batch, poll, and read
11
+ * results back.
12
+ *
13
+ * State persistence is intentionally not wired in yet — `add` stages
14
+ * in-memory for now. That layer comes next.
15
+ */
16
+ export class BatchKit {
17
+ client;
18
+ defaultModel;
19
+ defaultMaxTokens;
20
+ state;
21
+ constructor(options = {}) {
22
+ const apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
23
+ if (!apiKey) {
24
+ throw new Error("No API key provided. Pass { apiKey } or set ANTHROPIC_API_KEY.");
25
+ }
26
+ this.client = new Anthropic({ apiKey });
27
+ this.defaultModel = options.defaultModel ?? DEFAULT_MODEL;
28
+ this.defaultMaxTokens = options.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
29
+ this.state = new StateManager(options.stateDir);
30
+ }
31
+ /** Access the underlying state store (job history, latest lookup). */
32
+ get store() {
33
+ return this.state;
34
+ }
35
+ /**
36
+ * Resolve a batch id, supporting the special value `"latest"` which looks up
37
+ * the most recently submitted job from persisted state.
38
+ */
39
+ async resolveBatchId(batchIdOrLatest) {
40
+ if (batchIdOrLatest !== "latest")
41
+ return batchIdOrLatest;
42
+ const job = await this.state.latestJob();
43
+ if (!job) {
44
+ throw new Error("No previous batches found in state. Nothing to resolve for 'latest'.");
45
+ }
46
+ return job.batchId;
47
+ }
48
+ /**
49
+ * Read supported files from a directory, interpolate the prompt template,
50
+ * and stage them as requests. Returns the number of requests staged.
51
+ */
52
+ async add(dir, options) {
53
+ const model = options.model ?? this.defaultModel;
54
+ const maxTokens = options.maxTokens ?? this.defaultMaxTokens;
55
+ const allowed = new Set((options.extensions ?? DEFAULT_EXTENSIONS).map((e) => e.toLowerCase()));
56
+ const entries = await readdir(dir, { withFileTypes: true });
57
+ const files = entries
58
+ .filter((e) => e.isFile() && allowed.has(path.extname(e.name).toLowerCase()))
59
+ .map((e) => e.name)
60
+ .sort();
61
+ if (files.length === 0) {
62
+ throw new Error(`No files matching ${[...allowed].join(", ")} found in ${dir}`);
63
+ }
64
+ // Staging is disk-backed so add/review/send work across CLI invocations.
65
+ const staged = await this.state.loadStaged();
66
+ const startIndex = staged.length;
67
+ for (let i = 0; i < files.length; i++) {
68
+ const filename = files[i];
69
+ const raw = await readFile(path.join(dir, filename), "utf8");
70
+ const index = startIndex + i;
71
+ const prompt = interpolate(options.prompt, {
72
+ content: raw.trim(),
73
+ filename,
74
+ index,
75
+ });
76
+ staged.push({
77
+ customId: toCustomId(index, filename),
78
+ filename,
79
+ prompt,
80
+ model,
81
+ maxTokens,
82
+ });
83
+ }
84
+ await this.state.saveStaged(staged);
85
+ return files.length;
86
+ }
87
+ /** Preview what's currently staged. */
88
+ async review() {
89
+ const staged = await this.state.loadStaged();
90
+ return {
91
+ count: staged.length,
92
+ files: staged.map((r) => r.filename),
93
+ };
94
+ }
95
+ /** The currently staged requests. */
96
+ async stagedRequests() {
97
+ return this.state.loadStaged();
98
+ }
99
+ /** Discard all staged requests. */
100
+ async reset() {
101
+ await this.state.clearStaged();
102
+ }
103
+ /**
104
+ * Submit all staged requests as a single batch. Returns the batch id.
105
+ * Clears the staging area on success.
106
+ */
107
+ async send() {
108
+ const staged = await this.state.loadStaged();
109
+ if (staged.length === 0) {
110
+ throw new Error("Nothing staged. Call add() first.");
111
+ }
112
+ const requests = staged.map((r) => ({
113
+ custom_id: r.customId,
114
+ params: {
115
+ model: r.model,
116
+ max_tokens: r.maxTokens,
117
+ messages: [{ role: "user", content: r.prompt }],
118
+ },
119
+ }));
120
+ const batch = await this.client.messages.batches.create({ requests });
121
+ // Persist job metadata so future runs can find it (and map results -> files).
122
+ const job = {
123
+ batchId: batch.id,
124
+ createdAt: new Date().toISOString(),
125
+ model: staged[0]?.model ?? this.defaultModel,
126
+ requestCount: staged.length,
127
+ requests: staged.map((r) => ({
128
+ customId: r.customId,
129
+ filename: r.filename,
130
+ })),
131
+ lastStatus: batch.processing_status,
132
+ lastCheckedAt: new Date().toISOString(),
133
+ };
134
+ await this.state.saveJob(job);
135
+ await this.state.record({ op: "send", batchId: batch.id, detail: `${job.requestCount} requests` });
136
+ await this.state.clearStaged();
137
+ return batch.id;
138
+ }
139
+ /** Fetch the current status + counts for a batch. Accepts `"latest"`. */
140
+ async status(batchIdOrLatest) {
141
+ const batchId = await this.resolveBatchId(batchIdOrLatest);
142
+ const batch = await this.client.messages.batches.retrieve(batchId);
143
+ await this.state.updateStatus(batchId, batch.processing_status);
144
+ await this.state.record({ op: "status", batchId, detail: batch.processing_status });
145
+ return {
146
+ status: batch.processing_status,
147
+ counts: batch.request_counts,
148
+ endedAt: batch.ended_at,
149
+ batchId,
150
+ };
151
+ }
152
+ /** Poll until the batch finishes processing (or timeout). Accepts `"latest"`. */
153
+ async wait(batchIdOrLatest, options = {}) {
154
+ const batchId = await this.resolveBatchId(batchIdOrLatest);
155
+ const intervalMs = options.intervalMs ?? 5000;
156
+ const timeoutMs = options.timeoutMs ?? 24 * 60 * 60 * 1000;
157
+ const start = Date.now();
158
+ for (;;) {
159
+ const batch = await this.client.messages.batches.retrieve(batchId);
160
+ await this.state.updateStatus(batchId, batch.processing_status);
161
+ options.onPoll?.({
162
+ status: batch.processing_status,
163
+ counts: batch.request_counts,
164
+ });
165
+ if (batch.processing_status === "ended")
166
+ return;
167
+ if (Date.now() - start > timeoutMs) {
168
+ throw new Error(`Timed out waiting for batch ${batchId} (still ${batch.processing_status})`);
169
+ }
170
+ await new Promise((r) => setTimeout(r, intervalMs));
171
+ }
172
+ }
173
+ /**
174
+ * Stream normalized results for a completed batch. Results may arrive out of
175
+ * order; use `customId` to match them back to source files.
176
+ */
177
+ async *results(batchIdOrLatest) {
178
+ const batchId = await this.resolveBatchId(batchIdOrLatest);
179
+ await this.state.record({ op: "fetch", batchId });
180
+ const stream = await this.client.messages.batches.results(batchId);
181
+ for await (const item of stream) {
182
+ const { custom_id: customId, result } = item;
183
+ switch (result.type) {
184
+ case "succeeded": {
185
+ const text = result.message.content
186
+ .filter((b) => b.type === "text")
187
+ .map((b) => b.text)
188
+ .join("");
189
+ yield { customId, type: "succeeded", message: result.message, text };
190
+ break;
191
+ }
192
+ case "errored":
193
+ yield { customId, type: "errored", error: result.error };
194
+ break;
195
+ case "canceled":
196
+ yield { customId, type: "canceled" };
197
+ break;
198
+ case "expired":
199
+ yield { customId, type: "expired" };
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ }
205
+ //# sourceMappingURL=BatchKit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BatchKit.js","sourceRoot":"","sources":["../src/BatchKit.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,212 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { readFileSync, existsSync } from "node:fs";
4
+ import { writeFile } from "node:fs/promises";
5
+ import { BatchKit } from "./BatchKit.js";
6
+ // --- minimal .env loader (Node 18 has no --env-file) ---
7
+ function loadDotenv() {
8
+ if (!existsSync(".env"))
9
+ return;
10
+ for (const line of readFileSync(".env", "utf8").split("\n")) {
11
+ const m = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/);
12
+ if (!m || line.trim().startsWith("#"))
13
+ continue;
14
+ const key = m[1];
15
+ const val = (m[2] ?? "").trim().replace(/^['"]|['"]$/g, "");
16
+ if (!(key in process.env))
17
+ process.env[key] = val;
18
+ }
19
+ }
20
+ function makeKit(stateDir) {
21
+ loadDotenv();
22
+ try {
23
+ return new BatchKit(stateDir ? { stateDir } : {});
24
+ }
25
+ catch (err) {
26
+ fail(err.message);
27
+ }
28
+ }
29
+ function fail(msg) {
30
+ console.error(`error: ${msg}`);
31
+ process.exit(1);
32
+ }
33
+ const program = new Command();
34
+ program
35
+ .name("batch")
36
+ .description("Ergonomic CLI for the Anthropic Message Batches API")
37
+ .version("0.0.1")
38
+ .option("--state-dir <dir>", "directory for persisted state", "./.batch-state");
39
+ function stateDir() {
40
+ return program.opts().stateDir;
41
+ }
42
+ // --- add ---
43
+ program
44
+ .command("add")
45
+ .description("Stage documents from a directory with a prompt template")
46
+ .requiredOption("-d, --dir <dir>", "directory of documents")
47
+ .requiredOption("-p, --prompt <template>", "prompt template ({content}, {filename}, {index})")
48
+ .option("-m, --model <model>", "model override")
49
+ .option("--max-tokens <n>", "max_tokens override", (v) => parseInt(v, 10))
50
+ .option("-e, --ext <extensions>", "comma-separated extensions (e.g. .txt,.md)")
51
+ .action(async (opts) => {
52
+ const kit = makeKit(stateDir());
53
+ try {
54
+ const n = await kit.add(opts.dir, {
55
+ prompt: opts.prompt,
56
+ model: opts.model,
57
+ maxTokens: opts.maxTokens,
58
+ extensions: opts.ext
59
+ ? opts.ext.split(",").map((e) => (e.startsWith(".") ? e : `.${e}`).toLowerCase())
60
+ : undefined,
61
+ });
62
+ const { count } = await kit.review();
63
+ console.log(`Staged ${n} document(s). ${count} total staged.`);
64
+ }
65
+ catch (err) {
66
+ fail(err.message);
67
+ }
68
+ });
69
+ // --- review ---
70
+ program
71
+ .command("review")
72
+ .description("Preview what's currently staged")
73
+ .action(async () => {
74
+ const kit = makeKit(stateDir());
75
+ const { count, files } = await kit.review();
76
+ if (count === 0) {
77
+ console.log("Nothing staged. Use `batch add` first.");
78
+ return;
79
+ }
80
+ console.log(`${count} document(s) staged:`);
81
+ for (const f of files)
82
+ console.log(` - ${f}`);
83
+ });
84
+ // --- reset ---
85
+ program
86
+ .command("reset")
87
+ .description("Discard the staging area")
88
+ .action(async () => {
89
+ const kit = makeKit(stateDir());
90
+ await kit.reset();
91
+ console.log("Staging cleared.");
92
+ });
93
+ // --- send ---
94
+ program
95
+ .command("send")
96
+ .description("Submit staged documents as a batch")
97
+ .option("-w, --wait", "block until the batch finishes")
98
+ .action(async (opts) => {
99
+ const kit = makeKit(stateDir());
100
+ let id;
101
+ try {
102
+ id = await kit.send();
103
+ }
104
+ catch (err) {
105
+ fail(err.message);
106
+ }
107
+ console.log(`Batch submitted: ${id}`);
108
+ if (opts.wait) {
109
+ console.log("Waiting for completion...");
110
+ await kit.wait(id, {
111
+ onPoll: ({ status, counts }) => console.log(` ${status} (succeeded=${counts.succeeded} processing=${counts.processing} errored=${counts.errored})`),
112
+ });
113
+ console.log("Done. Use `batch fetch --latest` to retrieve results.");
114
+ }
115
+ else {
116
+ console.log("Check later with `batch status --latest` and `batch fetch --latest`.");
117
+ }
118
+ });
119
+ // --- status ---
120
+ program
121
+ .command("status [batchId]")
122
+ .description("Check batch status (use --latest for the most recent)")
123
+ .option("-l, --latest", "use the most recently submitted batch")
124
+ .action(async (batchId, opts) => {
125
+ const kit = makeKit(stateDir());
126
+ const target = opts.latest ? "latest" : batchId;
127
+ if (!target)
128
+ fail("provide a batchId or use --latest");
129
+ try {
130
+ const s = await kit.status(target);
131
+ console.log(`Batch ${s.batchId}`);
132
+ console.log(` status: ${s.status}`);
133
+ const c = s.counts;
134
+ console.log(` counts: succeeded=${c.succeeded} processing=${c.processing} errored=${c.errored} canceled=${c.canceled} expired=${c.expired}`);
135
+ if (s.endedAt)
136
+ console.log(` ended: ${s.endedAt}`);
137
+ }
138
+ catch (err) {
139
+ fail(err.message);
140
+ }
141
+ });
142
+ // --- fetch ---
143
+ program
144
+ .command("fetch [batchId]")
145
+ .description("Fetch results (use --latest for the most recent)")
146
+ .option("-l, --latest", "use the most recently submitted batch")
147
+ .option("-o, --output <file>", "write results as JSON to a file")
148
+ .option("-w, --wait", "wait for completion before fetching")
149
+ .action(async (batchId, opts) => {
150
+ const kit = makeKit(stateDir());
151
+ const target = opts.latest ? "latest" : batchId;
152
+ if (!target)
153
+ fail("provide a batchId or use --latest");
154
+ try {
155
+ const resolvedId = await kit.resolveBatchId(target);
156
+ const job = await kit.store.getJob(resolvedId);
157
+ const fileFor = new Map((job?.requests ?? []).map((r) => [r.customId, r.filename]));
158
+ if (opts.wait) {
159
+ console.log("Waiting for completion...");
160
+ await kit.wait(resolvedId, {
161
+ onPoll: ({ status, counts }) => console.log(` ${status} (succeeded=${counts.succeeded} processing=${counts.processing})`),
162
+ });
163
+ }
164
+ const collected = [];
165
+ let ok = 0;
166
+ for await (const r of kit.results(resolvedId)) {
167
+ const file = fileFor.get(r.customId) ?? r.customId;
168
+ const entry = {
169
+ customId: r.customId,
170
+ file,
171
+ type: r.type,
172
+ };
173
+ if (r.type === "succeeded") {
174
+ entry.text = r.text;
175
+ ok++;
176
+ }
177
+ collected.push(entry);
178
+ }
179
+ if (opts.output) {
180
+ await writeFile(opts.output, JSON.stringify(collected, null, 2), "utf8");
181
+ console.log(`Wrote ${collected.length} result(s) to ${opts.output} (${ok} succeeded).`);
182
+ }
183
+ else {
184
+ for (const e of collected) {
185
+ console.log(`\n--- ${e.file} [${e.type}] ---`);
186
+ if (e.text)
187
+ console.log(e.text.trim());
188
+ }
189
+ console.log(`\n${ok}/${collected.length} succeeded.`);
190
+ }
191
+ }
192
+ catch (err) {
193
+ fail(err.message);
194
+ }
195
+ });
196
+ // --- history ---
197
+ program
198
+ .command("history")
199
+ .description("Show the operation log")
200
+ .action(async () => {
201
+ const kit = makeKit(stateDir());
202
+ const entries = await kit.store.history();
203
+ if (entries.length === 0) {
204
+ console.log("No history yet.");
205
+ return;
206
+ }
207
+ for (const h of entries) {
208
+ console.log(`${h.at} ${h.op.padEnd(6)} ${h.batchId}${h.detail ? " (" + h.detail + ")" : ""}`);
209
+ }
210
+ });
211
+ program.parseAsync().catch((err) => fail(err.message));
212
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { BatchKit } from "./BatchKit.js";
2
+ export type { WaitOptions } from "./BatchKit.js";
3
+ export { StateManager } from "./stateManager.js";
4
+ export { interpolate, toCustomId } from "./template.js";
5
+ export type { TemplateVars } from "./template.js";
6
+ export type { AddOptions, BatchKitOptions, BatchResult, HistoryEntry, JobRecord, JobRequestRef, ProcessingStatus, RequestCounts, ReviewSummary, StagedRequest, } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EACV,UAAU,EACV,eAAe,EACf,WAAW,EACX,YAAY,EACZ,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,aAAa,GACd,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { BatchKit } from "./BatchKit.js";
2
+ export { StateManager } from "./stateManager.js";
3
+ export { interpolate, toCustomId } from "./template.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { HistoryEntry, JobRecord, StagedRequest } from "./types.js";
2
+ /**
3
+ * Persists batch job metadata to disk under a state directory.
4
+ *
5
+ * Layout:
6
+ * <stateDir>/
7
+ * jobs/<batchId>.json one file per submitted batch
8
+ * history.jsonl append-only operation log
9
+ *
10
+ * Assumptions (documented, MVP): single user, single machine, no concurrent
11
+ * processes. Writes are atomic (temp file + rename) so a crash mid-write won't
12
+ * corrupt an existing job file.
13
+ */
14
+ export declare class StateManager {
15
+ readonly stateDir: string;
16
+ private readonly jobsDir;
17
+ private readonly historyFile;
18
+ private readonly stagedFile;
19
+ constructor(stateDir?: string);
20
+ /** Ensure the state directory structure exists. */
21
+ private ensureDirs;
22
+ private jobPath;
23
+ /** Atomic write: write to a temp file, then rename over the target. */
24
+ private atomicWrite;
25
+ /** Persist (create or overwrite) a job record. */
26
+ saveJob(job: JobRecord): Promise<void>;
27
+ /** Load a job record by batch id, or null if not found. */
28
+ getJob(batchId: string): Promise<JobRecord | null>;
29
+ /** List all job records, most recently created first. */
30
+ listJobs(): Promise<JobRecord[]>;
31
+ /** The most recently created job, or null if none. */
32
+ latestJob(): Promise<JobRecord | null>;
33
+ /** Update the status fields on an existing job (no-op if not found). */
34
+ updateStatus(batchId: string, lastStatus: NonNullable<JobRecord["lastStatus"]>): Promise<void>;
35
+ /** Append an entry to the history log. */
36
+ record(entry: Omit<HistoryEntry, "at">): Promise<void>;
37
+ /** Load the currently staged requests (empty array if none). */
38
+ loadStaged(): Promise<StagedRequest[]>;
39
+ /** Persist the full staging area (overwrites). */
40
+ saveStaged(staged: StagedRequest[]): Promise<void>;
41
+ /** Clear the staging area. */
42
+ clearStaged(): Promise<void>;
43
+ /** Read the full history log (empty if none). */
44
+ history(): Promise<HistoryEntry[]>;
45
+ }
46
+ //# sourceMappingURL=stateManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateManager.d.ts","sourceRoot":"","sources":["../src/stateManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEzE;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,QAAQ,SAAmB;IAOvC,mDAAmD;YACrC,UAAU;IAIxB,OAAO,CAAC,OAAO;IAMf,uEAAuE;YACzD,WAAW;IAMzB,kDAAkD;IAC5C,OAAO,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,2DAA2D;IACrD,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAUxD,yDAAyD;IACnD,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAqBtC,sDAAsD;IAChD,SAAS,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAK5C,wEAAwE;IAClE,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,WAAW,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC;IAQhB,0CAA0C;IACpC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D,gEAAgE;IAC1D,UAAU,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAS5C,kDAAkD;IAC5C,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxD,8BAA8B;IACxB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,iDAAiD;IAC3C,OAAO,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;CAQzC"}
@@ -0,0 +1,132 @@
1
+ import { mkdir, readFile, writeFile, readdir, rename } from "node:fs/promises";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { randomBytes } from "node:crypto";
5
+ /**
6
+ * Persists batch job metadata to disk under a state directory.
7
+ *
8
+ * Layout:
9
+ * <stateDir>/
10
+ * jobs/<batchId>.json one file per submitted batch
11
+ * history.jsonl append-only operation log
12
+ *
13
+ * Assumptions (documented, MVP): single user, single machine, no concurrent
14
+ * processes. Writes are atomic (temp file + rename) so a crash mid-write won't
15
+ * corrupt an existing job file.
16
+ */
17
+ export class StateManager {
18
+ stateDir;
19
+ jobsDir;
20
+ historyFile;
21
+ stagedFile;
22
+ constructor(stateDir = "./.batch-state") {
23
+ this.stateDir = stateDir;
24
+ this.jobsDir = path.join(stateDir, "jobs");
25
+ this.historyFile = path.join(stateDir, "history.jsonl");
26
+ this.stagedFile = path.join(stateDir, "staged.json");
27
+ }
28
+ /** Ensure the state directory structure exists. */
29
+ async ensureDirs() {
30
+ await mkdir(this.jobsDir, { recursive: true });
31
+ }
32
+ jobPath(batchId) {
33
+ // batchId is API-generated (msgbatch_...), safe as a filename, but guard anyway.
34
+ const safe = batchId.replace(/[^a-zA-Z0-9_.-]/g, "_");
35
+ return path.join(this.jobsDir, `${safe}.json`);
36
+ }
37
+ /** Atomic write: write to a temp file, then rename over the target. */
38
+ async atomicWrite(target, data) {
39
+ const tmp = `${target}.${randomBytes(6).toString("hex")}.tmp`;
40
+ await writeFile(tmp, data, "utf8");
41
+ await rename(tmp, target);
42
+ }
43
+ /** Persist (create or overwrite) a job record. */
44
+ async saveJob(job) {
45
+ await this.ensureDirs();
46
+ await this.atomicWrite(this.jobPath(job.batchId), JSON.stringify(job, null, 2));
47
+ }
48
+ /** Load a job record by batch id, or null if not found. */
49
+ async getJob(batchId) {
50
+ const file = this.jobPath(batchId);
51
+ if (!existsSync(file))
52
+ return null;
53
+ try {
54
+ return JSON.parse(await readFile(file, "utf8"));
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ }
60
+ /** List all job records, most recently created first. */
61
+ async listJobs() {
62
+ if (!existsSync(this.jobsDir))
63
+ return [];
64
+ const files = (await readdir(this.jobsDir)).filter((f) => f.endsWith(".json"));
65
+ const jobs = [];
66
+ for (const f of files) {
67
+ try {
68
+ jobs.push(JSON.parse(await readFile(path.join(this.jobsDir, f), "utf8")));
69
+ }
70
+ catch {
71
+ // skip corrupt/partial files
72
+ }
73
+ }
74
+ jobs.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
75
+ return jobs;
76
+ }
77
+ /** The most recently created job, or null if none. */
78
+ async latestJob() {
79
+ const jobs = await this.listJobs();
80
+ return jobs[0] ?? null;
81
+ }
82
+ /** Update the status fields on an existing job (no-op if not found). */
83
+ async updateStatus(batchId, lastStatus) {
84
+ const job = await this.getJob(batchId);
85
+ if (!job)
86
+ return;
87
+ job.lastStatus = lastStatus;
88
+ job.lastCheckedAt = new Date().toISOString();
89
+ await this.saveJob(job);
90
+ }
91
+ /** Append an entry to the history log. */
92
+ async record(entry) {
93
+ await this.ensureDirs();
94
+ const line = JSON.stringify({ at: new Date().toISOString(), ...entry });
95
+ // Append is atomic enough for single-writer; each line is self-contained.
96
+ await writeFile(this.historyFile, line + "\n", { flag: "a" });
97
+ }
98
+ // --- staging (for the git-like CLI: add/review/send across invocations) ---
99
+ /** Load the currently staged requests (empty array if none). */
100
+ async loadStaged() {
101
+ if (!existsSync(this.stagedFile))
102
+ return [];
103
+ try {
104
+ return JSON.parse(await readFile(this.stagedFile, "utf8"));
105
+ }
106
+ catch {
107
+ return [];
108
+ }
109
+ }
110
+ /** Persist the full staging area (overwrites). */
111
+ async saveStaged(staged) {
112
+ await this.ensureDirs();
113
+ await this.atomicWrite(this.stagedFile, JSON.stringify(staged, null, 2));
114
+ }
115
+ /** Clear the staging area. */
116
+ async clearStaged() {
117
+ if (existsSync(this.stagedFile)) {
118
+ await this.atomicWrite(this.stagedFile, "[]");
119
+ }
120
+ }
121
+ /** Read the full history log (empty if none). */
122
+ async history() {
123
+ if (!existsSync(this.historyFile))
124
+ return [];
125
+ const raw = await readFile(this.historyFile, "utf8");
126
+ return raw
127
+ .split("\n")
128
+ .filter((l) => l.trim().length > 0)
129
+ .map((l) => JSON.parse(l));
130
+ }
131
+ }
132
+ //# sourceMappingURL=stateManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stateManager.js","sourceRoot":"","sources":["../src/stateManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Prompt template interpolation. Pure functions, no I/O — easy to unit test.
3
+ */
4
+ export interface TemplateVars {
5
+ content: string;
6
+ filename: string;
7
+ index: number;
8
+ }
9
+ /**
10
+ * Interpolate `{content}`, `{filename}`, `{index}` into a template string.
11
+ * Unknown `{tokens}` are left untouched.
12
+ */
13
+ export declare function interpolate(template: string, vars: TemplateVars): string;
14
+ /**
15
+ * Derive an API-safe custom_id from an index + filename.
16
+ * The Batch API requires custom_id to match [a-zA-Z0-9_-] and be <=64 chars.
17
+ */
18
+ export declare function toCustomId(index: number, filename: string): string;
19
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAKxE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGlE"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Prompt template interpolation. Pure functions, no I/O — easy to unit test.
3
+ */
4
+ /**
5
+ * Interpolate `{content}`, `{filename}`, `{index}` into a template string.
6
+ * Unknown `{tokens}` are left untouched.
7
+ */
8
+ export function interpolate(template, vars) {
9
+ return template
10
+ .replaceAll("{content}", vars.content)
11
+ .replaceAll("{filename}", vars.filename)
12
+ .replaceAll("{index}", String(vars.index));
13
+ }
14
+ /**
15
+ * Derive an API-safe custom_id from an index + filename.
16
+ * The Batch API requires custom_id to match [a-zA-Z0-9_-] and be <=64 chars.
17
+ */
18
+ export function toCustomId(index, filename) {
19
+ const safe = filename.replace(/[^a-zA-Z0-9_-]/g, "_");
20
+ return `${index}_${safe}`.slice(0, 64);
21
+ }
22
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,IAAkB;IAC9D,OAAO,QAAQ;SACZ,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC;SACrC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC;SACvC,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,QAAgB;IACxD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,GAAG,KAAK,IAAI,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Public types for batch-kit.
3
+ *
4
+ * We re-export a few SDK types so consumers don't need to import from
5
+ * @anthropic-ai/sdk directly for the common cases.
6
+ */
7
+ import type { Message } from "@anthropic-ai/sdk/resources/messages/messages";
8
+ /** Options for constructing a {@link BatchKit} instance. */
9
+ export interface BatchKitOptions {
10
+ /** Anthropic API key. Defaults to `process.env.ANTHROPIC_API_KEY`. */
11
+ apiKey?: string;
12
+ /** Directory for persisted job state. Defaults to `./.batch-state`. */
13
+ stateDir?: string;
14
+ /** Default model for requests when not specified per-`add`. */
15
+ defaultModel?: string;
16
+ /** Default max_tokens for requests when not specified per-`add`. */
17
+ defaultMaxTokens?: number;
18
+ }
19
+ /** Options passed to {@link BatchKit.add}. */
20
+ export interface AddOptions {
21
+ /**
22
+ * Prompt template. Supports `{content}`, `{filename}`, `{index}` variables.
23
+ */
24
+ prompt: string;
25
+ /** Model override for this batch of documents. */
26
+ model?: string;
27
+ /** max_tokens override for this batch of documents. */
28
+ maxTokens?: number;
29
+ /** File extensions to include (lowercase, with dot). Defaults to `.txt`, `.md`. */
30
+ extensions?: string[];
31
+ }
32
+ /** A single staged request, ready to be sent to the Batch API. */
33
+ export interface StagedRequest {
34
+ /** Unique, API-safe id ([a-zA-Z0-9_-], <=64 chars). */
35
+ customId: string;
36
+ /** Source filename this request was built from. */
37
+ filename: string;
38
+ /** Fully-interpolated prompt text. */
39
+ prompt: string;
40
+ /** Model for this request. */
41
+ model: string;
42
+ /** max_tokens for this request. */
43
+ maxTokens: number;
44
+ }
45
+ /** Result of {@link BatchKit.review}. */
46
+ export interface ReviewSummary {
47
+ /** Number of staged requests. */
48
+ count: number;
49
+ /** Filenames staged. */
50
+ files: string[];
51
+ }
52
+ /** Processing status mirrored from the Anthropic API. */
53
+ export type ProcessingStatus = "in_progress" | "canceling" | "ended";
54
+ /** Per-status tallies mirrored from the Anthropic API. */
55
+ export interface RequestCounts {
56
+ processing: number;
57
+ succeeded: number;
58
+ errored: number;
59
+ canceled: number;
60
+ expired: number;
61
+ }
62
+ /** Maps a request's customId back to its source filename. */
63
+ export interface JobRequestRef {
64
+ customId: string;
65
+ filename: string;
66
+ }
67
+ /** Persisted metadata for a single submitted batch. */
68
+ export interface JobRecord {
69
+ /** Anthropic batch id (e.g. msgbatch_...). */
70
+ batchId: string;
71
+ /** ISO timestamp when submitted via this tool. */
72
+ createdAt: string;
73
+ /** Model used for the batch. */
74
+ model: string;
75
+ /** Number of requests in the batch. */
76
+ requestCount: number;
77
+ /** customId -> filename mapping for matching results back to files. */
78
+ requests: JobRequestRef[];
79
+ /** Last known processing status (updated on status/wait/fetch). */
80
+ lastStatus?: ProcessingStatus;
81
+ /** ISO timestamp of the last status check. */
82
+ lastCheckedAt?: string;
83
+ }
84
+ /** A single line in the append-only history log. */
85
+ export interface HistoryEntry {
86
+ /** ISO timestamp of the operation. */
87
+ at: string;
88
+ /** Operation kind. */
89
+ op: "send" | "status" | "fetch";
90
+ /** Batch the operation concerns. */
91
+ batchId: string;
92
+ /** Optional free-form detail. */
93
+ detail?: string;
94
+ }
95
+ /** One result line from a completed batch, normalized for consumers. */
96
+ export type BatchResult = {
97
+ customId: string;
98
+ type: "succeeded";
99
+ message: Message;
100
+ text: string;
101
+ } | {
102
+ customId: string;
103
+ type: "errored";
104
+ error: unknown;
105
+ } | {
106
+ customId: string;
107
+ type: "canceled";
108
+ } | {
109
+ customId: string;
110
+ type: "expired";
111
+ };
112
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@otisworks/batch-kit",
3
+ "version": "0.0.1",
4
+ "description": "Ergonomic CLI + library for the Anthropic Message Batches API",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=18"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "bin": {
12
+ "batch": "./dist/cli.js"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "node --test",
27
+ "prepublishOnly": "npm run build && npm test"
28
+ },
29
+ "keywords": [
30
+ "anthropic",
31
+ "claude",
32
+ "batch",
33
+ "batches",
34
+ "cli",
35
+ "ai"
36
+ ],
37
+ "author": "",
38
+ "license": "MIT",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/otisworks/batch-kit.git"
42
+ },
43
+ "bugs": {
44
+ "url": "https://github.com/otisworks/batch-kit/issues"
45
+ },
46
+ "homepage": "https://github.com/otisworks/batch-kit#readme",
47
+ "dependencies": {
48
+ "@anthropic-ai/sdk": "^0.112.4",
49
+ "commander": "^12.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@types/node": "^20.14.0",
53
+ "typescript": "^5.6.0"
54
+ }
55
+ }