@elinpf/dsh-ops-knowledge 0.4.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/README.i18n.yaml +6 -0
- package/README.md +48 -0
- package/README.zh.md +48 -0
- package/cordis.patch.yml +1 -0
- package/lib/client.d.ts +22 -0
- package/lib/client.d.ts.map +1 -0
- package/lib/client.js +62 -0
- package/lib/client.js.map +1 -0
- package/lib/doctrine.d.ts +39 -0
- package/lib/doctrine.d.ts.map +1 -0
- package/lib/doctrine.js +48 -0
- package/lib/doctrine.js.map +1 -0
- package/lib/index.d.ts +128 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +252 -0
- package/lib/index.js.map +1 -0
- package/lib/search.d.ts +19 -0
- package/lib/search.d.ts.map +1 -0
- package/lib/search.js +46 -0
- package/lib/search.js.map +1 -0
- package/lib/types.d.ts +65 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +10 -0
- package/lib/types.js.map +1 -0
- package/package.json +55 -0
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "@elinpf/dsh-ops-knowledge"
|
|
3
|
+
description:
|
|
4
|
+
zh: "排错知识库 — 排查收口沉淀为病例(症状→根因→修复)集中存 access hub,后续会话搜索复用"
|
|
5
|
+
en: "Troubleshooting knowledge base — resolved investigations distilled into cases (symptoms→root cause→fix), stored in the access hub and searched by later sessions"
|
|
6
|
+
---
|
package/README.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @elinpf/dsh-ops-knowledge
|
|
2
|
+
|
|
3
|
+
Troubleshooting knowledge base for DeepSeek Harness ops mode — distilled postmortem **cases** (`symptoms → root cause → fix`) stored centrally in the [ops-access-hub](../ops-access-hub/) (`/cases` routes), so a later session can recall a prior investigation instead of re-diagnosing from scratch.
|
|
4
|
+
|
|
5
|
+
## How it works
|
|
6
|
+
|
|
7
|
+
Three model-facing tools, plus prompt wiring through `ops-prompts`:
|
|
8
|
+
|
|
9
|
+
- **`knowledge_search`** — keyword search over the case index (title ×3 / tags ×2 / symptoms ×2, substring, case-insensitive), returning the top full cases. The doctrine tells the agent to search *before* starting a diagnosis.
|
|
10
|
+
- **`knowledge_record`** — distill a resolved investigation into a case; with an `id` it updates the existing case instead (the doctrine says: search first, update near-duplicates, create only when nothing matches). Beyond the conclusion (`symptoms` / `root_cause` / `fix`), a case can carry `methodology` — *how* the root cause was found (the discriminating steps/commands), for reuse in similar-but-not-identical situations — and a self-assessed `difficulty` (1–5); hard-won cases (≥3) are expected to record the methodology.
|
|
11
|
+
- **`knowledge_hit`** — mark a case as adopted by this investigation; `hitCount` ranks the session-start index, so useful cases float and unused ones sink.
|
|
12
|
+
|
|
13
|
+
Two prompt surfaces (registered via `ops-prompts`, same dual-mode `ctx.get`/`ctx.inject` resolution as ops-tool-trace):
|
|
14
|
+
|
|
15
|
+
- a static methodology section (search-first / record-on-resolve / hit-on-adopt discipline, plus the case quality bar);
|
|
16
|
+
- a once-per-session reminder at the first pre-step injecting the case index (title + symptoms, top 10 by hits). The reminder's `check` is synchronous, so the index is pre-fetched into memory at plugin start and refreshed after every mutation.
|
|
17
|
+
|
|
18
|
+
## Config
|
|
19
|
+
|
|
20
|
+
| Key | Default | Purpose |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `hubUrl` | env `ACCESS_HUB_URL` | hub base URL, e.g. `http://127.0.0.1:3090` |
|
|
23
|
+
| `hubToken` | env `ACCESS_HUB_READ_TOKEN` | hub token — the **read** token suffices (the hub deliberately accepts read-role writes on `/cases`; cases hold no secrets) |
|
|
24
|
+
|
|
25
|
+
With neither config nor env set, the plugin logs one line and no-ops — no tools, no prompts. When the hub is unreachable at runtime, tools return an error *result* (never a throw) and the reminder stays silent: knowledge problems must never break a session.
|
|
26
|
+
|
|
27
|
+
## Wiring
|
|
28
|
+
|
|
29
|
+
Preset plane: one row inside the `ops-orchestration` isolate realm group (it consumes `opsPrompts`):
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
- id: tool-ops-knowledge
|
|
33
|
+
name: '@elinpf/dsh-ops-knowledge'
|
|
34
|
+
# optional; env fallback covers it
|
|
35
|
+
config:
|
|
36
|
+
hubUrl: http://127.0.0.1:3090
|
|
37
|
+
hubToken: <read-token>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The shipped `ops` preset (`packages/ops/presets/ops/agent.cordis.yml`) already carries this row without config, driven by the process env.
|
|
41
|
+
|
|
42
|
+
## Testing
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npm run build # tsc → lib/
|
|
46
|
+
npx vitest run # scoring units, export shape, HMR unload, no-hub no-op,
|
|
47
|
+
# full tool chain against an in-process hub server
|
|
48
|
+
```
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# @elinpf/dsh-ops-knowledge
|
|
2
|
+
|
|
3
|
+
DeepSeek Harness 运维模式的排错知识库 —— 把排查收口后的结晶沉淀为**病例**(`症状 → 根因 → 修复`),集中存放在 [ops-access-hub](../ops-access-hub/)(`/cases` 路由),让后续会话直接复用历史结论,避免重复排查。
|
|
4
|
+
|
|
5
|
+
## 工作方式
|
|
6
|
+
|
|
7
|
+
三个模型工具,外加经 `ops-prompts` 的 prompt 接线:
|
|
8
|
+
|
|
9
|
+
- **`knowledge_search`** —— 按关键字搜病例索引(title ×3 / tags ×2 / symptoms ×2,子串、忽略大小写),返回相关度最高的病例全文。纪律要求 agent 动手排查前先搜。
|
|
10
|
+
- **`knowledge_record`** —— 把一次收口的排查提炼成病例;带 `id` 则更新旧病例(纪律:先查重,有近似旧病例就更新,没有才新建)。病例除结论(症状/根因/修复)外还可带 `methodology`(方法论:当时怎么查出来的,关键判别步骤——供"症状不同但问题同类"的场景复用)和 `difficulty`(1-5 难度自评);难度 ≥3 的病例必须写方法论。
|
|
11
|
+
- **`knowledge_hit`** —— 标记某病例被本次排查采用;`hitCount` 决定会话启动索引的排序,有用的病例浮上来,没用的沉底。
|
|
12
|
+
|
|
13
|
+
两个 prompt 面(经 `ops-prompts` 注册,与 ops-tool-trace 同款 `ctx.get`/`ctx.inject` 双模式解析):
|
|
14
|
+
|
|
15
|
+
- 静态 methodology 一节(先搜后沉淀、采用计数的纪律 + 病例质量要求);
|
|
16
|
+
- 每会话一次的启动 reminder:在第一个 pre-step 注入病例索引(title + 症状,按采用数取 top 10)。reminder 的 `check` 是同步签名,索引在插件启动时预取进内存、每次写操作后刷新。
|
|
17
|
+
|
|
18
|
+
## 配置
|
|
19
|
+
|
|
20
|
+
| 键 | 缺省 | 用途 |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `hubUrl` | 环境变量 `ACCESS_HUB_URL` | hub 地址,如 `http://127.0.0.1:3090` |
|
|
23
|
+
| `hubToken` | 环境变量 `ACCESS_HUB_READ_TOKEN` | hub token——**read** 令牌即可(hub 刻意放行 read 角色写 `/cases`;病例不含机密) |
|
|
24
|
+
|
|
25
|
+
配置和环境变量都没有时,插件记一行日志后整体 no-op(不挂工具不挂 prompt)。运行期 hub 不可达时,工具返回错误**结果**(绝不抛出)、reminder 静默——知识库故障绝不拖垮会话。
|
|
26
|
+
|
|
27
|
+
## 接线
|
|
28
|
+
|
|
29
|
+
preset plane:`ops-orchestration` isolate realm 组内加一行(它消费 `opsPrompts`):
|
|
30
|
+
|
|
31
|
+
```yaml
|
|
32
|
+
- id: tool-ops-knowledge
|
|
33
|
+
name: '@elinpf/dsh-ops-knowledge'
|
|
34
|
+
# 可选;环境变量回退已够用
|
|
35
|
+
config:
|
|
36
|
+
hubUrl: http://127.0.0.1:3090
|
|
37
|
+
hubToken: <read-token>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
随套件发布的 `ops` preset(`packages/ops/presets/ops/agent.cordis.yml`)已带这一行且无 config,由进程环境变量驱动。
|
|
41
|
+
|
|
42
|
+
## 测试
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
npm run build # tsc → lib/
|
|
46
|
+
npx vitest run # 打分单测、export shape、HMR 卸载、无 hub no-op、
|
|
47
|
+
# 对 in-process hub server 的全链路工具测试
|
|
48
|
+
```
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
package/lib/client.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HTTP client for the hub's `/cases` routes. Bearer-token auth,
|
|
3
|
+
* JSON in/out, errors surface as thrown Errors with the hub's message.
|
|
4
|
+
*
|
|
5
|
+
* @module @elinpf/dsh-ops-knowledge/client
|
|
6
|
+
*/
|
|
7
|
+
import type { CaseIndexRow, CaseInput, CaseRecord } from './types.js';
|
|
8
|
+
export declare class KnowledgeClient {
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
private readonly token;
|
|
11
|
+
constructor(opts: {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
token: string;
|
|
14
|
+
});
|
|
15
|
+
private request;
|
|
16
|
+
listCases(): Promise<CaseIndexRow[]>;
|
|
17
|
+
getCase(id: string): Promise<CaseRecord>;
|
|
18
|
+
/** Create (no id) or update (id given) a case. Returns the case id. */
|
|
19
|
+
putCase(input: CaseInput, id?: string): Promise<string>;
|
|
20
|
+
hit(id: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAErE,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;gBAElB,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;YAKtC,OAAO;IA4BrB,SAAS,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAIpC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAIxC,uEAAuE;IACjE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAS7D,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|
package/lib/client.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal HTTP client for the hub's `/cases` routes. Bearer-token auth,
|
|
3
|
+
* JSON in/out, errors surface as thrown Errors with the hub's message.
|
|
4
|
+
*
|
|
5
|
+
* @module @elinpf/dsh-ops-knowledge/client
|
|
6
|
+
*/
|
|
7
|
+
export class KnowledgeClient {
|
|
8
|
+
baseUrl;
|
|
9
|
+
token;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
|
|
12
|
+
this.token = opts.token;
|
|
13
|
+
}
|
|
14
|
+
async request(method, path, body) {
|
|
15
|
+
let res;
|
|
16
|
+
try {
|
|
17
|
+
res = await fetch(this.baseUrl + path, {
|
|
18
|
+
method,
|
|
19
|
+
headers: {
|
|
20
|
+
authorization: `Bearer ${this.token}`,
|
|
21
|
+
...(body === undefined ? {} : { 'content-type': 'application/json' }),
|
|
22
|
+
},
|
|
23
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw new Error(`hub unreachable: ${err.message}`);
|
|
28
|
+
}
|
|
29
|
+
const text = await res.text();
|
|
30
|
+
let parsed;
|
|
31
|
+
try {
|
|
32
|
+
parsed = JSON.parse(text);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error(`hub returned non-JSON (HTTP ${res.status})`);
|
|
36
|
+
}
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const message = parsed.error ?? `HTTP ${res.status}`;
|
|
39
|
+
throw new Error(`hub: ${message}`);
|
|
40
|
+
}
|
|
41
|
+
return parsed;
|
|
42
|
+
}
|
|
43
|
+
listCases() {
|
|
44
|
+
return this.request('GET', '/cases');
|
|
45
|
+
}
|
|
46
|
+
getCase(id) {
|
|
47
|
+
return this.request('GET', `/cases/${encodeURIComponent(id)}`);
|
|
48
|
+
}
|
|
49
|
+
/** Create (no id) or update (id given) a case. Returns the case id. */
|
|
50
|
+
async putCase(input, id) {
|
|
51
|
+
if (id === undefined) {
|
|
52
|
+
const res = await this.request('POST', '/cases', input);
|
|
53
|
+
return res.id;
|
|
54
|
+
}
|
|
55
|
+
await this.request('PUT', `/cases/${encodeURIComponent(id)}`, input);
|
|
56
|
+
return id;
|
|
57
|
+
}
|
|
58
|
+
hit(id) {
|
|
59
|
+
return this.request('POST', `/cases/${encodeURIComponent(id)}/hit`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,OAAO,eAAe;IACT,OAAO,CAAQ;IACf,KAAK,CAAQ;IAE9B,YAAY,IAAwC;QAClD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAC/C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACzB,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY,EAAE,IAAc;QACnE,IAAI,GAAa,CAAA;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE;gBACrC,MAAM;gBACN,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;oBACrC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;iBACtE;gBACD,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;aAC5D,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,oBAAqB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAA;QAC/D,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;QAC7B,IAAI,MAAe,CAAA;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;QAC/D,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GAAI,MAA6B,CAAC,KAAK,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAA;YAC5E,MAAM,IAAI,KAAK,CAAC,QAAQ,OAAO,EAAE,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,MAAW,CAAA;IACpB,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;IACtC,CAAC;IAED,OAAO,CAAC,EAAU;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAChE,CAAC;IAED,uEAAuE;IACvE,KAAK,CAAC,OAAO,CAAC,KAAgB,EAAE,EAAW;QACzC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAiB,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAA;YACvE,OAAO,GAAG,CAAC,EAAE,CAAA;QACf,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;QACpE,OAAO,EAAE,CAAA;IACX,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,kBAAkB,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;IACrE,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The knowledge doctrine — one home per sentence, same discipline as
|
|
3
|
+
* ops-tool-trace's doctrine.ts: surfaces compose from these canonical
|
|
4
|
+
* sentences instead of re-phrasing them.
|
|
5
|
+
*
|
|
6
|
+
* @module @elinpf/dsh-ops-knowledge/doctrine
|
|
7
|
+
*/
|
|
8
|
+
/** What the knowledge base is, in one line. */
|
|
9
|
+
export declare const KB_ONE_LINER = "\u6392\u9519\u77E5\u8BC6\u5E93: \u5386\u53F2\u6392\u67E5\u6C89\u6DC0\u7684\u75C5\u4F8B (\u75C7\u72B6 \u2192 \u6839\u56E0 \u2192 \u4FEE\u590D), \u5B58\u5728 access hub \u91CC\u8DE8\u4F1A\u8BDD\u5171\u4EAB";
|
|
10
|
+
/** The search-first rule, quoted by the methodology section and tool descriptions. */
|
|
11
|
+
export declare const SEARCH_FIRST_RULE = "\u52A8\u624B\u6392\u67E5\u524D\u5148 knowledge_search \u67E5\u5386\u53F2\u75C5\u4F8B\u2014\u2014\u547D\u4E2D\u7684\u75C5\u4F8B\u76F4\u63A5\u7ED9\u6839\u56E0\u548C\u4FEE\u590D, \u4E0D\u7528\u4ECE\u5934\u6392\u67E5";
|
|
12
|
+
/** The record-on-resolve rule. */
|
|
13
|
+
export declare const RECORD_RULE = "\u5168\u6848\u6536\u53E3 (trace resolve) \u540E, \u82E5\u6839\u56E0+\u4FEE\u590D\u6709\u53EF\u590D\u7528\u4EF7\u503C: \u5148 knowledge_search \u67E5\u91CD, \u518D knowledge_record \u6C89\u6DC0\u2014\u2014\u6709\u8FD1\u4F3C\u65E7\u75C5\u4F8B\u5C31\u5E26 id \u66F4\u65B0\u5B83, \u6CA1\u6709\u624D\u65B0\u5EFA";
|
|
14
|
+
/** The case quality bar: the three questions a reusable case answers. */
|
|
15
|
+
export declare const QUALITY_BAR = "\u75C5\u4F8B\u8981\u56DE\u7B54\u4E09\u4E2A\u95EE\u9898: symptoms \u8BA9\u641C\u5F97\u5230 (\u6BCF\u6761 = \u75C7\u72B6\u7C7B\u5173\u952E\u8BCD + \u5F53\u65F6\u89C2\u5BDF\u5230\u7684\u5177\u4F53\u503C, \u5982 \"\u5C11\u76D8: lsblk \u5E94 7 \u5757\u53EA\u8BC6\u522B 6 \u5757\"\u2014\u2014\u7C7B\u8BCD\u8BA9\u8DE8\u57DF\u540C\u7C7B\u95EE\u9898\u4E5F\u80FD\u547D\u4E2D, \u5177\u4F53\u503C\u951A\u5B9A\u62A5\u9519\u539F\u6587/\u6307\u6807\u503C), root_cause+fix \u8BA9\u76F4\u63A5\u7528 (\u6839\u56E0\u5230\u7269\u7406\u5C42, \u4FEE\u590D\u53EF\u6267\u884C), methodology \u8BA9\u76F8\u4F3C\u573A\u666F\u590D\u7528\u65B9\u6CD5 (\u54EA\u4E00\u6B65\u5224\u522B\u4E86\u5047\u8BBE\u3001\u54EA\u6761\u547D\u4EE4\u662F\u5173\u952E)\u3002\u6392\u67E5\u7684\u4E2D\u95F4\u8FC7\u7A0B\u5C5E\u4E8E trace \u6811, \u77E5\u8BC6\u5E93\u53EA\u5B58\u7ED3\u6676";
|
|
16
|
+
/** Difficulty anchor text, shared by the methodology section and the tool parameter description. */
|
|
17
|
+
export declare const DIFFICULTY_ANCHORS = "difficulty \u662F\u6392\u67E5\u96BE\u5EA6\u81EA\u8BC4 1-5: 1=\u770B\u4E00\u773C\u5C31\u77E5\u9053; 2=\u5E38\u89C4\u8DEF\u5F84\u4E00\u5C0F\u65F6\u5185; 3=\u591A\u8F6E\u5047\u8BBE\u9A8C\u8BC1; 4=\u8DE8\u7EC4\u4EF6\u6DF1\u6316; 5=\u7F55\u89C1/\u590D\u73B0\u56F0\u96BE, \u4E00\u5929\u4EE5\u4E0A\u6216\u591A\u4EBA\u4F1A\u8BCA\u3002\u96BE\u5EA6\u8D8A\u9AD8\u8D8A\u503C\u5F97\u5199 methodology";
|
|
18
|
+
/** The hit feedback rule. */
|
|
19
|
+
export declare const HIT_RULE = "\u91C7\u7528\u4E86\u67D0\u75C5\u4F8B\u7684\u7ED3\u8BBA \u2192 knowledge_hit \u8BB0\u4E00\u6B21\u91C7\u7528; \u8D8A\u6709\u7528\u7684\u75C5\u4F8B\u5728\u7D22\u5F15\u91CC\u6D6E\u5F97\u8D8A\u9AD8";
|
|
20
|
+
/** One-liner descriptions for the three tools. */
|
|
21
|
+
export declare const SEARCH_TOOL_DESCRIPTION = "\u641C\u6392\u9519\u77E5\u8BC6\u5E93\u7684\u5386\u53F2\u75C5\u4F8B (\u75C7\u72B6 \u2192 \u6839\u56E0 \u2192 \u4FEE\u590D)\u3002\u52A8\u624B\u6392\u67E5\u524D\u5148 knowledge_search \u67E5\u5386\u53F2\u75C5\u4F8B\u2014\u2014\u547D\u4E2D\u7684\u75C5\u4F8B\u76F4\u63A5\u7ED9\u6839\u56E0\u548C\u4FEE\u590D, \u4E0D\u7528\u4ECE\u5934\u6392\u67E5\u3002query \u4F20 \"*\" \u5217\u51FA\u5168\u90E8\u75C5\u4F8B\u3002";
|
|
22
|
+
export declare const RECORD_TOOL_DESCRIPTION = "\u6C89\u6DC0\u4E00\u6761\u6392\u9519\u75C5\u4F8B\u5230\u77E5\u8BC6\u5E93\u3002\u5168\u6848\u6536\u53E3 (trace resolve) \u540E, \u82E5\u6839\u56E0+\u4FEE\u590D\u6709\u53EF\u590D\u7528\u4EF7\u503C: \u5148 knowledge_search \u67E5\u91CD, \u518D knowledge_record \u6C89\u6DC0\u2014\u2014\u6709\u8FD1\u4F3C\u65E7\u75C5\u4F8B\u5C31\u5E26 id \u66F4\u65B0\u5B83, \u6CA1\u6709\u624D\u65B0\u5EFA\u3002";
|
|
23
|
+
export declare const HIT_TOOL_DESCRIPTION = "\u6807\u8BB0\u67D0\u6761\u5386\u53F2\u75C5\u4F8B\u88AB\u672C\u6B21\u6392\u67E5\u91C7\u7528 (hit_count++, \u8BA9\u6709\u7528\u7684\u75C5\u4F8B\u5728\u7D22\u5F15\u91CC\u6D6E\u5F97\u66F4\u9AD8)\u3002";
|
|
24
|
+
/**
|
|
25
|
+
* Minimal always-on core for the system prompt (registered through
|
|
26
|
+
* ops-prompts as a methodology section).
|
|
27
|
+
*/
|
|
28
|
+
export declare const STATIC_PROMPT: string;
|
|
29
|
+
/**
|
|
30
|
+
* The session-start index reminder body. Rendered from the cached index,
|
|
31
|
+
* fired once per session at the first pre-step.
|
|
32
|
+
*/
|
|
33
|
+
export declare function indexReminderText(rows: Array<{
|
|
34
|
+
id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
symptoms: string[];
|
|
37
|
+
hitCount: number;
|
|
38
|
+
}>): string;
|
|
39
|
+
//# sourceMappingURL=doctrine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctrine.d.ts","sourceRoot":"","sources":["../src/doctrine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+CAA+C;AAC/C,eAAO,MAAM,YAAY,gNAA0D,CAAA;AAEnF,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,yNAAyD,CAAA;AAEvF,kCAAkC;AAClC,eAAO,MAAM,WAAW,uTACsF,CAAA;AAE9G,yEAAyE;AACzE,eAAO,MAAM,WAAW,y0BACkM,CAAA;AAE1N,oGAAoG;AACpG,eAAO,MAAM,kBAAkB,uYAC+E,CAAA;AAE9G,6BAA6B;AAC7B,eAAO,MAAM,QAAQ,qMAAoD,CAAA;AAEzE,kDAAkD;AAClD,eAAO,MAAM,uBAAuB,2ZAAwE,CAAA;AAC5G,eAAO,MAAM,uBAAuB,2YAAiC,CAAA;AACrE,eAAO,MAAM,oBAAoB,yMAAmD,CAAA;AAEpF;;;GAGG;AACH,eAAO,MAAM,aAAa,QAQd,CAAA;AAEZ;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAM1H"}
|
package/lib/doctrine.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The knowledge doctrine — one home per sentence, same discipline as
|
|
3
|
+
* ops-tool-trace's doctrine.ts: surfaces compose from these canonical
|
|
4
|
+
* sentences instead of re-phrasing them.
|
|
5
|
+
*
|
|
6
|
+
* @module @elinpf/dsh-ops-knowledge/doctrine
|
|
7
|
+
*/
|
|
8
|
+
/** What the knowledge base is, in one line. */
|
|
9
|
+
export const KB_ONE_LINER = '排错知识库: 历史排查沉淀的病例 (症状 → 根因 → 修复), 存在 access hub 里跨会话共享';
|
|
10
|
+
/** The search-first rule, quoted by the methodology section and tool descriptions. */
|
|
11
|
+
export const SEARCH_FIRST_RULE = '动手排查前先 knowledge_search 查历史病例——命中的病例直接给根因和修复, 不用从头排查';
|
|
12
|
+
/** The record-on-resolve rule. */
|
|
13
|
+
export const RECORD_RULE = '全案收口 (trace resolve) 后, 若根因+修复有可复用价值: 先 knowledge_search 查重, 再 knowledge_record 沉淀——有近似旧病例就带 id 更新它, 没有才新建';
|
|
14
|
+
/** The case quality bar: the three questions a reusable case answers. */
|
|
15
|
+
export const QUALITY_BAR = '病例要回答三个问题: symptoms 让搜得到 (每条 = 症状类关键词 + 当时观察到的具体值, 如 "少盘: lsblk 应 7 块只识别 6 块"——类词让跨域同类问题也能命中, 具体值锚定报错原文/指标值), root_cause+fix 让直接用 (根因到物理层, 修复可执行), methodology 让相似场景复用方法 (哪一步判别了假设、哪条命令是关键)。排查的中间过程属于 trace 树, 知识库只存结晶';
|
|
16
|
+
/** Difficulty anchor text, shared by the methodology section and the tool parameter description. */
|
|
17
|
+
export const DIFFICULTY_ANCHORS = 'difficulty 是排查难度自评 1-5: 1=看一眼就知道; 2=常规路径一小时内; 3=多轮假设验证; 4=跨组件深挖; 5=罕见/复现困难, 一天以上或多人会诊。难度越高越值得写 methodology';
|
|
18
|
+
/** The hit feedback rule. */
|
|
19
|
+
export const HIT_RULE = '采用了某病例的结论 → knowledge_hit 记一次采用; 越有用的病例在索引里浮得越高';
|
|
20
|
+
/** One-liner descriptions for the three tools. */
|
|
21
|
+
export const SEARCH_TOOL_DESCRIPTION = `搜排错知识库的历史病例 (症状 → 根因 → 修复)。${SEARCH_FIRST_RULE}。query 传 "*" 列出全部病例。`;
|
|
22
|
+
export const RECORD_TOOL_DESCRIPTION = `沉淀一条排错病例到知识库。${RECORD_RULE}。`;
|
|
23
|
+
export const HIT_TOOL_DESCRIPTION = '标记某条历史病例被本次排查采用 (hit_count++, 让有用的病例在索引里浮得更高)。';
|
|
24
|
+
/**
|
|
25
|
+
* Minimal always-on core for the system prompt (registered through
|
|
26
|
+
* ops-prompts as a methodology section).
|
|
27
|
+
*/
|
|
28
|
+
export const STATIC_PROMPT = [
|
|
29
|
+
'## knowledge — 排错知识库',
|
|
30
|
+
KB_ONE_LINER + '。',
|
|
31
|
+
`- ${SEARCH_FIRST_RULE}。`,
|
|
32
|
+
`- ${RECORD_RULE}。`,
|
|
33
|
+
`- ${QUALITY_BAR}。`,
|
|
34
|
+
`- 难度自评 difficulty 1-5; 难度 ≥3 的病例一定要写 methodology (怎么查出来的), 那才是最难复得的部分。`,
|
|
35
|
+
`- ${HIT_RULE}。`,
|
|
36
|
+
].join('\n');
|
|
37
|
+
/**
|
|
38
|
+
* The session-start index reminder body. Rendered from the cached index,
|
|
39
|
+
* fired once per session at the first pre-step.
|
|
40
|
+
*/
|
|
41
|
+
export function indexReminderText(rows) {
|
|
42
|
+
const lines = rows.map((r) => `- ${r.title} — 症状: ${r.symptoms.join('; ') || '(未记录)'} [采用 ${r.hitCount} 次]`);
|
|
43
|
+
return [
|
|
44
|
+
`## 排错知识库 — ${rows.length} 条历史病例 (按采用次数排序, knowledge_search 查全文)`,
|
|
45
|
+
...lines,
|
|
46
|
+
].join('\n');
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=doctrine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctrine.js","sourceRoot":"","sources":["../src/doctrine.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,+CAA+C;AAC/C,MAAM,CAAC,MAAM,YAAY,GAAG,uDAAuD,CAAA;AAEnF,sFAAsF;AACtF,MAAM,CAAC,MAAM,iBAAiB,GAAG,sDAAsD,CAAA;AAEvF,kCAAkC;AAClC,MAAM,CAAC,MAAM,WAAW,GACtB,4GAA4G,CAAA;AAE9G,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GACtB,wNAAwN,CAAA;AAE1N,oGAAoG;AACpG,MAAM,CAAC,MAAM,kBAAkB,GAC7B,4GAA4G,CAAA;AAE9G,6BAA6B;AAC7B,MAAM,CAAC,MAAM,QAAQ,GAAG,iDAAiD,CAAA;AAEzE,kDAAkD;AAClD,MAAM,CAAC,MAAM,uBAAuB,GAAG,8BAA8B,iBAAiB,sBAAsB,CAAA;AAC5G,MAAM,CAAC,MAAM,uBAAuB,GAAG,gBAAgB,WAAW,GAAG,CAAA;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,gDAAgD,CAAA;AAEpF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,sBAAsB;IACtB,YAAY,GAAG,GAAG;IAClB,KAAK,iBAAiB,GAAG;IACzB,KAAK,WAAW,GAAG;IACnB,KAAK,WAAW,GAAG;IACnB,wEAAwE;IACxE,KAAK,QAAQ,GAAG;CACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAEZ;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAgF;IAChH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,OAAO,QAAQ,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAA;IAC5G,OAAO;QACL,cAAc,IAAI,CAAC,MAAM,wCAAwC;QACjE,GAAG,KAAK;KACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ops-knowledge: a troubleshooting knowledge base backed by the access hub.
|
|
3
|
+
*
|
|
4
|
+
* Three model-facing tools — `knowledge_search` (search past postmortem
|
|
5
|
+
* cases before diagnosing), `knowledge_record` (distill a resolved
|
|
6
|
+
* investigation into a case), `knowledge_hit` (mark a case as useful, so the
|
|
7
|
+
* valuable ones float). A session-start reminder injects the case index
|
|
8
|
+
* (title + symptoms, ranked by hits) through ops-prompts, so later sessions
|
|
9
|
+
* see prior conclusions without being asked.
|
|
10
|
+
*
|
|
11
|
+
* The hub holds the durable data; this plugin is a thin, stateless client
|
|
12
|
+
* plus prompt wiring. When no hub is configured the plugin no-ops; when the
|
|
13
|
+
* hub is unreachable the tools return an error result — knowledge problems
|
|
14
|
+
* must never break a session.
|
|
15
|
+
*
|
|
16
|
+
* @module @elinpf/dsh-ops-knowledge
|
|
17
|
+
*/
|
|
18
|
+
import z from '@deepseek-ai/schemastery';
|
|
19
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
20
|
+
import type { OpsPromptsHandle } from '@elinpf/dsh-ops-prompts';
|
|
21
|
+
declare module '@deepseek-ai/cordis' {
|
|
22
|
+
interface Context {
|
|
23
|
+
opsPrompts?: OpsPromptsHandle;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
declare const name = "ops-knowledge";
|
|
27
|
+
declare const inject: string[];
|
|
28
|
+
interface Config {
|
|
29
|
+
/** Hub base URL, e.g. http://127.0.0.1:3090. Falls back to env ACCESS_HUB_URL. */
|
|
30
|
+
hubUrl?: string;
|
|
31
|
+
/** Hub token (read role is enough — /cases accepts read+ writes). Falls back to env ACCESS_HUB_READ_TOKEN. */
|
|
32
|
+
hubToken?: string;
|
|
33
|
+
}
|
|
34
|
+
declare const Config: z<Schemastery.ObjectS<{
|
|
35
|
+
hubUrl: z<string, string>;
|
|
36
|
+
hubToken: z<string, string>;
|
|
37
|
+
}>, Schemastery.ObjectT<{
|
|
38
|
+
hubUrl: z<string, string>;
|
|
39
|
+
hubToken: z<string, string>;
|
|
40
|
+
}>>;
|
|
41
|
+
export declare const outputSchemaSpec: {
|
|
42
|
+
readonly type: "object";
|
|
43
|
+
readonly additionalProperties: false;
|
|
44
|
+
readonly properties: {
|
|
45
|
+
readonly action: {
|
|
46
|
+
readonly type: "string";
|
|
47
|
+
readonly required: true;
|
|
48
|
+
};
|
|
49
|
+
readonly note: {
|
|
50
|
+
readonly type: "string";
|
|
51
|
+
};
|
|
52
|
+
readonly error: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
};
|
|
55
|
+
readonly id: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
};
|
|
58
|
+
readonly matches: {
|
|
59
|
+
readonly type: "array";
|
|
60
|
+
readonly items: {
|
|
61
|
+
readonly type: "object";
|
|
62
|
+
readonly additionalProperties: false;
|
|
63
|
+
readonly properties: {
|
|
64
|
+
readonly id: {
|
|
65
|
+
readonly type: "string";
|
|
66
|
+
readonly required: true;
|
|
67
|
+
};
|
|
68
|
+
readonly title: {
|
|
69
|
+
readonly type: "string";
|
|
70
|
+
readonly required: true;
|
|
71
|
+
};
|
|
72
|
+
readonly symptoms: {
|
|
73
|
+
readonly type: "array";
|
|
74
|
+
readonly items: {
|
|
75
|
+
readonly type: "string";
|
|
76
|
+
};
|
|
77
|
+
readonly required: true;
|
|
78
|
+
};
|
|
79
|
+
readonly rootCause: {
|
|
80
|
+
readonly type: "string";
|
|
81
|
+
readonly required: true;
|
|
82
|
+
};
|
|
83
|
+
readonly fix: {
|
|
84
|
+
readonly type: "string";
|
|
85
|
+
readonly required: true;
|
|
86
|
+
};
|
|
87
|
+
readonly evidence: {
|
|
88
|
+
readonly type: "string";
|
|
89
|
+
};
|
|
90
|
+
readonly methodology: {
|
|
91
|
+
readonly type: "string";
|
|
92
|
+
};
|
|
93
|
+
readonly difficulty: {
|
|
94
|
+
readonly type: "integer";
|
|
95
|
+
};
|
|
96
|
+
readonly tags: {
|
|
97
|
+
readonly type: "array";
|
|
98
|
+
readonly items: {
|
|
99
|
+
readonly type: "string";
|
|
100
|
+
};
|
|
101
|
+
readonly required: true;
|
|
102
|
+
};
|
|
103
|
+
readonly environment: {
|
|
104
|
+
readonly type: "string";
|
|
105
|
+
};
|
|
106
|
+
readonly hitCount: {
|
|
107
|
+
readonly type: "integer";
|
|
108
|
+
readonly required: true;
|
|
109
|
+
};
|
|
110
|
+
readonly score: {
|
|
111
|
+
readonly type: "number";
|
|
112
|
+
readonly required: true;
|
|
113
|
+
};
|
|
114
|
+
readonly updatedAt: {
|
|
115
|
+
readonly type: "string";
|
|
116
|
+
readonly required: true;
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
};
|
|
123
|
+
declare function apply(ctx: Context, config: Config): void;
|
|
124
|
+
export { Config, apply, inject, name };
|
|
125
|
+
export * from './types.js';
|
|
126
|
+
export { rankCases, queryTokens, scoreRow } from './search.js';
|
|
127
|
+
export { KnowledgeClient } from './client.js';
|
|
128
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAM/D,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,UAAU,CAAC,EAAE,gBAAgB,CAAA;KAC9B;CACF;AAID,QAAA,MAAM,IAAI,kBAAkB,CAAA;AAC5B,QAAA,MAAM,MAAM,UAAY,CAAA;AAIxB,UAAU,MAAM;IACd,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,QAAA,MAAM,MAAM;;;;;;GAGV,CAAA;AAsCF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAgB,CAAA;AAwB7C,iBAAS,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAuKjD;AAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;AACtC,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ops-knowledge: a troubleshooting knowledge base backed by the access hub.
|
|
3
|
+
*
|
|
4
|
+
* Three model-facing tools — `knowledge_search` (search past postmortem
|
|
5
|
+
* cases before diagnosing), `knowledge_record` (distill a resolved
|
|
6
|
+
* investigation into a case), `knowledge_hit` (mark a case as useful, so the
|
|
7
|
+
* valuable ones float). A session-start reminder injects the case index
|
|
8
|
+
* (title + symptoms, ranked by hits) through ops-prompts, so later sessions
|
|
9
|
+
* see prior conclusions without being asked.
|
|
10
|
+
*
|
|
11
|
+
* The hub holds the durable data; this plugin is a thin, stateless client
|
|
12
|
+
* plus prompt wiring. When no hub is configured the plugin no-ops; when the
|
|
13
|
+
* hub is unreachable the tools return an error result — knowledge problems
|
|
14
|
+
* must never break a session.
|
|
15
|
+
*
|
|
16
|
+
* @module @elinpf/dsh-ops-knowledge
|
|
17
|
+
*/
|
|
18
|
+
import z from '@deepseek-ai/schemastery';
|
|
19
|
+
import { defineTool } from '@deepseek-ai/dsh-tools';
|
|
20
|
+
import { KnowledgeClient } from './client.js';
|
|
21
|
+
import { DIFFICULTY_ANCHORS, HIT_TOOL_DESCRIPTION, RECORD_TOOL_DESCRIPTION, SEARCH_TOOL_DESCRIPTION, STATIC_PROMPT, indexReminderText } from './doctrine.js';
|
|
22
|
+
import { rankCases } from './search.js';
|
|
23
|
+
// ── Plugin identity ───────────────────────────────────────────────────────────
|
|
24
|
+
const name = 'ops-knowledge';
|
|
25
|
+
const inject = ['tools'];
|
|
26
|
+
const Config = z.object({
|
|
27
|
+
hubUrl: z.string(),
|
|
28
|
+
hubToken: z.string(),
|
|
29
|
+
});
|
|
30
|
+
// ── Shared output schema ─────────────────────────────────────────────────────
|
|
31
|
+
const MATCH_SCHEMA = {
|
|
32
|
+
type: 'object',
|
|
33
|
+
additionalProperties: false,
|
|
34
|
+
properties: {
|
|
35
|
+
id: { type: 'string', required: true },
|
|
36
|
+
title: { type: 'string', required: true },
|
|
37
|
+
symptoms: { type: 'array', items: { type: 'string' }, required: true },
|
|
38
|
+
rootCause: { type: 'string', required: true },
|
|
39
|
+
fix: { type: 'string', required: true },
|
|
40
|
+
evidence: { type: 'string' },
|
|
41
|
+
methodology: { type: 'string' },
|
|
42
|
+
difficulty: { type: 'integer' },
|
|
43
|
+
tags: { type: 'array', items: { type: 'string' }, required: true },
|
|
44
|
+
environment: { type: 'string' },
|
|
45
|
+
hitCount: { type: 'integer', required: true },
|
|
46
|
+
score: { type: 'number', required: true },
|
|
47
|
+
updatedAt: { type: 'string', required: true },
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
const OUTPUT_SCHEMA = {
|
|
51
|
+
type: 'object',
|
|
52
|
+
additionalProperties: false,
|
|
53
|
+
properties: {
|
|
54
|
+
action: { type: 'string', required: true },
|
|
55
|
+
note: { type: 'string' },
|
|
56
|
+
error: { type: 'string' },
|
|
57
|
+
id: { type: 'string' },
|
|
58
|
+
matches: { type: 'array', items: MATCH_SCHEMA },
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
// Exported for tests: lets a spec validate results through dsh-tools' real
|
|
62
|
+
// schema validator (the runtime rejects undeclared keys on tool output).
|
|
63
|
+
export const outputSchemaSpec = OUTPUT_SCHEMA;
|
|
64
|
+
function renderResult(value) {
|
|
65
|
+
if (value.error)
|
|
66
|
+
return `knowledge ${value.action} 失败: ${value.error}`;
|
|
67
|
+
if (value.matches) {
|
|
68
|
+
if (value.matches.length === 0)
|
|
69
|
+
return '没有命中的历史病例。';
|
|
70
|
+
return value.matches
|
|
71
|
+
.map((m, i) => [
|
|
72
|
+
`### ${i + 1}. ${m.title} [相关度 ${m.score} · 采用 ${m.hitCount} 次${m.difficulty !== undefined ? ` · 难度 ${m.difficulty}/5` : ''} · id: ${m.id}]`,
|
|
73
|
+
`症状: ${m.symptoms.join('; ')}`,
|
|
74
|
+
`根因: ${m.rootCause}`,
|
|
75
|
+
`修复: ${m.fix}`,
|
|
76
|
+
...(m.methodology ? [`方法论: ${m.methodology}`] : []),
|
|
77
|
+
...(m.evidence ? [`证据: ${m.evidence}`] : []),
|
|
78
|
+
].join('\n'))
|
|
79
|
+
.join('\n\n');
|
|
80
|
+
}
|
|
81
|
+
return value.note ?? 'ok';
|
|
82
|
+
}
|
|
83
|
+
const render = (_args, value) => [{ type: 'text', text: renderResult(value) }];
|
|
84
|
+
// ── Plugin body ──────────────────────────────────────────────────────────────
|
|
85
|
+
function apply(ctx, config) {
|
|
86
|
+
const logger = ctx.logger('ops-knowledge');
|
|
87
|
+
const hubUrl = (config.hubUrl || process.env.ACCESS_HUB_URL || '').replace(/\/+$/, '');
|
|
88
|
+
const hubToken = config.hubToken || process.env.ACCESS_HUB_READ_TOKEN || '';
|
|
89
|
+
if (hubUrl === '' || hubToken === '') {
|
|
90
|
+
logger.info('no hub configured (hubUrl/hubToken or ACCESS_HUB_URL/ACCESS_HUB_READ_TOKEN) — knowledge base disabled');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const client = new KnowledgeClient({ baseUrl: hubUrl, token: hubToken });
|
|
94
|
+
// The case index cache feeds the session-start reminder (whose check is
|
|
95
|
+
// synchronous). Refreshed at boot and after every successful mutation;
|
|
96
|
+
// failures keep the stale cache — a reminder with old data beats none.
|
|
97
|
+
let indexCache = [];
|
|
98
|
+
const refreshIndex = () => {
|
|
99
|
+
client.listCases().then((rows) => { indexCache = rows; }).catch((err) => {
|
|
100
|
+
logger.warn('case index refresh failed: %s', err.message);
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
refreshIndex();
|
|
104
|
+
// Sessions that already received the index reminder (fire once per session).
|
|
105
|
+
const remindedSessions = new Set();
|
|
106
|
+
ctx.effect(() => () => { remindedSessions.clear(); indexCache = []; });
|
|
107
|
+
const fail = (action, err) => ({
|
|
108
|
+
action,
|
|
109
|
+
error: err.message,
|
|
110
|
+
});
|
|
111
|
+
ctx.effect(() => ctx.tools.register(defineTool({
|
|
112
|
+
name: 'knowledge_search',
|
|
113
|
+
description: SEARCH_TOOL_DESCRIPTION,
|
|
114
|
+
parameters: {
|
|
115
|
+
query: { type: 'string', required: true, description: '症状/组件关键字, 如 "csi stuck ceph" 或报错原文片段。传 "*" 列出全部病例 (按采用次数排序)。' },
|
|
116
|
+
limit: { type: 'integer', description: '最多返回几条 (默认 5)。' },
|
|
117
|
+
},
|
|
118
|
+
output: { schema: OUTPUT_SCHEMA, render },
|
|
119
|
+
async execute(args) {
|
|
120
|
+
try {
|
|
121
|
+
const index = await client.listCases();
|
|
122
|
+
indexCache = index;
|
|
123
|
+
// "*" lists everything (browse intent), ranked by adoption count.
|
|
124
|
+
const ranked = args.query.trim() === '*'
|
|
125
|
+
? [...index].sort((a, b) => b.hitCount - a.hitCount).map((row) => ({ row, score: 0 }))
|
|
126
|
+
: rankCases(index, args.query);
|
|
127
|
+
const matches = [];
|
|
128
|
+
for (const { row, score } of ranked.slice(0, args.limit ?? 5)) {
|
|
129
|
+
const full = await client.getCase(row.id);
|
|
130
|
+
// Build the match field-by-field: the runtime validates tool output
|
|
131
|
+
// against OUTPUT_SCHEMA with additionalProperties:false, so a blind
|
|
132
|
+
// spread of the wire record (createdAt!) would fail validation.
|
|
133
|
+
matches.push({
|
|
134
|
+
id: full.id,
|
|
135
|
+
title: full.title,
|
|
136
|
+
symptoms: full.symptoms,
|
|
137
|
+
rootCause: full.rootCause,
|
|
138
|
+
fix: full.fix,
|
|
139
|
+
...(full.evidence !== undefined ? { evidence: full.evidence } : {}),
|
|
140
|
+
...(full.methodology !== undefined ? { methodology: full.methodology } : {}),
|
|
141
|
+
...(full.difficulty !== undefined ? { difficulty: full.difficulty } : {}),
|
|
142
|
+
tags: full.tags,
|
|
143
|
+
...(full.environment !== undefined ? { environment: full.environment } : {}),
|
|
144
|
+
hitCount: full.hitCount,
|
|
145
|
+
score,
|
|
146
|
+
updatedAt: full.updatedAt,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return { action: 'search', matches };
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
return fail('search', err);
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
})));
|
|
156
|
+
ctx.effect(() => ctx.tools.register(defineTool({
|
|
157
|
+
name: 'knowledge_record',
|
|
158
|
+
description: RECORD_TOOL_DESCRIPTION,
|
|
159
|
+
parameters: {
|
|
160
|
+
id: { type: 'string', description: '已有病例的 id — 带上它 = 更新那条 (查重后发现近似旧病例时用); 不带 = 新建。' },
|
|
161
|
+
title: { type: 'string', required: true, description: '一句话概括, 如 "CSI 卡住因为 Ceph 存储满"。' },
|
|
162
|
+
symptoms: { type: 'array', items: { type: 'string' }, required: true, description: '搜索入口。每条 = 症状类关键词 + 当时观察到的具体值 (报错原文片段、指标值、命令输出特征), 如 "少盘: lsblk 应 7 块只识别 6 块"——类词让跨域同类问题也能命中。' },
|
|
163
|
+
root_cause: { type: 'string', required: true, description: '根因, 到物理/基础设施层 (不是中间现象)。' },
|
|
164
|
+
fix: { type: 'string', required: true, description: '可执行的修复动作。' },
|
|
165
|
+
evidence: { type: 'string', description: '关键证据 (日志行、命令输出)。' },
|
|
166
|
+
methodology: { type: 'string', description: '方法论: 当时怎么从症状定位到根因的——关键的判别步骤/命令 (哪一步区分了两个假设、哪个证据判伪了错误方向)。给"症状不同但问题同类"的未来排查复用。' },
|
|
167
|
+
difficulty: { type: 'integer', description: DIFFICULTY_ANCHORS + '。' },
|
|
168
|
+
tags: { type: 'array', items: { type: 'string' }, description: '组件/领域标签, 如 ["ceph", "csi"]。' },
|
|
169
|
+
environment: { type: 'string', description: '适用环境, 如 "prod k8s 集群"。' },
|
|
170
|
+
},
|
|
171
|
+
output: { schema: OUTPUT_SCHEMA, render },
|
|
172
|
+
async execute(args) {
|
|
173
|
+
const input = {
|
|
174
|
+
title: args.title,
|
|
175
|
+
symptoms: args.symptoms,
|
|
176
|
+
rootCause: args.root_cause,
|
|
177
|
+
fix: args.fix,
|
|
178
|
+
...(args.evidence !== undefined ? { evidence: args.evidence } : {}),
|
|
179
|
+
...(args.methodology !== undefined ? { methodology: args.methodology } : {}),
|
|
180
|
+
...(args.difficulty !== undefined ? { difficulty: args.difficulty } : {}),
|
|
181
|
+
...(args.tags !== undefined ? { tags: args.tags } : {}),
|
|
182
|
+
...(args.environment !== undefined ? { environment: args.environment } : {}),
|
|
183
|
+
};
|
|
184
|
+
try {
|
|
185
|
+
const id = await client.putCase(input, args.id);
|
|
186
|
+
refreshIndex();
|
|
187
|
+
return { action: 'record', id, note: args.id ? `病例 ${id} 已更新。` : `病例已沉淀, id: ${id}。` };
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
return fail('record', err);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
})));
|
|
194
|
+
ctx.effect(() => ctx.tools.register(defineTool({
|
|
195
|
+
name: 'knowledge_hit',
|
|
196
|
+
description: HIT_TOOL_DESCRIPTION,
|
|
197
|
+
parameters: {
|
|
198
|
+
id: { type: 'string', required: true, description: '病例 id (knowledge_search 结果里有)。' },
|
|
199
|
+
},
|
|
200
|
+
output: { schema: OUTPUT_SCHEMA, render },
|
|
201
|
+
async execute(args) {
|
|
202
|
+
try {
|
|
203
|
+
await client.hit(args.id);
|
|
204
|
+
refreshIndex();
|
|
205
|
+
return { action: 'hit', id: args.id, note: `已记录对病例 ${args.id} 的采用。` };
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
return fail('hit', err);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
})));
|
|
212
|
+
// ── Prompt wiring (through ops-prompts) ────────────────────────────────────
|
|
213
|
+
// Same dual-mode resolution as ops-tool-trace: a one-shot ctx.get can lose
|
|
214
|
+
// the race against ops-prompts' provide, so fall back to ctx.inject.
|
|
215
|
+
const registerThroughHandle = (rctx, opsPrompts) => {
|
|
216
|
+
rctx.effect(() => {
|
|
217
|
+
const disposeMethodology = opsPrompts.registerMethodology({
|
|
218
|
+
name: 'knowledge:usage',
|
|
219
|
+
order: 250,
|
|
220
|
+
text: STATIC_PROMPT,
|
|
221
|
+
});
|
|
222
|
+
const disposeIndex = opsPrompts.registerReminder({
|
|
223
|
+
name: 'knowledge:index',
|
|
224
|
+
check: (agent) => {
|
|
225
|
+
const sessionId = agent?.session?.id;
|
|
226
|
+
if (!sessionId || remindedSessions.has(sessionId))
|
|
227
|
+
return null;
|
|
228
|
+
if (indexCache.length === 0)
|
|
229
|
+
return null;
|
|
230
|
+
remindedSessions.add(sessionId);
|
|
231
|
+
const top = [...indexCache].sort((a, b) => b.hitCount - a.hitCount).slice(0, 10);
|
|
232
|
+
return indexReminderText(top);
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
return () => { disposeMethodology(); disposeIndex(); };
|
|
236
|
+
});
|
|
237
|
+
};
|
|
238
|
+
const immediateOpsPrompts = ctx.get('opsPrompts');
|
|
239
|
+
if (immediateOpsPrompts !== undefined) {
|
|
240
|
+
registerThroughHandle(ctx, immediateOpsPrompts);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
ctx.inject(['opsPrompts'], (pctx) => {
|
|
244
|
+
registerThroughHandle(pctx, pctx.opsPrompts);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
export { Config, apply, inject, name };
|
|
249
|
+
export * from './types.js';
|
|
250
|
+
export { rankCases, queryTokens, scoreRow } from './search.js';
|
|
251
|
+
export { KnowledgeClient } from './client.js';
|
|
252
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/search.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyword relevance scoring over the case index. Deliberately simple:
|
|
3
|
+
* case-insensitive substring matching, weighted by field — title ×3,
|
|
4
|
+
* tags ×2, symptoms ×2. No embeddings; scores are predictable and the
|
|
5
|
+
* index is small (hundreds at most).
|
|
6
|
+
*
|
|
7
|
+
* @module @elinpf/dsh-ops-knowledge/search
|
|
8
|
+
*/
|
|
9
|
+
import type { CaseIndexRow } from './types.js';
|
|
10
|
+
/** Split a query into lowercase match tokens (whitespace-separated, plus the whole query). */
|
|
11
|
+
export declare function queryTokens(query: string): string[];
|
|
12
|
+
/** Score one index row against the query tokens; 0 means no match. */
|
|
13
|
+
export declare function scoreRow(row: CaseIndexRow, tokens: string[]): number;
|
|
14
|
+
/** Rank index rows by relevance; rows with no match drop out. */
|
|
15
|
+
export declare function rankCases(rows: CaseIndexRow[], query: string): Array<{
|
|
16
|
+
row: CaseIndexRow;
|
|
17
|
+
score: number;
|
|
18
|
+
}>;
|
|
19
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQnD;AAED,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAWpE;AAED,iEAAiE;AACjE,wBAAgB,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,GAAG,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAO1G"}
|
package/lib/search.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyword relevance scoring over the case index. Deliberately simple:
|
|
3
|
+
* case-insensitive substring matching, weighted by field — title ×3,
|
|
4
|
+
* tags ×2, symptoms ×2. No embeddings; scores are predictable and the
|
|
5
|
+
* index is small (hundreds at most).
|
|
6
|
+
*
|
|
7
|
+
* @module @elinpf/dsh-ops-knowledge/search
|
|
8
|
+
*/
|
|
9
|
+
/** Split a query into lowercase match tokens (whitespace-separated, plus the whole query). */
|
|
10
|
+
export function queryTokens(query) {
|
|
11
|
+
const tokens = query
|
|
12
|
+
.toLowerCase()
|
|
13
|
+
.split(/\s+/)
|
|
14
|
+
.filter((t) => t !== '');
|
|
15
|
+
const whole = query.trim().toLowerCase();
|
|
16
|
+
if (whole !== '' && !tokens.includes(whole))
|
|
17
|
+
tokens.push(whole);
|
|
18
|
+
return tokens;
|
|
19
|
+
}
|
|
20
|
+
/** Score one index row against the query tokens; 0 means no match. */
|
|
21
|
+
export function scoreRow(row, tokens) {
|
|
22
|
+
const title = row.title.toLowerCase();
|
|
23
|
+
const tags = row.tags.map((t) => t.toLowerCase());
|
|
24
|
+
const symptoms = row.symptoms.map((s) => s.toLowerCase());
|
|
25
|
+
let score = 0;
|
|
26
|
+
for (const token of tokens) {
|
|
27
|
+
if (title.includes(token))
|
|
28
|
+
score += 3;
|
|
29
|
+
if (tags.some((t) => t.includes(token)))
|
|
30
|
+
score += 2;
|
|
31
|
+
if (symptoms.some((s) => s.includes(token)))
|
|
32
|
+
score += 2;
|
|
33
|
+
}
|
|
34
|
+
return score;
|
|
35
|
+
}
|
|
36
|
+
/** Rank index rows by relevance; rows with no match drop out. */
|
|
37
|
+
export function rankCases(rows, query) {
|
|
38
|
+
const tokens = queryTokens(query);
|
|
39
|
+
if (tokens.length === 0)
|
|
40
|
+
return [];
|
|
41
|
+
return rows
|
|
42
|
+
.map((row) => ({ row, score: scoreRow(row, tokens) }))
|
|
43
|
+
.filter((m) => m.score > 0)
|
|
44
|
+
.sort((a, b) => b.score - a.score || b.row.hitCount - a.row.hitCount);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,8FAA8F;AAC9F,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,MAAM,GAAG,KAAK;SACjB,WAAW,EAAE;SACb,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;IAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IACxC,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC/D,OAAO,MAAM,CAAA;AACf,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,GAAiB,EAAE,MAAgB;IAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAA;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAA;IACzD,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,KAAK,IAAI,CAAC,CAAA;QACrC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAAE,KAAK,IAAI,CAAC,CAAA;QACnD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAAE,KAAK,IAAI,CAAC,CAAA;IACzD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,SAAS,CAAC,IAAoB,EAAE,KAAa;IAC3D,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAA;IACjC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAClC,OAAO,IAAI;SACR,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;SACrD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;SAC1B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;AACzE,CAAC"}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the ops-knowledge plugin.
|
|
3
|
+
*
|
|
4
|
+
* The wire shape mirrors the hub's `/cases` API (camelCase there); tool
|
|
5
|
+
* arguments facing the model use snake_case and are mapped in index.ts.
|
|
6
|
+
*
|
|
7
|
+
* @module @elinpf/dsh-ops-knowledge/types
|
|
8
|
+
*/
|
|
9
|
+
/** A full case record as the hub returns it from `GET /cases/:id`. */
|
|
10
|
+
export interface CaseRecord {
|
|
11
|
+
id: string;
|
|
12
|
+
title: string;
|
|
13
|
+
symptoms: string[];
|
|
14
|
+
rootCause: string;
|
|
15
|
+
fix: string;
|
|
16
|
+
evidence?: string;
|
|
17
|
+
/** How the root cause was found — the discriminating steps/commands (方法论). */
|
|
18
|
+
methodology?: string;
|
|
19
|
+
/** Self-assessed diagnosis difficulty, 1–5. */
|
|
20
|
+
difficulty?: number;
|
|
21
|
+
tags: string[];
|
|
22
|
+
environment?: string;
|
|
23
|
+
hitCount: number;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
}
|
|
27
|
+
/** An index row as the hub returns it from `GET /cases` — no full text. */
|
|
28
|
+
export interface CaseIndexRow {
|
|
29
|
+
id: string;
|
|
30
|
+
title: string;
|
|
31
|
+
symptoms: string[];
|
|
32
|
+
tags: string[];
|
|
33
|
+
hitCount: number;
|
|
34
|
+
updatedAt: string;
|
|
35
|
+
}
|
|
36
|
+
/** Fields a caller may write on a case. */
|
|
37
|
+
export interface CaseInput {
|
|
38
|
+
title?: string;
|
|
39
|
+
symptoms?: string[];
|
|
40
|
+
rootCause?: string;
|
|
41
|
+
fix?: string;
|
|
42
|
+
evidence?: string;
|
|
43
|
+
methodology?: string;
|
|
44
|
+
difficulty?: number;
|
|
45
|
+
tags?: string[];
|
|
46
|
+
environment?: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A search hit: the full case plus its relevance score. Matches the tool
|
|
50
|
+
* output schema exactly — the runtime rejects undeclared keys, so this is
|
|
51
|
+
* `Omit<CaseRecord, 'createdAt'>`, not a blind spread of the wire record.
|
|
52
|
+
*/
|
|
53
|
+
export interface CaseMatch extends Omit<CaseRecord, 'createdAt'> {
|
|
54
|
+
score: number;
|
|
55
|
+
}
|
|
56
|
+
/** Result shape shared by the three tools. */
|
|
57
|
+
export interface KnowledgeToolResult {
|
|
58
|
+
action: 'record' | 'search' | 'hit';
|
|
59
|
+
note?: string;
|
|
60
|
+
error?: string;
|
|
61
|
+
id?: string;
|
|
62
|
+
/** search: matched cases, best first. */
|
|
63
|
+
matches?: CaseMatch[];
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,+CAA+C;IAC/C,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,2CAA2C;AAC3C,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAU,SAAQ,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC;IAC9D,KAAK,EAAE,MAAM,CAAA;CACd;AAED,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAA;IACnC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,yCAAyC;IACzC,OAAO,CAAC,EAAE,SAAS,EAAE,CAAA;CACtB"}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the ops-knowledge plugin.
|
|
3
|
+
*
|
|
4
|
+
* The wire shape mirrors the hub's `/cases` API (camelCase there); tool
|
|
5
|
+
* arguments facing the model use snake_case and are mapped in index.ts.
|
|
6
|
+
*
|
|
7
|
+
* @module @elinpf/dsh-ops-knowledge/types
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
package/lib/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elinpf/dsh-ops-knowledge",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Troubleshooting knowledge base for ops mode — distilled postmortem cases stored in the access hub, searched before diagnosing and recorded after resolving.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"types": "lib/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./lib/index.d.ts",
|
|
11
|
+
"default": "./lib/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./types": {
|
|
14
|
+
"types": "./lib/types.d.ts",
|
|
15
|
+
"default": "./lib/types.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib",
|
|
21
|
+
"cordis.patch.yml"
|
|
22
|
+
],
|
|
23
|
+
"dsh": {
|
|
24
|
+
"bundle": {
|
|
25
|
+
"patch": "./cordis.patch.yml"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@deepseek-ai/schemastery": "^3.18.1"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
33
|
+
"@deepseek-ai/dsh-tools": "^0.1.0-rc.8",
|
|
34
|
+
"@elinpf/dsh-ops-prompts": "^0.4.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
38
|
+
"@deepseek-ai/dsh-tools": "0.0.1-rc.1",
|
|
39
|
+
"@types/node": "^22.0.0",
|
|
40
|
+
"typescript": "^5.4.0",
|
|
41
|
+
"vitest": "^4.1.11",
|
|
42
|
+
"@elinpf/dsh-ops-prompts": "0.4.0",
|
|
43
|
+
"@elinpf/dsh-ops-test-support": "0.0.0",
|
|
44
|
+
"@elinpf/dsh-ops-access-hub": "0.3.0"
|
|
45
|
+
},
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc",
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"test": "vitest run"
|
|
54
|
+
}
|
|
55
|
+
}
|