@the-ai-company/cbio-node-runtime 0.31.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 +46 -0
- package/dist/agent/agent.d.ts +234 -0
- package/dist/agent/agent.js +565 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/audit/ActivityLog.d.ts +25 -0
- package/dist/audit/ActivityLog.js +66 -0
- package/dist/audit/ActivityLog.js.map +1 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/http/authClient.d.ts +26 -0
- package/dist/http/authClient.js +132 -0
- package/dist/http/authClient.js.map +1 -0
- package/dist/http/localAuthProxy.d.ts +33 -0
- package/dist/http/localAuthProxy.js +93 -0
- package/dist/http/localAuthProxy.js.map +1 -0
- package/dist/http/secretAcquisition.d.ts +54 -0
- package/dist/http/secretAcquisition.js +177 -0
- package/dist/http/secretAcquisition.js.map +1 -0
- package/dist/protocol/childSecretNaming.d.ts +7 -0
- package/dist/protocol/childSecretNaming.js +12 -0
- package/dist/protocol/childSecretNaming.js.map +1 -0
- package/dist/protocol/crypto.d.ts +23 -0
- package/dist/protocol/crypto.js +37 -0
- package/dist/protocol/crypto.js.map +1 -0
- package/dist/protocol/identity.d.ts +8 -0
- package/dist/protocol/identity.js +16 -0
- package/dist/protocol/identity.js.map +1 -0
- package/dist/runtime/index.d.ts +14 -0
- package/dist/runtime/index.js +11 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/sealed/index.d.ts +6 -0
- package/dist/sealed/index.js +6 -0
- package/dist/sealed/index.js.map +1 -0
- package/dist/sealed/seal.d.ts +19 -0
- package/dist/sealed/seal.js +56 -0
- package/dist/sealed/seal.js.map +1 -0
- package/dist/storage/fs.d.ts +16 -0
- package/dist/storage/fs.js +68 -0
- package/dist/storage/fs.js.map +1 -0
- package/dist/storage/memory.d.ts +11 -0
- package/dist/storage/memory.js +19 -0
- package/dist/storage/memory.js.map +1 -0
- package/dist/storage/provider.d.ts +12 -0
- package/dist/storage/provider.js +6 -0
- package/dist/storage/provider.js.map +1 -0
- package/dist/vault/secretPolicy.d.ts +3 -0
- package/dist/vault/secretPolicy.js +14 -0
- package/dist/vault/secretPolicy.js.map +1 -0
- package/dist/vault/vault.d.ts +91 -0
- package/dist/vault/vault.js +534 -0
- package/dist/vault/vault.js.map +1 -0
- package/docs/ARCHITECTURE.md +100 -0
- package/docs/REFERENCE.md +184 -0
- package/docs/TODO-multi-vault.md +29 -0
- package/docs/WORKS_WITH_CUSTOM_FETCH.md +196 -0
- package/docs/es/README.md +27 -0
- package/docs/fr/README.md +27 -0
- package/docs/ja/README.md +27 -0
- package/docs/ko/README.md +27 -0
- package/docs/pt/README.md +27 -0
- package/docs/spec/runtime/README.md +27 -0
- package/docs/spec/runtime/activity-log.md +67 -0
- package/docs/spec/runtime/managed-agent-record.md +52 -0
- package/docs/spec/runtime/merge-rules.md +52 -0
- package/docs/spec/runtime/secret-origin-policy.md +46 -0
- package/docs/zh/README.md +27 -0
- package/examples/minimal.ts +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# CBIO Runtime Architecture
|
|
2
|
+
|
|
3
|
+
This document defines the architectural boundaries and naming rules for the runtime.
|
|
4
|
+
|
|
5
|
+
For cross-language runtime rules that Node and Rust must share, see [spec/runtime/README.md](./spec/runtime/README.md).
|
|
6
|
+
|
|
7
|
+
## Layer Boundaries
|
|
8
|
+
|
|
9
|
+
- `runtime/`: public consumer surface only.
|
|
10
|
+
- `protocol/`: protocol adapters and identity/crypto helpers layered on top of `cbio-protocol`.
|
|
11
|
+
- `vault/`: local secret storage, persistence, recovery, and secret policy enforcement.
|
|
12
|
+
- `agent/`: identity and managed-agent orchestration.
|
|
13
|
+
- `http/`: HTTP-facing workflows and local proxy helpers.
|
|
14
|
+
- `audit/`: activity log data structures and persistence helpers.
|
|
15
|
+
- `docs/`: examples, guidance, and integration patterns. Not executable product logic.
|
|
16
|
+
- `docs/spec/runtime/`: shared runtime contracts for multi-language implementations.
|
|
17
|
+
|
|
18
|
+
## Naming Rules
|
|
19
|
+
|
|
20
|
+
### 1. One name, one layer
|
|
21
|
+
|
|
22
|
+
Do not use the same term for different layers of authority or behavior.
|
|
23
|
+
|
|
24
|
+
- Protocol-level privileges must be named differently from runtime handle permissions.
|
|
25
|
+
- Internal storage records must not be named like public API concepts.
|
|
26
|
+
|
|
27
|
+
Good examples:
|
|
28
|
+
|
|
29
|
+
- `issuedCapabilities`: privileges embedded into a signed identity document
|
|
30
|
+
- `runtimePermissions`: permissions granted to a returned `CbioAgent` handle
|
|
31
|
+
|
|
32
|
+
### 2. Name by responsibility
|
|
33
|
+
|
|
34
|
+
Names should describe what the code does, not merely what topic it is near.
|
|
35
|
+
|
|
36
|
+
Good:
|
|
37
|
+
|
|
38
|
+
- `startLocalAuthProxy`
|
|
39
|
+
- `fetchWithAuth`
|
|
40
|
+
- `getManagedAgentCapabilities`
|
|
41
|
+
|
|
42
|
+
Bad:
|
|
43
|
+
|
|
44
|
+
- vague helper names
|
|
45
|
+
- names that only imply a provider or product example
|
|
46
|
+
|
|
47
|
+
### 3. Name public contracts by actual requirements
|
|
48
|
+
|
|
49
|
+
Public option and parameter names must reflect what callers truly need.
|
|
50
|
+
|
|
51
|
+
Good:
|
|
52
|
+
|
|
53
|
+
- `IdentityLoadKeys`: requires `privateKey`, allows optional `publicKey`
|
|
54
|
+
|
|
55
|
+
Bad:
|
|
56
|
+
|
|
57
|
+
- names that imply stronger requirements than the implementation actually needs
|
|
58
|
+
|
|
59
|
+
### 4. Do not promote examples into core abstractions
|
|
60
|
+
|
|
61
|
+
Common configurations belong in docs, not in the core naming system.
|
|
62
|
+
|
|
63
|
+
- External service examples such as OpenAI, Anthropic, or Resend are documentation concerns.
|
|
64
|
+
- Core APIs should accept general configuration such as `upstreamBaseUrl`, `authHeaderName`, and `authPrefix`.
|
|
65
|
+
|
|
66
|
+
### 5. Split option objects by operation
|
|
67
|
+
|
|
68
|
+
If one options type starts describing multiple operations, split it.
|
|
69
|
+
|
|
70
|
+
A single options object may still group inputs that are consumed by one concrete operation path.
|
|
71
|
+
For example, an identity load API may accept both storage binding and issued-identity binding if both are applied during the same load step.
|
|
72
|
+
|
|
73
|
+
Good:
|
|
74
|
+
|
|
75
|
+
- `ManagedAgentIssueOptions`
|
|
76
|
+
- `ManagedAgentLoadOptions`
|
|
77
|
+
- `RegisterChildIdentityOptions`
|
|
78
|
+
|
|
79
|
+
Bad:
|
|
80
|
+
|
|
81
|
+
- one broad options object that mixes issue, load, storage, and permission semantics
|
|
82
|
+
|
|
83
|
+
### 6. Internal escape hatches stay internal
|
|
84
|
+
|
|
85
|
+
If a method exists only to let implementation pieces cooperate, it should not become part of the public API shape.
|
|
86
|
+
|
|
87
|
+
- Prefer module-local coordination over public bridge methods.
|
|
88
|
+
- Avoid exposing internal records, vault objects, or persistence schemas from `runtime/`.
|
|
89
|
+
|
|
90
|
+
## Review Checklist
|
|
91
|
+
|
|
92
|
+
When evaluating a new function, type, or field name, ask:
|
|
93
|
+
|
|
94
|
+
1. Does this name describe one thing only?
|
|
95
|
+
2. Does it reveal the correct layer and authority level?
|
|
96
|
+
3. Would a user infer the correct behavior without reading implementation code?
|
|
97
|
+
4. Is this a stable domain concept, or just a popular example?
|
|
98
|
+
5. Is this exposing an internal detail as if it were public API?
|
|
99
|
+
|
|
100
|
+
If any answer is "no", rename or split before expanding the API surface.
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# CBIO SDK Deep Reference
|
|
2
|
+
|
|
3
|
+
This document provides a comprehensive technical reference for the CBIO SDK, covering advanced API usage, custom storage implementation, and structured error handling.
|
|
4
|
+
|
|
5
|
+
For high-level concepts and quick start, see [README.md](../README.md). For module structure and naming rules, see [ARCHITECTURE.md](./ARCHITECTURE.md). For cross-language runtime contracts, see [spec/runtime/README.md](./spec/runtime/README.md).
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Advanced Identity APIs
|
|
10
|
+
|
|
11
|
+
These methods are available under `identity.admin` and its sub-facets, and are intended for administrative or high-privilege bootstrap logic.
|
|
12
|
+
|
|
13
|
+
### 1.1 Vault Synchronization & Merging
|
|
14
|
+
- **`identity.admin.vault.mergeFrom(otherIdentity, options?)`**: Atomically merges secrets from another vault.
|
|
15
|
+
- `onConflict`: `'abort'` (default), `'skip'`, or `'overwrite'`.
|
|
16
|
+
- Throws `MERGE_IDENTITY_MISMATCH` if root identities differ.
|
|
17
|
+
|
|
18
|
+
### 1.2 Backups & Sealing
|
|
19
|
+
- **`identity.admin.vault.seal(kdk: string): string`**: Exports the entire vault as an encrypted blob.
|
|
20
|
+
- **`identity.admin.vault.loadFromSealedBlob(kdk: string, blob: string)`**: Restores a vault from a sealed backup.
|
|
21
|
+
- **`identity.admin.vault.saveVault()`**: Persists the current vault back to its bound storage.
|
|
22
|
+
- **`identity.admin.vault.saveVaultAs(storageKey)`**: One-time save of the vault to an explicit key/path. Does NOT change the bound storage for subsequent `saveVault()` or autosave.
|
|
23
|
+
|
|
24
|
+
Lower-level sealed blob primitives are also exported from the package subpath:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { sealBlob, unsealBlob } from '@the-ai-company/cbio-node-runtime/sealed';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 1.3 Audit & Lifecycle
|
|
31
|
+
- **`identity.admin.vault.getActivityLog()`**: Returns a read-only list of all vault-authenticated actions.
|
|
32
|
+
- **`identity.admin.managedAgents.revokeManagedAgent(publicKey, reason?)`**: Permanently revokes a child identity.
|
|
33
|
+
- **`identity.admin.managedAgents.getManagedAgentCapabilities(publicKey)`**: Returns `{ status, capabilities }` for a managed agent, so callers can distinguish active, revoked, missing, and invalid records.
|
|
34
|
+
|
|
35
|
+
### 1.4 Agent Handles
|
|
36
|
+
- **`getAgent()`**: Returns a minimally privileged handle with `vault:fetch` and `vault:list`.
|
|
37
|
+
- **`getAgent({ permissions })`**: Returns a handle with explicitly provided runtime permissions.
|
|
38
|
+
- **`getAgent({ deriveFromIssuedIdentity: true })`**: Derives runtime permissions from the issued identity's protocol capabilities.
|
|
39
|
+
|
|
40
|
+
`permissions` and `deriveFromIssuedIdentity` are mutually exclusive; do not pass both.
|
|
41
|
+
|
|
42
|
+
### 1.5 Recursive Child Identity Management
|
|
43
|
+
When a child is registered via `registerChildIdentity(keys)`, its key material is stored in the parent vault. The method returns `{ publicKey }` (domain-level identifier). The record naming scheme is an internal runtime detail; use the protocol subpath for low-level vault access:
|
|
44
|
+
```ts
|
|
45
|
+
import { getChildIdentitySecretName } from '@the-ai-company/cbio-node-runtime/protocol';
|
|
46
|
+
|
|
47
|
+
const { publicKey: childPublicKey } = await identity.registerChildIdentity(keys);
|
|
48
|
+
const secretName = getChildIdentitySecretName(childPublicKey);
|
|
49
|
+
const stored = identity.admin.vault.getSecret(secretName);
|
|
50
|
+
if (stored) {
|
|
51
|
+
const { privateKey, publicKey } = JSON.parse(stored);
|
|
52
|
+
const childIdentity = await CbioIdentity.load({ privateKey, publicKey });
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 2. Storage Customization
|
|
59
|
+
|
|
60
|
+
The SDK can run on any backend by implementing the `IStorageProvider` interface.
|
|
61
|
+
|
|
62
|
+
### 2.1 Interface Definition
|
|
63
|
+
```ts
|
|
64
|
+
export interface IStorageProvider {
|
|
65
|
+
read(key: string): Promise<Buffer | null>;
|
|
66
|
+
write(key: string, data: Buffer): Promise<void>;
|
|
67
|
+
delete(key: string): Promise<void>;
|
|
68
|
+
has(key: string): Promise<boolean>;
|
|
69
|
+
rename?(fromKey: string, toKey: string): Promise<void>; // Improves atomic writes
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 2.2 Pre-built Providers
|
|
74
|
+
- **`MemoryStorageProvider`**: Ephemeral storage for testing or in-memory caches.
|
|
75
|
+
- **Filesystem (Default)**: Persists to `~/.c-bio/`. Use `C_BIO_VAULT_DIR` environment variable to override.
|
|
76
|
+
|
|
77
|
+
When loading an identity, use `storageKey` to choose the persisted vault location or provider key. Activity log behavior is configured explicitly with `activityLog`, for example `activityLog: { key: 'my-vault.activity.jsonl' }` or `activityLog: { enabled: false }`.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 3. Advanced Request Patterns
|
|
82
|
+
|
|
83
|
+
### 3.1 Custom Fetch for SDKs (OpenAI/Anthropic)
|
|
84
|
+
If a third-party SDK supports a custom `fetch` implementation, use `createFetchWithAuth`. This keeps the vault boundary while using the official client.
|
|
85
|
+
```ts
|
|
86
|
+
const openai = new OpenAI({
|
|
87
|
+
fetch: agent.createFetchWithAuth('openai'),
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3.2 Complex HTTP Calls
|
|
92
|
+
Use full request options for `fetchWithAuth`:
|
|
93
|
+
```ts
|
|
94
|
+
const response = await agent.fetchWithAuth('my-secret', 'https://api.example.com', {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: { 'Content-Type': 'application/json' },
|
|
97
|
+
body: JSON.stringify({ key: 'value' }),
|
|
98
|
+
authPrefix: 'Token ', // Optional: default is 'Bearer '
|
|
99
|
+
withSignature: true, // Optional: adds X-CBIO-Signature
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 3.3 JSON Secret Acquisition
|
|
104
|
+
Use `fetchJsonAndAddSecret(...)` and `fetchJsonAndUpdateSecret(...)` when the upstream returns a JSON payload that contains a secret value to store or rotate.
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
const acquired = await agent.fetchJsonAndAddSecret({
|
|
108
|
+
secretName: 'service-token',
|
|
109
|
+
url: 'https://issuer.example.com/token',
|
|
110
|
+
body: { scope: 'read' },
|
|
111
|
+
extractKey: (response: { api_key?: string }) => response.api_key ?? '',
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
These methods are intentionally JSON-specific:
|
|
116
|
+
- request bodies are JSON-stringified
|
|
117
|
+
- responses are parsed with `response.json()`
|
|
118
|
+
- `extractKey(...)` receives the parsed JSON body
|
|
119
|
+
|
|
120
|
+
### 3.4 Local Auth Proxy
|
|
121
|
+
Use `startLocalAuthProxy(...)` when a local process should forward requests to an upstream API while vault-backed auth is injected automatically.
|
|
122
|
+
|
|
123
|
+
Required fields:
|
|
124
|
+
- `authHandle`: any object with `fetchWithAuth(...)`
|
|
125
|
+
- `secretName`: vault secret to inject
|
|
126
|
+
- `upstreamBaseUrl`: upstream API base URL
|
|
127
|
+
|
|
128
|
+
Optional fields:
|
|
129
|
+
- `authHeaderName`: defaults to `Authorization`
|
|
130
|
+
- `authPrefix`: defaults to `Bearer `
|
|
131
|
+
- `host`: defaults to `127.0.0.1`
|
|
132
|
+
- `port`: defaults to an ephemeral port
|
|
133
|
+
|
|
134
|
+
OpenAI example:
|
|
135
|
+
```ts
|
|
136
|
+
const proxy = await startLocalAuthProxy({
|
|
137
|
+
authHandle: agent,
|
|
138
|
+
secretName: 'openai',
|
|
139
|
+
upstreamBaseUrl: 'https://api.openai.com',
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Anthropic example:
|
|
144
|
+
```ts
|
|
145
|
+
const proxy = await startLocalAuthProxy({
|
|
146
|
+
authHandle: agent,
|
|
147
|
+
secretName: 'anthropic',
|
|
148
|
+
upstreamBaseUrl: 'https://api.anthropic.com',
|
|
149
|
+
authHeaderName: 'x-api-key',
|
|
150
|
+
authPrefix: '',
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Resend example:
|
|
155
|
+
```ts
|
|
156
|
+
const proxy = await startLocalAuthProxy({
|
|
157
|
+
authHandle: agent,
|
|
158
|
+
secretName: 'resend',
|
|
159
|
+
upstreamBaseUrl: 'https://api.resend.com',
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 4. Error Code Dictionary
|
|
166
|
+
|
|
167
|
+
The SDK uses structured `IdentityError` objects with the following codes:
|
|
168
|
+
|
|
169
|
+
| Code | Meaning | Typical Fix / Recovery |
|
|
170
|
+
| :--- | :--- | :--- |
|
|
171
|
+
| `PERMISSION_DENIED` | Handle lacks the required runtime capability. | Check `agent.can()` before calling. |
|
|
172
|
+
| `SECRET_NOT_FOUND` | Secret name does not exist in the vault. | Add it first or check the naming. |
|
|
173
|
+
| `ISSUED_IDENTITY_INVALID` | Bound or persisted issued identity failed protocol or authority/subject validation. | Re-issue the managed identity or load with the correct authority context. |
|
|
174
|
+
| `SECRET_ALREADY_EXISTS` | `addSecret` used on an existing name. | Use a new name or `update`. |
|
|
175
|
+
| `SECRET_POLICY_REQUIRED` | Agent rotation attempted without allowed origins. | Set origins in identity code. |
|
|
176
|
+
| `SECRET_SOURCE_ORIGIN_MISMATCH` | Rotation came from a disallowed origin. | Check secret policy and rotation URL. |
|
|
177
|
+
| `VAULT_PERSISTENCE_FAILED` | Storage is not writable. | Fix permissions or check storage path. |
|
|
178
|
+
| `VAULT_FILE_NOT_FOUND` | Expected vault file does not exist. | Initialize identity or check storage key. |
|
|
179
|
+
| `VAULT_WRITE_INTEGRITY_FAILED` | Save verification failed. | Check disk space/integrity. |
|
|
180
|
+
| `VAULT_CORRUPTED` | Vault file is truncated or unreadable. | Restore from backup; do not overwrite. |
|
|
181
|
+
| `VAULT_DECRYPT_FAILED` | Decryption failed (wrong key or tampered). | Verify the correct Private Key was used. |
|
|
182
|
+
| `MERGE_IDENTITY_MISMATCH` | Tried to merge vaults of different identities. | Only merge vaults of the same identity. |
|
|
183
|
+
| `CHILD_IDENTITY_REQUIRES_PRIVATE_KEY` | Child keys were incomplete on registration. | Ensure child keys include Private Key. |
|
|
184
|
+
| `SIGNER_REQUIRES_PRIVATE_KEY` | Administrative action requires a full signer. | Load identity from a full private key. |
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# TODO: Multi-Vault Management
|
|
2
|
+
|
|
3
|
+
TUI startup flow: list vaults first, then select or create. No direct key prompt at start.
|
|
4
|
+
|
|
5
|
+
## Core Flow
|
|
6
|
+
|
|
7
|
+
1. **Startup**: Scan `C_BIO_VAULT_DIR` (default `~/.c-bio/`) for `vault_*.enc`
|
|
8
|
+
2. **List**: Show all vault files with full path; add "Create vault" option
|
|
9
|
+
3. **Select**: User picks vault → prompt for private key → load
|
|
10
|
+
4. **Create**: Generate new identity (like `init`) → show keys for user to save → load vault
|
|
11
|
+
|
|
12
|
+
## Edge Cases
|
|
13
|
+
|
|
14
|
+
- [ ] Empty directory: show only "Create vault", no empty list
|
|
15
|
+
- [ ] Wrong key: decrypt fails → show error, allow retry or back to list
|
|
16
|
+
- [ ] Corrupted vault: load fails → show error, allow back to list
|
|
17
|
+
- [ ] Quit: from vault list, allow Quit without selecting
|
|
18
|
+
- [ ] Directory permission: `C_BIO_VAULT_DIR` unreadable → show permission error
|
|
19
|
+
|
|
20
|
+
## Optional Enhancements
|
|
21
|
+
|
|
22
|
+
- [ ] Vault label: optional `.label` file next to vault for user-friendly identification
|
|
23
|
+
- [ ] Import from backup: "Import vault" alongside "Create vault"
|
|
24
|
+
- [ ] Switch vault: from main menu, return to vault list and select another
|
|
25
|
+
|
|
26
|
+
## Out of Scope (for now)
|
|
27
|
+
|
|
28
|
+
- Label file format and storage convention
|
|
29
|
+
- Reading activity log metadata for display before unlock (requires decrypt)
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Works With SDKs That Support Custom Fetch
|
|
2
|
+
|
|
3
|
+
This is the recommended integration path for `@the-ai-company/agent-identity-sdk`.
|
|
4
|
+
|
|
5
|
+
If a provider SDK accepts a custom `fetch`, you can keep the provider's official client and still avoid ever reading the API key in plaintext.
|
|
6
|
+
|
|
7
|
+
## Why this is the preferred path
|
|
8
|
+
|
|
9
|
+
- you keep using the provider's official SDK surface
|
|
10
|
+
- the vault still injects authentication headers for each request
|
|
11
|
+
- agent logic never needs `identity.getSecret(...)`
|
|
12
|
+
- the integration stays close to normal provider examples
|
|
13
|
+
|
|
14
|
+
## General pattern
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
const authFetch = agent.createFetchWithAuth('provider-secret-name');
|
|
18
|
+
|
|
19
|
+
const client = new ProviderSDK({
|
|
20
|
+
fetch: authFetch,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Use `fetchWithAuth(...)` instead when you do not need the provider SDK at all.
|
|
25
|
+
|
|
26
|
+
## OpenAI
|
|
27
|
+
|
|
28
|
+
The official OpenAI JavaScript SDK supports a custom `fetch` function.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import OpenAI from 'openai';
|
|
32
|
+
import { CbioIdentity } from '@the-ai-company/agent-identity-sdk';
|
|
33
|
+
|
|
34
|
+
const identity = await CbioIdentity.load({
|
|
35
|
+
privateKey: process.env.AGENT_PRIV_KEY!,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const agent = identity.getAgent();
|
|
39
|
+
|
|
40
|
+
const openai = new OpenAI({
|
|
41
|
+
fetch: agent.createFetchWithAuth('openai'),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const response = await openai.responses.create({
|
|
45
|
+
model: 'gpt-4.1',
|
|
46
|
+
input: 'Say hello in one sentence.',
|
|
47
|
+
});
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Store the secret under a name like `openai`, then reuse that secret name for all OpenAI requests.
|
|
51
|
+
|
|
52
|
+
## Anthropic
|
|
53
|
+
|
|
54
|
+
The official Anthropic TypeScript SDK also supports a custom `fetch` function.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
58
|
+
import { CbioIdentity } from '@the-ai-company/agent-identity-sdk';
|
|
59
|
+
|
|
60
|
+
const identity = await CbioIdentity.load({
|
|
61
|
+
privateKey: process.env.AGENT_PRIV_KEY!,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const agent = identity.getAgent();
|
|
65
|
+
|
|
66
|
+
const anthropic = new Anthropic({
|
|
67
|
+
fetch: agent.createFetchWithAuth('anthropic'),
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const message = await anthropic.messages.create({
|
|
71
|
+
model: 'claude-sonnet-4-5',
|
|
72
|
+
max_tokens: 256,
|
|
73
|
+
messages: [{ role: 'user', content: 'Say hello in one sentence.' }],
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Use a dedicated secret name such as `anthropic`.
|
|
78
|
+
|
|
79
|
+
## Other SDKs that support custom fetch
|
|
80
|
+
|
|
81
|
+
Use the same pattern for any SDK that accepts:
|
|
82
|
+
|
|
83
|
+
- `fetch`
|
|
84
|
+
- a custom HTTP client built on `fetch`
|
|
85
|
+
- request options that let you swap the transport layer
|
|
86
|
+
|
|
87
|
+
The SDK does not need to know anything about Claw-biometric. It only needs to accept a `fetch` implementation.
|
|
88
|
+
|
|
89
|
+
## If the SDK does not support custom fetch
|
|
90
|
+
|
|
91
|
+
Do not solve that by calling `identity.getSecret(...)` inside agent logic just to feed a constructor that wants `apiKey: string`.
|
|
92
|
+
|
|
93
|
+
Use one of these official alternatives instead:
|
|
94
|
+
|
|
95
|
+
## Option 1: Call the provider API directly
|
|
96
|
+
|
|
97
|
+
Best when:
|
|
98
|
+
|
|
99
|
+
- the provider has a normal HTTP API
|
|
100
|
+
- you only need a few endpoints
|
|
101
|
+
- you want the smallest trusted surface
|
|
102
|
+
|
|
103
|
+
Example:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
const response = await agent.fetchWithAuth(
|
|
107
|
+
'resend',
|
|
108
|
+
'https://api.resend.com/emails',
|
|
109
|
+
{
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: { 'Content-Type': 'application/json' },
|
|
112
|
+
body: JSON.stringify({
|
|
113
|
+
from: 'onboarding@example.com',
|
|
114
|
+
to: ['user@example.com'],
|
|
115
|
+
subject: 'Hello',
|
|
116
|
+
html: '<strong>Welcome</strong>',
|
|
117
|
+
}),
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This is the recommended path for SDKs whose official client only accepts a raw API key.
|
|
123
|
+
|
|
124
|
+
## Option 2: Use a local trusted proxy or broker
|
|
125
|
+
|
|
126
|
+
Best when:
|
|
127
|
+
|
|
128
|
+
- your team wants to keep the provider's official SDK
|
|
129
|
+
- the SDK only accepts `apiKey: string`
|
|
130
|
+
- you want to isolate key use from agent logic
|
|
131
|
+
|
|
132
|
+
Pattern:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
agent/runtime -> local trusted broker -> provider API
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The agent talks to a local process over HTTP or IPC. The local process holds `identity` privileges or another trusted handle and injects authentication on the outbound request.
|
|
139
|
+
|
|
140
|
+
With the runtime helper, configure the upstream explicitly:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
const proxy = await startLocalAuthProxy({
|
|
144
|
+
authHandle: agent,
|
|
145
|
+
secretName: 'openai',
|
|
146
|
+
upstreamBaseUrl: 'https://api.openai.com',
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
For providers that do not use `Authorization: Bearer ...`, override the auth settings:
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const proxy = await startLocalAuthProxy({
|
|
154
|
+
authHandle: agent,
|
|
155
|
+
secretName: 'anthropic',
|
|
156
|
+
upstreamBaseUrl: 'https://api.anthropic.com',
|
|
157
|
+
authHeaderName: 'x-api-key',
|
|
158
|
+
authPrefix: '',
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Common examples:
|
|
163
|
+
|
|
164
|
+
- OpenAI: `upstreamBaseUrl: 'https://api.openai.com'`
|
|
165
|
+
- Anthropic: `upstreamBaseUrl: 'https://api.anthropic.com'`, `authHeaderName: 'x-api-key'`, `authPrefix: ''`
|
|
166
|
+
- Resend: `upstreamBaseUrl: 'https://api.resend.com'`
|
|
167
|
+
|
|
168
|
+
## Option 3: Run key-holding code in a separate trusted process
|
|
169
|
+
|
|
170
|
+
Best when:
|
|
171
|
+
|
|
172
|
+
- you already have a worker/service boundary
|
|
173
|
+
- you need the provider SDK exactly as-is
|
|
174
|
+
- you want process-level separation without introducing a local HTTP proxy
|
|
175
|
+
|
|
176
|
+
Pattern:
|
|
177
|
+
|
|
178
|
+
1. trusted process loads `AGENT_PRIV_KEY`
|
|
179
|
+
2. trusted process creates `identity`, then `agent`
|
|
180
|
+
3. untrusted process calls into the trusted process over RPC, IPC, or a queue
|
|
181
|
+
|
|
182
|
+
The important part is not the transport. The important part is that the untrusted runtime never gets plaintext credentials and never gets `identity`.
|
|
183
|
+
|
|
184
|
+
## Decision guide
|
|
185
|
+
|
|
186
|
+
Use this order:
|
|
187
|
+
|
|
188
|
+
1. If the SDK supports custom `fetch`, use `createFetchWithAuth(...)`.
|
|
189
|
+
2. If you only need HTTP calls, use `fetchWithAuth(...)` directly.
|
|
190
|
+
3. If the SDK only accepts a raw key, use a trusted proxy or separate trusted process.
|
|
191
|
+
|
|
192
|
+
Avoid:
|
|
193
|
+
|
|
194
|
+
- `identity.getSecret(...)` inside agent logic
|
|
195
|
+
- passing plaintext API keys into prompts, tools, or third-party SDK constructors
|
|
196
|
+
- loading `AGENT_PRIV_KEY` in the same process as untrusted tools or model-driven code
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# cbio Node Runtime
|
|
2
|
+
|
|
3
|
+
Runtime Node.js para caja de identidad y credenciales cbio. Solo biblioteca, sin CLI ni TUI.
|
|
4
|
+
|
|
5
|
+
Importa y usa `CbioIdentity`, `CbioAgent` desde el export principal.
|
|
6
|
+
|
|
7
|
+
## Instalación
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @the-ai-company/cbio-node-runtime
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Uso
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { CbioIdentity, generateIdentityKeys } from '@the-ai-company/cbio-node-runtime';
|
|
17
|
+
|
|
18
|
+
const keys = generateIdentityKeys();
|
|
19
|
+
const identity = await CbioIdentity.load({ privateKey: keys.privateKey });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Compilación
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
npm run test
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# cbio Node Runtime
|
|
2
|
+
|
|
3
|
+
Runtime Node.js pour le coffre d'identité et de credentials cbio. Bibliothèque uniquement, pas de CLI ni TUI.
|
|
4
|
+
|
|
5
|
+
Importez et utilisez `CbioIdentity`, `CbioAgent` depuis l'export principal.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @the-ai-company/cbio-node-runtime
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Utilisation
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { CbioIdentity, generateIdentityKeys } from '@the-ai-company/cbio-node-runtime';
|
|
17
|
+
|
|
18
|
+
const keys = generateIdentityKeys();
|
|
19
|
+
const identity = await CbioIdentity.load({ privateKey: keys.privateKey });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Compilation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
npm run test
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# cbio Node Runtime
|
|
2
|
+
|
|
3
|
+
cbio アイデンティティと credential vault の Node.js ランタイム。ライブラリのみ、CLI / TUI なし。
|
|
4
|
+
|
|
5
|
+
メインエクスポートから `CbioIdentity`、`CbioAgent` をインポートして使用。
|
|
6
|
+
|
|
7
|
+
## インストール
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @the-ai-company/cbio-node-runtime
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 使用例
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { CbioIdentity, generateIdentityKeys } from '@the-ai-company/cbio-node-runtime';
|
|
17
|
+
|
|
18
|
+
const keys = generateIdentityKeys();
|
|
19
|
+
const identity = await CbioIdentity.load({ privateKey: keys.privateKey });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## ビルド
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
npm run test
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# cbio Node Runtime
|
|
2
|
+
|
|
3
|
+
cbio identity 및 credential vault용 Node.js 런타임. 라이브러리만 제공, CLI/TUI 없음.
|
|
4
|
+
|
|
5
|
+
메인 export에서 `CbioIdentity`, `CbioAgent`를 import하여 사용.
|
|
6
|
+
|
|
7
|
+
## 설치
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @the-ai-company/cbio-node-runtime
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 사용법
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { CbioIdentity, generateIdentityKeys } from '@the-ai-company/cbio-node-runtime';
|
|
17
|
+
|
|
18
|
+
const keys = generateIdentityKeys();
|
|
19
|
+
const identity = await CbioIdentity.load({ privateKey: keys.privateKey });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 빌드
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
npm run test
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# cbio Node Runtime
|
|
2
|
+
|
|
3
|
+
Runtime Node.js para cofre de identidade e credenciais cbio. Apenas biblioteca, sem CLI ou TUI.
|
|
4
|
+
|
|
5
|
+
Importe e use `CbioIdentity`, `CbioAgent` do export principal.
|
|
6
|
+
|
|
7
|
+
## Instalação
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @the-ai-company/cbio-node-runtime
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Uso
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { CbioIdentity, generateIdentityKeys } from '@the-ai-company/cbio-node-runtime';
|
|
17
|
+
|
|
18
|
+
const keys = generateIdentityKeys();
|
|
19
|
+
const identity = await CbioIdentity.load({ privateKey: keys.privateKey });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Compilação
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
npm run test
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CBIO Runtime Spec
|
|
2
|
+
|
|
3
|
+
This directory defines runtime rules that must stay consistent across language implementations such as Node and Rust.
|
|
4
|
+
|
|
5
|
+
These files are not Node-specific API docs. They are shared runtime contracts.
|
|
6
|
+
|
|
7
|
+
Use this directory for:
|
|
8
|
+
- local persisted record schemas
|
|
9
|
+
- runtime-only policy rules
|
|
10
|
+
- merge and recovery semantics
|
|
11
|
+
- audit/event semantics
|
|
12
|
+
|
|
13
|
+
Do not use this directory for:
|
|
14
|
+
- Node-only helper APIs
|
|
15
|
+
- examples or tutorials
|
|
16
|
+
- protocol-layer governance objects already defined by `@the-ai-company/cbio-protocol`
|
|
17
|
+
|
|
18
|
+
## Current Runtime Spec Set
|
|
19
|
+
|
|
20
|
+
- [managed-agent-record.md](./managed-agent-record.md): persisted local record for a managed agent identity
|
|
21
|
+
- [merge-rules.md](./merge-rules.md): vault merge preconditions and conflict behavior
|
|
22
|
+
- [secret-origin-policy.md](./secret-origin-policy.md): allowed origin policy for acquired and rotated secrets
|
|
23
|
+
- [activity-log.md](./activity-log.md): local audit event schema and failure semantics
|
|
24
|
+
|
|
25
|
+
## Design Goal
|
|
26
|
+
|
|
27
|
+
If a Node runtime and a Rust runtime both claim to implement CBIO runtime behavior, these rules must mean the same thing in both implementations.
|