@aliyunrds/ctxdb 1.0.0 → 1.0.1-beta.1
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/README.md +5 -1
- package/dist/{chunk-QPFFMW52.js → chunk-CYCD234A.js} +4 -2
- package/dist/{chunk-QHYJ7OXC.js → chunk-TKMIWM6Q.js} +6 -0
- package/dist/{chunk-PLWEIEFH.js → chunk-UULWJJT4.js} +1 -1
- package/dist/cli/main.js +1 -1
- package/dist/hooks/session-start.js +3 -3
- package/dist/hooks/stop.js +12 -4
- package/dist/hooks/user-prompt-submit.js +3 -3
- package/dist/opencode/index.js +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,6 +117,8 @@ Field reference:
|
|
|
117
117
|
| Key | Type | Default | Meaning |
|
|
118
118
|
|---|---|---|---|
|
|
119
119
|
| `user_id` | str | `"default"` | mem0-layer bucket key on every capture/recall call. The server's tenant isolation runs on `member_id` (injected from `X-API-Key`), so this is an optional per-user/agent slice. Override with `ctxdb setup --agent <a> --user-id <bucket>` or `CTXDB_USER_ID=<bucket>` when you need to isolate this install from another access layer or machine sharing the same workspace |
|
|
120
|
+
| `agent_id` | str | null | Optional scope dimension on every capture/recall call. **Default null = not sent** — the server counts `agent_id` as scope on the search path, so emitting it by default would narrow every existing user's recall. Set only when you want per-agent isolation: `CTXDB_AGENT_ID=<id>` (env-only; no setup flag) |
|
|
121
|
+
| `app_id` | str | null | Optional app-scope dimension, same contract as `agent_id` (default null = not sent). Set via `CTXDB_APP_ID=<id>` (env-only) |
|
|
120
122
|
| `auto_capture` | bool | `true` | Stop hook captures each turn into long-term memory for the selected agent |
|
|
121
123
|
| `auto_recall` | bool | `true` | UserPromptSubmit hook recalls memory on each user prompt for the selected agent |
|
|
122
124
|
| `warmup_recall` | bool | `false` | SessionStart hook recalls cwd/git-related memories for the selected agent. **Default is off** — open it per-agent when you want session-start warmup (adds one bounded, circuit-protected recall call on session start) |
|
|
@@ -125,7 +127,9 @@ Field reference:
|
|
|
125
127
|
| `knowledge_top_k` | int | `6` | KB chunks pulled per recall (only effective when `recall_knowledge: true`) |
|
|
126
128
|
| `debug` | bool | `false` | Verbose hook logging (`~/.ctxdb/logs/ctxdb.log`) |
|
|
127
129
|
|
|
128
|
-
Env-var overrides apply to the selected agent config (env wins): `CTXDB_AGENT` / `CTXDB_API_KEY` / `CTXDB_BASE_URL` / `CTXDB_USER_ID`.
|
|
130
|
+
Env-var overrides apply to the selected agent config (env wins): `CTXDB_AGENT` / `CTXDB_API_KEY` / `CTXDB_BASE_URL` / `CTXDB_USER_ID` / `CTXDB_AGENT_ID` / `CTXDB_APP_ID`. The last two default to unset — the request body omits `agent_id`/`app_id` entirely; set them only when you want per-agent / per-app scope isolation on the server.
|
|
131
|
+
|
|
132
|
+
`run_id` is **not** env-driven: the Stop hook reads the host's `session_id` from the hook payload (Qoder / Codex / Claude Code all pass it at the top level; opencode reads `ev.properties.sessionID`) and sends it as `run_id` on capture only, so the server can associate turns within one session for richer extraction context. Recall never sends `run_id`. If the payload has no `session_id`, `run_id` is omitted and capture proceeds normally (the server falls back to baseMessages).
|
|
129
133
|
|
|
130
134
|
## Architecture
|
|
131
135
|
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
isConnectionError,
|
|
7
7
|
resetCircuit,
|
|
8
8
|
tripCircuit
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-UULWJJT4.js";
|
|
10
10
|
import {
|
|
11
11
|
CtxdbError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-TKMIWM6Q.js";
|
|
13
13
|
|
|
14
14
|
// src/lib/recall-orchestrator.ts
|
|
15
15
|
import {
|
|
@@ -109,6 +109,8 @@ async function recallTurn(prompt, cfg, client, agent = "default") {
|
|
|
109
109
|
if (cfg.recallKnowledge) {
|
|
110
110
|
body.knowledge = { enable: true, top_k: cfg.knowledgeTopK };
|
|
111
111
|
}
|
|
112
|
+
if (cfg.agentId) body.agent_id = cfg.agentId;
|
|
113
|
+
if (cfg.appId) body.app_id = cfg.appId;
|
|
112
114
|
let resp;
|
|
113
115
|
try {
|
|
114
116
|
resp = await client.postJson("/v3/memories/search/", body);
|
|
@@ -387,6 +387,8 @@ function configFromDisk(raw) {
|
|
|
387
387
|
apiKey: typeof raw.api_key === "string" && raw.api_key ? raw.api_key : null,
|
|
388
388
|
baseUrl: typeof raw.base_url === "string" && raw.base_url ? String(raw.base_url).replace(/\/+$/, "") : DEFAULT_BASE_URL,
|
|
389
389
|
userId: typeof raw.user_id === "string" && raw.user_id ? raw.user_id : DEFAULT_USER_ID,
|
|
390
|
+
agentId: typeof raw.agent_id === "string" && raw.agent_id ? raw.agent_id : null,
|
|
391
|
+
appId: typeof raw.app_id === "string" && raw.app_id ? raw.app_id : null,
|
|
390
392
|
autoCapture: coerceBool(raw.auto_capture, true),
|
|
391
393
|
autoRecall: coerceBool(raw.auto_recall, true),
|
|
392
394
|
warmupRecall: coerceBool(raw.warmup_recall, false),
|
|
@@ -402,6 +404,8 @@ function applyEnv(cfg, env) {
|
|
|
402
404
|
if (env.CTXDB_API_KEY) cfg.apiKey = env.CTXDB_API_KEY;
|
|
403
405
|
if (env.CTXDB_BASE_URL) cfg.baseUrl = env.CTXDB_BASE_URL.replace(/\/+$/, "");
|
|
404
406
|
if (env.CTXDB_USER_ID) cfg.userId = env.CTXDB_USER_ID;
|
|
407
|
+
if (env.CTXDB_AGENT_ID) cfg.agentId = env.CTXDB_AGENT_ID;
|
|
408
|
+
if (env.CTXDB_APP_ID) cfg.appId = env.CTXDB_APP_ID;
|
|
405
409
|
return cfg;
|
|
406
410
|
}
|
|
407
411
|
function load(options = {}) {
|
|
@@ -437,6 +441,8 @@ function configToDisk(cfg) {
|
|
|
437
441
|
api_key: cfg.apiKey,
|
|
438
442
|
base_url: cfg.baseUrl,
|
|
439
443
|
user_id: cfg.userId,
|
|
444
|
+
agent_id: cfg.agentId,
|
|
445
|
+
app_id: cfg.appId,
|
|
440
446
|
auto_capture: cfg.autoCapture,
|
|
441
447
|
auto_recall: cfg.autoRecall,
|
|
442
448
|
warmup_recall: cfg.warmupRecall,
|
package/dist/cli/main.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
fetchKbCatalogBlock,
|
|
4
4
|
recallTurn
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-CYCD234A.js";
|
|
6
6
|
import "../chunk-6S5RJYBC.js";
|
|
7
7
|
import {
|
|
8
8
|
isCircuitOpen
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-UULWJJT4.js";
|
|
10
10
|
import {
|
|
11
11
|
HttpClient,
|
|
12
12
|
agentFromArgvWithFallback,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
isComplete,
|
|
15
15
|
load,
|
|
16
16
|
setDebug
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-TKMIWM6Q.js";
|
|
18
18
|
|
|
19
19
|
// src/hooks/session-start.ts
|
|
20
20
|
import { pathToFileURL } from "url";
|
package/dist/hooks/stop.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
isConnectionError,
|
|
5
5
|
resetCircuit,
|
|
6
6
|
tripCircuit
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-UULWJJT4.js";
|
|
8
8
|
import {
|
|
9
9
|
CtxdbError,
|
|
10
10
|
HttpClient,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
isDebug,
|
|
14
14
|
load,
|
|
15
15
|
setDebug
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-TKMIWM6Q.js";
|
|
17
17
|
|
|
18
18
|
// src/lib/capture-orchestrator.ts
|
|
19
19
|
import {
|
|
@@ -304,7 +304,7 @@ function extractSkillSignals(rows) {
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
// src/lib/capture-orchestrator.ts
|
|
307
|
-
async function captureTurn(transcriptPath, cfg, client, agent = "default") {
|
|
307
|
+
async function captureTurn(transcriptPath, cfg, client, agent = "default", sessionId) {
|
|
308
308
|
if (!cfg.apiKey || !cfg.baseUrl) {
|
|
309
309
|
return { captured: false, reason: "config_incomplete", messageCount: 0 };
|
|
310
310
|
}
|
|
@@ -373,6 +373,9 @@ async function captureTurn(transcriptPath, cfg, client, agent = "default") {
|
|
|
373
373
|
user_id: cfg.userId,
|
|
374
374
|
async_mode: true
|
|
375
375
|
};
|
|
376
|
+
if (cfg.agentId) payload.agent_id = cfg.agentId;
|
|
377
|
+
if (cfg.appId) payload.app_id = cfg.appId;
|
|
378
|
+
if (sessionId) payload.run_id = sessionId;
|
|
376
379
|
let resp;
|
|
377
380
|
try {
|
|
378
381
|
resp = await client.postJson("/v3/memories/add/", payload);
|
|
@@ -504,6 +507,10 @@ async function readStdinJson() {
|
|
|
504
507
|
return {};
|
|
505
508
|
}
|
|
506
509
|
}
|
|
510
|
+
function extractHookSessionId(event) {
|
|
511
|
+
const v = event.session_id ?? event.sessionId;
|
|
512
|
+
return typeof v === "string" && v ? v : void 0;
|
|
513
|
+
}
|
|
507
514
|
async function main() {
|
|
508
515
|
try {
|
|
509
516
|
const event = await readStdinJson();
|
|
@@ -516,6 +523,7 @@ async function main() {
|
|
|
516
523
|
}
|
|
517
524
|
const transcriptPath = event.transcript_path;
|
|
518
525
|
if (typeof transcriptPath !== "string" || !transcriptPath) return 0;
|
|
526
|
+
const sessionId = extractHookSessionId(event);
|
|
519
527
|
const cfg = load({ agent });
|
|
520
528
|
setDebug(cfg.debug);
|
|
521
529
|
debug("capture", "start", { transcriptPath, userId: cfg.userId });
|
|
@@ -524,7 +532,7 @@ async function main() {
|
|
|
524
532
|
return 0;
|
|
525
533
|
}
|
|
526
534
|
const client = new HttpClient({ baseUrl: cfg.baseUrl, apiKey: cfg.apiKey, timeoutMs: 5e3 });
|
|
527
|
-
const result = await captureTurn(transcriptPath, cfg, client, agent);
|
|
535
|
+
const result = await captureTurn(transcriptPath, cfg, client, agent, sessionId);
|
|
528
536
|
if (result.captured) {
|
|
529
537
|
debug("capture", `ok (${result.messageCount} msgs)`, result);
|
|
530
538
|
process.stderr.write(
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
fetchKbCatalogBlock,
|
|
4
4
|
recallTurn
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-CYCD234A.js";
|
|
6
6
|
import "../chunk-6S5RJYBC.js";
|
|
7
7
|
import {
|
|
8
8
|
isCircuitOpen
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-UULWJJT4.js";
|
|
10
10
|
import {
|
|
11
11
|
HttpClient,
|
|
12
12
|
agentFromArgvWithFallback,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
isComplete,
|
|
15
15
|
load,
|
|
16
16
|
setDebug
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-TKMIWM6Q.js";
|
|
18
18
|
|
|
19
19
|
// src/hooks/user-prompt-submit.ts
|
|
20
20
|
import { pathToFileURL } from "url";
|
package/dist/opencode/index.js
CHANGED
|
@@ -54,6 +54,8 @@ function applyEnv(cfg, env) {
|
|
|
54
54
|
if (env.CTXDB_API_KEY) cfg.apiKey = env.CTXDB_API_KEY;
|
|
55
55
|
if (env.CTXDB_BASE_URL) cfg.baseUrl = env.CTXDB_BASE_URL.replace(/\/+$/, "");
|
|
56
56
|
if (env.CTXDB_USER_ID) cfg.userId = env.CTXDB_USER_ID;
|
|
57
|
+
if (env.CTXDB_AGENT_ID) cfg.agentId = env.CTXDB_AGENT_ID;
|
|
58
|
+
if (env.CTXDB_APP_ID) cfg.appId = env.CTXDB_APP_ID;
|
|
57
59
|
return cfg;
|
|
58
60
|
}
|
|
59
61
|
function loadOpencodeConfig(options = {}) {
|
|
@@ -65,6 +67,8 @@ function loadOpencodeConfig(options = {}) {
|
|
|
65
67
|
apiKey: typeof section.api_key === "string" && section.api_key ? section.api_key : null,
|
|
66
68
|
baseUrl: typeof section.base_url === "string" && section.base_url ? String(section.base_url).replace(/\/+$/, "") : DEFAULT_BASE_URL,
|
|
67
69
|
userId: typeof section.user_id === "string" && section.user_id ? section.user_id : DEFAULT_USER_ID,
|
|
70
|
+
agentId: typeof section.agent_id === "string" && section.agent_id ? section.agent_id : null,
|
|
71
|
+
appId: typeof section.app_id === "string" && section.app_id ? section.app_id : null,
|
|
68
72
|
autoCapture: coerceBool(section.auto_capture, true),
|
|
69
73
|
autoRecall: coerceBool(section.auto_recall, true),
|
|
70
74
|
warmupRecall: coerceBool(section.warmup_recall, false),
|
|
@@ -590,6 +594,8 @@ async function searchAndFormatRecall(prompt, cfg, client, timeoutMs) {
|
|
|
590
594
|
if (cfg.recallKnowledge) {
|
|
591
595
|
body.knowledge = { enable: true, top_k: cfg.knowledgeTopK };
|
|
592
596
|
}
|
|
597
|
+
if (cfg.agentId) body.agent_id = cfg.agentId;
|
|
598
|
+
if (cfg.appId) body.app_id = cfg.appId;
|
|
593
599
|
let resp;
|
|
594
600
|
try {
|
|
595
601
|
resp = await client.postJson("/v3/memories/search/", body, { timeoutMs });
|
|
@@ -772,7 +778,7 @@ function fingerprintMessages(messages) {
|
|
|
772
778
|
}
|
|
773
779
|
return h.digest("hex");
|
|
774
780
|
}
|
|
775
|
-
async function runCapture(messages, cfg, client, timeoutMs, lastFingerprint) {
|
|
781
|
+
async function runCapture(messages, cfg, client, timeoutMs, lastFingerprint, sessionId) {
|
|
776
782
|
if (!cfg.autoCapture) return { ...EMPTY2, reason: "auto_capture_disabled" };
|
|
777
783
|
if (!cfg.baseUrl) return { ...EMPTY2, reason: "config_incomplete" };
|
|
778
784
|
if (messages.length === 0) return { ...EMPTY2, reason: "empty_transcript" };
|
|
@@ -796,6 +802,9 @@ async function runCapture(messages, cfg, client, timeoutMs, lastFingerprint) {
|
|
|
796
802
|
user_id: cfg.userId,
|
|
797
803
|
async_mode: true
|
|
798
804
|
};
|
|
805
|
+
if (cfg.agentId) payload.agent_id = cfg.agentId;
|
|
806
|
+
if (cfg.appId) payload.app_id = cfg.appId;
|
|
807
|
+
if (sessionId) payload.run_id = sessionId;
|
|
799
808
|
let resp;
|
|
800
809
|
try {
|
|
801
810
|
resp = await client.postJson("/v3/memories/add/", payload, { timeoutMs });
|
|
@@ -944,7 +953,8 @@ async function buildHooks(input) {
|
|
|
944
953
|
rt.config,
|
|
945
954
|
rt.http,
|
|
946
955
|
CAPTURE_TIMEOUT_MS,
|
|
947
|
-
state.lastFingerprint
|
|
956
|
+
state.lastFingerprint,
|
|
957
|
+
sessionID
|
|
948
958
|
);
|
|
949
959
|
if (outcome.captured && outcome.fingerprint) {
|
|
950
960
|
state.lastFingerprint = outcome.fingerprint;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aliyunrds/ctxdb",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Unified access layer for RDS ContextDatabase: `ctxdb` CLI (memory + KB ops), one-shot `setup --agent <qoder|qoderwork|codex|claude|opencode>` installer, per-agent config, hooks/plugins, and SKILL.md.",
|
|
6
6
|
"license": "Apache-2.0",
|