@agentidentity/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Naol Ketema
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,171 @@
1
+ # @agentidentity/sdk
2
+
3
+ TypeScript client for **Agent Identity** — give an agent its own email address, a durable event
4
+ stream it can block on, and an encrypted secret vault.
5
+
6
+ Zero runtime dependencies. Node 20+.
7
+
8
+ ```bash
9
+ npm install @agentidentity/sdk
10
+ ```
11
+
12
+ ## Quickstart
13
+
14
+ ```ts
15
+ import { AgentClient } from "@agentidentity/sdk";
16
+
17
+ const client = new AgentClient({
18
+ baseUrl: "https://api.agent-identity.dev",
19
+ apiKey: process.env.AID_API_KEY!,
20
+ });
21
+
22
+ // Give your agent an identity — this provisions a real, deliverable mailbox.
23
+ const agent = await client.identities.create({ handle: "support", displayName: "Support Bot" });
24
+ console.log(agent.mailboxAddress); // support@yourdomain.com
25
+
26
+ await client.mail.send({
27
+ identityId: agent.id,
28
+ to: ["customer@example.com"],
29
+ subject: "We got your ticket",
30
+ text: "Someone will be with you shortly.",
31
+ });
32
+ ```
33
+
34
+ Don't have an org yet? Bootstrap one — these run before you have a key, so they're plain
35
+ functions rather than client methods:
36
+
37
+ ```ts
38
+ import { signUp, logIn, createOrganization } from "@agentidentity/sdk";
39
+
40
+ const session = await signUp("https://api.agent-identity.dev", {
41
+ orgName: "Acme",
42
+ orgSlug: "acme",
43
+ email: "you@acme.com",
44
+ password: "…",
45
+ });
46
+ // session.apiKey is what you pass to AgentClient
47
+ ```
48
+
49
+ ## Reacting to mail
50
+
51
+ The point of an agent mailbox is that your code can *wait* on it. `events.subscribe()` is an
52
+ async iterator that yields events as they arrive:
53
+
54
+ ```ts
55
+ for await (const event of client.events.subscribe({ type: "mail.received", identityId: agent.id })) {
56
+ const thread = await client.mail.getThread(agent.id, event.payload.threadId);
57
+ const reply = await yourModel(thread);
58
+
59
+ await client.mail.send({
60
+ identityId: agent.id,
61
+ to: [event.payload.from!],
62
+ subject: `Re: ${event.payload.subject}`,
63
+ text: reply,
64
+ inReplyToMessageId: event.payload.messageId,
65
+ });
66
+ }
67
+ ```
68
+
69
+ `event.payload` is typed per event type — narrowing on `event.type` narrows the payload with it,
70
+ so there are no casts. Use `events.wait()` directly if you want a single event instead of a loop.
71
+
72
+ Subscribing handles the parts a hand-rolled loop gets wrong: it advances its cursor using each
73
+ event's own `createdAt` rather than the client's wall clock (which can skip events under clock
74
+ skew), re-polls transparently when the server's long-poll window elapses, and retries failures
75
+ with exponential backoff. Stop it with an `AbortSignal`:
76
+
77
+ ```ts
78
+ const controller = new AbortController();
79
+ setTimeout(() => controller.abort(), 60_000);
80
+
81
+ for await (const event of client.events.subscribe({ type: "mail.received", signal: controller.signal })) {
82
+ // loop exits normally when aborted
83
+ }
84
+ ```
85
+
86
+ ### Event types
87
+
88
+ | Type | Payload |
89
+ | --- | --- |
90
+ | `mail.received` | `messageId`, `threadId`, `from`, `subject` |
91
+ | `mail.sent` | `messageId`, `threadId` |
92
+ | `mail.delivered` | `messageId`, `threadId`, `detail?` |
93
+ | `mail.bounced` | `messageId`, `threadId`, `detail?` |
94
+ | `mail.complained` | `messageId`, `threadId`, `detail?` |
95
+ | `a2a.task.created` | `taskId`, `callerIdentityId`, `message` |
96
+ | `a2a.task.updated` | `taskId`, `state`, `result` |
97
+
98
+ Unknown types stay representable — a newer server can emit events this SDK version hasn't been
99
+ taught yet, and they arrive with a `Record<string, unknown>` payload rather than failing.
100
+
101
+ ## Errors
102
+
103
+ Two error types, so you can tell "the server rejected this" apart from "I never reached the
104
+ server" — they need different fixes.
105
+
106
+ ```ts
107
+ import { AidApiError, AidConnectionError } from "@agentidentity/sdk";
108
+
109
+ try {
110
+ await client.mail.send({ /* … */ });
111
+ } catch (err) {
112
+ if (err instanceof AidApiError) {
113
+ err.status; // 429 — the API responded
114
+ err.code; // "rate_limit.exceeded"
115
+ err.requestId; // pass this to support
116
+ err.retryable; // whether trying again could work
117
+ } else if (err instanceof AidConnectionError) {
118
+ err.method; // "POST" — the request never got there
119
+ err.url;
120
+ err.timedOut; // deadline elapsed, vs. connection refused/DNS failure
121
+ err.cause; // the underlying transport error
122
+ }
123
+ }
124
+ ```
125
+
126
+ Cancelling via an `AbortSignal` throws the usual `AbortError` untouched, so signal-based control
127
+ flow keeps working.
128
+
129
+ ## Timeouts and retries
130
+
131
+ Requests time out after 30s and retry twice by default:
132
+
133
+ ```ts
134
+ const client = new AgentClient({ baseUrl, apiKey, timeoutMs: 10_000, maxRetries: 5 });
135
+ ```
136
+
137
+ Retries cover rate limits (429), errors the server marks `retryable`, and — for idempotent
138
+ methods only — network failures and 5xx. A `POST` that fails mid-flight is never replayed
139
+ automatically, since it may already have been applied: that's the difference between a retry and
140
+ a duplicate email. `Retry-After` is honoured when the server sends it.
141
+
142
+ Every call accepts an `AbortSignal` for cancellation.
143
+
144
+ ## Vault
145
+
146
+ Secrets are sealed client-side with X25519 + AES-256-GCM. The API stores only ciphertext — your
147
+ private key never leaves the machine that generated it:
148
+
149
+ ```ts
150
+ const keypair = await client.vault.generateIdentityKey(agent.id); // private half returned once
151
+
152
+ const stored = await client.vault.createSecret({
153
+ identityId: agent.id,
154
+ name: "stripe",
155
+ plaintext: "sk_live_…",
156
+ });
157
+
158
+ const lease = await client.vault.createLease(stored.id, { operation: "charge" });
159
+ const { secret } = await client.vault.redeemLease(lease.leaseId, keypair);
160
+ ```
161
+
162
+ Store `keypair.privateKey` yourself — it is returned exactly once and the server cannot recover it.
163
+
164
+ ## What else is here
165
+
166
+ `client.identities`, `client.mail`, `client.events`, `client.contacts`, `client.contactRules`,
167
+ `client.apiKeys`, `client.webhooks`, `client.domains`, `client.providerAccounts`,
168
+ `client.a2a`, `client.vault`, `client.tunnels`, `client.status`.
169
+
170
+ Full reference: <https://github.com/ALPHACOD3RS/agent-identity>. The API's own OpenAPI document
171
+ is at `{baseUrl}/v1/openapi.json` and is authoritative for every endpoint.