@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 +21 -0
- package/README.md +171 -0
- package/dist/client.d.ts +788 -0
- package/dist/client.js +985 -0
- package/dist/errors.d.ts +26 -0
- package/dist/errors.js +55 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/vault-crypto.d.ts +11 -0
- package/dist/vault-crypto.js +55 -0
- package/package.json +57 -0
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.
|