@tpsdev-ai/adk-flair 0.40.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 +19 -0
- package/README.md +112 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/memory_service.d.ts +65 -0
- package/dist/memory_service.d.ts.map +1 -0
- package/dist/memory_service.js +326 -0
- package/dist/memory_service.js.map +1 -0
- package/dist/signing.d.ts +33 -0
- package/dist/signing.d.ts.map +1 -0
- package/dist/signing.js +80 -0
- package/dist/signing.js.map +1 -0
- package/dist/tag.d.ts +18 -0
- package/dist/tag.d.ts.map +1 -0
- package/dist/tag.js +23 -0
- package/dist/tag.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
Copyright 2026 TPS Dev AI
|
|
8
|
+
|
|
9
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
you may not use this file except in compliance with the License.
|
|
11
|
+
You may obtain a copy of the License at
|
|
12
|
+
|
|
13
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
|
|
15
|
+
Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
See the License for the specific language governing permissions and
|
|
19
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# adk-flair — Flair memory backend for Google ADK (JS/TS)
|
|
2
|
+
|
|
3
|
+
`@tpsdev-ai/adk-flair` is a TypeScript memory service that backs
|
|
4
|
+
[Google ADK](https://github.com/google/adk-js) agents with
|
|
5
|
+
[Flair](https://github.com/tpsdev-ai/flair) — a self-hosted, federated
|
|
6
|
+
semantic memory engine. Keep your agent memory yours.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @tpsdev-ai/adk-flair
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Quickstart
|
|
13
|
+
|
|
14
|
+
Swap the memory service in your ADK agent:
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import { FlairMemoryService } from "@tpsdev-ai/adk-flair";
|
|
18
|
+
import { Runner } from "@google/adk";
|
|
19
|
+
|
|
20
|
+
const memoryService = new FlairMemoryService({
|
|
21
|
+
url: "http://localhost:19926",
|
|
22
|
+
agentId: "my-adk-app",
|
|
23
|
+
keyfile: "~/.flair/keys/my-adk-app.key",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const runner = new Runner({
|
|
27
|
+
agent,
|
|
28
|
+
appName: "my-app",
|
|
29
|
+
sessionService,
|
|
30
|
+
memoryService,
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Dev UI (AdkApiServer)
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { AdkApiServer } from "@google/adk";
|
|
38
|
+
|
|
39
|
+
const server = new AdkApiServer({
|
|
40
|
+
memoryService: new FlairMemoryService(),
|
|
41
|
+
});
|
|
42
|
+
server.start();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
| Variable | Required | Default | Description |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| `FLAIR_URL` | No | `http://localhost:19926` | Flair HTTP endpoint |
|
|
50
|
+
| `FLAIR_AGENT_ID` | Yes | — | Flair agent identity |
|
|
51
|
+
| `FLAIR_KEYFILE` | Yes | — | Path to Ed25519 PKCS8 base64 keyfile |
|
|
52
|
+
| `FLAIR_ALLOW_REMOTE_URL` | No | — | Set to `1` to allow non-localhost URLs |
|
|
53
|
+
|
|
54
|
+
All values can also be passed directly to the constructor.
|
|
55
|
+
|
|
56
|
+
## Architecture
|
|
57
|
+
|
|
58
|
+
### Scope model
|
|
59
|
+
|
|
60
|
+
Each ADK app authenticates as **one Flair agent** (its service identity).
|
|
61
|
+
Per-user isolation is enforced by a **compound tag** — `adk:<app_name>:<user_id>`
|
|
62
|
+
— attached to every record and filtered on every search. Colons in `app_name`
|
|
63
|
+
or `user_id` are replaced with underscores to prevent delimiter breakage.
|
|
64
|
+
|
|
65
|
+
### Search path
|
|
66
|
+
|
|
67
|
+
- `user_id` is mandatory — empty/missing returns empty, never searches unscoped
|
|
68
|
+
- Every hit is re-verified against the compound tag before mapping to `MemoryEntry`
|
|
69
|
+
- Timeout budget: 2s total (connect 500ms, read 1500ms), one attempt, no retry
|
|
70
|
+
- Search failures degrade silently with a structured warning (host, elapsed, phase)
|
|
71
|
+
|
|
72
|
+
### Write path
|
|
73
|
+
|
|
74
|
+
- Deterministic record IDs: `app:user:session:eventId` — re-ingestion upserts
|
|
75
|
+
- Write failures log a structured warning (session id, event count, HTTP status)
|
|
76
|
+
- No-text events are filtered (Vertex parity)
|
|
77
|
+
|
|
78
|
+
## Security
|
|
79
|
+
|
|
80
|
+
### Raw text is sent to the configured Flair instance
|
|
81
|
+
|
|
82
|
+
All memory content — session transcripts, user messages, agent responses —
|
|
83
|
+
is transmitted as raw text to the Flair instance at the configured URL.
|
|
84
|
+
The Flair operator (which may be you) has full access to this data.
|
|
85
|
+
Do not point `FLAIR_URL` at an instance you do not trust.
|
|
86
|
+
|
|
87
|
+
### Metadata-level isolation, not cryptographic isolation
|
|
88
|
+
|
|
89
|
+
All users of one ADK app share one Flair principal. Per-user isolation is
|
|
90
|
+
enforced by tag-based server-side filtering, not cryptographic key separation.
|
|
91
|
+
A bug in that filter would leak cross-user memories. For key-level isolation,
|
|
92
|
+
use per-org Flair principals (the org layer).
|
|
93
|
+
|
|
94
|
+
## API
|
|
95
|
+
|
|
96
|
+
### `FlairMemoryService`
|
|
97
|
+
|
|
98
|
+
Implements `BaseMemoryService` from `@google/adk`.
|
|
99
|
+
|
|
100
|
+
#### Required methods (called by ADK)
|
|
101
|
+
|
|
102
|
+
- **`addSessionToMemory(session)`** — batch-write session events to Flair
|
|
103
|
+
- **`searchMemory(request)`** — semantic search with compound-tag scoping
|
|
104
|
+
|
|
105
|
+
#### Extra methods (Vertex parity, not called by ADK)
|
|
106
|
+
|
|
107
|
+
- **`addEventsToMemory(appName, userId, events, sessionId)`** — incremental per-turn writes
|
|
108
|
+
- **`addMemory(appName, userId, memories)`** — direct memory writes
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
Apache-2.0
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adk-flair — Flair as the memory backend for Google ADK (JS/TS).
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { FlairMemoryService } from "./memory_service.js";
|
|
7
|
+
export { compoundTag, sanitizeTagSegment } from "./tag.js";
|
|
8
|
+
export { loadEd25519Key, signRequest } from "./signing.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* adk-flair — Flair as the memory backend for Google ADK (JS/TS).
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
export { FlairMemoryService } from "./memory_service.js";
|
|
7
|
+
export { compoundTag, sanitizeTagSegment } from "./tag.js";
|
|
8
|
+
export { loadEd25519Key, signRequest } from "./signing.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlairMemoryService — Flair as the memory backend for Google ADK (JS/TS).
|
|
3
|
+
*
|
|
4
|
+
* Implements @google/adk's `BaseMemoryService` interface (2 required methods)
|
|
5
|
+
* plus the Vertex-parity extras (`addEventsToMemory`, `addMemory`).
|
|
6
|
+
*
|
|
7
|
+
* Ported from the Python `adk-flair` package. See specs/ADK-FLAIR-ADAPTER.md
|
|
8
|
+
* in the tpsdev-ai/cli repo for the full design.
|
|
9
|
+
*/
|
|
10
|
+
import type { BaseMemoryService, SearchMemoryRequest, SearchMemoryResponse } from "@google/adk";
|
|
11
|
+
import type { MemoryEntry } from "@google/adk";
|
|
12
|
+
import type { Session } from "@google/adk";
|
|
13
|
+
import type { Event } from "@google/adk";
|
|
14
|
+
export declare class FlairMemoryService implements BaseMemoryService {
|
|
15
|
+
private readonly _url;
|
|
16
|
+
private readonly _agentId;
|
|
17
|
+
private readonly _privateKey;
|
|
18
|
+
private readonly _timeoutMs;
|
|
19
|
+
/** Per-session state for custom_metadata warn-once (Python parity). */
|
|
20
|
+
private _warnedSessions;
|
|
21
|
+
/**
|
|
22
|
+
* @param url - Flair HTTP URL (default: FLAIR_URL env or http://localhost:19926)
|
|
23
|
+
* @param agentId - Flair agent ID (default: FLAIR_AGENT_ID env)
|
|
24
|
+
* @param keyfile - Path to Ed25519 PKCS8 base64 keyfile (default: FLAIR_KEYFILE env)
|
|
25
|
+
* @param timeoutMs - Total request timeout in ms (default: 2000)
|
|
26
|
+
*/
|
|
27
|
+
constructor(opts?: {
|
|
28
|
+
url?: string;
|
|
29
|
+
agentId?: string;
|
|
30
|
+
keyfile?: string;
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
});
|
|
33
|
+
addSessionToMemory(session: Session): Promise<void>;
|
|
34
|
+
searchMemory(request: SearchMemoryRequest): Promise<SearchMemoryResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Add events to memory incrementally (the quickstart's after_agent_callback path).
|
|
37
|
+
* Not called by ADK — use in after_agent_callback or directly.
|
|
38
|
+
*
|
|
39
|
+
* @param customMetadata - If provided, logs a once-per-session warning that
|
|
40
|
+
* custom_metadata is not supported by adk-flair (Python parity).
|
|
41
|
+
*/
|
|
42
|
+
addEventsToMemory(appName: string, userId: string, events: Event[], sessionId: string, customMetadata?: Record<string, unknown>): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Add memory entries directly.
|
|
45
|
+
* Not called by ADK — use for direct memory writes.
|
|
46
|
+
*
|
|
47
|
+
* @param customMetadata - If provided, logs a once-per-session warning that
|
|
48
|
+
* custom_metadata is not supported by adk-flair (Python parity).
|
|
49
|
+
*/
|
|
50
|
+
addMemory(appName: string, userId: string, memories: MemoryEntry[], customMetadata?: Record<string, unknown>): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Write a single record to Flair via PUT /Memory/{recordId}.
|
|
53
|
+
*
|
|
54
|
+
* The deterministic record ID is embedded in the URL path so the server
|
|
55
|
+
* can perform an idempotent upsert. The signing payload covers the full
|
|
56
|
+
* path (METHOD:pathname), so the path MUST include the record ID.
|
|
57
|
+
*/
|
|
58
|
+
private _writeRecord;
|
|
59
|
+
/**
|
|
60
|
+
* Close the service. No-op for the HTTP-based implementation;
|
|
61
|
+
* provided for API compatibility with the Python package.
|
|
62
|
+
*/
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=memory_service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory_service.d.ts","sourceRoot":"","sources":["../src/memory_service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAChG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAiDzC,qBAAa,kBAAmB,YAAW,iBAAiB;IAC1D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,uEAAuE;IACvE,OAAO,CAAC,eAAe,CAA0B;IAEjD;;;;;OAKG;gBACS,IAAI,CAAC,EAAE;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;IAqCK,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCnD,YAAY,CAChB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,oBAAoB,CAAC;IAmGhC;;;;;;OAMG;IACG,iBAAiB,CACrB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,KAAK,EAAE,EACf,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC;IAgDhB;;;;;;OAMG;IACG,SAAS,CACb,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,WAAW,EAAE,EACvB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC;IAqDhB;;;;;;OAMG;YACW,YAAY;IAqC1B;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlairMemoryService — Flair as the memory backend for Google ADK (JS/TS).
|
|
3
|
+
*
|
|
4
|
+
* Implements @google/adk's `BaseMemoryService` interface (2 required methods)
|
|
5
|
+
* plus the Vertex-parity extras (`addEventsToMemory`, `addMemory`).
|
|
6
|
+
*
|
|
7
|
+
* Ported from the Python `adk-flair` package. See specs/ADK-FLAIR-ADAPTER.md
|
|
8
|
+
* in the tpsdev-ai/cli repo for the full design.
|
|
9
|
+
*/
|
|
10
|
+
import * as crypto from "node:crypto";
|
|
11
|
+
import { loadEd25519Key, signRequest } from "./signing.js";
|
|
12
|
+
import { compoundTag } from "./tag.js";
|
|
13
|
+
// ─── Constants ──────────────────────────────────────────────────────────────
|
|
14
|
+
const LOCALHOST_HOSTS = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
15
|
+
const ALLOW_REMOTE_ENV = "FLAIR_ALLOW_REMOTE_URL";
|
|
16
|
+
const DEFAULT_FLAIR_URL = "http://localhost:19926";
|
|
17
|
+
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
18
|
+
function isLocalhost(hostname) {
|
|
19
|
+
return LOCALHOST_HOSTS.has(hostname);
|
|
20
|
+
}
|
|
21
|
+
function resolveUrl(raw) {
|
|
22
|
+
let url;
|
|
23
|
+
try {
|
|
24
|
+
url = new URL(raw);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new Error(`FLAIR_URL: invalid URL: ${raw}`);
|
|
28
|
+
}
|
|
29
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
30
|
+
throw new Error(`FLAIR_URL: unsupported protocol "${url.protocol}" — must be http or https`);
|
|
31
|
+
}
|
|
32
|
+
return url;
|
|
33
|
+
}
|
|
34
|
+
function epochMsToIso(ms) {
|
|
35
|
+
return new Date(ms).toISOString();
|
|
36
|
+
}
|
|
37
|
+
function extractText(content) {
|
|
38
|
+
if (!content || !content.parts)
|
|
39
|
+
return "";
|
|
40
|
+
return content.parts
|
|
41
|
+
.map((p) => p.text ?? "")
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.join(" ");
|
|
44
|
+
}
|
|
45
|
+
// ─── FlairMemoryService ─────────────────────────────────────────────────────
|
|
46
|
+
export class FlairMemoryService {
|
|
47
|
+
_url;
|
|
48
|
+
_agentId;
|
|
49
|
+
_privateKey;
|
|
50
|
+
_timeoutMs;
|
|
51
|
+
/** Per-session state for custom_metadata warn-once (Python parity). */
|
|
52
|
+
_warnedSessions = new Set();
|
|
53
|
+
/**
|
|
54
|
+
* @param url - Flair HTTP URL (default: FLAIR_URL env or http://localhost:19926)
|
|
55
|
+
* @param agentId - Flair agent ID (default: FLAIR_AGENT_ID env)
|
|
56
|
+
* @param keyfile - Path to Ed25519 PKCS8 base64 keyfile (default: FLAIR_KEYFILE env)
|
|
57
|
+
* @param timeoutMs - Total request timeout in ms (default: 2000)
|
|
58
|
+
*/
|
|
59
|
+
constructor(opts) {
|
|
60
|
+
const rawUrl = opts?.url ?? process.env["FLAIR_URL"] ?? DEFAULT_FLAIR_URL;
|
|
61
|
+
const parsed = resolveUrl(rawUrl);
|
|
62
|
+
// URL gate: non-localhost requires explicit opt-in
|
|
63
|
+
if (!isLocalhost(parsed.hostname)) {
|
|
64
|
+
if (process.env[ALLOW_REMOTE_ENV] !== "1") {
|
|
65
|
+
throw new Error(`FLAIR_URL: refused non-localhost URL "${rawUrl}" — ` +
|
|
66
|
+
`set ${ALLOW_REMOTE_ENV}=1 to allow remote Flair instances`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
this._url = parsed.origin;
|
|
70
|
+
const agentId = opts?.agentId ?? process.env["FLAIR_AGENT_ID"];
|
|
71
|
+
if (!agentId) {
|
|
72
|
+
throw new Error("FLAIR_AGENT_ID: missing — set FLAIR_AGENT_ID or pass agentId to constructor");
|
|
73
|
+
}
|
|
74
|
+
this._agentId = agentId;
|
|
75
|
+
const keyfile = opts?.keyfile ?? process.env["FLAIR_KEYFILE"];
|
|
76
|
+
if (!keyfile) {
|
|
77
|
+
throw new Error("FLAIR_KEYFILE: missing — set FLAIR_KEYFILE or pass keyfile to constructor");
|
|
78
|
+
}
|
|
79
|
+
this._privateKey = loadEd25519Key(keyfile);
|
|
80
|
+
this._timeoutMs = opts?.timeoutMs ?? 2000;
|
|
81
|
+
}
|
|
82
|
+
// ─── BaseMemoryService required methods ───────────────────────────────────
|
|
83
|
+
async addSessionToMemory(session) {
|
|
84
|
+
const { appName, userId, events } = session;
|
|
85
|
+
if (!events || events.length === 0)
|
|
86
|
+
return;
|
|
87
|
+
const tag = compoundTag(appName, userId);
|
|
88
|
+
let written = 0;
|
|
89
|
+
for (const event of events) {
|
|
90
|
+
const text = extractText(event.content);
|
|
91
|
+
if (!text)
|
|
92
|
+
continue; // filter no-text events (Vertex parity)
|
|
93
|
+
const recordId = `${appName}:${userId}:${session.id}:${event.id}`;
|
|
94
|
+
const body = {
|
|
95
|
+
id: recordId,
|
|
96
|
+
agentId: this._agentId,
|
|
97
|
+
content: text,
|
|
98
|
+
type: "session",
|
|
99
|
+
durability: "standard",
|
|
100
|
+
tags: [tag],
|
|
101
|
+
createdAt: epochMsToIso(event.timestamp),
|
|
102
|
+
};
|
|
103
|
+
try {
|
|
104
|
+
await this._writeRecord(recordId, body);
|
|
105
|
+
written++;
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
109
|
+
console.warn(`[adk-flair] write failed for session ${session.id} event ${event.id} ` +
|
|
110
|
+
`(written=${written}/${events.length}): ${msg}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (written === 0)
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
async searchMemory(request) {
|
|
117
|
+
const { appName, userId, query } = request;
|
|
118
|
+
// Mandatory userId: empty ⇒ return empty, never search unscoped
|
|
119
|
+
if (!userId) {
|
|
120
|
+
return { memories: [] };
|
|
121
|
+
}
|
|
122
|
+
const tag = compoundTag(appName, userId);
|
|
123
|
+
const path = "/SemanticSearch";
|
|
124
|
+
const body = JSON.stringify({
|
|
125
|
+
agentId: this._agentId,
|
|
126
|
+
q: query,
|
|
127
|
+
tag,
|
|
128
|
+
limit: 20,
|
|
129
|
+
});
|
|
130
|
+
const start = Date.now();
|
|
131
|
+
let phase = "connect";
|
|
132
|
+
try {
|
|
133
|
+
const authHeader = signRequest(this._privateKey, this._agentId, "POST", path);
|
|
134
|
+
const controller = new AbortController();
|
|
135
|
+
const timeoutId = setTimeout(() => controller.abort(), this._timeoutMs);
|
|
136
|
+
try {
|
|
137
|
+
phase = "connect";
|
|
138
|
+
const resp = await fetch(`${this._url}${path}`, {
|
|
139
|
+
method: "POST",
|
|
140
|
+
headers: {
|
|
141
|
+
"Authorization": authHeader,
|
|
142
|
+
"Content-Type": "application/json",
|
|
143
|
+
},
|
|
144
|
+
body,
|
|
145
|
+
signal: controller.signal,
|
|
146
|
+
});
|
|
147
|
+
phase = "read";
|
|
148
|
+
if (!resp.ok) {
|
|
149
|
+
const elapsed = Date.now() - start;
|
|
150
|
+
console.warn(`[adk-flair] searchMemory HTTP ${resp.status}: ` +
|
|
151
|
+
`host=${this._url} elapsed=${elapsed}ms phase=${phase}`);
|
|
152
|
+
return { memories: [] };
|
|
153
|
+
}
|
|
154
|
+
const data = (await resp.json());
|
|
155
|
+
const results = data.results ?? [];
|
|
156
|
+
const memories = [];
|
|
157
|
+
for (const hit of results) {
|
|
158
|
+
// Per-hit tag re-verification: drop hits missing the compound tag
|
|
159
|
+
const hitTags = hit.tags ?? [];
|
|
160
|
+
if (!hitTags.includes(tag))
|
|
161
|
+
continue;
|
|
162
|
+
const content = {
|
|
163
|
+
role: "user",
|
|
164
|
+
parts: [{ text: hit.content ?? "" }],
|
|
165
|
+
};
|
|
166
|
+
memories.push({
|
|
167
|
+
content,
|
|
168
|
+
author: hit.author,
|
|
169
|
+
timestamp: hit.timestamp,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return { memories };
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
clearTimeout(timeoutId);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
const elapsed = Date.now() - start;
|
|
180
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
181
|
+
console.warn(`[adk-flair] searchMemory failed: host=${this._url} ` +
|
|
182
|
+
`elapsed=${elapsed}ms phase=${phase} error="${msg}"`);
|
|
183
|
+
return { memories: [] };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// ─── Vertex-parity extras (not called by ADK, documented for direct use) ──
|
|
187
|
+
/**
|
|
188
|
+
* Add events to memory incrementally (the quickstart's after_agent_callback path).
|
|
189
|
+
* Not called by ADK — use in after_agent_callback or directly.
|
|
190
|
+
*
|
|
191
|
+
* @param customMetadata - If provided, logs a once-per-session warning that
|
|
192
|
+
* custom_metadata is not supported by adk-flair (Python parity).
|
|
193
|
+
*/
|
|
194
|
+
async addEventsToMemory(appName, userId, events, sessionId, customMetadata) {
|
|
195
|
+
if (!events || events.length === 0)
|
|
196
|
+
return;
|
|
197
|
+
// custom_metadata warn-once per session (Python parity)
|
|
198
|
+
if (customMetadata) {
|
|
199
|
+
const sessionKey = `${appName}:${userId}:${sessionId}`;
|
|
200
|
+
if (!this._warnedSessions.has(sessionKey)) {
|
|
201
|
+
this._warnedSessions.add(sessionKey);
|
|
202
|
+
console.warn("adk-flair: custom_metadata ignored — adk-flair does not " +
|
|
203
|
+
`support custom_metadata keys (session=${sessionKey})`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const tag = compoundTag(appName, userId);
|
|
207
|
+
let written = 0;
|
|
208
|
+
for (const event of events) {
|
|
209
|
+
const text = extractText(event.content);
|
|
210
|
+
if (!text)
|
|
211
|
+
continue;
|
|
212
|
+
const recordId = `${appName}:${userId}:${sessionId}:${event.id}`;
|
|
213
|
+
const body = {
|
|
214
|
+
id: recordId,
|
|
215
|
+
agentId: this._agentId,
|
|
216
|
+
content: text,
|
|
217
|
+
type: "session",
|
|
218
|
+
durability: "standard",
|
|
219
|
+
tags: [tag],
|
|
220
|
+
createdAt: epochMsToIso(event.timestamp),
|
|
221
|
+
};
|
|
222
|
+
try {
|
|
223
|
+
await this._writeRecord(recordId, body);
|
|
224
|
+
written++;
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
228
|
+
console.warn(`[adk-flair] write failed for session ${sessionId} event ${event.id} ` +
|
|
229
|
+
`(written=${written}/${events.length}): ${msg}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (written === 0)
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Add memory entries directly.
|
|
237
|
+
* Not called by ADK — use for direct memory writes.
|
|
238
|
+
*
|
|
239
|
+
* @param customMetadata - If provided, logs a once-per-session warning that
|
|
240
|
+
* custom_metadata is not supported by adk-flair (Python parity).
|
|
241
|
+
*/
|
|
242
|
+
async addMemory(appName, userId, memories, customMetadata) {
|
|
243
|
+
if (!memories || memories.length === 0)
|
|
244
|
+
return;
|
|
245
|
+
// custom_metadata warn-once (Python parity)
|
|
246
|
+
if (customMetadata) {
|
|
247
|
+
const sessionKey = `${appName}:${userId}:direct`;
|
|
248
|
+
if (!this._warnedSessions.has(sessionKey)) {
|
|
249
|
+
this._warnedSessions.add(sessionKey);
|
|
250
|
+
console.warn("adk-flair: custom_metadata ignored — adk-flair does not " +
|
|
251
|
+
"support custom_metadata keys");
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
const tag = compoundTag(appName, userId);
|
|
255
|
+
let written = 0;
|
|
256
|
+
for (const mem of memories) {
|
|
257
|
+
const text = extractText(mem.content);
|
|
258
|
+
if (!text)
|
|
259
|
+
continue;
|
|
260
|
+
const recordId = `${appName}:${userId}:direct:${crypto.randomUUID()}`;
|
|
261
|
+
const body = {
|
|
262
|
+
id: recordId,
|
|
263
|
+
agentId: this._agentId,
|
|
264
|
+
content: text,
|
|
265
|
+
type: "session",
|
|
266
|
+
durability: "standard",
|
|
267
|
+
tags: [tag],
|
|
268
|
+
createdAt: mem.timestamp ?? new Date().toISOString(),
|
|
269
|
+
};
|
|
270
|
+
if (mem.author) {
|
|
271
|
+
body.author = mem.author;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
await this._writeRecord(recordId, body);
|
|
275
|
+
written++;
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
279
|
+
console.warn(`[adk-flair] direct memory write failed for id ${recordId} ` +
|
|
280
|
+
`(written=${written}/${memories.length}): ${msg}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (written === 0)
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
// ─── Internal ─────────────────────────────────────────────────────────────
|
|
287
|
+
/**
|
|
288
|
+
* Write a single record to Flair via PUT /Memory/{recordId}.
|
|
289
|
+
*
|
|
290
|
+
* The deterministic record ID is embedded in the URL path so the server
|
|
291
|
+
* can perform an idempotent upsert. The signing payload covers the full
|
|
292
|
+
* path (METHOD:pathname), so the path MUST include the record ID.
|
|
293
|
+
*/
|
|
294
|
+
async _writeRecord(recordId, body) {
|
|
295
|
+
const path = `/Memory/${recordId}`;
|
|
296
|
+
const authHeader = signRequest(this._privateKey, this._agentId, "PUT", path);
|
|
297
|
+
const controller = new AbortController();
|
|
298
|
+
const timeoutId = setTimeout(() => controller.abort(), this._timeoutMs);
|
|
299
|
+
try {
|
|
300
|
+
const resp = await fetch(`${this._url}${path}`, {
|
|
301
|
+
method: "PUT",
|
|
302
|
+
headers: {
|
|
303
|
+
"Authorization": authHeader,
|
|
304
|
+
"Content-Type": "application/json",
|
|
305
|
+
},
|
|
306
|
+
body: JSON.stringify(body),
|
|
307
|
+
signal: controller.signal,
|
|
308
|
+
});
|
|
309
|
+
if (!resp.ok) {
|
|
310
|
+
const text = await resp.text().catch(() => "");
|
|
311
|
+
throw new Error(`HTTP ${resp.status}${text ? `: ${text.slice(0, 200)}` : ""}`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
clearTimeout(timeoutId);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Close the service. No-op for the HTTP-based implementation;
|
|
320
|
+
* provided for API compatibility with the Python package.
|
|
321
|
+
*/
|
|
322
|
+
async close() {
|
|
323
|
+
// no-op: no persistent connections to close
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=memory_service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory_service.js","sourceRoot":"","sources":["../src/memory_service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TPS-Ed25519 request signing for adk-flair.
|
|
3
|
+
*
|
|
4
|
+
* Loads a PKCS8 base64-encoded Ed25519 private key from a keyfile and
|
|
5
|
+
* produces `TPS-Ed25519 <agent-id>:<timestamp>:<nonce>:<base64-sig>`
|
|
6
|
+
* Authorization headers for Flair API requests.
|
|
7
|
+
*/
|
|
8
|
+
import * as crypto from "node:crypto";
|
|
9
|
+
/**
|
|
10
|
+
* Load and validate an Ed25519 private key from a PKCS8 base64 keyfile.
|
|
11
|
+
*
|
|
12
|
+
* Parses the key material in the constructor path so that a bad keyfile
|
|
13
|
+
* fails immediately (before ADK's exception-swallowing search path can
|
|
14
|
+
* turn it into permanent silent empty recall).
|
|
15
|
+
*
|
|
16
|
+
* @param keyfilePath - Path to the keyfile (PKCS8 DER, base64-encoded)
|
|
17
|
+
* @returns A Node.js KeyObject for the Ed25519 private key
|
|
18
|
+
* @throws If the keyfile is missing, unreadable, or contains invalid key material
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadEd25519Key(keyfilePath: string): crypto.KeyObject;
|
|
21
|
+
/**
|
|
22
|
+
* Build the TPS-Ed25519 Authorization header value.
|
|
23
|
+
*
|
|
24
|
+
* Format: `TPS-Ed25519 <agent-id>:<timestamp>:<nonce>:<base64-sig>`
|
|
25
|
+
*
|
|
26
|
+
* @param privateKey - The loaded Ed25519 private key
|
|
27
|
+
* @param agentId - The Flair agent ID
|
|
28
|
+
* @param method - HTTP method (e.g. "POST")
|
|
29
|
+
* @param path - Request path (e.g. "/SemanticSearch")
|
|
30
|
+
* @returns The Authorization header value
|
|
31
|
+
*/
|
|
32
|
+
export declare function signRequest(privateKey: crypto.KeyObject, agentId: string, method: string, path: string): string;
|
|
33
|
+
//# sourceMappingURL=signing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAGtC;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC,SAAS,CAgDpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,MAAM,CAAC,SAAS,EAC5B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAOR"}
|
package/dist/signing.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TPS-Ed25519 request signing for adk-flair.
|
|
3
|
+
*
|
|
4
|
+
* Loads a PKCS8 base64-encoded Ed25519 private key from a keyfile and
|
|
5
|
+
* produces `TPS-Ed25519 <agent-id>:<timestamp>:<nonce>:<base64-sig>`
|
|
6
|
+
* Authorization headers for Flair API requests.
|
|
7
|
+
*/
|
|
8
|
+
import * as crypto from "node:crypto";
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
/**
|
|
11
|
+
* Load and validate an Ed25519 private key from a PKCS8 base64 keyfile.
|
|
12
|
+
*
|
|
13
|
+
* Parses the key material in the constructor path so that a bad keyfile
|
|
14
|
+
* fails immediately (before ADK's exception-swallowing search path can
|
|
15
|
+
* turn it into permanent silent empty recall).
|
|
16
|
+
*
|
|
17
|
+
* @param keyfilePath - Path to the keyfile (PKCS8 DER, base64-encoded)
|
|
18
|
+
* @returns A Node.js KeyObject for the Ed25519 private key
|
|
19
|
+
* @throws If the keyfile is missing, unreadable, or contains invalid key material
|
|
20
|
+
*/
|
|
21
|
+
export function loadEd25519Key(keyfilePath) {
|
|
22
|
+
let b64;
|
|
23
|
+
try {
|
|
24
|
+
b64 = fs.readFileSync(keyfilePath, "utf-8").trim();
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
28
|
+
throw new Error(`FLAIR_KEYFILE: cannot read keyfile: ${msg}`);
|
|
29
|
+
}
|
|
30
|
+
if (b64.length === 0) {
|
|
31
|
+
throw new Error("FLAIR_KEYFILE: keyfile is empty");
|
|
32
|
+
}
|
|
33
|
+
let der;
|
|
34
|
+
try {
|
|
35
|
+
der = Buffer.from(b64, "base64");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
throw new Error("FLAIR_KEYFILE: keyfile is not valid base64");
|
|
39
|
+
}
|
|
40
|
+
if (der.length === 0) {
|
|
41
|
+
throw new Error("FLAIR_KEYFILE: keyfile decoded to empty key material");
|
|
42
|
+
}
|
|
43
|
+
let key;
|
|
44
|
+
try {
|
|
45
|
+
key = crypto.createPrivateKey({
|
|
46
|
+
key: der,
|
|
47
|
+
format: "der",
|
|
48
|
+
type: "pkcs8",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53
|
+
throw new Error(`FLAIR_KEYFILE: invalid Ed25519 key material: ${msg}`);
|
|
54
|
+
}
|
|
55
|
+
// Verify it's actually an Ed25519 key
|
|
56
|
+
if (key.asymmetricKeyType !== "ed25519") {
|
|
57
|
+
throw new Error(`FLAIR_KEYFILE: expected Ed25519 key, got ${key.asymmetricKeyType ?? "unknown"}`);
|
|
58
|
+
}
|
|
59
|
+
return key;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the TPS-Ed25519 Authorization header value.
|
|
63
|
+
*
|
|
64
|
+
* Format: `TPS-Ed25519 <agent-id>:<timestamp>:<nonce>:<base64-sig>`
|
|
65
|
+
*
|
|
66
|
+
* @param privateKey - The loaded Ed25519 private key
|
|
67
|
+
* @param agentId - The Flair agent ID
|
|
68
|
+
* @param method - HTTP method (e.g. "POST")
|
|
69
|
+
* @param path - Request path (e.g. "/SemanticSearch")
|
|
70
|
+
* @returns The Authorization header value
|
|
71
|
+
*/
|
|
72
|
+
export function signRequest(privateKey, agentId, method, path) {
|
|
73
|
+
const ts = String(Date.now());
|
|
74
|
+
const nonce = crypto.randomUUID();
|
|
75
|
+
const payload = `${agentId}:${ts}:${nonce}:${method}:${path}`;
|
|
76
|
+
const sig = crypto.sign(null, Buffer.from(payload, "utf-8"), privateKey);
|
|
77
|
+
const sigB64 = sig.toString("base64");
|
|
78
|
+
return `TPS-Ed25519 ${agentId}:${ts}:${nonce}:${sigB64}`;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=signing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signing.js","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACrD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,uCAAuC,GAAG,EAAE,CAC7C,CAAC;IACJ,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,IAAI,GAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC;YAC5B,GAAG,EAAE,GAAG;YACR,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,IAAI,KAAK,CACb,gDAAgD,GAAG,EAAE,CACtD,CAAC;IACJ,CAAC;IAED,sCAAsC;IACtC,IAAI,GAAG,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,4CAA4C,GAAG,CAAC,iBAAiB,IAAI,SAAS,EAAE,CACjF,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,UAA4B,EAC5B,OAAe,EACf,MAAc,EACd,IAAY;IAEZ,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,GAAG,OAAO,IAAI,EAAE,IAAI,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;IAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,eAAe,OAAO,IAAI,EAAE,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;AAC3D,CAAC"}
|
package/dist/tag.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compound tag helpers for adk-flair.
|
|
3
|
+
*
|
|
4
|
+
* Builds the `adk:<app_name>:<user_id>` compound tag used for per-user
|
|
5
|
+
* scoping in Flair. Colons in segments are replaced with underscores to
|
|
6
|
+
* prevent delimiter breakage.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Sanitize a tag segment by replacing colons with underscores.
|
|
10
|
+
* A colon in a segment would break the compound tag delimiter.
|
|
11
|
+
*/
|
|
12
|
+
export declare function sanitizeTagSegment(segment: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Build the compound tag `adk:<app_name>:<user_id>`.
|
|
15
|
+
* Both segments are sanitized to prevent delimiter breakage.
|
|
16
|
+
*/
|
|
17
|
+
export declare function compoundTag(appName: string, userId: string): string;
|
|
18
|
+
//# sourceMappingURL=tag.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag.d.ts","sourceRoot":"","sources":["../src/tag.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnE"}
|
package/dist/tag.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compound tag helpers for adk-flair.
|
|
3
|
+
*
|
|
4
|
+
* Builds the `adk:<app_name>:<user_id>` compound tag used for per-user
|
|
5
|
+
* scoping in Flair. Colons in segments are replaced with underscores to
|
|
6
|
+
* prevent delimiter breakage.
|
|
7
|
+
*/
|
|
8
|
+
const TAG_PREFIX = "adk";
|
|
9
|
+
/**
|
|
10
|
+
* Sanitize a tag segment by replacing colons with underscores.
|
|
11
|
+
* A colon in a segment would break the compound tag delimiter.
|
|
12
|
+
*/
|
|
13
|
+
export function sanitizeTagSegment(segment) {
|
|
14
|
+
return segment.replace(/:/g, "_");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build the compound tag `adk:<app_name>:<user_id>`.
|
|
18
|
+
* Both segments are sanitized to prevent delimiter breakage.
|
|
19
|
+
*/
|
|
20
|
+
export function compoundTag(appName, userId) {
|
|
21
|
+
return `${TAG_PREFIX}:${sanitizeTagSegment(appName)}:${sanitizeTagSegment(userId)}`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=tag.js.map
|
package/dist/tag.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tag.js","sourceRoot":"","sources":["../src/tag.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,UAAU,GAAG,KAAK,CAAC;AAEzB;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,MAAc;IACzD,OAAO,GAAG,UAAU,IAAI,kBAAkB,CAAC,OAAO,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;AACtF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tpsdev-ai/adk-flair",
|
|
3
|
+
"version": "0.40.0",
|
|
4
|
+
"description": "Flair memory backend for Google ADK — self-hosted, federated, portable agent memory",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc --noCheck",
|
|
15
|
+
"prepublishOnly": "npm run build",
|
|
16
|
+
"test": "bun test"
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"adk",
|
|
26
|
+
"google-adk",
|
|
27
|
+
"flair",
|
|
28
|
+
"memory",
|
|
29
|
+
"agent",
|
|
30
|
+
"semantic-search"
|
|
31
|
+
],
|
|
32
|
+
"homepage": "https://github.com/tpsdev-ai/flair/tree/main/packages/adk-flair-js",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/tpsdev-ai/flair.git",
|
|
36
|
+
"directory": "packages/adk-flair-js"
|
|
37
|
+
},
|
|
38
|
+
"license": "Apache-2.0",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@google/adk": "^1.6.0",
|
|
41
|
+
"@google/genai": "^1.52.0"
|
|
42
|
+
}
|
|
43
|
+
}
|