dsh-data-domain-knowledge 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +360 -0
- package/cordis.patch.yml +410 -0
- package/eval/README.md +76 -0
- package/eval/evaluate-retrieval.mjs +121 -0
- package/eval/queries.example.jsonl +2 -0
- package/lib/client.js +111415 -0
- package/lib/types/config-schema.d.ts +35 -0
- package/lib/types/config-schema.d.ts.map +1 -0
- package/lib/types/config-schema.js +34 -0
- package/lib/types/config-schema.js.map +1 -0
- package/lib/types/convert/core-loader.d.ts +32 -0
- package/lib/types/convert/core-loader.d.ts.map +1 -0
- package/lib/types/convert/core-loader.js +60 -0
- package/lib/types/convert/core-loader.js.map +1 -0
- package/lib/types/convert/host.d.ts +88 -0
- package/lib/types/convert/host.d.ts.map +1 -0
- package/lib/types/convert/host.js +479 -0
- package/lib/types/convert/host.js.map +1 -0
- package/lib/types/convert/ingest.d.ts +125 -0
- package/lib/types/convert/ingest.d.ts.map +1 -0
- package/lib/types/convert/ingest.js +228 -0
- package/lib/types/convert/ingest.js.map +1 -0
- package/lib/types/convert/settings-schema.d.ts +18 -0
- package/lib/types/convert/settings-schema.d.ts.map +1 -0
- package/lib/types/convert/settings-schema.js +26 -0
- package/lib/types/convert/settings-schema.js.map +1 -0
- package/lib/types/convert/types.d.ts +46 -0
- package/lib/types/convert/types.d.ts.map +1 -0
- package/lib/types/convert/types.js +41 -0
- package/lib/types/convert/types.js.map +1 -0
- package/lib/types/diagnosis/cards.d.ts +71 -0
- package/lib/types/diagnosis/cards.d.ts.map +1 -0
- package/lib/types/diagnosis/cards.js +482 -0
- package/lib/types/diagnosis/cards.js.map +1 -0
- package/lib/types/diagnosis/problem-classes.d.ts +51 -0
- package/lib/types/diagnosis/problem-classes.d.ts.map +1 -0
- package/lib/types/diagnosis/problem-classes.js +66 -0
- package/lib/types/diagnosis/problem-classes.js.map +1 -0
- package/lib/types/diagnosis/schema.d.ts +65 -0
- package/lib/types/diagnosis/schema.d.ts.map +1 -0
- package/lib/types/diagnosis/schema.js +208 -0
- package/lib/types/diagnosis/schema.js.map +1 -0
- package/lib/types/diagnosis/seed-source.d.ts +20 -0
- package/lib/types/diagnosis/seed-source.d.ts.map +1 -0
- package/lib/types/diagnosis/seed-source.js +96 -0
- package/lib/types/diagnosis/seed-source.js.map +1 -0
- package/lib/types/diagnosis/seed.d.ts +50 -0
- package/lib/types/diagnosis/seed.d.ts.map +1 -0
- package/lib/types/diagnosis/seed.js +242 -0
- package/lib/types/diagnosis/seed.js.map +1 -0
- package/lib/types/diagnosis/store.d.ts +81 -0
- package/lib/types/diagnosis/store.d.ts.map +1 -0
- package/lib/types/diagnosis/store.js +409 -0
- package/lib/types/diagnosis/store.js.map +1 -0
- package/lib/types/diagnosis/types.d.ts +124 -0
- package/lib/types/diagnosis/types.d.ts.map +1 -0
- package/lib/types/diagnosis/types.js +13 -0
- package/lib/types/diagnosis/types.js.map +1 -0
- package/lib/types/directory-picker.d.ts +94 -0
- package/lib/types/directory-picker.d.ts.map +1 -0
- package/lib/types/directory-picker.js +110 -0
- package/lib/types/directory-picker.js.map +1 -0
- package/lib/types/extract-model.d.ts +76 -0
- package/lib/types/extract-model.d.ts.map +1 -0
- package/lib/types/extract-model.js +193 -0
- package/lib/types/extract-model.js.map +1 -0
- package/lib/types/extract.d.ts +121 -0
- package/lib/types/extract.d.ts.map +1 -0
- package/lib/types/extract.js +549 -0
- package/lib/types/extract.js.map +1 -0
- package/lib/types/fts.d.ts +96 -0
- package/lib/types/fts.d.ts.map +1 -0
- package/lib/types/fts.js +184 -0
- package/lib/types/fts.js.map +1 -0
- package/lib/types/index.d.ts +39 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index.js +1112 -0
- package/lib/types/index.js.map +1 -0
- package/lib/types/intent/engine.d.ts +108 -0
- package/lib/types/intent/engine.d.ts.map +1 -0
- package/lib/types/intent/engine.js +501 -0
- package/lib/types/intent/engine.js.map +1 -0
- package/lib/types/intent/host.d.ts +88 -0
- package/lib/types/intent/host.d.ts.map +1 -0
- package/lib/types/intent/host.js +389 -0
- package/lib/types/intent/host.js.map +1 -0
- package/lib/types/intent/preset-tools.d.ts +37 -0
- package/lib/types/intent/preset-tools.d.ts.map +1 -0
- package/lib/types/intent/preset-tools.js +45 -0
- package/lib/types/intent/preset-tools.js.map +1 -0
- package/lib/types/intent/settings-schema.d.ts +59 -0
- package/lib/types/intent/settings-schema.d.ts.map +1 -0
- package/lib/types/intent/settings-schema.js +57 -0
- package/lib/types/intent/settings-schema.js.map +1 -0
- package/lib/types/intent/store.d.ts +75 -0
- package/lib/types/intent/store.d.ts.map +1 -0
- package/lib/types/intent/store.js +139 -0
- package/lib/types/intent/store.js.map +1 -0
- package/lib/types/intent/tools.d.ts +63 -0
- package/lib/types/intent/tools.d.ts.map +1 -0
- package/lib/types/intent/tools.js +108 -0
- package/lib/types/intent/tools.js.map +1 -0
- package/lib/types/intent/types.d.ts +189 -0
- package/lib/types/intent/types.d.ts.map +1 -0
- package/lib/types/intent/types.js +62 -0
- package/lib/types/intent/types.js.map +1 -0
- package/lib/types/knowledge-bases.d.ts +266 -0
- package/lib/types/knowledge-bases.d.ts.map +1 -0
- package/lib/types/knowledge-bases.js +1107 -0
- package/lib/types/knowledge-bases.js.map +1 -0
- package/lib/types/layout.d.ts +262 -0
- package/lib/types/layout.d.ts.map +1 -0
- package/lib/types/layout.js +312 -0
- package/lib/types/layout.js.map +1 -0
- package/lib/types/migrate.d.ts +110 -0
- package/lib/types/migrate.d.ts.map +1 -0
- package/lib/types/migrate.js +280 -0
- package/lib/types/migrate.js.map +1 -0
- package/lib/types/recall-rank.d.ts +158 -0
- package/lib/types/recall-rank.d.ts.map +1 -0
- package/lib/types/recall-rank.js +261 -0
- package/lib/types/recall-rank.js.map +1 -0
- package/lib/types/runtime.d.ts +568 -0
- package/lib/types/runtime.d.ts.map +1 -0
- package/lib/types/runtime.js +3045 -0
- package/lib/types/runtime.js.map +1 -0
- package/lib/types/settings-schema.d.ts +117 -0
- package/lib/types/settings-schema.d.ts.map +1 -0
- package/lib/types/settings-schema.js +92 -0
- package/lib/types/settings-schema.js.map +1 -0
- package/lib/types/settings-volatile.d.ts +102 -0
- package/lib/types/settings-volatile.d.ts.map +1 -0
- package/lib/types/settings-volatile.js +114 -0
- package/lib/types/settings-volatile.js.map +1 -0
- package/lib/types/types.d.ts +799 -0
- package/lib/types/types.d.ts.map +1 -0
- package/lib/types/types.js +387 -0
- package/lib/types/types.js.map +1 -0
- package/lib/types/wiki-types.d.ts +68 -0
- package/lib/types/wiki-types.d.ts.map +1 -0
- package/lib/types/wiki-types.js +322 -0
- package/lib/types/wiki-types.js.map +1 -0
- package/package.json +101 -0
- package/preset/tita-data-agent/agent.cordis.yml +376 -0
- package/preset/tita-data-agent/preset.yml +3 -0
- package/python/requirements.txt +8 -0
- package/scripts/doctor.mjs +70 -0
- package/scripts/e2e-pipeline.mjs +355 -0
- package/scripts/install-agent-preset.mjs +92 -0
- package/scripts/setup-embedding.sh +34 -0
- package/scripts/sync-agent-preset.mjs +188 -0
- package/src/client/AgentPresetCard.tsx +247 -0
- package/src/client/DirectoryPicker.tsx +357 -0
- package/src/client/InfoHint.tsx +65 -0
- package/src/client/IntentLogicTab.tsx +185 -0
- package/src/client/IntentTab.tsx +715 -0
- package/src/client/KnowledgeBaseTab.tsx +1454 -0
- package/src/client/KnowledgeGraphView.tsx +306 -0
- package/src/client/KnowledgePanel.tsx +381 -0
- package/src/client/KnowledgeStepRail.tsx +60 -0
- package/src/client/NodeSettings.tsx +392 -0
- package/src/client/PreviewSections.tsx +116 -0
- package/src/client/RecallPanel.tsx +399 -0
- package/src/client/TypeDefinitionDrawer.tsx +215 -0
- package/src/client/WikiFlowCard.tsx +226 -0
- package/src/client/WikiTypeEditor.tsx +332 -0
- package/src/client/agent-preset.ts +121 -0
- package/src/client/arch/AgentArchitectureGraph.tsx +219 -0
- package/src/client/arch/NodeLogicPanel.tsx +133 -0
- package/src/client/arch/ProblemDetailPanel.tsx +88 -0
- package/src/client/arch/model.ts +691 -0
- package/src/client/architecture.css +191 -0
- package/src/client/architecture.tsx +530 -0
- package/src/client/attribution/AttributionGraph.tsx +104 -0
- package/src/client/attribution/AttributionTab.tsx +332 -0
- package/src/client/attribution/CaseView.tsx +102 -0
- package/src/client/attribution/GraphStage.tsx +87 -0
- package/src/client/attribution/RunView.tsx +184 -0
- package/src/client/attribution/StageChrome.tsx +403 -0
- package/src/client/attribution/ViewSwitch.tsx +107 -0
- package/src/client/attribution/graph-options.ts +381 -0
- package/src/client/attribution/model.ts +462 -0
- package/src/client/config-scope.ts +119 -0
- package/src/client/convert/ConvertPanel.tsx +594 -0
- package/src/client/convert/styles.css +138 -0
- package/src/client/convert/styles.ts +49 -0
- package/src/client/format.ts +39 -0
- package/src/client/graph/layout.ts +181 -0
- package/src/client/graph.css +113 -0
- package/src/client/index.ts +98 -0
- package/src/client/problem-domains.ts +114 -0
- package/src/client/styles.css +940 -0
- package/src/client/styles.ts +11 -0
- package/src/client/useFitScale.ts +68 -0
- package/src/config-schema.ts +45 -0
- package/src/convert/core-loader.ts +68 -0
- package/src/convert/host.ts +579 -0
- package/src/convert/ingest.ts +367 -0
- package/src/convert/settings-schema.ts +27 -0
- package/src/convert/types.ts +65 -0
- package/src/diagnosis/cards.ts +498 -0
- package/src/diagnosis/problem-classes.ts +117 -0
- package/src/diagnosis/schema.ts +260 -0
- package/src/diagnosis/seed-source.ts +107 -0
- package/src/diagnosis/seed.ts +291 -0
- package/src/diagnosis/store.ts +432 -0
- package/src/diagnosis/types.ts +152 -0
- package/src/directory-picker.ts +164 -0
- package/src/extract-model.ts +227 -0
- package/src/extract.ts +632 -0
- package/src/fts.ts +203 -0
- package/src/index.ts +1091 -0
- package/src/intent/README.md +63 -0
- package/src/intent/engine.ts +527 -0
- package/src/intent/host.ts +462 -0
- package/src/intent/preset-tools.ts +48 -0
- package/src/intent/settings-schema.ts +63 -0
- package/src/intent/store.ts +143 -0
- package/src/intent/tools.ts +139 -0
- package/src/intent/types.ts +245 -0
- package/src/knowledge-bases.ts +1160 -0
- package/src/layout.ts +350 -0
- package/src/migrate.ts +262 -0
- package/src/python/embedding_worker.py +471 -0
- package/src/recall-rank.ts +299 -0
- package/src/runtime.ts +3069 -0
- package/src/settings-schema.ts +94 -0
- package/src/settings-volatile.ts +122 -0
- package/src/types.ts +1140 -0
- package/src/wiki-types.ts +357 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 意图的**落盘**(0033)。
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么需要它
|
|
5
|
+
*
|
|
6
|
+
* 0033 之前,意图的两半都不在磁盘上属于这个 Agent 的地方:
|
|
7
|
+
*
|
|
8
|
+
* - **分类 / act 注册表**住在宿主的 settings 文档(`settings.yaml`)里。它确实落盘了,
|
|
9
|
+
* 但那是**宿主的配置**,不是这个 Agent 的文件 —— 备份知识库不会带上它,换一台机器
|
|
10
|
+
* 也不跟着走,而它恰恰决定了「同一句话被理解成什么」。
|
|
11
|
+
* - **每轮记录**只在内存里(`IntentStore` 的 Map,TTL 600 秒)。重启即丢。而架构图上
|
|
12
|
+
* 写着「意图记录…都已落盘」——**那句话当时是假的**。
|
|
13
|
+
*
|
|
14
|
+
* 现在两份东西都在 `<agentRoot>/intent/`:
|
|
15
|
+
*
|
|
16
|
+
* ```
|
|
17
|
+
* <agentRoot>/intent/
|
|
18
|
+
* registry.json 分类 / act 词表(可编辑,面板就地改)
|
|
19
|
+
* records.ndjson 每轮一条记录,append-only
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* ## 为什么记录是 append-only 而不是「覆盖写」
|
|
23
|
+
*
|
|
24
|
+
* 记录本身按 `sessionKey#turn` upsert(同一轮重复调用只算一条事实),但**文件是审计
|
|
25
|
+
* 留痕**:追加每一版比原地覆盖更能回答「这一轮改过什么」。读的时候按同一个 key 取
|
|
26
|
+
* 最后一条,于是内存里那份「一轮一条」的语义不变,而磁盘上留下了完整过程。
|
|
27
|
+
*
|
|
28
|
+
* 代价是文件会随使用增长。这是审计流的固有代价,且它是纯追加、没有读放大 ——
|
|
29
|
+
* 真到需要清理时应该按时间归档,而不是在这里改成覆盖写。
|
|
30
|
+
*
|
|
31
|
+
* @module
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
|
35
|
+
import { appendFile, mkdir, readFile } from 'node:fs/promises'
|
|
36
|
+
import { dirname, join } from 'node:path'
|
|
37
|
+
import type { IntentActDef, IntentRecord } from './types.js'
|
|
38
|
+
|
|
39
|
+
/** 注册表文件名。分类与 act 住一起:它们是一份词表的两半,分开存只会漂移。 */
|
|
40
|
+
export const INTENT_REGISTRY_FILE = 'registry.json'
|
|
41
|
+
/** 记录文件名。NDJSON 而不是 JSON 数组:追加是 O(1),且半行坏数据只坏一行。 */
|
|
42
|
+
export const INTENT_RECORDS_FILE = 'records.ndjson'
|
|
43
|
+
|
|
44
|
+
export interface IntentRegistryFile {
|
|
45
|
+
version: 1
|
|
46
|
+
acts: IntentActDef[]
|
|
47
|
+
categories: Array<{ id: string; label: string; route: string; description: string; examples: string[]; enabled: boolean }>
|
|
48
|
+
updatedAt?: string
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 原子写:先写 `.tmp` 再 rename。半截的 registry.json 会让引擎按出厂预置启动。
|
|
53
|
+
*
|
|
54
|
+
* **同步**,与 `migrate.ts` 同一个理由:注册表的读发生在**设置解析的回调里**
|
|
55
|
+
* (`setSource` → `apply()` → 灌进引擎),而那条路径必须同步完成 —— 异步化会让
|
|
56
|
+
* 「设置改了,引擎还是旧的」重新出现,而且窗口期随磁盘快慢变化。文件只有几 KB,
|
|
57
|
+
* 一次启动读一次。
|
|
58
|
+
*/
|
|
59
|
+
function writeAtomicSync(path: string, content: string): void {
|
|
60
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
61
|
+
const temp = `${path}.tmp`
|
|
62
|
+
writeFileSync(temp, content, 'utf8')
|
|
63
|
+
renameSync(temp, path)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
67
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 读注册表文件。
|
|
72
|
+
*
|
|
73
|
+
* **不抛异常**:文件坏了、被手改坏了、写了一半 —— 都返回 `undefined`,调用方按
|
|
74
|
+
* 出厂预置启动。注册表读不出来不该让整个意图引擎起不来,更不该让插件起不来。
|
|
75
|
+
*/
|
|
76
|
+
export function readIntentRegistry(root: string): IntentRegistryFile | undefined {
|
|
77
|
+
const path = join(root, INTENT_REGISTRY_FILE)
|
|
78
|
+
if (!existsSync(path)) return undefined
|
|
79
|
+
try {
|
|
80
|
+
const parsed: unknown = JSON.parse(readFileSync(path, 'utf8'))
|
|
81
|
+
if (!isPlainObject(parsed)) return undefined
|
|
82
|
+
if (!Array.isArray(parsed.acts) || !Array.isArray(parsed.categories)) return undefined
|
|
83
|
+
return {
|
|
84
|
+
version: 1,
|
|
85
|
+
acts: parsed.acts as IntentActDef[],
|
|
86
|
+
categories: parsed.categories as IntentRegistryFile['categories'],
|
|
87
|
+
...(typeof parsed.updatedAt === 'string' ? { updatedAt: parsed.updatedAt } : {}),
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
return undefined
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 写注册表文件。`updatedAt` 由调用方给,便于测试与审计对齐。 */
|
|
95
|
+
export function writeIntentRegistry(root: string, registry: { acts: IntentActDef[]; categories: IntentRegistryFile['categories'] }, updatedAt = new Date().toISOString()): IntentRegistryFile {
|
|
96
|
+
const payload: IntentRegistryFile = { version: 1, acts: registry.acts, categories: registry.categories, updatedAt }
|
|
97
|
+
writeAtomicSync(join(root, INTENT_REGISTRY_FILE), `${JSON.stringify(payload, null, 2)}\n`)
|
|
98
|
+
return payload
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** 追加一条记录。失败不抛:留痕写不进去不该影响这一轮的回答。 */
|
|
102
|
+
export async function appendIntentRecord(root: string, record: IntentRecord): Promise<void> {
|
|
103
|
+
try {
|
|
104
|
+
await mkdir(root, { recursive: true })
|
|
105
|
+
await appendFile(join(root, INTENT_RECORDS_FILE), `${JSON.stringify(record)}\n`, 'utf8')
|
|
106
|
+
} catch { /* 磁盘满 / 只读卷:这一轮照常回答,留痕缺失 */ }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 读记录(新→旧按时间,返回时升序)。
|
|
111
|
+
*
|
|
112
|
+
* 三条纪律:
|
|
113
|
+
* 1. **坏行只丢它自己。** 追加写天然会留下「最后一行写了一半」的可能(进程被杀),
|
|
114
|
+
* 一行 JSON.parse 失败不该让整份历史读不出来。
|
|
115
|
+
* 2. **按 `sessionKey#turnKey` 取最后一条。** 与内存里那份 upsert 语义一致。
|
|
116
|
+
* 3. `limit` 是**每个会话**的上限,不是总数:面板一次只显示一个会话。
|
|
117
|
+
*/
|
|
118
|
+
export async function readIntentRecords(root: string, sessionKey?: string, limit = 200): Promise<IntentRecord[]> {
|
|
119
|
+
const path = join(root, INTENT_RECORDS_FILE)
|
|
120
|
+
if (!existsSync(path)) return []
|
|
121
|
+
let text: string
|
|
122
|
+
try {
|
|
123
|
+
text = await readFile(path, 'utf8')
|
|
124
|
+
} catch {
|
|
125
|
+
return []
|
|
126
|
+
}
|
|
127
|
+
const latest = new Map<string, IntentRecord>()
|
|
128
|
+
for (const line of text.split(/\r?\n/)) {
|
|
129
|
+
if (!line.trim()) continue
|
|
130
|
+
let record: IntentRecord
|
|
131
|
+
try {
|
|
132
|
+
record = JSON.parse(line) as IntentRecord
|
|
133
|
+
} catch {
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
if (!isPlainObject(record) || typeof record.sessionKey !== 'string' || typeof record.turnKey !== 'string') continue
|
|
137
|
+
if (sessionKey !== undefined && record.sessionKey !== sessionKey) continue
|
|
138
|
+
latest.set(`${record.sessionKey}#${record.turnKey}`, record)
|
|
139
|
+
}
|
|
140
|
+
return [...latest.values()]
|
|
141
|
+
.sort((left, right) => String(left.updatedAt ?? left.createdAt).localeCompare(String(right.updatedAt ?? right.createdAt)))
|
|
142
|
+
.slice(-limit)
|
|
143
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 三个 `intent_*` 工具的**注册器**:与「引擎住在哪个平面」解耦。
|
|
3
|
+
*
|
|
4
|
+
* ## 为什么要单独一个文件
|
|
5
|
+
*
|
|
6
|
+
* 0029 之前这三个工具由宿主平面的 `applyIntent` 直接 `ctx.tools.register(...)`,
|
|
7
|
+
* 于是它们是**全局工具**:任何 agent、任何 preset 的会话都会在提示词里看到
|
|
8
|
+
* `intent_record`,也都能调它。而意图记录是这个方案自己的东西 —— 只有跑
|
|
9
|
+
* TitaAgent 那套组合的会话才该有它,别的 agent 场景(别的 preset、临时会话)
|
|
10
|
+
* 不该被塞一个用不上的工具。
|
|
11
|
+
*
|
|
12
|
+
* DSH 里「只有某个 preset 能用」的**唯一**支持形态是**注册作用域**:注册在哪个
|
|
13
|
+
* 作用域,就只在哪个作用域可见(`dsh-tools` 的 `register` 是 scope-layered)。
|
|
14
|
+
* `ctx.tools.restrict()` 只能做减法(从继承来的工具里减掉),宿主平面调它还会
|
|
15
|
+
* 直接抛 —— 没有「只给某一个作用域」的正向开关。所以正确的做法是把注册搬到
|
|
16
|
+
* **agent 平面**:一个只被自定义 preset 的 `agent.cordis.yml` 挂载的行
|
|
17
|
+
* (`./preset-tools.ts`),它注册的工具只覆盖那个 preset 的会话。
|
|
18
|
+
*
|
|
19
|
+
* 注册逻辑本身与平面无关,所以它留在这里:宿主平面负责「引擎怎么跑」(设置、
|
|
20
|
+
* 轮次记账、HTTP 只读面),agent 平面负责「模型看到什么工具」。两边共用这一份,
|
|
21
|
+
* 不各写一套工具定义。
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { defineTool, type ToolRunContext } from '@deepseek-ai/dsh-tools'
|
|
27
|
+
import type { LineageContext } from 'dsh-data-contracts/refs'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 注册这三个工具需要引擎提供的能力。
|
|
31
|
+
*
|
|
32
|
+
* 刻意是**结构化的最小面**而不是 `IntentEngine` 本身:宿主平面通过
|
|
33
|
+
* `INTENT_SERVICE` 提供它,agent 平面的行只按这个形状取用。这样 preset 行不必
|
|
34
|
+
* import 引擎、也不必知道引擎住在哪个模块里。
|
|
35
|
+
*/
|
|
36
|
+
export interface IntentToolHost {
|
|
37
|
+
/** `intent_record` 的**工具描述就是路由提示词**(0023)。 */
|
|
38
|
+
routingPrompt(): string
|
|
39
|
+
record(args: Record<string, unknown>, exec?: ToolRunContext): unknown
|
|
40
|
+
view(sessionKey: string, includePrompt?: boolean): unknown
|
|
41
|
+
registry(): unknown
|
|
42
|
+
/** 提示词 / 词表变化时通知,返回取消订阅。 */
|
|
43
|
+
subscribe(listener: () => void): () => void
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** `intent_record` 的参数表。描述是路由提示词(工具级),所以这里只声明字段。 */
|
|
47
|
+
const INTENT_RECORD_PARAMS: Record<string, unknown> = {
|
|
48
|
+
user_input: { type: 'string', required: true, description: '本轮用户原文' },
|
|
49
|
+
act: { type: 'string', description: '本轮动作 id,取自工具描述里的 act 词表' },
|
|
50
|
+
category: { type: 'string', description: '意图分类 id:先按预置分类匹配,命中就直接用它的 id;全不命中才自行新起一个 id 或落 unknown' },
|
|
51
|
+
predicate: { type: 'string', description: '要执行的动作,例如 query_babel_data' },
|
|
52
|
+
slots: { type: 'json', description: '从用户输入抽取的关键参数' },
|
|
53
|
+
confidence: { type: 'number', description: '0-1,用于标注 lowConfidence' },
|
|
54
|
+
refs: { type: 'array', description: '引用对象,例如 { id, kind, label }' },
|
|
55
|
+
relation: { type: 'string', enum: ['new_task', 'subtask_of'], description: '本轮是新任务还是已有任务的子任务' },
|
|
56
|
+
session_key: { type: 'string' },
|
|
57
|
+
turn_id: { type: 'string', description: '当前对话轮次 id;不传则由 Host 生成' },
|
|
58
|
+
task_id: { type: 'string', description: 'relation=subtask_of 时指向的已有业务任务 id;新任务不传' },
|
|
59
|
+
subtask_id: { type: 'string', description: '已有子任务 id;新子任务不传,由 Host 生成' },
|
|
60
|
+
parent_subtask_id: { type: 'string', description: '父任务节点 id;通常由 Host 生成' },
|
|
61
|
+
run_id: { type: 'string', description: '已有执行尝试 id;重试时传新值' },
|
|
62
|
+
trace_id: { type: 'string' },
|
|
63
|
+
domain: { type: 'string' },
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** 工具的最小注册面。测试替身与真实 `ctx` 都满足它。 */
|
|
67
|
+
export interface ToolRegistryLike {
|
|
68
|
+
register(definition: unknown): unknown
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function jsonTool(name: string, description: string, parameters: Record<string, unknown>, execute: (args: any, exec?: ToolRunContext) => unknown) {
|
|
72
|
+
return defineTool({
|
|
73
|
+
name, description, parameters: parameters as any,
|
|
74
|
+
output: { schema: { type: 'json' }, render: (_args: unknown, value: unknown) => [{ type: 'text' as const, text: JSON.stringify(value) }] },
|
|
75
|
+
execute: async (args: any, exec: ToolRunContext) => execute(args, exec),
|
|
76
|
+
} as any)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function lineageOf(args: Record<string, unknown>, exec?: ToolRunContext): Partial<LineageContext> | undefined {
|
|
80
|
+
const lineage: Partial<LineageContext> = {}
|
|
81
|
+
const sessionId = typeof args.session_key === 'string' && args.session_key.trim() ? args.session_key.trim() : exec?.agent?.session.header.id
|
|
82
|
+
if (sessionId) lineage.sessionId = sessionId
|
|
83
|
+
const fields: Array<[keyof LineageContext, string]> = [
|
|
84
|
+
['turnId', 'turn_id'], ['taskId', 'task_id'], ['subtaskId', 'subtask_id'],
|
|
85
|
+
['parentSubtaskId', 'parent_subtask_id'], ['runId', 'run_id'], ['traceId', 'trace_id'], ['domain', 'domain'],
|
|
86
|
+
]
|
|
87
|
+
for (const [target, source] of fields) if (typeof args[source] === 'string' && args[source].trim()) lineage[target] = args[source].trim()
|
|
88
|
+
return Object.keys(lineage).length > 0 ? lineage : undefined
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function sessionKeyOf(args: Record<string, unknown>, exec?: ToolRunContext): string {
|
|
92
|
+
const explicit = typeof args.session_key === 'string' ? args.session_key.trim() : ''
|
|
93
|
+
return explicit || exec?.agent?.session.header.id || 'default'
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 注册三个 `intent_*` 工具,返回一个把三者一起撤掉的 disposer。
|
|
98
|
+
*
|
|
99
|
+
* `intent_record` 的描述是**动态**的:分类 / act 词表可以在设置里改,而工具描述
|
|
100
|
+
* 是静态字符串。所以设置一变就 dispose 旧的、按新文本重新注册 —— 下一轮模型看到
|
|
101
|
+
* 的规则就是新的。这是「保存后下一轮生效」在工具这一侧的实现。
|
|
102
|
+
*
|
|
103
|
+
* 类型守卫(`typeof disposer === 'function'`)是因为测试替身的 `register` 不一定
|
|
104
|
+
* 返回 disposer。
|
|
105
|
+
*/
|
|
106
|
+
export function registerIntentTools(ctx: { tools: ToolRegistryLike }, host: IntentToolHost): () => void {
|
|
107
|
+
let disposeRecord: (() => void) | undefined
|
|
108
|
+
let registeredDescription = ''
|
|
109
|
+
const ensureRecordTool = (): void => {
|
|
110
|
+
const description = host.routingPrompt()
|
|
111
|
+
if (registeredDescription === description && disposeRecord) return
|
|
112
|
+
disposeRecord?.()
|
|
113
|
+
disposeRecord = undefined
|
|
114
|
+
registeredDescription = description
|
|
115
|
+
const disposer: unknown = ctx.tools.register(jsonTool('intent_record', description, INTENT_RECORD_PARAMS, (args, exec) => host.record(args, exec)))
|
|
116
|
+
if (typeof disposer === 'function') disposeRecord = disposer as () => void
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
ensureRecordTool()
|
|
120
|
+
const disposeView: unknown = ctx.tools.register(jsonTool(
|
|
121
|
+
'intent_store_view', 'View recent intent records and the active task ids for the current session.',
|
|
122
|
+
{ session_key: { type: 'string' }, include_prompt: { type: 'boolean' } },
|
|
123
|
+
(args: { session_key?: string; include_prompt?: boolean }, exec) => host.view(sessionKeyOf(args, exec), args.include_prompt),
|
|
124
|
+
))
|
|
125
|
+
const disposeRegistry: unknown = ctx.tools.register(jsonTool(
|
|
126
|
+
'intent_registry_list', 'List the configured intent acts, categories and predicates together with the routing prompt that ships as the intent_record tool description.',
|
|
127
|
+
{},
|
|
128
|
+
() => host.registry(),
|
|
129
|
+
))
|
|
130
|
+
|
|
131
|
+
const unsubscribe = host.subscribe(ensureRecordTool)
|
|
132
|
+
return () => {
|
|
133
|
+
unsubscribe()
|
|
134
|
+
disposeRecord?.()
|
|
135
|
+
disposeRecord = undefined
|
|
136
|
+
if (typeof disposeView === 'function') (disposeView as () => void)()
|
|
137
|
+
if (typeof disposeRegistry === 'function') (disposeRegistry as () => void)()
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import type { ToolStatus } from 'dsh-data-contracts/envelope'
|
|
2
|
+
import type { LineageContext } from 'dsh-data-contracts/refs'
|
|
3
|
+
|
|
4
|
+
export type { ToolStatus }
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 一个动作类型(act)。
|
|
8
|
+
*
|
|
9
|
+
* act 回答"这一轮用户在**做什么**",与 category(做什么**业务**)正交:同一句
|
|
10
|
+
* "帮我看下上个月的 GMV" 是 `query` × `data_analysis`。光有 id 时模型只能猜
|
|
11
|
+
* `query` 和 `request` 的区别,所以每一类都带 label 与 description。
|
|
12
|
+
*/
|
|
13
|
+
export interface IntentActDef {
|
|
14
|
+
id: string
|
|
15
|
+
label: string
|
|
16
|
+
description: string
|
|
17
|
+
enabled: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 出厂 act 词表。16 个动作覆盖"提问 / 让做 / 补充 / 反馈 / 终止 / 闲聊"六种交互。
|
|
22
|
+
*
|
|
23
|
+
* 记录仍是自由文本(模型可以写没配置过的 act,只给 warning),这份词表是**先验**:
|
|
24
|
+
* 它进 routing prompt,也进设置页与 `intent_registry_list`。
|
|
25
|
+
*/
|
|
26
|
+
export const DEFAULT_ACTS: IntentActDef[] = [
|
|
27
|
+
{ id: 'query', label: '查询', description: '向数据或知识提问,要一个答案或一批结果。', enabled: true },
|
|
28
|
+
{ id: 'request', label: '执行请求', description: '让 Agent 做一件事并产生副作用:写入、发送、导出、修改。', enabled: true },
|
|
29
|
+
{ id: 'inform', label: '补充信息', description: '用户提供事实、参数或上下文,本身不要求动作。', enabled: true },
|
|
30
|
+
{ id: 'confirm', label: '确认', description: '用户认可某个提议或方案,允许继续。', enabled: true },
|
|
31
|
+
{ id: 'select', label: '选择', description: '在多个候选中指定一个。', enabled: true },
|
|
32
|
+
{ id: 'correct', label: '纠正', description: '指出前面的理解或结果不对,要求改。', enabled: true },
|
|
33
|
+
{ id: 'cancel', label: '取消', description: '终止或撤回正在进行的任务。', enabled: true },
|
|
34
|
+
{ id: 'review', label: '审阅', description: '对已产出的内容做检查、评估与把关。', enabled: true },
|
|
35
|
+
{ id: 'explain', label: '解释', description: '要求讲清原理、口径或原因,而不是要新数据。', enabled: true },
|
|
36
|
+
{ id: 'compare', label: '对比', description: '把两个及以上对象放在一起比较差异。', enabled: true },
|
|
37
|
+
{ id: 'recommend', label: '推荐', description: '要建议与取舍意见。', enabled: true },
|
|
38
|
+
{ id: 'resume', label: '继续', description: '回到之前中断的任务继续做。', enabled: true },
|
|
39
|
+
{ id: 'reject', label: '拒绝', description: '不接受某个提议或结果。', enabled: true },
|
|
40
|
+
{ id: 'greet', label: '问候', description: '打招呼、开场。', enabled: true },
|
|
41
|
+
{ id: 'chat', label: '闲聊', description: '非任务性的对话。', enabled: true },
|
|
42
|
+
{ id: 'unknown', label: '未判定', description: '无法归入以上任何一类,或本轮信息不足以判断。', enabled: true },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
/** Free-form act id; configured in `IntentSettings.acts`. */
|
|
46
|
+
export type IntentAct = string
|
|
47
|
+
|
|
48
|
+
/** How one turn relates to the session's existing tasks. */
|
|
49
|
+
export type IntentRelation = 'new_task' | 'subtask_of' | 'unknown'
|
|
50
|
+
|
|
51
|
+
/** `model` is a model-authored record; `fallback` is the Host's turn-end backfill. */
|
|
52
|
+
export type IntentSource = 'model' | 'fallback'
|
|
53
|
+
|
|
54
|
+
export interface IntentSlotMap {
|
|
55
|
+
[name: string]: unknown
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface IntentRef {
|
|
59
|
+
id: string
|
|
60
|
+
kind?: string
|
|
61
|
+
label?: string
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* One configurable intent category; `route` names the act it usually maps to.
|
|
66
|
+
*
|
|
67
|
+
* 预置分类的作用是**把模型的自由判断收窄成一次匹配**:
|
|
68
|
+
* {@link description} 说明这一类"是什么",{@link examples} 给出用户可能怎么说。
|
|
69
|
+
* 两者都会被拼进 routing prompt,模型先按它们匹配,命中就直接用该 id。
|
|
70
|
+
*/
|
|
71
|
+
export interface IntentCategory {
|
|
72
|
+
id: string
|
|
73
|
+
label: string
|
|
74
|
+
route: string
|
|
75
|
+
description: string
|
|
76
|
+
/**
|
|
77
|
+
* 预置说法(few-shot):用户可能怎么表达这一类意图,每行一条。
|
|
78
|
+
*
|
|
79
|
+
* 可选——0012 时代的持久化配置没有这个字段,缺省按空数组处理,注册表 schema
|
|
80
|
+
* 也会补默认值。
|
|
81
|
+
*/
|
|
82
|
+
examples?: string[]
|
|
83
|
+
enabled: boolean
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Recorder settings. The classification vocabulary is user-editable: nothing
|
|
88
|
+
* here constrains what a model may record, it only describes the options the
|
|
89
|
+
* routing prompt offers and what `intent_registry_list` reports.
|
|
90
|
+
*/
|
|
91
|
+
export interface IntentSettings {
|
|
92
|
+
/** Below this confidence a record is annotated lowConfidence; the model decides whether to clarify. */
|
|
93
|
+
clarifyThreshold: number
|
|
94
|
+
ttlSeconds: number
|
|
95
|
+
/**
|
|
96
|
+
* 0023:路由提示词**没有开关**。它随 `intent_record` 的工具描述一起下发,
|
|
97
|
+
* 分类规则必须始终在场——否则模型退化成每轮从零判断。
|
|
98
|
+
*/
|
|
99
|
+
/** Backfill one `unknown` record when a turn ends without a model record. */
|
|
100
|
+
fallbackEnabled: boolean
|
|
101
|
+
categories: IntentCategory[]
|
|
102
|
+
acts: IntentActDef[]
|
|
103
|
+
predicates: string[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function category(id: string, label: string, route: string, description: string, examples: string[]): IntentCategory & { examples: string[] } {
|
|
107
|
+
return { id, label, route, description, examples, enabled: true }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 出厂预置的意图分类。
|
|
112
|
+
*
|
|
113
|
+
* 每一项都**必须**带 `description` 与 `examples`:只给标签("数据分析")时模型
|
|
114
|
+
* 只能靠猜,同一句话在不同轮次会被分到不同类。这些文案是模型的匹配依据,全部
|
|
115
|
+
* 可以在「意图」页里改。
|
|
116
|
+
*/
|
|
117
|
+
export const DEFAULT_CATEGORIES: Array<IntentCategory & { examples: string[] }> = [
|
|
118
|
+
category('data_analysis', '数据分析', 'query', '取数、算指标、拆口径的请求:给一个数或一段分析结论。', ['帮我算一下上个月的 GMV', '这个指标怎么拆', '跑个数看看环比']),
|
|
119
|
+
category('metadata_exploration', '元数据探索', 'query', '问"有哪些表/字段/口径"本身,要的是结构而不是数字。', ['这张表有哪些字段', '库里有几张订单表', '这些指标的口径是怎么定义的']),
|
|
120
|
+
category('data_validation', '数据校验', 'query', '核对数据是否可信:对不上、空值、重复、异常波动。', ['这两个数对不上,查一下', '帮我看下这列有没有重复', '空值率是不是偏高了']),
|
|
121
|
+
category('knowledge_consultation', '知识咨询', 'query', '问组织既有的结论、规则、流程或负责人,答案在知识库里。', ['我们去年是怎么定这个口径的', '知识库里有没有相关文档', '这个流程找谁确认']),
|
|
122
|
+
category('knowledge_building', '知识构建', 'request', '把材料沉淀进知识库:录入来源、写卡片、重建索引。', ['把这份文档存进知识库', '记一条:这个口径改成…', '帮我整理成一张知识卡片']),
|
|
123
|
+
category('document_research', '文档研究', 'query', '对一份或多份长文档做通读、归纳、对比、找证据。', ['把这份 PRD 读一遍,总结需求点', '这几篇文档有没有冲突', '从报告里找出支持这个结论的证据']),
|
|
124
|
+
category('message_collaboration', '消息协作', 'request', '替用户发消息、同步进度、在群里通知或拉人。', ['发条消息给张三', '在群里同步一下进度', '@一下负责人催确认']),
|
|
125
|
+
category('artifact_delivery', '产物交付', 'request', '要一个可交付的文件:表格、报告、周报、导出件。', ['导出一份 Excel', '生成这周的周报', '把结果做成表格发我']),
|
|
126
|
+
category('agent_engineering', 'Agent 工程', 'request', '改 Agent 自身:加工具、调提示词、改 skill、查它为什么这么答。', ['加一个工具', '这个 skill 怎么改', '它刚才为什么没调那个工具']),
|
|
127
|
+
category('tooling_operations', '工具运维', 'request', '运维动作:重启、看队列、清缓存、处理环境报错。', ['重启一下服务', '看看任务队列', '这个报错怎么修']),
|
|
128
|
+
category('personal_assistant', '个人助理', 'request', '个人日程与提醒类事务。', ['明天提醒我开会', '帮我约个会', '看下我今天的日程']),
|
|
129
|
+
category('conversation', '普通对话', 'chat', '寒暄、闲聊、对 Agent 本身的提问,没有数据或交付目标。', ['你好', '你是谁', '谢谢,先这样']),
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
export const DEFAULT_PREDICATES: string[] = [
|
|
133
|
+
'query_babel_data', 'query_knowledge', 'query_source_truth', 'query_metadata',
|
|
134
|
+
'query_graph', 'add_source', 'write_knowledge_card', 'rebuild_knowledge',
|
|
135
|
+
'send_message', 'export_artifact', 'unknown',
|
|
136
|
+
]
|
|
137
|
+
|
|
138
|
+
export const DEFAULT_INTENT_SETTINGS: IntentSettings = {
|
|
139
|
+
clarifyThreshold: 0.65,
|
|
140
|
+
ttlSeconds: 600,
|
|
141
|
+
fallbackEnabled: true,
|
|
142
|
+
categories: DEFAULT_CATEGORIES,
|
|
143
|
+
acts: DEFAULT_ACTS,
|
|
144
|
+
predicates: DEFAULT_PREDICATES,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** One recorded intent. The record is an audit fact; it never drives control flow. */
|
|
148
|
+
export interface IntentRecord {
|
|
149
|
+
id: string
|
|
150
|
+
sessionKey: string
|
|
151
|
+
/** `sessionKey#turn` — the upsert key that keeps one record per turn. */
|
|
152
|
+
turnKey: string
|
|
153
|
+
turnId: string
|
|
154
|
+
userInput: string
|
|
155
|
+
act: IntentAct
|
|
156
|
+
category?: string
|
|
157
|
+
predicate?: string
|
|
158
|
+
slots: IntentSlotMap
|
|
159
|
+
confidence?: number
|
|
160
|
+
lowConfidence?: boolean
|
|
161
|
+
refs: IntentRef[]
|
|
162
|
+
relation: IntentRelation
|
|
163
|
+
source: IntentSource
|
|
164
|
+
createdAt: string
|
|
165
|
+
updatedAt: string
|
|
166
|
+
lineage: LineageContext
|
|
167
|
+
meta: Record<string, unknown>
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface IntentRecordInput {
|
|
171
|
+
userInput: string
|
|
172
|
+
act?: string
|
|
173
|
+
category?: string
|
|
174
|
+
predicate?: string
|
|
175
|
+
slots?: IntentSlotMap
|
|
176
|
+
confidence?: number
|
|
177
|
+
refs?: IntentRef[]
|
|
178
|
+
relation?: IntentRelation
|
|
179
|
+
sessionKey: string
|
|
180
|
+
turnId?: string
|
|
181
|
+
lineage?: Partial<LineageContext>
|
|
182
|
+
now?: number
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Compact task context returned to the model so it can pick the next relation. */
|
|
186
|
+
export interface IntentTaskSummary {
|
|
187
|
+
taskId: string
|
|
188
|
+
lastSubtaskId?: string
|
|
189
|
+
category?: string
|
|
190
|
+
ageSeconds: number
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface IntentRegistry {
|
|
194
|
+
/** 可编辑的 act 词表(带 label / description),面板就地增删改。 */
|
|
195
|
+
acts: IntentActDef[]
|
|
196
|
+
/**
|
|
197
|
+
* 可用的意图分类。带 `description` / `examples`,因为「意图」页要就地编辑它们,
|
|
198
|
+
* 而不是只渲染成一组只读徽标。
|
|
199
|
+
*/
|
|
200
|
+
categories: Array<{ id: string; label: string; route: string; description: string; examples: string[]; enabled: boolean }>
|
|
201
|
+
predicates: string[]
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface IntentStoreView {
|
|
205
|
+
sessionKey: string
|
|
206
|
+
activeTaskId?: string
|
|
207
|
+
activeIntentId?: string
|
|
208
|
+
tasks: IntentTaskSummary[]
|
|
209
|
+
recent: IntentRecord[]
|
|
210
|
+
expiresAt?: string
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface IntentResultData {
|
|
214
|
+
intentId?: string
|
|
215
|
+
taskId?: string
|
|
216
|
+
subtaskId?: string
|
|
217
|
+
parentSubtaskId?: string
|
|
218
|
+
runId?: string
|
|
219
|
+
turnId?: string
|
|
220
|
+
act?: string
|
|
221
|
+
category?: string
|
|
222
|
+
relation?: IntentRelation
|
|
223
|
+
source?: IntentSource
|
|
224
|
+
lowConfidence?: boolean
|
|
225
|
+
activeTasks?: IntentTaskSummary[]
|
|
226
|
+
store?: IntentStoreView
|
|
227
|
+
registry?: IntentRegistry
|
|
228
|
+
prompt?: string
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface IntentResult {
|
|
232
|
+
ok: boolean
|
|
233
|
+
status: ToolStatus
|
|
234
|
+
data: IntentResultData
|
|
235
|
+
warnings: string[]
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Live turn state: the provisional ids allocated before the model records. */
|
|
239
|
+
export interface IntentTurnState {
|
|
240
|
+
turn: number
|
|
241
|
+
userInput: string
|
|
242
|
+
subtaskId: string
|
|
243
|
+
taskId?: string
|
|
244
|
+
committed: boolean
|
|
245
|
+
}
|