@hivemagnus/hivemem-sdk 1.0.3 → 1.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/CHANGELOG.md +27 -0
- package/README.md +28 -3
- package/dist/client.d.ts +9 -1
- package/dist/client.js +35 -2
- package/dist/types.d.ts +66 -0
- package/package.json +10 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@hivemagnus/hivemem-sdk`.
|
|
4
|
+
|
|
5
|
+
## [1.1.0] - 2026-11-12
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `createWorkspace(workspaceId, options)` calls `POST /v1/workspaces` and returns the
|
|
10
|
+
`WorkspaceRecord`. It is idempotent: an existing workspace the caller can read is returned
|
|
11
|
+
unchanged. New `WorkspaceRecord`, `WorkspaceMember`, `WorkspacePolicy` and
|
|
12
|
+
`WorkspaceCreateOptions` types.
|
|
13
|
+
- `tokenProvider` option for short-lived credentials such as Oathweave service tokens. It is
|
|
14
|
+
called before each request and, after a 401, called again with `forceRefresh: true` and the
|
|
15
|
+
request retried once. A static `token` keeps working unchanged.
|
|
16
|
+
- `headers` option: extra headers on every request, static or from a function called per
|
|
17
|
+
request, for example to propagate `x-request-id` and `traceparent`. They cannot replace
|
|
18
|
+
`Accept`, `Content-Type` or `Authorization`.
|
|
19
|
+
|
|
20
|
+
### Security
|
|
21
|
+
|
|
22
|
+
- Every request is sent with `redirect: "error"`, so a redirect can no longer carry the bearer
|
|
23
|
+
token to another origin.
|
|
24
|
+
|
|
25
|
+
## [1.0.3]
|
|
26
|
+
|
|
27
|
+
- Earlier releases are described in the HiveMem repository changelog.
|
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# @hivemagnus/hivemem-sdk
|
|
2
2
|
|
|
3
|
-
TypeScript client for [HiveMem](https://github.com/ChefTaco/
|
|
3
|
+
TypeScript client for [HiveMem](https://github.com/ChefTaco/HiveMem), the shared long-term memory service for AI agents. It wraps the HiveMem REST API with typed helpers for memories, search, sessions, prompt context, peer cards, conclusions, queue operations, and webhooks.
|
|
4
4
|
|
|
5
5
|
- Zero runtime dependencies; uses the platform `fetch` (Node.js 18.17+, Deno, Bun, browsers, edge runtimes).
|
|
6
6
|
- ESM-only, with bundled type declarations.
|
|
7
|
-
- Retries 5xx responses, supports request timeouts, request IDs, and token refresh
|
|
7
|
+
- Retries 5xx responses, supports request timeouts, request IDs, extra headers, and token providers that refresh on 401.
|
|
8
|
+
- Never follows redirects (`redirect: "error"`), so the bearer token stays with the configured origin.
|
|
8
9
|
|
|
9
10
|
## Install
|
|
10
11
|
|
|
@@ -12,7 +13,7 @@ TypeScript client for [HiveMem](https://github.com/ChefTaco/hive/tree/main/servi
|
|
|
12
13
|
npm install @hivemagnus/hivemem-sdk
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
You need a running HiveMem server and an agent token. See the [HiveMem README](https://github.com/ChefTaco/
|
|
16
|
+
You need a running HiveMem server and an agent token. See the [HiveMem README](https://github.com/ChefTaco/HiveMem#readme) for how to run the server and register an agent.
|
|
16
17
|
|
|
17
18
|
## Quick start
|
|
18
19
|
|
|
@@ -53,10 +54,30 @@ const messages = context.toOpenAI(); // or context.toAnthropic()
|
|
|
53
54
|
| `fetchImpl` | | global `fetch` |
|
|
54
55
|
| `requestIdProvider` | | sends `X-Request-ID` when set |
|
|
55
56
|
| `authRefresh` | | called before each attempt; a returned token replaces the current one |
|
|
57
|
+
| `tokenProvider` | | `({ forceRefresh }) => token`; called before each request, and again with `forceRefresh: true` after a 401, when the request is retried once |
|
|
58
|
+
| `headers` | | extra headers on every request, or a function returning them per request; cannot replace `Accept`, `Content-Type` or `Authorization` |
|
|
56
59
|
| `onRequest` / `onResponse` | | observability hooks |
|
|
57
60
|
|
|
58
61
|
Explicit constructor options win over environment variables. Environment variables are only read where `process.env` exists.
|
|
59
62
|
|
|
63
|
+
### Service tokens and request propagation
|
|
64
|
+
|
|
65
|
+
A product calling HiveMem with a short-lived Oathweave service token passes a `tokenProvider`
|
|
66
|
+
instead of a static `token`. Cache the token in the provider and fetch a new one when
|
|
67
|
+
`forceRefresh` is true (HiveMem answered 401) or the cached one is near expiry. Use `headers` to
|
|
68
|
+
forward the caller's request ID and trace context:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const hivemem = new HiveMem({
|
|
72
|
+
baseUrl: "https://memory.example.com",
|
|
73
|
+
tokenProvider: ({ forceRefresh }) => serviceTokens.get({ forceRefresh }),
|
|
74
|
+
headers: () => ({ "x-request-id": currentRequestId(), traceparent: currentTraceparent() }),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Create the workspace your agents join; returns the existing one if it is already there.
|
|
78
|
+
const workspace = await hivemem.createWorkspace("team-alpha", { title: "Team Alpha" });
|
|
79
|
+
```
|
|
80
|
+
|
|
60
81
|
## Common operations
|
|
61
82
|
|
|
62
83
|
```ts
|
|
@@ -115,6 +136,10 @@ const ok = await verifyHiveMemWebhook({
|
|
|
115
136
|
});
|
|
116
137
|
```
|
|
117
138
|
|
|
139
|
+
## Releasing
|
|
140
|
+
|
|
141
|
+
Maintainers: see [RELEASING.md](https://github.com/ChefTaco/HiveMem/blob/main/sdks/typescript/RELEASING.md). In short, bump the version, push a tag `sdk-vX.Y.Z`, and approve the publish run.
|
|
142
|
+
|
|
118
143
|
## License
|
|
119
144
|
|
|
120
145
|
Apache-2.0. See [LICENSE](LICENSE).
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ContextPackage } from "./context.js";
|
|
2
|
-
import type { ConclusionPage, ConclusionRecord, HiveMemOptions, KnowledgeSourceSyncResponse, MemoryRecord, PeerCardResponse, QueueJobRecord, QueueStatusResponse, SearchResponse, SessionRecord, WebhookEndpoint } from "./types.js";
|
|
2
|
+
import type { ConclusionPage, ConclusionRecord, HiveMemOptions, KnowledgeSourceSyncResponse, MemoryRecord, PeerCardResponse, QueueJobRecord, QueueStatusResponse, SearchResponse, SessionRecord, WebhookEndpoint, WorkspaceCreateOptions, WorkspaceRecord } from "./types.js";
|
|
3
3
|
export declare class HiveMem {
|
|
4
4
|
readonly baseUrl: string;
|
|
5
5
|
token?: string;
|
|
@@ -9,12 +9,20 @@ export declare class HiveMem {
|
|
|
9
9
|
private readonly fetchImpl;
|
|
10
10
|
private readonly requestIdProvider?;
|
|
11
11
|
private readonly authRefresh?;
|
|
12
|
+
private readonly tokenProvider?;
|
|
13
|
+
private readonly extraHeaders?;
|
|
12
14
|
private readonly onRequest?;
|
|
13
15
|
private readonly onResponse?;
|
|
14
16
|
constructor(options?: HiveMemOptions);
|
|
15
17
|
private url;
|
|
16
18
|
private request;
|
|
17
19
|
health(): Promise<Record<string, unknown>>;
|
|
20
|
+
/**
|
|
21
|
+
* Create a workspace, owned by the caller (`POST /v1/workspaces`, scope `workspaces:write`).
|
|
22
|
+
* Idempotent: when the workspace already exists and the caller can read it, the server returns
|
|
23
|
+
* it unchanged. An archived workspace ID is a 409.
|
|
24
|
+
*/
|
|
25
|
+
createWorkspace(workspaceId: string, options?: WorkspaceCreateOptions): Promise<WorkspaceRecord>;
|
|
18
26
|
getMemory(memoryId: string, options?: {
|
|
19
27
|
includeHistory?: boolean;
|
|
20
28
|
}): Promise<MemoryRecord>;
|
package/dist/client.js
CHANGED
|
@@ -13,6 +13,8 @@ export class HiveMem {
|
|
|
13
13
|
fetchImpl;
|
|
14
14
|
requestIdProvider;
|
|
15
15
|
authRefresh;
|
|
16
|
+
tokenProvider;
|
|
17
|
+
extraHeaders;
|
|
16
18
|
onRequest;
|
|
17
19
|
onResponse;
|
|
18
20
|
constructor(options = {}) {
|
|
@@ -24,6 +26,8 @@ export class HiveMem {
|
|
|
24
26
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
25
27
|
this.requestIdProvider = options.requestIdProvider;
|
|
26
28
|
this.authRefresh = options.authRefresh;
|
|
29
|
+
this.tokenProvider = options.tokenProvider;
|
|
30
|
+
this.extraHeaders = options.headers;
|
|
27
31
|
this.onRequest = options.onRequest;
|
|
28
32
|
this.onResponse = options.onResponse;
|
|
29
33
|
}
|
|
@@ -36,14 +40,23 @@ export class HiveMem {
|
|
|
36
40
|
if (value !== undefined && value !== null)
|
|
37
41
|
url.searchParams.set(key, String(value));
|
|
38
42
|
}
|
|
39
|
-
const
|
|
43
|
+
const extra = typeof this.extraHeaders === "function" ? await this.extraHeaders() : this.extraHeaders;
|
|
44
|
+
const headers = new Headers(extra);
|
|
45
|
+
new Headers(init.headers).forEach((value, key) => headers.set(key, value));
|
|
40
46
|
headers.set("Accept", "application/json");
|
|
41
47
|
if (init.body && !headers.has("Content-Type"))
|
|
42
48
|
headers.set("Content-Type", "application/json");
|
|
43
49
|
if (this.requestIdProvider)
|
|
44
50
|
headers.set("X-Request-ID", this.requestIdProvider());
|
|
51
|
+
headers.delete("Authorization");
|
|
52
|
+
if (this.tokenProvider) {
|
|
53
|
+
const provided = await this.tokenProvider({ forceRefresh: false });
|
|
54
|
+
if (provided)
|
|
55
|
+
this.token = provided;
|
|
56
|
+
}
|
|
45
57
|
if (this.token)
|
|
46
58
|
headers.set("Authorization", `Bearer ${this.token}`);
|
|
59
|
+
let reauthorized = false;
|
|
47
60
|
for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {
|
|
48
61
|
const refreshed = await this.authRefresh?.();
|
|
49
62
|
if (refreshed) {
|
|
@@ -53,10 +66,22 @@ export class HiveMem {
|
|
|
53
66
|
const controller = new AbortController();
|
|
54
67
|
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
55
68
|
try {
|
|
56
|
-
const requestInit = { ...init, method, headers, signal: controller.signal };
|
|
69
|
+
const requestInit = { ...init, method, headers, signal: controller.signal, redirect: "error" };
|
|
57
70
|
this.onRequest?.(method, String(url), requestInit);
|
|
58
71
|
const response = await this.fetchImpl(url, requestInit);
|
|
59
72
|
this.onResponse?.(response);
|
|
73
|
+
if (response.status === 401 && this.tokenProvider && !reauthorized) {
|
|
74
|
+
// A service token may have expired or been revoked: fetch a fresh one and retry once.
|
|
75
|
+
reauthorized = true;
|
|
76
|
+
const fresh = await this.tokenProvider({ forceRefresh: true });
|
|
77
|
+
if (fresh) {
|
|
78
|
+
await response.body?.cancel().catch(() => undefined);
|
|
79
|
+
this.token = fresh;
|
|
80
|
+
headers.set("Authorization", `Bearer ${this.token}`);
|
|
81
|
+
attempt -= 1;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
60
85
|
if (response.status >= 500 && attempt < this.maxRetries)
|
|
61
86
|
continue;
|
|
62
87
|
if (!response.ok) {
|
|
@@ -85,6 +110,14 @@ export class HiveMem {
|
|
|
85
110
|
health() {
|
|
86
111
|
return this.request("GET", "/v1/health");
|
|
87
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Create a workspace, owned by the caller (`POST /v1/workspaces`, scope `workspaces:write`).
|
|
115
|
+
* Idempotent: when the workspace already exists and the caller can read it, the server returns
|
|
116
|
+
* it unchanged. An archived workspace ID is a 409.
|
|
117
|
+
*/
|
|
118
|
+
createWorkspace(workspaceId, options = {}) {
|
|
119
|
+
return this.request("POST", "/v1/workspaces", { body: JSON.stringify({ ...options, workspace_id: workspaceId }) });
|
|
120
|
+
}
|
|
88
121
|
getMemory(memoryId, options = {}) {
|
|
89
122
|
const params = options.includeHistory ? { include_history: true } : {};
|
|
90
123
|
return this.request("GET", `/v1/memories/${encodeURIComponent(memoryId)}`, {}, params);
|
package/dist/types.d.ts
CHANGED
|
@@ -10,9 +10,75 @@ export interface HiveMemOptions {
|
|
|
10
10
|
fetchImpl?: typeof fetch;
|
|
11
11
|
requestIdProvider?: () => string;
|
|
12
12
|
authRefresh?: () => string | undefined | Promise<string | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* Supplies the bearer token, for example a short-lived Oathweave service token. Called before
|
|
15
|
+
* each request with `forceRefresh: false`; after a 401 it is called again with
|
|
16
|
+
* `forceRefresh: true` and the request is retried once with the token it returns. Returning
|
|
17
|
+
* `undefined` falls back to `token`.
|
|
18
|
+
*/
|
|
19
|
+
tokenProvider?: TokenProvider;
|
|
20
|
+
/**
|
|
21
|
+
* Extra headers sent on every request, such as `x-request-id` or `traceparent` taken from the
|
|
22
|
+
* caller's request context. A function is called once per request. They never replace the
|
|
23
|
+
* client's own `Accept` or `Content-Type` headers, and `Authorization` comes only from `token`,
|
|
24
|
+
* `tokenProvider` or `authRefresh`.
|
|
25
|
+
*/
|
|
26
|
+
headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
|
|
13
27
|
onRequest?: (method: string, url: string, init: RequestInit) => void;
|
|
14
28
|
onResponse?: (response: Response) => void;
|
|
15
29
|
}
|
|
30
|
+
export interface TokenProviderContext {
|
|
31
|
+
/** True after the server answered 401: the cached token must not be reused. */
|
|
32
|
+
forceRefresh: boolean;
|
|
33
|
+
}
|
|
34
|
+
export type TokenProvider = (context: TokenProviderContext) => string | undefined | Promise<string | undefined>;
|
|
35
|
+
export type WorkspaceRole = "viewer" | "member" | "admin" | "owner";
|
|
36
|
+
export interface WorkspaceMember {
|
|
37
|
+
agent_id: string;
|
|
38
|
+
role: WorkspaceRole;
|
|
39
|
+
scopes: string[];
|
|
40
|
+
added_by: string | null;
|
|
41
|
+
created_at: string | null;
|
|
42
|
+
updated_at: string | null;
|
|
43
|
+
}
|
|
44
|
+
export interface WorkspaceSanitizationPolicy {
|
|
45
|
+
mode: "warn" | "redact" | "reject" | null;
|
|
46
|
+
detect_pii: boolean | null;
|
|
47
|
+
detect_secrets: boolean | null;
|
|
48
|
+
deny_regexes: string[];
|
|
49
|
+
}
|
|
50
|
+
export interface WorkspacePolicy {
|
|
51
|
+
retention_days: number | null;
|
|
52
|
+
allowed_scopes: string[];
|
|
53
|
+
reasoning_provider: string | null;
|
|
54
|
+
consolidation_cadence_seconds: number | null;
|
|
55
|
+
webhooks_enabled: boolean;
|
|
56
|
+
sanitization: WorkspaceSanitizationPolicy;
|
|
57
|
+
agent_overrides: Record<string, Record<string, unknown>>;
|
|
58
|
+
session_overrides: Record<string, Record<string, unknown>>;
|
|
59
|
+
}
|
|
60
|
+
export interface WorkspaceRecord {
|
|
61
|
+
workspace_id: string;
|
|
62
|
+
owner_agent_id: string;
|
|
63
|
+
title: string | null;
|
|
64
|
+
description: string | null;
|
|
65
|
+
metadata: Record<string, unknown>;
|
|
66
|
+
policy: WorkspacePolicy;
|
|
67
|
+
members: WorkspaceMember[];
|
|
68
|
+
created_at: string;
|
|
69
|
+
updated_at: string;
|
|
70
|
+
deleted_at: string | null;
|
|
71
|
+
}
|
|
72
|
+
/** Optional fields of `POST /v1/workspaces`; `workspace_id` is the method's first argument. */
|
|
73
|
+
export interface WorkspaceCreateOptions {
|
|
74
|
+
title?: string | null;
|
|
75
|
+
description?: string | null;
|
|
76
|
+
metadata?: Record<string, unknown>;
|
|
77
|
+
policy?: Partial<Omit<WorkspacePolicy, "sanitization">> & {
|
|
78
|
+
sanitization?: Partial<WorkspaceSanitizationPolicy>;
|
|
79
|
+
};
|
|
80
|
+
members?: Array<Pick<WorkspaceMember, "agent_id"> & Partial<Pick<WorkspaceMember, "role" | "scopes">>>;
|
|
81
|
+
}
|
|
16
82
|
export interface MemoryRecord {
|
|
17
83
|
id: string;
|
|
18
84
|
agent_id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hivemagnus/hivemem-sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "TypeScript client for HiveMem, the shared long-term memory service for AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hivemem",
|
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
"context",
|
|
14
14
|
"sdk"
|
|
15
15
|
],
|
|
16
|
-
"homepage": "https://github.com/ChefTaco/
|
|
16
|
+
"homepage": "https://github.com/ChefTaco/HiveMem/tree/main/sdks/typescript#readme",
|
|
17
17
|
"bugs": {
|
|
18
|
-
"url": "https://github.com/ChefTaco/
|
|
18
|
+
"url": "https://github.com/ChefTaco/HiveMem/issues"
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/ChefTaco/
|
|
23
|
-
"directory": "
|
|
22
|
+
"url": "git+https://github.com/ChefTaco/HiveMem.git",
|
|
23
|
+
"directory": "sdks/typescript"
|
|
24
24
|
},
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"author": "ChefTaco",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"files": [
|
|
39
39
|
"dist",
|
|
40
40
|
"README.md",
|
|
41
|
+
"CHANGELOG.md",
|
|
41
42
|
"LICENSE"
|
|
42
43
|
],
|
|
43
44
|
"sideEffects": false,
|
|
@@ -51,9 +52,11 @@
|
|
|
51
52
|
"build": "tsc -p tsconfig.json",
|
|
52
53
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
53
54
|
"test": "node --test test/*.test.mjs",
|
|
54
|
-
"prepublishOnly": "npm run build && npm test"
|
|
55
|
+
"prepublishOnly": "npm run build && npm test",
|
|
56
|
+
"pack:check": "node scripts/check-package.mjs"
|
|
55
57
|
},
|
|
56
58
|
"devDependencies": {
|
|
57
|
-
"typescript": "^5.6.0"
|
|
59
|
+
"typescript": "^5.6.0",
|
|
60
|
+
"yaml": "2.9.1"
|
|
58
61
|
}
|
|
59
62
|
}
|