dsh-hypatia-auto-memory 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +454 -0
- package/cordis.patch.yml +20 -0
- package/lib/client.js +1081 -0
- package/lib/client.js.map +1 -0
- package/package.json +90 -0
- package/skills/hypatia/SKILL.md +585 -0
- package/skills/hypatia-dream/SKILL.md +246 -0
- package/skills/hypatia-dream/evals/evals.json +92 -0
- package/skills/hypatia-memory/SKILL.md +175 -0
- package/src/auto-approve.js +133 -0
- package/src/cascade.js +190 -0
- package/src/client/SettingsCard.module.css +420 -0
- package/src/client/SettingsCard.tsx +700 -0
- package/src/client/card-form.ts +450 -0
- package/src/client/consolidation-models.ts +69 -0
- package/src/client/css-modules.d.ts +4 -0
- package/src/client/index.tsx +106 -0
- package/src/client/locales.ts +111 -0
- package/src/client/shelves.ts +88 -0
- package/src/client/slot-contract.ts +17 -0
- package/src/collector.js +596 -0
- package/src/config.js +225 -0
- package/src/consolidator.js +592 -0
- package/src/content-policy.js +301 -0
- package/src/housekeeping.js +197 -0
- package/src/hypatia-cli.js +294 -0
- package/src/hypatia-client.js +72 -0
- package/src/hypatia-mcp.js +477 -0
- package/src/index.js +418 -0
- package/src/persisted-session.js +99 -0
- package/src/progress.js +56 -0
- package/src/queue.js +466 -0
- package/src/recall.js +148 -0
- package/src/shelf.js +180 -0
- package/src/skills.js +166 -0
- package/src/state.js +87 -0
- package/src/status.js +53 -0
- package/src/writer.js +320 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** `hypatia-auto-memory` namespace dictionaries. */
|
|
2
|
+
|
|
3
|
+
/** Dictionary namespace owned by this plugin. */
|
|
4
|
+
export const NS = 'hypatia-auto-memory'
|
|
5
|
+
|
|
6
|
+
/** Simplified Chinese dictionary and key source of truth. */
|
|
7
|
+
export const zh = {
|
|
8
|
+
loading: '正在加载 {ns} 设置…',
|
|
9
|
+
unavailable: '当前上下文不可用 {ns} 设置。',
|
|
10
|
+
title: 'Hypatia Auto Memory',
|
|
11
|
+
description:
|
|
12
|
+
'自动将对话轮次记录到 Hypatia,并在新内容足够多时通过独立模型路由进行后台整合。',
|
|
13
|
+
enable: '启用自动记忆',
|
|
14
|
+
autoApprove: '自动批准模型发起的 hypatia 命令',
|
|
15
|
+
autoApproveHint: '仅限不含管道、重定向、命令串联的纯 hypatia 调用;插件自身的写入不经过此路径。关闭后模型每次检索都会弹出批准框。修改后需重载配置档生效。',
|
|
16
|
+
shelf: '记忆写入的 shelf',
|
|
17
|
+
shelfHint: '插件的记录、整合与会话开始时的规则预加载都读写这个 shelf;不是 default 时,会话开头会提示模型为 hypatia 命令加上 --shelf。修改后需重载配置档生效。每个 shelf 的记录进度单独保存,切回原来的 shelf 会从上次的位置继续;切到新的 shelf 后,每个有活动的会话会把完整历史重新记录进去并整合一遍(会消耗模型调用)。列表来自 hypatia list,约每分钟刷新一次。',
|
|
18
|
+
shelfLoading: '正在读取 hypatia list…',
|
|
19
|
+
shelfLoadFailed: '无法读取 shelf 列表。',
|
|
20
|
+
shelfListingFailed: 'hypatia list 执行失败,列表可能已过时:{message}',
|
|
21
|
+
shelfDisconnected: '未连接',
|
|
22
|
+
shelfOptionStatus: '({status})',
|
|
23
|
+
shelfNotListed: '不在 hypatia list 中',
|
|
24
|
+
shelfDisconnectedWarning: 'shelf {shelf} 已注册但未连接,写入会失败。',
|
|
25
|
+
shelfNotListedWarning: 'hypatia 没有注册 shelf {shelf},写入会失败;请先执行 hypatia connect <目录> --name {shelf}。',
|
|
26
|
+
consolidationTitle: '整合候选模型',
|
|
27
|
+
modelSelectionHint: '选择一个或多个模型。每次整合尝试(含重试)会按所选顺序轮转;未选择时只记录对话,不执行整合。',
|
|
28
|
+
modelCatalogLoading: '正在读取可用模型…',
|
|
29
|
+
modelCatalogFailed: '无法读取可用模型。',
|
|
30
|
+
modelCatalogPartial: '部分提供方未能返回模型目录。',
|
|
31
|
+
modelCatalogEmpty: '当前没有可选择的模型。',
|
|
32
|
+
selectedModels: '用于轮转的模型',
|
|
33
|
+
unavailableModels: '不可用或未再声明的模型',
|
|
34
|
+
modelUnavailable: '当前不可用',
|
|
35
|
+
retry: '重试',
|
|
36
|
+
checkEveryTurns: '两次整合至少间隔 N 轮',
|
|
37
|
+
minNewTokens: '最小新增 token 数',
|
|
38
|
+
cascadeBatchSize: '归档批量',
|
|
39
|
+
dedupMaxDistance: '关联距离上限',
|
|
40
|
+
cascadeHint: '每积累这么多同层摘要,就归档为上一层的一条;关联距离上限决定新记忆要多接近既有条目才值得判定关系。',
|
|
41
|
+
limitsTitle: '单次整合体量',
|
|
42
|
+
limitsHint: '输入预算决定送入模型的对话长度(超出部分截断保留最近内容);输出预算需容纳摘要与全部工作单元,过小会导致整合失败。',
|
|
43
|
+
maxInputTokens: '输入预算(token)',
|
|
44
|
+
maxOutputTokens: '输出预算(token)',
|
|
45
|
+
maxWorkUnitsPerRun: '每次最多提取工作单元数',
|
|
46
|
+
recallPreload: '召回:会话开始时预加载规则与禁忌',
|
|
47
|
+
advancedHint:
|
|
48
|
+
'高级字段(二进制、收集器上限、队列调优)可直接在 settings.yaml 的 {ns} 键下编辑。',
|
|
49
|
+
reset: '重置',
|
|
50
|
+
discard: '放弃',
|
|
51
|
+
save: '保存',
|
|
52
|
+
saving: '保存中…',
|
|
53
|
+
saveFailed: '保存失败:{message}',
|
|
54
|
+
readOnly: '只读:当前上下文不可写入设置文档。',
|
|
55
|
+
unsaved: '未保存',
|
|
56
|
+
} as const satisfies Record<string, string>
|
|
57
|
+
|
|
58
|
+
/** Key domain of the `hypatia-auto-memory` namespace. */
|
|
59
|
+
export type AutoMemoryLocaleKey = keyof typeof zh
|
|
60
|
+
|
|
61
|
+
/** English dictionary checked against the Chinese key set. */
|
|
62
|
+
export const en = {
|
|
63
|
+
loading: 'Loading {ns} settings…',
|
|
64
|
+
unavailable: '{ns} settings are not available in this context.',
|
|
65
|
+
title: 'Hypatia Auto Memory',
|
|
66
|
+
description:
|
|
67
|
+
'Auto-memory logs conversation turns into Hypatia and runs background consolidation on a dedicated model route.',
|
|
68
|
+
enable: 'Enable auto-memory',
|
|
69
|
+
autoApprove: "Auto-approve the agent's own hypatia commands",
|
|
70
|
+
autoApproveHint: 'Only plain hypatia calls with no pipe, redirect or chaining; this plugin\'s own writes never take that path. With it off, every retrieval raises an approval prompt. Takes effect after a profile reload.',
|
|
71
|
+
shelf: 'Memory shelf',
|
|
72
|
+
shelfHint: 'Logging, consolidation and the session-start rules preload all read and write this shelf; when it is not default, each session is told to pass --shelf to its hypatia commands. Takes effect after a profile reload. Progress is kept per shelf, so switching back resumes where that shelf left off; on a new shelf, each session is logged from its start the next time it is active, and consolidated again (model calls). Choices come from hypatia list, refreshed about once a minute.',
|
|
73
|
+
shelfLoading: 'Reading hypatia list…',
|
|
74
|
+
shelfLoadFailed: 'Unable to load the shelf list.',
|
|
75
|
+
shelfListingFailed: 'hypatia list failed; the list may be stale: {message}',
|
|
76
|
+
shelfDisconnected: 'not connected',
|
|
77
|
+
shelfOptionStatus: ' ({status})',
|
|
78
|
+
shelfNotListed: 'not in hypatia list',
|
|
79
|
+
shelfDisconnectedWarning: 'Shelf {shelf} is registered but not connected; writes will fail.',
|
|
80
|
+
shelfNotListedWarning: 'hypatia has no shelf named {shelf}; writes will fail until you run hypatia connect <dir> --name {shelf}.',
|
|
81
|
+
consolidationTitle: 'Consolidation candidate models',
|
|
82
|
+
modelSelectionHint: 'Choose one or more models. Every consolidation attempt, including a retry, rotates through this order; without a selection, conversations continue logging but consolidation stays idle.',
|
|
83
|
+
modelCatalogLoading: 'Loading available models…',
|
|
84
|
+
modelCatalogFailed: 'Unable to load available models.',
|
|
85
|
+
modelCatalogPartial: 'Some providers did not return a model catalog.',
|
|
86
|
+
modelCatalogEmpty: 'No models are currently available.',
|
|
87
|
+
selectedModels: 'Models used for rotation',
|
|
88
|
+
unavailableModels: 'Unavailable or no longer advertised',
|
|
89
|
+
modelUnavailable: 'Unavailable',
|
|
90
|
+
retry: 'Retry',
|
|
91
|
+
checkEveryTurns: 'Minimum turns between consolidations',
|
|
92
|
+
minNewTokens: 'Min new tokens',
|
|
93
|
+
cascadeBatchSize: 'Archive batch',
|
|
94
|
+
dedupMaxDistance: 'Relation distance',
|
|
95
|
+
cascadeHint: 'Every batch of same-tier summaries is archived into one entry a tier up. Relation distance is how near a new memory must be to an existing one to be worth judging a relationship.',
|
|
96
|
+
limitsTitle: 'Per-run consolidation size',
|
|
97
|
+
limitsHint: 'The input budget caps how much conversation is sent to the model (overflow keeps the most recent content); the output budget must fit the summary plus every work unit — too small and consolidation fails.',
|
|
98
|
+
maxInputTokens: 'Input budget (tokens)',
|
|
99
|
+
maxOutputTokens: 'Output budget (tokens)',
|
|
100
|
+
maxWorkUnitsPerRun: 'Max work units per run',
|
|
101
|
+
recallPreload: 'Recall: preload rules & taboos at session start',
|
|
102
|
+
advancedHint:
|
|
103
|
+
'Advanced fields (binaries, collector caps, queue tuning) can be edited directly in settings.yaml under the {ns} key.',
|
|
104
|
+
reset: 'Reset',
|
|
105
|
+
discard: 'Discard',
|
|
106
|
+
save: 'Save',
|
|
107
|
+
saving: 'Saving…',
|
|
108
|
+
saveFailed: 'Save failed: {message}',
|
|
109
|
+
readOnly: 'Read-only: settings document is not writable in this context.',
|
|
110
|
+
unsaved: 'Unsaved',
|
|
111
|
+
} satisfies Record<AutoMemoryLocaleKey, string>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shelf choices for the settings card.
|
|
3
|
+
*
|
|
4
|
+
* The Host publishes `hypatia list` as the read-only `hypatia-auto-memory-shelves`
|
|
5
|
+
* settings namespace (see `src/config.js`); the card reads it through the
|
|
6
|
+
* settings descriptor. Zero runtime imports, so it is unit-tested under
|
|
7
|
+
* `node:test` like `card-form.ts`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Namespace the Host publishes the shelf listing under. */
|
|
11
|
+
export const INVENTORY_NAMESPACE = 'hypatia-auto-memory-shelves'
|
|
12
|
+
|
|
13
|
+
/** Shelf hypatia uses when none is named. */
|
|
14
|
+
export const DEFAULT_SHELF = 'default'
|
|
15
|
+
|
|
16
|
+
/** One shelf as `hypatia list` reports it. */
|
|
17
|
+
export interface ShelfInfo {
|
|
18
|
+
name: string
|
|
19
|
+
path: string
|
|
20
|
+
connected: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The Host's latest listing; `error` is non-empty when it could not list. */
|
|
24
|
+
export interface ShelfInventory {
|
|
25
|
+
shelves: ShelfInfo[]
|
|
26
|
+
error: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Load the Host's latest listing for the settings card. */
|
|
30
|
+
export type LoadShelfInventory = () => Promise<ShelfInventory>
|
|
31
|
+
|
|
32
|
+
/** One dropdown option. */
|
|
33
|
+
export interface ShelfChoice {
|
|
34
|
+
name: string
|
|
35
|
+
path: string
|
|
36
|
+
/** False for a shelf that is registered but not connected. */
|
|
37
|
+
connected: boolean
|
|
38
|
+
/** False for a stored value the listing no longer reports. */
|
|
39
|
+
listed: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
43
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Pick the inventory namespace out of a settings descriptor.
|
|
48
|
+
*
|
|
49
|
+
* Reads the composition layer (`base`), which only the Host sets, rather than
|
|
50
|
+
* the resolved value: a stray user-layer section for this namespace would
|
|
51
|
+
* otherwise freeze the list.
|
|
52
|
+
* @param described - the `namespaces` array a settings `describe()` returns.
|
|
53
|
+
* @returns the listing, or undefined when the Host does not serve one.
|
|
54
|
+
*/
|
|
55
|
+
export function readShelfInventory(described: readonly unknown[]): ShelfInventory | undefined {
|
|
56
|
+
const view = described.find(entry => isRecord(entry) && entry.ns === INVENTORY_NAMESPACE)
|
|
57
|
+
if (!isRecord(view) || !isRecord(view.base)) return undefined
|
|
58
|
+
const { shelves, error } = view.base
|
|
59
|
+
return {
|
|
60
|
+
shelves: Array.isArray(shelves)
|
|
61
|
+
? shelves.flatMap((shelf): ShelfInfo[] => isRecord(shelf) && typeof shelf.name === 'string'
|
|
62
|
+
? [{
|
|
63
|
+
name: shelf.name,
|
|
64
|
+
path: typeof shelf.path === 'string' ? shelf.path : '',
|
|
65
|
+
connected: shelf.connected === true,
|
|
66
|
+
}]
|
|
67
|
+
: [])
|
|
68
|
+
: [],
|
|
69
|
+
error: typeof error === 'string' ? error : '',
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Every shelf the dropdown offers: the listing, plus the stored and composed
|
|
75
|
+
* values when the listing does not carry them, so the current choice always
|
|
76
|
+
* renders and never silently changes to the first option.
|
|
77
|
+
* @param shelves - the Host's listing.
|
|
78
|
+
* @param keep - values that must stay selectable (current draft, stored, composed).
|
|
79
|
+
* @returns options, listed shelves first in listing order.
|
|
80
|
+
*/
|
|
81
|
+
export function shelfChoices(shelves: readonly ShelfInfo[], keep: readonly string[]): ShelfChoice[] {
|
|
82
|
+
const choices: ShelfChoice[] = shelves.map(shelf => ({ ...shelf, listed: true }))
|
|
83
|
+
for (const name of keep) {
|
|
84
|
+
if (name === '' || choices.some(choice => choice.name === name)) continue
|
|
85
|
+
choices.push({ name, path: '', connected: false, listed: false })
|
|
86
|
+
}
|
|
87
|
+
return choices
|
|
88
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-only slot contract: this plugin contributes one card under
|
|
3
|
+
* `settings.plugin.item`, keyed by its settings namespace.
|
|
4
|
+
*
|
|
5
|
+
* The slot itself is declared by `@deepseek-ai/dsh-client-ui-settings-plugins`;
|
|
6
|
+
* we only need the type merges so TypeScript knows what `ctx.slots.register`
|
|
7
|
+
* expects here and what locale namespace the card consumes.
|
|
8
|
+
*/
|
|
9
|
+
import type {} from '@deepseek-ai/dsh-client-ui-slots'
|
|
10
|
+
import type { AutoMemoryLocaleKey } from './locales'
|
|
11
|
+
|
|
12
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
13
|
+
interface LocaleNamespaceMap {
|
|
14
|
+
/** Settings card copy for dsh-hypatia-auto-memory. */
|
|
15
|
+
'hypatia-auto-memory': AutoMemoryLocaleKey
|
|
16
|
+
}
|
|
17
|
+
}
|