hippo-memory 1.24.0 → 1.25.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/bin/hippo.js +2 -2
- package/dist/api.d.ts +12 -17
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +25 -55
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts +5 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +88 -10
- package/dist/cli.js.map +1 -1
- package/dist/connectors/github/backfill.js +4 -4
- package/dist/connectors/github/cli-impl.js +6 -6
- package/dist/connectors/github/dlq.js +14 -14
- package/dist/connectors/slack/backfill.js +1 -1
- package/dist/connectors/slack/dlq.js +10 -10
- package/dist/connectors/slack/workspaces.js +4 -4
- package/dist/dag.js +6 -6
- package/dist/dashboard.js +7 -7
- package/dist/hooks.js +24 -24
- package/dist/predictions.js +67 -67
- package/dist/recall-scope.d.ts +60 -0
- package/dist/recall-scope.d.ts.map +1 -0
- package/dist/recall-scope.js +84 -0
- package/dist/recall-scope.js.map +1 -0
- package/dist/refine-llm.js +13 -13
- package/dist/shared.d.ts +30 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +41 -9
- package/dist/shared.js.map +1 -1
- package/dist/sleep-redact.d.ts +3 -0
- package/dist/sleep-redact.d.ts.map +1 -1
- package/dist/sleep-redact.js +3 -0
- package/dist/sleep-redact.js.map +1 -1
- package/dist/src/api.js +25 -55
- package/dist/src/api.js.map +1 -1
- package/dist/src/cli.js +88 -10
- package/dist/src/cli.js.map +1 -1
- package/dist/src/connectors/github/backfill.js +4 -4
- package/dist/src/connectors/github/cli-impl.js +6 -6
- package/dist/src/connectors/github/dlq.js +14 -14
- package/dist/src/connectors/slack/backfill.js +1 -1
- package/dist/src/connectors/slack/dlq.js +10 -10
- package/dist/src/connectors/slack/workspaces.js +4 -4
- package/dist/src/dag.js +6 -6
- package/dist/src/dashboard.js +7 -7
- package/dist/src/hooks.js +24 -24
- package/dist/src/predictions.js +67 -67
- package/dist/src/recall-scope.js +84 -0
- package/dist/src/recall-scope.js.map +1 -0
- package/dist/src/refine-llm.js +13 -13
- package/dist/src/shared.js +41 -9
- package/dist/src/shared.js.map +1 -1
- package/dist/src/sleep-redact.js +3 -0
- package/dist/src/sleep-redact.js.map +1 -1
- package/dist/src/store.js +57 -17
- package/dist/src/store.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/working-memory.js +19 -19
- package/dist/store.d.ts +30 -9
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +57 -17
- package/dist/store.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.js +19 -19
- package/dist-ui/index.html +12 -12
- package/extensions/openclaw-plugin/index.ts +650 -650
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/benchmarks/e1.3/scenarios.json +0 -2587
|
@@ -30,7 +30,7 @@ function readCursor(root, tenantId, repo) {
|
|
|
30
30
|
const db = openHippoDb(root);
|
|
31
31
|
try {
|
|
32
32
|
const row = db
|
|
33
|
-
.prepare(`SELECT issues_hwm, issue_comments_hwm, pr_review_comments_hwm
|
|
33
|
+
.prepare(`SELECT issues_hwm, issue_comments_hwm, pr_review_comments_hwm
|
|
34
34
|
FROM github_cursors WHERE tenant_id = ? AND repo_full_name = ?`)
|
|
35
35
|
.get(tenantId, repo);
|
|
36
36
|
return {
|
|
@@ -46,9 +46,9 @@ function readCursor(root, tenantId, repo) {
|
|
|
46
46
|
function writeOneHwm(root, tenantId, repo, column, value) {
|
|
47
47
|
const db = openHippoDb(root);
|
|
48
48
|
try {
|
|
49
|
-
db.prepare(`INSERT INTO github_cursors (tenant_id, repo_full_name, ${column}, updated_at)
|
|
50
|
-
VALUES (?, ?, ?, ?)
|
|
51
|
-
ON CONFLICT(tenant_id, repo_full_name)
|
|
49
|
+
db.prepare(`INSERT INTO github_cursors (tenant_id, repo_full_name, ${column}, updated_at)
|
|
50
|
+
VALUES (?, ?, ?, ?)
|
|
51
|
+
ON CONFLICT(tenant_id, repo_full_name)
|
|
52
52
|
DO UPDATE SET ${column} = excluded.${column}, updated_at = excluded.updated_at`).run(tenantId, repo, value, new Date().toISOString());
|
|
53
53
|
}
|
|
54
54
|
finally {
|
|
@@ -83,12 +83,12 @@ export async function cmdGithubBackfill(hippoRoot, flags, fetcher = realGitHubFe
|
|
|
83
83
|
if (sinceIso) {
|
|
84
84
|
const db = openHippoDb(hippoRoot);
|
|
85
85
|
try {
|
|
86
|
-
db.prepare(`INSERT INTO github_cursors (tenant_id, repo_full_name, issues_hwm, issue_comments_hwm, pr_review_comments_hwm, updated_at)
|
|
87
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
88
|
-
ON CONFLICT(tenant_id, repo_full_name) DO UPDATE SET
|
|
89
|
-
issues_hwm = COALESCE(github_cursors.issues_hwm, excluded.issues_hwm),
|
|
90
|
-
issue_comments_hwm = COALESCE(github_cursors.issue_comments_hwm, excluded.issue_comments_hwm),
|
|
91
|
-
pr_review_comments_hwm = COALESCE(github_cursors.pr_review_comments_hwm, excluded.pr_review_comments_hwm),
|
|
86
|
+
db.prepare(`INSERT INTO github_cursors (tenant_id, repo_full_name, issues_hwm, issue_comments_hwm, pr_review_comments_hwm, updated_at)
|
|
87
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
88
|
+
ON CONFLICT(tenant_id, repo_full_name) DO UPDATE SET
|
|
89
|
+
issues_hwm = COALESCE(github_cursors.issues_hwm, excluded.issues_hwm),
|
|
90
|
+
issue_comments_hwm = COALESCE(github_cursors.issue_comments_hwm, excluded.issue_comments_hwm),
|
|
91
|
+
pr_review_comments_hwm = COALESCE(github_cursors.pr_review_comments_hwm, excluded.pr_review_comments_hwm),
|
|
92
92
|
updated_at = excluded.updated_at`).run(tenantId, repo, sinceIso, sinceIso, sinceIso, new Date().toISOString());
|
|
93
93
|
}
|
|
94
94
|
finally {
|
|
@@ -3,30 +3,30 @@ import { verifyGitHubSignature } from './signature.js';
|
|
|
3
3
|
import { isGitHubWebhookEnvelope } from './types.js';
|
|
4
4
|
export function writeToDlq(db, opts) {
|
|
5
5
|
const result = db
|
|
6
|
-
.prepare(`INSERT INTO github_dlq
|
|
7
|
-
(tenant_id, raw_payload, error, event_name, delivery_id, signature,
|
|
8
|
-
installation_id, repo_full_name, received_at, bucket)
|
|
6
|
+
.prepare(`INSERT INTO github_dlq
|
|
7
|
+
(tenant_id, raw_payload, error, event_name, delivery_id, signature,
|
|
8
|
+
installation_id, repo_full_name, received_at, bucket)
|
|
9
9
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
10
10
|
.run(opts.tenantId ?? '__unroutable__', opts.rawPayload, opts.error, opts.eventName ?? null, opts.deliveryId ?? null, opts.signature ?? null, opts.installationId ?? null, opts.repoFullName ?? null, new Date().toISOString(), opts.bucket ?? 'parse_error');
|
|
11
11
|
return Number(result.lastInsertRowid);
|
|
12
12
|
}
|
|
13
|
-
const SELECT_COLUMNS = `id, tenant_id, raw_payload, error, event_name, delivery_id,
|
|
14
|
-
signature, installation_id, repo_full_name, retry_count,
|
|
13
|
+
const SELECT_COLUMNS = `id, tenant_id, raw_payload, error, event_name, delivery_id,
|
|
14
|
+
signature, installation_id, repo_full_name, retry_count,
|
|
15
15
|
received_at, retried_at, bucket`;
|
|
16
16
|
export function listDlq(db, opts) {
|
|
17
17
|
const rows = db
|
|
18
|
-
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
19
|
-
FROM github_dlq
|
|
20
|
-
WHERE tenant_id = ?
|
|
21
|
-
ORDER BY received_at ASC
|
|
18
|
+
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
19
|
+
FROM github_dlq
|
|
20
|
+
WHERE tenant_id = ?
|
|
21
|
+
ORDER BY received_at ASC
|
|
22
22
|
LIMIT ?`)
|
|
23
23
|
.all(opts.tenantId, opts.limit ?? 100);
|
|
24
24
|
return rows.map(rowToItem);
|
|
25
25
|
}
|
|
26
26
|
export function getDlqEntry(db, id) {
|
|
27
27
|
const row = db
|
|
28
|
-
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
29
|
-
FROM github_dlq
|
|
28
|
+
.prepare(`SELECT ${SELECT_COLUMNS}
|
|
29
|
+
FROM github_dlq
|
|
30
30
|
WHERE id = ?`)
|
|
31
31
|
.get(id);
|
|
32
32
|
if (!row)
|
|
@@ -53,9 +53,9 @@ function rowToItem(r) {
|
|
|
53
53
|
function bumpRetryCount(hippoRoot, id) {
|
|
54
54
|
const db = openHippoDb(hippoRoot);
|
|
55
55
|
try {
|
|
56
|
-
db.prepare(`UPDATE github_dlq
|
|
57
|
-
SET retry_count = retry_count + 1,
|
|
58
|
-
retried_at = ?
|
|
56
|
+
db.prepare(`UPDATE github_dlq
|
|
57
|
+
SET retry_count = retry_count + 1,
|
|
58
|
+
retried_at = ?
|
|
59
59
|
WHERE id = ?`).run(new Date().toISOString(), id);
|
|
60
60
|
}
|
|
61
61
|
finally {
|
|
@@ -15,7 +15,7 @@ function readCursor(root, tenantId, channelId) {
|
|
|
15
15
|
function writeCursor(root, tenantId, channelId, latestTs) {
|
|
16
16
|
const db = openHippoDb(root);
|
|
17
17
|
try {
|
|
18
|
-
db.prepare(`INSERT INTO slack_cursors (tenant_id, channel_id, latest_ts, updated_at) VALUES (?,?,?,?)
|
|
18
|
+
db.prepare(`INSERT INTO slack_cursors (tenant_id, channel_id, latest_ts, updated_at) VALUES (?,?,?,?)
|
|
19
19
|
ON CONFLICT(tenant_id, channel_id) DO UPDATE SET latest_ts = excluded.latest_ts, updated_at = excluded.updated_at`).run(tenantId, channelId, latestTs, new Date().toISOString());
|
|
20
20
|
}
|
|
21
21
|
finally {
|
|
@@ -7,28 +7,28 @@ import { isSlackEventEnvelope, isSlackMessageEvent } from './types.js';
|
|
|
7
7
|
import { handleMessageDeleted } from './deletion.js';
|
|
8
8
|
export function writeToDlq(db, opts) {
|
|
9
9
|
const result = db
|
|
10
|
-
.prepare(`INSERT INTO slack_dlq
|
|
11
|
-
(tenant_id, team_id, raw_payload, error, received_at, bucket, signature, slack_timestamp)
|
|
10
|
+
.prepare(`INSERT INTO slack_dlq
|
|
11
|
+
(tenant_id, team_id, raw_payload, error, received_at, bucket, signature, slack_timestamp)
|
|
12
12
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
13
13
|
.run(opts.tenantId ?? '__unroutable__', opts.teamId ?? null, opts.rawPayload, opts.error, new Date().toISOString(), opts.bucket ?? 'parse_error', opts.signature ?? null, opts.slackTimestamp ?? null);
|
|
14
14
|
return Number(result.lastInsertRowid);
|
|
15
15
|
}
|
|
16
16
|
export function listDlq(db, opts) {
|
|
17
17
|
const rows = db
|
|
18
|
-
.prepare(`SELECT id, tenant_id, team_id, raw_payload, error, received_at, retried_at,
|
|
19
|
-
bucket, retry_count, signature, slack_timestamp
|
|
20
|
-
FROM slack_dlq
|
|
21
|
-
WHERE tenant_id = ?
|
|
22
|
-
ORDER BY received_at ASC
|
|
18
|
+
.prepare(`SELECT id, tenant_id, team_id, raw_payload, error, received_at, retried_at,
|
|
19
|
+
bucket, retry_count, signature, slack_timestamp
|
|
20
|
+
FROM slack_dlq
|
|
21
|
+
WHERE tenant_id = ?
|
|
22
|
+
ORDER BY received_at ASC
|
|
23
23
|
LIMIT ?`)
|
|
24
24
|
.all(opts.tenantId, opts.limit ?? 100);
|
|
25
25
|
return rows.map(rowToItem);
|
|
26
26
|
}
|
|
27
27
|
export function getDlqEntry(db, id) {
|
|
28
28
|
const row = db
|
|
29
|
-
.prepare(`SELECT id, tenant_id, team_id, raw_payload, error, received_at, retried_at,
|
|
30
|
-
bucket, retry_count, signature, slack_timestamp
|
|
31
|
-
FROM slack_dlq
|
|
29
|
+
.prepare(`SELECT id, tenant_id, team_id, raw_payload, error, received_at, retried_at,
|
|
30
|
+
bucket, retry_count, signature, slack_timestamp
|
|
31
|
+
FROM slack_dlq
|
|
32
32
|
WHERE id = ?`)
|
|
33
33
|
.get(id);
|
|
34
34
|
if (!row)
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
*/
|
|
27
27
|
export function addWorkspace(db, opts) {
|
|
28
28
|
const addedAt = new Date().toISOString();
|
|
29
|
-
db.prepare(`INSERT INTO slack_workspaces (team_id, tenant_id, added_at)
|
|
30
|
-
VALUES (?, ?, ?)
|
|
31
|
-
ON CONFLICT(team_id) DO UPDATE SET
|
|
32
|
-
tenant_id = excluded.tenant_id,
|
|
29
|
+
db.prepare(`INSERT INTO slack_workspaces (team_id, tenant_id, added_at)
|
|
30
|
+
VALUES (?, ?, ?)
|
|
31
|
+
ON CONFLICT(team_id) DO UPDATE SET
|
|
32
|
+
tenant_id = excluded.tenant_id,
|
|
33
33
|
added_at = excluded.added_at`).run(opts.teamId, opts.tenantId, addedAt);
|
|
34
34
|
return { teamId: opts.teamId, tenantId: opts.tenantId, addedAt };
|
|
35
35
|
}
|
package/dist/dag.js
CHANGED
|
@@ -31,12 +31,12 @@ export function clusterFacts(facts) {
|
|
|
31
31
|
}
|
|
32
32
|
return clusters;
|
|
33
33
|
}
|
|
34
|
-
const DAG_SUMMARY_PROMPT = `You are summarizing a cluster of facts about a specific topic/entity for a memory system.
|
|
35
|
-
|
|
36
|
-
Topic: {label}
|
|
37
|
-
Facts:
|
|
38
|
-
{facts}
|
|
39
|
-
|
|
34
|
+
const DAG_SUMMARY_PROMPT = `You are summarizing a cluster of facts about a specific topic/entity for a memory system.
|
|
35
|
+
|
|
36
|
+
Topic: {label}
|
|
37
|
+
Facts:
|
|
38
|
+
{facts}
|
|
39
|
+
|
|
40
40
|
Write a single concise paragraph (2-4 sentences) that captures all the key information from these facts. This summary will be used to quickly determine if this cluster is relevant to a future query, so include specific names, dates, numbers, and key details. Output ONLY the summary paragraph, no preamble.`;
|
|
41
41
|
export async function generateDagSummary(label, factContents, opts) {
|
|
42
42
|
const model = opts.model ?? 'claude-sonnet-4-6';
|
package/dist/dashboard.js
CHANGED
|
@@ -202,13 +202,13 @@ export function serveDashboard(hippoRoot, port = 3333) {
|
|
|
202
202
|
// was removed in the hybrid-v4 revamp E1 since dist-ui/ is now the
|
|
203
203
|
// sole UI surface). ---
|
|
204
204
|
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
205
|
-
res.end(`<!doctype html>
|
|
206
|
-
<html lang="en"><head><title>Hippo Dashboard</title><meta charset="utf-8"></head>
|
|
207
|
-
<body style="font-family:Georgia,'Palatino Linotype',serif;max-width:640px;margin:60px auto;padding:24px;line-height:1.6;background:#f4efe6;color:#3a3228">
|
|
208
|
-
<h1 style="color:#c45c3c">Hippo Dashboard</h1>
|
|
209
|
-
<p>The React UI bundle is not built yet. Run:</p>
|
|
210
|
-
<pre style="background:#faf7f2;padding:16px;border:1px solid #c4b9a8;border-radius:3px;font-family:Consolas,monospace">cd ui && npm install && npm run build</pre>
|
|
211
|
-
<p>Then refresh this page. The dashboard server will serve <code>dist-ui/index.html</code> automatically once present.</p>
|
|
205
|
+
res.end(`<!doctype html>
|
|
206
|
+
<html lang="en"><head><title>Hippo Dashboard</title><meta charset="utf-8"></head>
|
|
207
|
+
<body style="font-family:Georgia,'Palatino Linotype',serif;max-width:640px;margin:60px auto;padding:24px;line-height:1.6;background:#f4efe6;color:#3a3228">
|
|
208
|
+
<h1 style="color:#c45c3c">Hippo Dashboard</h1>
|
|
209
|
+
<p>The React UI bundle is not built yet. Run:</p>
|
|
210
|
+
<pre style="background:#faf7f2;padding:16px;border:1px solid #c4b9a8;border-radius:3px;font-family:Consolas,monospace">cd ui && npm install && npm run build</pre>
|
|
211
|
+
<p>Then refresh this page. The dashboard server will serve <code>dist-ui/index.html</code> automatically once present.</p>
|
|
212
212
|
</body></html>`);
|
|
213
213
|
});
|
|
214
214
|
server.listen(port, '127.0.0.1', () => {
|
package/dist/hooks.js
CHANGED
|
@@ -77,30 +77,30 @@ const HIPPO_OPENCODE_PLUGIN_MARKER = 'HIPPO_OPENCODE_PLUGIN_V1';
|
|
|
77
77
|
* marker match AND content equality, so a plugin-source revision under
|
|
78
78
|
* the same V1 marker re-writes the file on next install.
|
|
79
79
|
*/
|
|
80
|
-
export const OPENCODE_PLUGIN_SOURCE = `// ${HIPPO_OPENCODE_PLUGIN_MARKER}
|
|
81
|
-
// hippo-memory opencode plugin. DO NOT EDIT — regenerated on every
|
|
82
|
-
// \`hippo hook install opencode\` from src/hooks.ts OPENCODE_PLUGIN_SOURCE
|
|
83
|
-
// in https://github.com/kitfunso/hippo-memory. Local changes will be lost.
|
|
84
|
-
|
|
85
|
-
export const HippoPlugin = async ({ $ }) => {
|
|
86
|
-
return {
|
|
87
|
-
event: async ({ event }) => {
|
|
88
|
-
// Defense in depth: opencode currently runs in Bun where $ is the shell
|
|
89
|
-
// template helper. A non-Bun runtime would have $ as undefined; fail
|
|
90
|
-
// closed instead of crashing the host session.
|
|
91
|
-
if (typeof $ !== "function") return;
|
|
92
|
-
try {
|
|
93
|
-
if (event.type === "session.idle") {
|
|
94
|
-
await $\`hippo session-end\`.quiet().nothrow();
|
|
95
|
-
} else if (event.type === "session.created") {
|
|
96
|
-
await $\`hippo last-sleep\`.quiet().nothrow();
|
|
97
|
-
}
|
|
98
|
-
} catch {
|
|
99
|
-
// hippo CLI not on PATH or other failure — never crash the host session.
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
};
|
|
80
|
+
export const OPENCODE_PLUGIN_SOURCE = `// ${HIPPO_OPENCODE_PLUGIN_MARKER}
|
|
81
|
+
// hippo-memory opencode plugin. DO NOT EDIT — regenerated on every
|
|
82
|
+
// \`hippo hook install opencode\` from src/hooks.ts OPENCODE_PLUGIN_SOURCE
|
|
83
|
+
// in https://github.com/kitfunso/hippo-memory. Local changes will be lost.
|
|
84
|
+
|
|
85
|
+
export const HippoPlugin = async ({ $ }) => {
|
|
86
|
+
return {
|
|
87
|
+
event: async ({ event }) => {
|
|
88
|
+
// Defense in depth: opencode currently runs in Bun where $ is the shell
|
|
89
|
+
// template helper. A non-Bun runtime would have $ as undefined; fail
|
|
90
|
+
// closed instead of crashing the host session.
|
|
91
|
+
if (typeof $ !== "function") return;
|
|
92
|
+
try {
|
|
93
|
+
if (event.type === "session.idle") {
|
|
94
|
+
await $\`hippo session-end\`.quiet().nothrow();
|
|
95
|
+
} else if (event.type === "session.created") {
|
|
96
|
+
await $\`hippo last-sleep\`.quiet().nothrow();
|
|
97
|
+
}
|
|
98
|
+
} catch {
|
|
99
|
+
// hippo CLI not on PATH or other failure — never crash the host session.
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
104
|
`;
|
|
105
105
|
export { HIPPO_OPENCODE_PLUGIN_MARKER };
|
|
106
106
|
function homeDir() {
|
package/dist/predictions.js
CHANGED
|
@@ -86,20 +86,20 @@ export function savePrediction(hippoRoot, tenantId, opts, actor = 'cli') {
|
|
|
86
86
|
writeEntry(hippoRoot, mem, {
|
|
87
87
|
actor,
|
|
88
88
|
afterWrite: (db, memoryId) => {
|
|
89
|
-
const result = db.prepare(`
|
|
90
|
-
INSERT INTO predictions(
|
|
91
|
-
memory_id, tenant_id, class_tag, claim_text,
|
|
92
|
-
estimate_value, estimate_unit, target_date,
|
|
93
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
94
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'open', NULL, NULL, ?)
|
|
89
|
+
const result = db.prepare(`
|
|
90
|
+
INSERT INTO predictions(
|
|
91
|
+
memory_id, tenant_id, class_tag, claim_text,
|
|
92
|
+
estimate_value, estimate_unit, target_date,
|
|
93
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
94
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'open', NULL, NULL, ?)
|
|
95
95
|
`).run(memoryId, tenantId, opts.classTag, opts.claimText, opts.estimateValue ?? null, opts.estimateUnit ?? null, opts.targetDate ?? null, null, // actual_value — null until close
|
|
96
96
|
now);
|
|
97
97
|
const predictionId = Number(result.lastInsertRowid ?? 0);
|
|
98
|
-
const row = db.prepare(`
|
|
99
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
100
|
-
estimate_value, estimate_unit, target_date,
|
|
101
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
102
|
-
FROM predictions WHERE id = ?
|
|
98
|
+
const row = db.prepare(`
|
|
99
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
100
|
+
estimate_value, estimate_unit, target_date,
|
|
101
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
102
|
+
FROM predictions WHERE id = ?
|
|
103
103
|
`).get(predictionId);
|
|
104
104
|
if (!row) {
|
|
105
105
|
throw new Error('Failed to reload saved prediction row');
|
|
@@ -150,16 +150,16 @@ export function closePrediction(hippoRoot, tenantId, id, opts, actor = 'cli') {
|
|
|
150
150
|
// predict_close audit row. Zero changed rows → caller decides
|
|
151
151
|
// whether it's a "not found" or "already closed" case based on the
|
|
152
152
|
// load-then-close pattern.
|
|
153
|
-
const updateResult = db.prepare(`
|
|
154
|
-
UPDATE predictions
|
|
155
|
-
SET actual_value = ?, closure_state = ?, closed_at = ?, closure_note = ?
|
|
156
|
-
WHERE id = ? AND tenant_id = ? AND closure_state = 'open'
|
|
153
|
+
const updateResult = db.prepare(`
|
|
154
|
+
UPDATE predictions
|
|
155
|
+
SET actual_value = ?, closure_state = ?, closed_at = ?, closure_note = ?
|
|
156
|
+
WHERE id = ? AND tenant_id = ? AND closure_state = 'open'
|
|
157
157
|
`).run(opts.actualValue ?? null, opts.closureState, now, opts.closureNote ?? null, id, tenantId);
|
|
158
158
|
if (updateResult.changes === 0) {
|
|
159
159
|
// Distinguish "not found" from "already closed" so callers (CLI, HTTP)
|
|
160
160
|
// can surface the right error to the user.
|
|
161
|
-
const existing = db.prepare(`
|
|
162
|
-
SELECT closure_state FROM predictions WHERE id = ? AND tenant_id = ?
|
|
161
|
+
const existing = db.prepare(`
|
|
162
|
+
SELECT closure_state FROM predictions WHERE id = ? AND tenant_id = ?
|
|
163
163
|
`).get(id, tenantId);
|
|
164
164
|
if (!existing) {
|
|
165
165
|
throw new Error(`closePrediction: prediction ${id} not found for tenant ${tenantId}`);
|
|
@@ -167,11 +167,11 @@ export function closePrediction(hippoRoot, tenantId, id, opts, actor = 'cli') {
|
|
|
167
167
|
throw new Error(`closePrediction: prediction ${id} is already closed (state='${existing.closure_state}'); ` +
|
|
168
168
|
`cannot re-close. Open predictions only.`);
|
|
169
169
|
}
|
|
170
|
-
const row = db.prepare(`
|
|
171
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
172
|
-
estimate_value, estimate_unit, target_date,
|
|
173
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
174
|
-
FROM predictions WHERE id = ? AND tenant_id = ?
|
|
170
|
+
const row = db.prepare(`
|
|
171
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
172
|
+
estimate_value, estimate_unit, target_date,
|
|
173
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
174
|
+
FROM predictions WHERE id = ? AND tenant_id = ?
|
|
175
175
|
`).get(id, tenantId);
|
|
176
176
|
if (!row) {
|
|
177
177
|
throw new Error(`closePrediction: prediction ${id} not found after UPDATE`);
|
|
@@ -208,11 +208,11 @@ export function loadPredictionById(hippoRoot, tenantId, id) {
|
|
|
208
208
|
assertTenantId('loadPredictionById', tenantId);
|
|
209
209
|
const db = openHippoDb(hippoRoot);
|
|
210
210
|
try {
|
|
211
|
-
const row = db.prepare(`
|
|
212
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
213
|
-
estimate_value, estimate_unit, target_date,
|
|
214
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
215
|
-
FROM predictions WHERE id = ? AND tenant_id = ?
|
|
211
|
+
const row = db.prepare(`
|
|
212
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
213
|
+
estimate_value, estimate_unit, target_date,
|
|
214
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
215
|
+
FROM predictions WHERE id = ? AND tenant_id = ?
|
|
216
216
|
`).get(id, tenantId);
|
|
217
217
|
return row ? rowToPrediction(row) : null;
|
|
218
218
|
}
|
|
@@ -230,25 +230,25 @@ export function loadPredictionsByClass(hippoRoot, tenantId, classTag, opts = {})
|
|
|
230
230
|
if (!VALID_CLOSURE_STATES.has(opts.closureState)) {
|
|
231
231
|
throw new Error(`loadPredictionsByClass: closureState must be one of ${Array.from(VALID_CLOSURE_STATES).join('|')}; got ${opts.closureState}`);
|
|
232
232
|
}
|
|
233
|
-
rows = db.prepare(`
|
|
234
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
235
|
-
estimate_value, estimate_unit, target_date,
|
|
236
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
237
|
-
FROM predictions
|
|
238
|
-
WHERE tenant_id = ? AND class_tag = ? AND closure_state = ?
|
|
239
|
-
ORDER BY created_at DESC, id DESC
|
|
240
|
-
LIMIT ?
|
|
233
|
+
rows = db.prepare(`
|
|
234
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
235
|
+
estimate_value, estimate_unit, target_date,
|
|
236
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
237
|
+
FROM predictions
|
|
238
|
+
WHERE tenant_id = ? AND class_tag = ? AND closure_state = ?
|
|
239
|
+
ORDER BY created_at DESC, id DESC
|
|
240
|
+
LIMIT ?
|
|
241
241
|
`).all(tenantId, classTag, opts.closureState, limit);
|
|
242
242
|
}
|
|
243
243
|
else {
|
|
244
|
-
rows = db.prepare(`
|
|
245
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
246
|
-
estimate_value, estimate_unit, target_date,
|
|
247
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
248
|
-
FROM predictions
|
|
249
|
-
WHERE tenant_id = ? AND class_tag = ?
|
|
250
|
-
ORDER BY created_at DESC, id DESC
|
|
251
|
-
LIMIT ?
|
|
244
|
+
rows = db.prepare(`
|
|
245
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
246
|
+
estimate_value, estimate_unit, target_date,
|
|
247
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
248
|
+
FROM predictions
|
|
249
|
+
WHERE tenant_id = ? AND class_tag = ?
|
|
250
|
+
ORDER BY created_at DESC, id DESC
|
|
251
|
+
LIMIT ?
|
|
252
252
|
`).all(tenantId, classTag, limit);
|
|
253
253
|
}
|
|
254
254
|
return rows.map(rowToPrediction);
|
|
@@ -286,14 +286,14 @@ emitAudit = true) {
|
|
|
286
286
|
throw new Error('computePredictionBaserate: classTag is required');
|
|
287
287
|
const db = openHippoDb(hippoRoot);
|
|
288
288
|
try {
|
|
289
|
-
const rows = db.prepare(`
|
|
290
|
-
SELECT estimate_value, actual_value
|
|
291
|
-
FROM predictions
|
|
292
|
-
WHERE tenant_id = ?
|
|
293
|
-
AND class_tag = ?
|
|
294
|
-
AND closure_state = 'closed'
|
|
295
|
-
AND estimate_value IS NOT NULL
|
|
296
|
-
AND actual_value IS NOT NULL
|
|
289
|
+
const rows = db.prepare(`
|
|
290
|
+
SELECT estimate_value, actual_value
|
|
291
|
+
FROM predictions
|
|
292
|
+
WHERE tenant_id = ?
|
|
293
|
+
AND class_tag = ?
|
|
294
|
+
AND closure_state = 'closed'
|
|
295
|
+
AND estimate_value IS NOT NULL
|
|
296
|
+
AND actual_value IS NOT NULL
|
|
297
297
|
`).all(tenantId, classTag);
|
|
298
298
|
const nClosed = rows.length;
|
|
299
299
|
if (nClosed === 0) {
|
|
@@ -373,25 +373,25 @@ export function loadOpenPredictions(hippoRoot, tenantId, opts = {}) {
|
|
|
373
373
|
try {
|
|
374
374
|
let rows;
|
|
375
375
|
if (opts.classTag) {
|
|
376
|
-
rows = db.prepare(`
|
|
377
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
378
|
-
estimate_value, estimate_unit, target_date,
|
|
379
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
380
|
-
FROM predictions
|
|
381
|
-
WHERE tenant_id = ? AND class_tag = ? AND closure_state = 'open'
|
|
382
|
-
ORDER BY created_at DESC, id DESC
|
|
383
|
-
LIMIT ?
|
|
376
|
+
rows = db.prepare(`
|
|
377
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
378
|
+
estimate_value, estimate_unit, target_date,
|
|
379
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
380
|
+
FROM predictions
|
|
381
|
+
WHERE tenant_id = ? AND class_tag = ? AND closure_state = 'open'
|
|
382
|
+
ORDER BY created_at DESC, id DESC
|
|
383
|
+
LIMIT ?
|
|
384
384
|
`).all(tenantId, opts.classTag, limit);
|
|
385
385
|
}
|
|
386
386
|
else {
|
|
387
|
-
rows = db.prepare(`
|
|
388
|
-
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
389
|
-
estimate_value, estimate_unit, target_date,
|
|
390
|
-
actual_value, closure_state, closed_at, closure_note, created_at
|
|
391
|
-
FROM predictions
|
|
392
|
-
WHERE tenant_id = ? AND closure_state = 'open'
|
|
393
|
-
ORDER BY created_at DESC, id DESC
|
|
394
|
-
LIMIT ?
|
|
387
|
+
rows = db.prepare(`
|
|
388
|
+
SELECT id, memory_id, tenant_id, class_tag, claim_text,
|
|
389
|
+
estimate_value, estimate_unit, target_date,
|
|
390
|
+
actual_value, closure_state, closed_at, closure_note, created_at
|
|
391
|
+
FROM predictions
|
|
392
|
+
WHERE tenant_id = ? AND closure_state = 'open'
|
|
393
|
+
ORDER BY created_at DESC, id DESC
|
|
394
|
+
LIMIT ?
|
|
395
395
|
`).all(tenantId, limit);
|
|
396
396
|
}
|
|
397
397
|
return rows.map(rowToPrediction);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.25.0 — recall-side scope predicates, extracted from api.ts into a leaf
|
|
3
|
+
* module so shared.ts (which api.ts imports) can apply the same default-deny
|
|
4
|
+
* rule to searchBothHybrid's internal candidate loads without an import
|
|
5
|
+
* cycle. Mirrors the v39 `project-identity.ts` precedent. api.ts imports
|
|
6
|
+
* these for its own call sites AND re-exports them for back-compat
|
|
7
|
+
* (`api.isPrivateScope`, test imports of `passesScopeFilterForRecall`).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* v1.2.1: source-agnostic private-scope detector. A scope string is treated
|
|
11
|
+
* as private when it has the shape `<lowercase-source>:private:<rest>`.
|
|
12
|
+
*
|
|
13
|
+
* Examples that match:
|
|
14
|
+
* slack:private:Cabc, github:private:owner/repo, jira:private:PROJ-1
|
|
15
|
+
* Examples that DO NOT match:
|
|
16
|
+
* slack:public:Cgeneral, acme:public:my-private-channel, null, '',
|
|
17
|
+
* 'unknown:legacy', 'private' (alone), 'private:foo' (no source prefix).
|
|
18
|
+
*
|
|
19
|
+
* Used by api.recall, mcp/server.ts (hippo_recall + hippo_context),
|
|
20
|
+
* cli.ts (cmdRecall + cmdExplain + continuity), shared.ts (searchBothHybrid
|
|
21
|
+
* recall mode). Keep these in sync — the export is the single source of
|
|
22
|
+
* truth so connector work cannot drift.
|
|
23
|
+
*/
|
|
24
|
+
export declare const PRIVATE_SCOPE_RE: RegExp;
|
|
25
|
+
/** True when `scope` matches the `<source>:private:*` shape. */
|
|
26
|
+
export declare function isPrivateScope(scope: string | null | undefined): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Recall-side scope filter — the canonical JS half of the recall default-deny
|
|
29
|
+
* rule (the SQL half lives in `loadSearchRows` via `loadRecallSearchEntries`).
|
|
30
|
+
*
|
|
31
|
+
* - When `requested` is set and non-empty: exact match required.
|
|
32
|
+
* - When `requested` is undefined/empty: default-deny on any
|
|
33
|
+
* `<source>:private:*` scope and on the `RECALL_DEFAULT_DENY_SCOPES`
|
|
34
|
+
* quarantine buckets. `null` and public scopes pass.
|
|
35
|
+
*
|
|
36
|
+
* @internal v1.7.2 — exported for test parity with
|
|
37
|
+
* `RECALL_DEFAULT_DENY_SCOPES` (single-source-of-truth verification). NOT part
|
|
38
|
+
* of the public API surface; not re-exported from `src/index.ts`. Subject to
|
|
39
|
+
* change without semver bump.
|
|
40
|
+
*/
|
|
41
|
+
export declare function passesScopeFilterForRecall(scope: string | null, requested: string | undefined): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* v1.25.0 — the CLI `--scope` variant of the recall filter (JS half of the
|
|
44
|
+
* SQL 'default-deny-or-exact' mode in loadSearchRows).
|
|
45
|
+
*
|
|
46
|
+
* The CLI flag predates the envelope column as a TAG-boost ranking hint
|
|
47
|
+
* (`scope:<v>` tags, HIPPO_SCOPE, detectScope()), so an explicit `--scope X`
|
|
48
|
+
* UNLOCKS envelope scope X in addition to the default-admitted set — it does
|
|
49
|
+
* NOT narrow the result to X (that would return zero rows for every
|
|
50
|
+
* tag-scoped workflow, whose envelope scope is NULL). api.recall keeps the
|
|
51
|
+
* narrowing 'exact' semantics via `passesScopeFilterForRecall`.
|
|
52
|
+
*
|
|
53
|
+
* Note the unlock applies to whatever scope was explicitly named — including
|
|
54
|
+
* a private scope or a quarantine bucket (`--scope unknown:legacy`). That is
|
|
55
|
+
* deliberate owner access, identical in reach to api.recall's exact-match
|
|
56
|
+
* for the same input; only NON-requested private/quarantine scopes stay
|
|
57
|
+
* denied.
|
|
58
|
+
*/
|
|
59
|
+
export declare function passesCliRecallScopeFilter(scope: string | null, requested: string | undefined): boolean;
|
|
60
|
+
//# sourceMappingURL=recall-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall-scope.d.ts","sourceRoot":"","sources":["../src/recall-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,QAA+B,CAAC;AAE7D,gEAAgE;AAChE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAExE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAaT;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAKT"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1.25.0 — recall-side scope predicates, extracted from api.ts into a leaf
|
|
3
|
+
* module so shared.ts (which api.ts imports) can apply the same default-deny
|
|
4
|
+
* rule to searchBothHybrid's internal candidate loads without an import
|
|
5
|
+
* cycle. Mirrors the v39 `project-identity.ts` precedent. api.ts imports
|
|
6
|
+
* these for its own call sites AND re-exports them for back-compat
|
|
7
|
+
* (`api.isPrivateScope`, test imports of `passesScopeFilterForRecall`).
|
|
8
|
+
*/
|
|
9
|
+
import { RECALL_DEFAULT_DENY_SCOPES } from './store.js';
|
|
10
|
+
/**
|
|
11
|
+
* v1.2.1: source-agnostic private-scope detector. A scope string is treated
|
|
12
|
+
* as private when it has the shape `<lowercase-source>:private:<rest>`.
|
|
13
|
+
*
|
|
14
|
+
* Examples that match:
|
|
15
|
+
* slack:private:Cabc, github:private:owner/repo, jira:private:PROJ-1
|
|
16
|
+
* Examples that DO NOT match:
|
|
17
|
+
* slack:public:Cgeneral, acme:public:my-private-channel, null, '',
|
|
18
|
+
* 'unknown:legacy', 'private' (alone), 'private:foo' (no source prefix).
|
|
19
|
+
*
|
|
20
|
+
* Used by api.recall, mcp/server.ts (hippo_recall + hippo_context),
|
|
21
|
+
* cli.ts (cmdRecall + cmdExplain + continuity), shared.ts (searchBothHybrid
|
|
22
|
+
* recall mode). Keep these in sync — the export is the single source of
|
|
23
|
+
* truth so connector work cannot drift.
|
|
24
|
+
*/
|
|
25
|
+
export const PRIVATE_SCOPE_RE = /^[a-z][a-z0-9_-]*:private:/;
|
|
26
|
+
/** True when `scope` matches the `<source>:private:*` shape. */
|
|
27
|
+
export function isPrivateScope(scope) {
|
|
28
|
+
return typeof scope === 'string' && PRIVATE_SCOPE_RE.test(scope);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Recall-side scope filter — the canonical JS half of the recall default-deny
|
|
32
|
+
* rule (the SQL half lives in `loadSearchRows` via `loadRecallSearchEntries`).
|
|
33
|
+
*
|
|
34
|
+
* - When `requested` is set and non-empty: exact match required.
|
|
35
|
+
* - When `requested` is undefined/empty: default-deny on any
|
|
36
|
+
* `<source>:private:*` scope and on the `RECALL_DEFAULT_DENY_SCOPES`
|
|
37
|
+
* quarantine buckets. `null` and public scopes pass.
|
|
38
|
+
*
|
|
39
|
+
* @internal v1.7.2 — exported for test parity with
|
|
40
|
+
* `RECALL_DEFAULT_DENY_SCOPES` (single-source-of-truth verification). NOT part
|
|
41
|
+
* of the public API surface; not re-exported from `src/index.ts`. Subject to
|
|
42
|
+
* change without semver bump.
|
|
43
|
+
*/
|
|
44
|
+
export function passesScopeFilterForRecall(scope, requested) {
|
|
45
|
+
if (requested !== undefined && requested !== '') {
|
|
46
|
+
return scope === requested;
|
|
47
|
+
}
|
|
48
|
+
if (scope === null)
|
|
49
|
+
return true;
|
|
50
|
+
if (isPrivateScope(scope))
|
|
51
|
+
return false;
|
|
52
|
+
// v1.7.2 — read from RECALL_DEFAULT_DENY_SCOPES (single source of truth
|
|
53
|
+
// shared with the SQL clause in loadSearchRows). Cast the array to
|
|
54
|
+
// readonly string[] so .includes() accepts arbitrary string scopes
|
|
55
|
+
// without a cast on the input (codex P0-2: casting `scope` would defeat
|
|
56
|
+
// the constant's safety).
|
|
57
|
+
if (RECALL_DEFAULT_DENY_SCOPES.includes(scope))
|
|
58
|
+
return false;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* v1.25.0 — the CLI `--scope` variant of the recall filter (JS half of the
|
|
63
|
+
* SQL 'default-deny-or-exact' mode in loadSearchRows).
|
|
64
|
+
*
|
|
65
|
+
* The CLI flag predates the envelope column as a TAG-boost ranking hint
|
|
66
|
+
* (`scope:<v>` tags, HIPPO_SCOPE, detectScope()), so an explicit `--scope X`
|
|
67
|
+
* UNLOCKS envelope scope X in addition to the default-admitted set — it does
|
|
68
|
+
* NOT narrow the result to X (that would return zero rows for every
|
|
69
|
+
* tag-scoped workflow, whose envelope scope is NULL). api.recall keeps the
|
|
70
|
+
* narrowing 'exact' semantics via `passesScopeFilterForRecall`.
|
|
71
|
+
*
|
|
72
|
+
* Note the unlock applies to whatever scope was explicitly named — including
|
|
73
|
+
* a private scope or a quarantine bucket (`--scope unknown:legacy`). That is
|
|
74
|
+
* deliberate owner access, identical in reach to api.recall's exact-match
|
|
75
|
+
* for the same input; only NON-requested private/quarantine scopes stay
|
|
76
|
+
* denied.
|
|
77
|
+
*/
|
|
78
|
+
export function passesCliRecallScopeFilter(scope, requested) {
|
|
79
|
+
if (requested !== undefined && requested !== '' && scope === requested) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return passesScopeFilterForRecall(scope, undefined);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=recall-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recall-scope.js","sourceRoot":"","sources":["../src/recall-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;AAE7D,gEAAgE;AAChE,MAAM,UAAU,cAAc,CAAC,KAAgC;IAC7D,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAAoB,EACpB,SAA6B;IAE7B,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE,EAAE,CAAC;QAChD,OAAO,KAAK,KAAK,SAAS,CAAC;IAC7B,CAAC;IACD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,cAAc,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,wEAAwE;IACxE,mEAAmE;IACnE,mEAAmE;IACnE,wEAAwE;IACxE,0BAA0B;IAC1B,IAAK,0BAAgD,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAAoB,EACpB,SAA6B;IAE7B,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,0BAA0B,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AACtD,CAAC"}
|
package/dist/refine-llm.js
CHANGED
|
@@ -31,19 +31,19 @@ export async function refineSemanticMemory(merged, sources, opts) {
|
|
|
31
31
|
.slice(0, 8)
|
|
32
32
|
.map((s, i) => `[source ${i + 1}] ${s.content.slice(0, 400)}`)
|
|
33
33
|
.join('\n\n');
|
|
34
|
-
const prompt = `You are refining a semantic memory in an agent's memory store. The rule-based consolidator merged several related episodic memories into one, but the output is clumsy. Produce a single coherent semantic memory that captures the underlying principle.
|
|
35
|
-
|
|
36
|
-
Rules:
|
|
37
|
-
- Output ONLY the refined content — no preamble, no quote marks, no "Here is...".
|
|
38
|
-
- Keep it concise: one paragraph, no headers, no bullet lists unless the sources are inherently a list.
|
|
39
|
-
- Preserve specific facts (names, numbers, paths, IDs) from the sources.
|
|
40
|
-
- Generalize: state the pattern, not each instance.
|
|
41
|
-
- Do NOT include the "[Consolidated from N ...]" marker.
|
|
42
|
-
|
|
43
|
-
Current merged content:
|
|
44
|
-
${merged}
|
|
45
|
-
|
|
46
|
-
Source memories (up to 8 shown):
|
|
34
|
+
const prompt = `You are refining a semantic memory in an agent's memory store. The rule-based consolidator merged several related episodic memories into one, but the output is clumsy. Produce a single coherent semantic memory that captures the underlying principle.
|
|
35
|
+
|
|
36
|
+
Rules:
|
|
37
|
+
- Output ONLY the refined content — no preamble, no quote marks, no "Here is...".
|
|
38
|
+
- Keep it concise: one paragraph, no headers, no bullet lists unless the sources are inherently a list.
|
|
39
|
+
- Preserve specific facts (names, numbers, paths, IDs) from the sources.
|
|
40
|
+
- Generalize: state the pattern, not each instance.
|
|
41
|
+
- Do NOT include the "[Consolidated from N ...]" marker.
|
|
42
|
+
|
|
43
|
+
Current merged content:
|
|
44
|
+
${merged}
|
|
45
|
+
|
|
46
|
+
Source memories (up to 8 shown):
|
|
47
47
|
${sourceBlock}`;
|
|
48
48
|
let res;
|
|
49
49
|
try {
|