@m8tes/sdk 0.1.0-alpha.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/CHANGELOG.md ADDED
@@ -0,0 +1,100 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@m8tes/sdk`.
4
+
5
+ > **Release process** (mirrors `sdk/py`): every change to behaviour or public API
6
+ > lands an entry under `## [Unreleased]` in the same commit. A RELEASE then bumps
7
+ > `package.json` `version` (semver) and retitles that section. Entries are never
8
+ > skipped — without one, a consumer cannot tell what changed. Publish via the `Publish @m8tes/sdk` workflow — never `npm publish` by
9
+ > hand (it does not rewrite the pnpm `workspace:` protocol).
10
+ >
11
+ > While the version is a `-alpha.N` prerelease, publish with dist-tag `alpha`.
12
+ > The first stable release is published with `--tag latest` deliberately.
13
+
14
+ ## [0.1.0-alpha.1]
15
+
16
+ Initial release. TypeScript client for the m8tes V2 API, at parity with the
17
+ Python SDK on the core loop.
18
+
19
+ ### Added
20
+
21
+ - **`M8tes` client** — `runs`, `agents` (alias `teammates`), `tasks` (+ `tasks.triggers`),
22
+ `users`, `apps`, `webhooks`, `settings`. Reads `M8TES_API_KEY`, or pass `apiKey`.
23
+ `client.http` is the escape hatch for endpoints this version does not wrap yet.
24
+ - **Streaming `RunStream`** — async-iterable of normalized events, plus `iterText()`,
25
+ `text()`, `runId`, `errors`, and `conversation` (the full accumulated
26
+ conversation: messages, tool calls, notices). `raiseOnError` turns a run that
27
+ emitted error events into a thrown `RunFailedError`, so a mid-run failure is
28
+ never mistaken for a successful empty run.
29
+ - **Typed errors** — `M8tesApiError` plus a subclass per status
30
+ (`ValidationError`, `AuthenticationError`, `BillingError`,
31
+ `PermissionDeniedError`, `NotFoundError`, `ConflictError`, `RateLimitError`,
32
+ `APIError`), each carrying `status`, `errorCode`, `requestId`, `docUrl`,
33
+ `retryAfter`, and `details`.
34
+ - **Automatic retries** on 429/5xx for idempotent requests only, honouring
35
+ `Retry-After`. A `POST` is never retried: one that timed out may already have
36
+ started a billable run.
37
+ - **Auto-paging** — every `list()` returns a `Page` you can `for await` straight
38
+ through; it fetches subsequent pages for you.
39
+ - **`verifySignature()`** — HMAC-SHA256 webhook verification with optional replay
40
+ protection. Needs no client and no API key, and interoperates with the Python
41
+ SDK (same signing scheme, pinned by a shared test vector).
42
+ - **`@m8tes/sdk/protocol`** — the wire protocol (event union, SSE decoder,
43
+ normalizer, conversation accumulator, error classes) as a browser-safe entry
44
+ point with no auth code. `@m8tes/react` consumes this, so there is ONE
45
+ implementation of the protocol rather than one per package.
46
+ - **`@m8tes/sdk/fixtures`** — the recorded wire scenarios both packages test
47
+ against, exported so you can test your own protocol consumers.
48
+ - **Base-URL diagnostics** — an HTML response or a 404 with no error envelope
49
+ produces an actionable message ("check your baseUrl includes the /api/v2
50
+ prefix") instead of a wall of HTML or a bare 404.
51
+
52
+ ### Corrections from review (before first publish)
53
+
54
+ An adversarial Codex review plus a second live-backend pass caught these while
55
+ the package was still unpublished. Each was verified against the backend schema,
56
+ not assumed, and each is pinned by a test in `test/review-findings.test.ts`:
57
+
58
+ - **Field names are the API's own snake_case** (`user_id`, `created_at`) in params
59
+ and responses, matching `/docs/api-reference` and the Python SDK. This removed
60
+ the case-mapping layer entirely — and with it the class of bug where a key
61
+ rewriter silently mangled caller-defined keys.
62
+ - `apps.connectOauth` sends **`redirect_uri`** (not `redirect_url` — a 422) and
63
+ returns `{authorization_url, connection_id}`; `apps.connectComplete` requires
64
+ `connection_id`.
65
+ - `runs.get()` sends **no query parameters** — `GET /runs/{id}` declares none, so
66
+ passing `user_id` was a 422.
67
+ - `runs.cancel()` returns the updated `Run`, matching the Python SDK.
68
+ - `PermissionMode` is `"autonomous" | "approval" | "plan"` — the previous type
69
+ offered the Claude Agent SDK's names, which the API rejects.
70
+ - `tasks.create()` requires an owning agent; `POST /tasks/` requires `teammate_id`.
71
+ - Update params carry **only** what each PATCH schema accepts. Create-only fields
72
+ sent to PATCH return 200 and change nothing, which reads as success.
73
+ - Explicit `null` is expressible on update params — that is how a field is cleared.
74
+ - An unmapped HTTP status maps to `APIError`, matching Python's
75
+ `STATUS_MAP.get(status, APIError)`.
76
+ - Auto-pagination terminates if the cursor stops advancing instead of looping forever.
77
+ - An abort is observed **during** retry backoff (a `Retry-After: 3600` no longer
78
+ strands a cancelled caller for an hour).
79
+ - Constructing a client in a browser throws: the secret key would otherwise be
80
+ readable by every visitor.
81
+
82
+ ### Notes from validating against a live backend
83
+
84
+ Two things the mocked unit suite could not have caught, both fixed before release:
85
+
86
+ - `client.settings` is in v0.1 because strict multi-tenant mode is ON by default
87
+ for API accounts, and the backend's 422 tells you to call
88
+ `client.settings.update(...)`. Without the resource, that instruction dead-ends.
89
+ - `apps.list()` sends only `user_id`. `GET /apps/` rejects `limit` /
90
+ `starting_after` with a 422 (`unknown_query_parameter`), so the endpoint is not
91
+ paginated and iterating one page terminates instead of looping.
92
+
93
+ ### Notes
94
+
95
+ - Server-only: this package holds your secret key. To render an agent in a
96
+ browser use [`@m8tes/react`](https://www.npmjs.com/package/@m8tes/react).
97
+ - Parameters and response fields are camelCase, matching `@m8tes/react`; the
98
+ snake_case wire mapping happens inside the SDK. Caller-defined keys
99
+ (`metadata`, `answers`, `outputSchema` properties, `triggerConfig`) are passed
100
+ through verbatim and never rewritten.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 m8tes.ai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @m8tes/sdk
2
+
3
+ TypeScript client for the [m8tes](https://www.m8tes.ai) API. Create agents, schedule tasks, stream runs, and verify webhooks from Node, Deno, or Bun.
4
+
5
+ > **Alpha.** Published under the `alpha` dist-tag. Method signatures may change before 1.0; the streaming wire protocol (`m8tes.stream.v2`) is semver-stable.
6
+
7
+ ```bash
8
+ npm i @m8tes/sdk@alpha
9
+ ```
10
+
11
+ Requires Node 18+, Deno, or Bun. No dependencies. (`verifySignature` uses `node:crypto`, so edge runtimes need Node compatibility enabled.)
12
+
13
+ ## Your first run
14
+
15
+ ```ts
16
+ import { M8tes } from "@m8tes/sdk";
17
+
18
+ const client = new M8tes(); // reads M8TES_API_KEY
19
+
20
+ const run = client.runs.create({
21
+ message: "A customer asked to cancel. Draft a warm reply that offers to pause instead.",
22
+ });
23
+
24
+ for await (const chunk of run.iterText()) process.stdout.write(chunk);
25
+ console.log("\nrun", run.runId, "cost", run.conversation.status);
26
+ ```
27
+
28
+ No agent to create first: a brand-new key auto-provisions a default agent.
29
+
30
+ Get a key at [m8tes.ai/developer](https://m8tes.ai/developer).
31
+
32
+ ## Multi-tenancy
33
+
34
+ `user_id` is **your** id for one of your customers. Pass it and that person's memory, run history, and tool connections stay isolated — strictly, with no fallback to account-level data.
35
+
36
+ ```ts
37
+ const run = client.runs.create({ message: "Summarize my open tickets", user_id: "customer_42" });
38
+ ```
39
+
40
+ Register end-users explicitly when you want per-person budgets:
41
+
42
+ ```ts
43
+ await client.users.create({ user_id: "customer_42", run_limit: 50, rate_per_minute: 5 });
44
+ ```
45
+
46
+ ## Not streaming
47
+
48
+ ```ts
49
+ const run = await client.runs.createAsync({ message: "Prep the weekly recap" });
50
+ // poll, or receive a webhook
51
+ const done = await client.runs.get(run.id);
52
+ console.log(done.status, done.output);
53
+ ```
54
+
55
+ ## Agents and scheduled tasks
56
+
57
+ ```ts
58
+ const agent = await client.agents.create({
59
+ name: "Support Triage",
60
+ instructions: "Sort inbound tickets by urgency and draft first replies.",
61
+ tools: ["gmail"],
62
+ });
63
+
64
+ const task = await client.tasks.create({
65
+ agent_id: agent.id,
66
+ instructions: "Review yesterday's tickets and post a summary.",
67
+ schedule: "0 9 * * 1-5", // weekday mornings
68
+ schedule_timezone: "Europe/Copenhagen",
69
+ });
70
+ ```
71
+
72
+ Triggers beyond cron — webhook, email, and app events:
73
+
74
+ ```ts
75
+ await client.tasks.triggers.create(task.id, { type: "app", app: "github", trigger_name: "pull_request_opened" });
76
+ const { url } = await client.tasks.enableWebhook(task.id);
77
+ ```
78
+
79
+ ## Human-in-the-loop
80
+
81
+ When a run pauses, the stream emits an `approval-request` or `question` event. Answer it and the run resumes.
82
+
83
+ ```ts
84
+ const run = client.runs.create({ message: "Refund order 1234", human_in_the_loop: true });
85
+
86
+ for await (const event of run) {
87
+ // run.runId is populated from the first event, so it's available by the time a gate arrives.
88
+ if (event.type === "approval-request" && run.runId) {
89
+ await client.runs.approve(run.runId, { request_id: event.requestId, decision: "allow" });
90
+ }
91
+ if (event.type === "question" && run.runId) {
92
+ const q = event.questions[0];
93
+ if (q) await client.runs.answer(run.runId, { answers: { [q.question]: "Yes" } });
94
+ }
95
+ }
96
+ ```
97
+
98
+ Every snippet in this README is mirrored by a compiled file in [`examples/`](./examples), so `tsc` fails if one of them stops type-checking.
99
+
100
+ ## Webhooks
101
+
102
+ Verification needs no client and no API key. Pass the **raw** body: a parsed-then-restringified object will not match.
103
+
104
+ ```ts
105
+ import { verifySignature } from "@m8tes/sdk";
106
+
107
+ export async function POST(req: Request) {
108
+ const raw = await req.text();
109
+ if (!verifySignature(raw, req.headers, process.env.M8TES_WEBHOOK_SECRET!, { toleranceSeconds: 300 })) {
110
+ return new Response("bad signature", { status: 401 });
111
+ }
112
+ const event = JSON.parse(raw);
113
+ return new Response("ok");
114
+ }
115
+ ```
116
+
117
+ ## Errors
118
+
119
+ Every failure is a typed subclass of `M8tesApiError`, carrying `status`, `errorCode`, `requestId`, `docUrl`, and `retryAfter`.
120
+
121
+ Field names throughout are the API's own **snake_case** (`user_id`, `created_at`) — the same names as the [API reference](https://www.m8tes.ai/docs/api-reference) and the Python SDK, so nothing is renamed in transit. Things the SDK owns rather than sends — client options, method names, `RunStream`, stream events — stay camelCase.
122
+
123
+ ```ts
124
+ import { BillingError, RateLimitError } from "@m8tes/sdk";
125
+
126
+ try {
127
+ await client.runs.createAsync({ message: "..." });
128
+ } catch (err) {
129
+ if (err instanceof RateLimitError) await sleep((err.retryAfter ?? 1) * 1000);
130
+ else if (err instanceof BillingError) console.error(err.errorCode, err.docUrl);
131
+ else throw err;
132
+ }
133
+ ```
134
+
135
+ Retries are automatic on 429 and 5xx for idempotent requests only. A `POST` is **never** retried: one that timed out may already have started a billable run.
136
+
137
+ ## Pagination
138
+
139
+ Every `list()` returns a page you can iterate straight through — it fetches the rest for you.
140
+
141
+ ```ts
142
+ for await (const run of await client.runs.list({ user_id: "customer_42" })) {
143
+ console.log(run.id, run.status);
144
+ }
145
+ ```
146
+
147
+ ## Browser UI
148
+
149
+ This package is **server-only** — it holds your secret key. To render an agent in a browser, use [`@m8tes/react`](https://www.npmjs.com/package/@m8tes/react), which ships a `<MateChat>` component plus a locked-down server proxy so the key never reaches the client. Both packages share this one wire-protocol implementation, exported separately as the browser-safe `@m8tes/sdk/protocol`.
150
+
151
+ ## Docs
152
+
153
+ - [TypeScript SDK guide](https://www.m8tes.ai/docs/typescript-sdk)
154
+ - [API reference](https://www.m8tes.ai/docs/api-reference)
155
+ - [Multi-tenancy](https://www.m8tes.ai/docs/users)
156
+ - [Streaming & events](https://www.m8tes.ai/docs/streaming)
157
+
158
+ ## License
159
+
160
+ MIT