@keemakr/agent-sdk 0.8.0 → 0.10.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/dist/client.d.ts +66 -0
- package/dist/client.js +90 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tool-directory.d.ts +9 -1
- package/package.json +3 -3
package/dist/client.d.ts
CHANGED
|
@@ -13,6 +13,26 @@ export declare class MemoryConflictError extends Error {
|
|
|
13
13
|
current: MemoryEntry | null;
|
|
14
14
|
constructor(current: MemoryEntry | null);
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* A conditional record write (`ifVersion`) lost the race — another agent wrote
|
|
18
|
+
* the record first. `current` is the record as it now stands (null when it was
|
|
19
|
+
* deleted concurrently). Re-read, re-derive, retry.
|
|
20
|
+
*/
|
|
21
|
+
export declare class RecordConflictError extends Error {
|
|
22
|
+
status: 409;
|
|
23
|
+
current: RecordEntry | null;
|
|
24
|
+
constructor(current: RecordEntry | null);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The record didn't match the field spec the entry declared for the collection
|
|
28
|
+
* — core validates every write server-side against what the tenant consented
|
|
29
|
+
* to at install. `issues` lists the exact mismatches.
|
|
30
|
+
*/
|
|
31
|
+
export declare class RecordValidationError extends Error {
|
|
32
|
+
status: 422;
|
|
33
|
+
issues: string[];
|
|
34
|
+
constructor(issues: string[]);
|
|
35
|
+
}
|
|
16
36
|
export interface KeeContext {
|
|
17
37
|
session?: {
|
|
18
38
|
auth?: {
|
|
@@ -106,6 +126,51 @@ export interface KeeKb {
|
|
|
106
126
|
k?: number;
|
|
107
127
|
}): Promise<KBHit[]>;
|
|
108
128
|
}
|
|
129
|
+
/** One stored typed record. */
|
|
130
|
+
export interface RecordEntry {
|
|
131
|
+
collection: string;
|
|
132
|
+
record_id: string;
|
|
133
|
+
data: Record<string, unknown>;
|
|
134
|
+
written_by_agent: string | null;
|
|
135
|
+
/** Monotonic write counter — pass as `ifVersion` for compare-and-swap writes. */
|
|
136
|
+
version: number;
|
|
137
|
+
created_at: string;
|
|
138
|
+
updated_at: string;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Typed record collections — the structured counterpart to memory (leads,
|
|
142
|
+
* tickets, anything row-shaped). A collection must be declared in the entry's
|
|
143
|
+
* entry.json as a kind:'records' dependency (collection + field spec); the
|
|
144
|
+
* tenant consents at install, and the grant then carries the per-collection
|
|
145
|
+
* `records:<collection>:read` / `records:<collection>:write` scopes. Core
|
|
146
|
+
* validates every write against the declared spec — a mismatch throws
|
|
147
|
+
* RecordValidationError with the exact issues. TENANT-SHARED like memory.
|
|
148
|
+
*/
|
|
149
|
+
export interface KeeRecords {
|
|
150
|
+
/**
|
|
151
|
+
* Write a record. When the spec declares an upsertKey, the record id derives
|
|
152
|
+
* from that field's value — saving the same lead email twice updates one
|
|
153
|
+
* record (idempotent). Pass `id` to address a specific record (PUT), and
|
|
154
|
+
* `ifVersion` (from a prior get/list) for compare-and-swap: throws
|
|
155
|
+
* RecordConflictError when another agent wrote it in between.
|
|
156
|
+
*/
|
|
157
|
+
upsert(collection: string, data: Record<string, unknown>, opts?: {
|
|
158
|
+
id?: string;
|
|
159
|
+
ifVersion?: number;
|
|
160
|
+
}): Promise<RecordEntry>;
|
|
161
|
+
/** Read one record, or null if absent. */
|
|
162
|
+
get(collection: string, id: string): Promise<RecordEntry | null>;
|
|
163
|
+
/** List a collection page by page (keyset cursor — pass back `nextCursor`). */
|
|
164
|
+
list(collection: string, opts?: {
|
|
165
|
+
limit?: number;
|
|
166
|
+
cursor?: string;
|
|
167
|
+
}): Promise<{
|
|
168
|
+
records: RecordEntry[];
|
|
169
|
+
nextCursor: string | null;
|
|
170
|
+
}>;
|
|
171
|
+
/** Delete one record. Returns whether it existed. */
|
|
172
|
+
delete(collection: string, id: string): Promise<boolean>;
|
|
173
|
+
}
|
|
109
174
|
/** Platform registry tools (Shape B) — defined in core, run server-side. */
|
|
110
175
|
export interface KeeTools {
|
|
111
176
|
/** List the registry tools this grant is entitled to. */
|
|
@@ -125,6 +190,7 @@ export interface Kee {
|
|
|
125
190
|
get(provider: string): KeeConnection;
|
|
126
191
|
};
|
|
127
192
|
memory: KeeMemory;
|
|
193
|
+
records: KeeRecords;
|
|
128
194
|
kb: KeeKb;
|
|
129
195
|
tools: KeeTools;
|
|
130
196
|
}
|
package/dist/client.js
CHANGED
|
@@ -31,6 +31,34 @@ export class MemoryConflictError extends Error {
|
|
|
31
31
|
this.current = current;
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* A conditional record write (`ifVersion`) lost the race — another agent wrote
|
|
36
|
+
* the record first. `current` is the record as it now stands (null when it was
|
|
37
|
+
* deleted concurrently). Re-read, re-derive, retry.
|
|
38
|
+
*/
|
|
39
|
+
export class RecordConflictError extends Error {
|
|
40
|
+
status = 409;
|
|
41
|
+
current;
|
|
42
|
+
constructor(current) {
|
|
43
|
+
super('record version conflict — the record changed since it was read');
|
|
44
|
+
this.name = 'RecordConflictError';
|
|
45
|
+
this.current = current;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The record didn't match the field spec the entry declared for the collection
|
|
50
|
+
* — core validates every write server-side against what the tenant consented
|
|
51
|
+
* to at install. `issues` lists the exact mismatches.
|
|
52
|
+
*/
|
|
53
|
+
export class RecordValidationError extends Error {
|
|
54
|
+
status = 422;
|
|
55
|
+
issues;
|
|
56
|
+
constructor(issues) {
|
|
57
|
+
super(`record does not match the declared spec: ${issues.join('; ')}`);
|
|
58
|
+
this.name = 'RecordValidationError';
|
|
59
|
+
this.issues = issues;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
34
62
|
function readGrant(ctx) {
|
|
35
63
|
const attrs = ctx?.session?.auth?.current?.attributes ?? {};
|
|
36
64
|
const token = typeof attrs.grant_token === 'string' ? attrs.grant_token : undefined;
|
|
@@ -193,6 +221,59 @@ export function useKee(ctx) {
|
|
|
193
221
|
return json.hits ?? [];
|
|
194
222
|
},
|
|
195
223
|
};
|
|
224
|
+
// Shared 409/422 mapping for record writes (POST to the collection or PUT to
|
|
225
|
+
// a specific id) — typed errors the agent's model can act on.
|
|
226
|
+
const recordWrite = async (path, method, body) => {
|
|
227
|
+
try {
|
|
228
|
+
const json = (await capabilityFetch(grant, path, body, method));
|
|
229
|
+
return json.entry;
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
const err = e;
|
|
233
|
+
const body409 = err.body;
|
|
234
|
+
if (err.status === 409 && body409?.error === 'version_conflict') {
|
|
235
|
+
throw new RecordConflictError(body409.entry ?? null);
|
|
236
|
+
}
|
|
237
|
+
if (err.status === 422 && body409?.issues) {
|
|
238
|
+
throw new RecordValidationError(body409.issues);
|
|
239
|
+
}
|
|
240
|
+
throw e;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
const records = {
|
|
244
|
+
async upsert(collection, data, opts) {
|
|
245
|
+
const payload = { data, expected_version: opts?.ifVersion };
|
|
246
|
+
if (opts?.id) {
|
|
247
|
+
return recordWrite(`records/${enc(collection)}/${enc(opts.id)}`, 'PUT', payload);
|
|
248
|
+
}
|
|
249
|
+
return recordWrite(`records/${enc(collection)}`, 'POST', payload);
|
|
250
|
+
},
|
|
251
|
+
async get(collection, id) {
|
|
252
|
+
try {
|
|
253
|
+
const json = (await capabilityFetch(grant, `records/${enc(collection)}/${enc(id)}`, undefined, 'GET'));
|
|
254
|
+
return json.entry ?? null;
|
|
255
|
+
}
|
|
256
|
+
catch (e) {
|
|
257
|
+
if (e.status === 404)
|
|
258
|
+
return null;
|
|
259
|
+
throw e;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
async list(collection, opts) {
|
|
263
|
+
const qs = new URLSearchParams();
|
|
264
|
+
if (opts?.limit)
|
|
265
|
+
qs.set('limit', String(opts.limit));
|
|
266
|
+
if (opts?.cursor)
|
|
267
|
+
qs.set('cursor', opts.cursor);
|
|
268
|
+
const suffix = qs.size ? `?${qs}` : '';
|
|
269
|
+
const json = (await capabilityFetch(grant, `records/${enc(collection)}${suffix}`, undefined, 'GET'));
|
|
270
|
+
return { records: json.records ?? [], nextCursor: json.next_cursor ?? null };
|
|
271
|
+
},
|
|
272
|
+
async delete(collection, id) {
|
|
273
|
+
const json = (await capabilityFetch(grant, `records/${enc(collection)}/${enc(id)}`, undefined, 'DELETE'));
|
|
274
|
+
return !!json.deleted;
|
|
275
|
+
},
|
|
276
|
+
};
|
|
196
277
|
const kb = {
|
|
197
278
|
async search(query, opts) {
|
|
198
279
|
const json = (await capabilityFetch(grant, 'kb/retrieve', {
|
|
@@ -214,5 +295,13 @@ export function useKee(ctx) {
|
|
|
214
295
|
return json.result;
|
|
215
296
|
},
|
|
216
297
|
};
|
|
217
|
-
return {
|
|
298
|
+
return {
|
|
299
|
+
tenantId: grant.tenantId,
|
|
300
|
+
scopes: grant.scopes,
|
|
301
|
+
connections,
|
|
302
|
+
memory,
|
|
303
|
+
records,
|
|
304
|
+
kb,
|
|
305
|
+
tools,
|
|
306
|
+
};
|
|
218
307
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { grantAuth } from './grant-auth.js';
|
|
2
2
|
export { verifyGrant, type VerifiedGrant } from './verify-grant.js';
|
|
3
|
-
export { useKee, MemoryConflictError, type Kee, type KeeConnection, type KeeContext, type KeeError, type KeeMemory, type KeeKb, type KBHit, type KeeTools, type MemoryEntry, type MemorySearchHit, } from './client.js';
|
|
3
|
+
export { useKee, MemoryConflictError, RecordConflictError, RecordValidationError, type Kee, type KeeConnection, type KeeContext, type KeeError, type KeeMemory, type KeeRecords, type KeeKb, type KBHit, type KeeTools, type MemoryEntry, type MemorySearchHit, type RecordEntry, } from './client.js';
|
|
4
4
|
export { keemakrToolDirectory } from './tool-directory.js';
|
|
5
5
|
export { refreshGrant, REFRESH_THRESHOLD_SECONDS } from './refresh.js';
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,6 @@
|
|
|
10
10
|
// const r = await kee.connections.hunter.call('email-finder', { domain, first_name, last_name });
|
|
11
11
|
export { grantAuth } from './grant-auth.js';
|
|
12
12
|
export { verifyGrant } from './verify-grant.js';
|
|
13
|
-
export { useKee, MemoryConflictError, } from './client.js';
|
|
13
|
+
export { useKee, MemoryConflictError, RecordConflictError, RecordValidationError, } from './client.js';
|
|
14
14
|
export { keemakrToolDirectory } from './tool-directory.js';
|
|
15
15
|
export { refreshGrant, REFRESH_THRESHOLD_SECONDS } from './refresh.js';
|
package/dist/tool-directory.d.ts
CHANGED
|
@@ -1 +1,9 @@
|
|
|
1
|
-
export declare const keemakrToolDirectory: import("eve/tools").DynamicSentinel
|
|
1
|
+
export declare const keemakrToolDirectory: import("eve/tools").DynamicSentinel<{
|
|
2
|
+
[k: string]: import("eve/tools").ToolDefinition<{
|
|
3
|
+
args?: Record<string, unknown> | undefined;
|
|
4
|
+
}, {
|
|
5
|
+
ok: boolean;
|
|
6
|
+
tool: string;
|
|
7
|
+
result: unknown;
|
|
8
|
+
}>;
|
|
9
|
+
} | null>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keemakr/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "The floor for keemakr marketplace agents: verify the capability grant and reach tenant connections, memory, and shared platform tools through keemakr-core — without holding raw secrets or resolving the tenant yourself.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"prepublishOnly": "npm run build"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"eve": "0.
|
|
42
|
+
"eve": "0.22.1",
|
|
43
43
|
"jose": "^6.2.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@types/node": "^20.19.43",
|
|
47
|
-
"eve": "0.
|
|
47
|
+
"eve": "0.22.1",
|
|
48
48
|
"jose": "^6.2.3",
|
|
49
49
|
"typescript": "^5"
|
|
50
50
|
},
|