@h-ai/cli 0.1.0-alpha.35 → 0.1.0-alpha.37
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/package.json +2 -2
- package/templates/base/package.json.hbs +1 -1
- package/templates/skills/hai-ai/SKILL.md +101 -26
- package/templates/skills/hai-ai/reference.md +41 -11
- package/templates/skills/hai-api-client/SKILL.md +14 -0
- package/templates/skills/hai-api-contract/SKILL.md +10 -0
- package/templates/skills/hai-app-create/SKILL.md +10 -0
- package/templates/skills/hai-app-review/SKILL.md +10 -0
- package/templates/skills/hai-app-tests/SKILL.md +10 -0
- package/templates/skills/hai-audit/SKILL.md +10 -0
- package/templates/skills/hai-build/SKILL.md +10 -0
- package/templates/skills/hai-cache/SKILL.md +10 -0
- package/templates/skills/hai-capacitor/SKILL.md +10 -0
- package/templates/skills/hai-ci/SKILL.md +10 -0
- package/templates/skills/hai-core/SKILL.md +10 -0
- package/templates/skills/hai-crypto/SKILL.md +10 -0
- package/templates/skills/hai-datapipe/SKILL.md +10 -0
- package/templates/skills/hai-deploy/SKILL.md +10 -0
- package/templates/skills/hai-framework-sync/SKILL.md +10 -0
- package/templates/skills/hai-iam/SKILL.md +31 -0
- package/templates/skills/hai-kit/SKILL.md +12 -0
- package/templates/skills/hai-payment/SKILL.md +10 -0
- package/templates/skills/hai-pr-review/SKILL.md +10 -0
- package/templates/skills/hai-reach/SKILL.md +12 -0
- package/templates/skills/hai-reldb/SKILL.md +10 -0
- package/templates/skills/hai-scheduler/SKILL.md +10 -0
- package/templates/skills/hai-serv/SKILL.md +33 -0
- package/templates/skills/hai-storage/SKILL.md +10 -0
- package/templates/skills/hai-ui/SKILL.md +18 -5
- package/templates/skills/hai-vecdb/SKILL.md +10 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.37",
|
|
5
5
|
"description": "Hai Framework CLI for project scaffolding and code generation.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"ora": "^9.1.0",
|
|
35
35
|
"prompts": "^2.4.2",
|
|
36
36
|
"yaml": "^2.7.0",
|
|
37
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
37
|
+
"@h-ai/core": "0.1.0-alpha.37"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{projectName}}",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.37",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "{{#if_eq appType 'admin'}}Enterprise management system built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'website'}}Enterprise website built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'h5'}}Mobile H5 app built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'api'}}REST API service built with hai Agent Framework{{/if_eq}}{{#if_eq appType 'mobile-app'}}Mobile app built with hai Agent Framework{{/if_eq}}",
|
|
6
6
|
"keywords": ["hai", {{#unless isSvelteOnlyApp}}"sveltekit", {{/unless}}"svelte5", "{{appType}}"],
|
|
@@ -1,40 +1,59 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hai-ai
|
|
3
|
-
description:
|
|
3
|
+
description: "Use when: using @h-ai/ai for LLM calls, tools, MCP, streaming, memory/context, RAG, audio, A2A, or the AI client. 当需求涉及 AI 对话、工具、Audio、会话、知识库或 AI 客户端时使用。"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# hai-ai — @h-ai/ai 快速指南
|
|
7
7
|
|
|
8
|
-
`@h-ai/ai` 统一提供 LLM、工具、MCP、Embedding、Memory、Retrieval/RAG、Knowledge、Context、File、Rerank 与 A2A 能力。
|
|
8
|
+
`@h-ai/ai` 统一提供 LLM、工具、MCP、Embedding、Memory、Retrieval/RAG、Knowledge、Context、File、Rerank、Audio 与 A2A 能力。
|
|
9
9
|
|
|
10
10
|
> 详细 API 表、错误码与长示例见同目录 `reference.md`。只有需要完整契约或边界用例时再读取,避免把长参考塞进上下文。
|
|
11
11
|
|
|
12
|
+
## 能力契约
|
|
13
|
+
|
|
14
|
+
| 项目 | 契约 |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| 能力 | LLM/流式生成、结构化 Tool、MCP、Embedding、Memory、RAG/Knowledge、Context、Audio、A2A |
|
|
17
|
+
| 适用场景 | 服务端 AI 对话、Agent 工具链、知识问答、长期记忆、语音交互和 Agent-to-Agent;浏览器通过 client/API 代理 |
|
|
18
|
+
| 输入 | `AIConfigInput`、消息/文本/音频、Zod Tool schema、`objectId/sessionId/scope`、`AbortSignal` |
|
|
19
|
+
| 输出 | 领域操作返回 `HaiResult<T>`;流式 API 返回 `AsyncIterable`;Tool 返回 `ToolMessage`;客户端传输可能抛异常 |
|
|
20
|
+
| 限制 | 框架不替代业务授权、沙箱、人工确认和网络出口策略;临时 Store 不持久化;Prompt、检索内容和模型 Tool Call 均视为不可信输入 |
|
|
21
|
+
|
|
12
22
|
## 使用边界
|
|
13
23
|
|
|
14
24
|
- `ai.tools`、`ai.stream` 是纯函数能力,无需 `ai.init()`。
|
|
15
|
-
- `ai.llm`、`ai.embedding`、`ai.memory`、`ai.retrieval`、`ai.rag`、`ai.knowledge`、`ai.context`、`ai.a2a` 需要先 `await ai.init(...)`。
|
|
16
|
-
-
|
|
25
|
+
- `ai.llm`、`ai.embedding`、`ai.memory`、`ai.retrieval`、`ai.rag`、`ai.knowledge`、`ai.context`、`ai.audio`、`ai.a2a` 需要先 `await ai.init(...)`。
|
|
26
|
+
- 未初始化 reldb/vecdb 时,`ai.init()` 使用进程内临时 Store,适合 LLM-only 与本地原型;数据在 `ai.close()` 或进程退出后丢失。
|
|
27
|
+
- reldb 与 vecdb 均已初始化时自动使用持久化 DB Provider;生产 Memory/Context/Persona/Knowledge 应使用该路径或自定义 `AIStoreProvider`。
|
|
17
28
|
- 浏览器端不要直接调用 Node-only 能力;通过 `@h-ai/api-client` 或应用自定义 API/SSE endpoint 代理。
|
|
18
29
|
- 公共 API 返回 `HaiResult<T>` 时按 `if (!result.success) return result` 处理;不要用 `try/catch` 包裹正常业务错误。
|
|
19
30
|
|
|
20
31
|
## 初始化与关闭
|
|
21
32
|
|
|
22
33
|
```ts
|
|
34
|
+
import { core } from '@h-ai/core'
|
|
23
35
|
import { ai } from '@h-ai/ai'
|
|
24
|
-
import { reldb } from '@h-ai/reldb'
|
|
25
|
-
import { vecdb } from '@h-ai/vecdb'
|
|
26
|
-
|
|
27
|
-
await reldb.init(core.config.get('db'))
|
|
28
|
-
await vecdb.init(core.config.get('vecdb'))
|
|
29
36
|
|
|
30
37
|
const init = await ai.init(core.config.get('ai'))
|
|
31
38
|
if (!init.success) return init
|
|
32
39
|
|
|
33
|
-
//
|
|
40
|
+
// LLM-only:未初始化 DB 时使用进程内临时 Store
|
|
41
|
+
// ... 使用 ai.llm
|
|
34
42
|
|
|
35
43
|
await ai.close()
|
|
36
44
|
```
|
|
37
45
|
|
|
46
|
+
需要持久化时先初始化 DB:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { reldb } from '@h-ai/reldb'
|
|
50
|
+
import { vecdb } from '@h-ai/vecdb'
|
|
51
|
+
|
|
52
|
+
await reldb.init(core.config.get('db'))
|
|
53
|
+
await vecdb.init(core.config.get('vecdb'))
|
|
54
|
+
await ai.init(core.config.get('ai'))
|
|
55
|
+
```
|
|
56
|
+
|
|
38
57
|
自定义存储:
|
|
39
58
|
|
|
40
59
|
```ts
|
|
@@ -71,10 +90,11 @@ knowledge:
|
|
|
71
90
|
maxSize: 1500
|
|
72
91
|
overlap: 200
|
|
73
92
|
|
|
74
|
-
#
|
|
93
|
+
# 可选:mem0ai/oss 引擎;无法映射持久化后端时默认 fail-fast
|
|
75
94
|
memory:
|
|
76
95
|
provider: mem0
|
|
77
96
|
defaultTopK: 10
|
|
97
|
+
# allowEphemeralFallback: true # 仅明确接受重启丢失数据时开启
|
|
78
98
|
```
|
|
79
99
|
|
|
80
100
|
`ai.config` 是脱敏快照;`apiKey`、`privateKey`、URL 内嵌凭证会被隐藏。
|
|
@@ -88,29 +108,42 @@ memory:
|
|
|
88
108
|
| 多协议 | 模型 `api: chat/responses/anthropic` | 底层走 Chat Completions / Responses / Anthropic,公共形状不变 |
|
|
89
109
|
| 请求取消 | `ai.llm.chat({ messages, signal })` | 传 `AbortSignal`,`abort()` 立即停上游生成 |
|
|
90
110
|
| 临时模型 | `ai.llm.chat({ messages, tempModel })` | 单次请求级临时端点,客户端按 TTL 缓存 |
|
|
91
|
-
| 工具定义 | `ai.tools.define(...)` | Zod schema 转 JSON Schema |
|
|
92
|
-
|
|
|
111
|
+
| 工具定义 | `ai.tools.define(...)` | Zod schema 转 JSON Schema;`handler(input, ctx)` 第二参为执行上下文 |
|
|
112
|
+
| 工具注册 | `registry.register/replace` | `register` 默认拒绝同名并返回 HaiResult;只有 `replace` 可显式替换 |
|
|
113
|
+
| 工具执行 | `registry.execute(tc, { signal, objectId, sessionId, deadline?, timeoutMs?, authorize? })` / `executeAll(...)` | Registry/单次授权必须同时通过;默认串行,支持取消/超时;只有确认无副作用时才 `parallel: true` |
|
|
93
114
|
| MCP 服务 | `createMcpServer(...)` | 按需连接 HTTP/SSE/Stdio transport |
|
|
94
115
|
| Embedding | `ai.embedding.embedText(text)` | 批量用 `embedBatch` |
|
|
95
116
|
| 记忆 | `ai.memory.extract/recall/injectMemories` | 用 `objectId` 做主体隔离,`scope` 做业务作用域隔离;scope 隔离越细,`candidateMultiplier` 调大以防漏召回 |
|
|
96
|
-
|
|
|
117
|
+
| 记忆作用域 | `ai.memory.scoped({ objectId, scope })` | **多租户推荐入口**:所有操作自动绑定 objectId/scope(含归属校验);`clear` 仅清作用域内 |
|
|
118
|
+
| 记忆管理 | `ai.memory.admin.clearAll({ confirm: true })` | 唯一的全局清空入口(需显式确认);`ai.memory.clear()` 空过滤会被拒绝,防误清全局 |
|
|
119
|
+
| 角色人格 | `ai.persona.save/get/compose` | 定义 AI 身份(systemPrompt + traits),`compose` 组合系统提示词;按 `objectId` 隔离多租户(不传默认 `system` 平台角色),`scope: { personaId }` 关联长期记忆 |
|
|
97
120
|
| Retrieval/RAG | `ai.retrieval.retrieve` / `ai.rag.query` | Retrieval source 先注册或由配置预置 |
|
|
98
121
|
| Knowledge | `ai.knowledge.setup/ingest/ask` | 入库前会调用 datapipe 清洗分块 |
|
|
99
122
|
| Context | `ai.context.createManager` | 编排 LLM + Memory + RAG + 压缩;`manager.consolidate()` 把会话固化为长期记忆 |
|
|
123
|
+
| Context 并发 | `createManager({ concurrency: 'reject' \| 'queue' })` | 默认单活动生成防消息乱序;活动生成期间新 chat 返回 `CONTEXT_BUSY`(reject)或排队(queue) |
|
|
124
|
+
| Context 重置 | `await manager.reset({ preserveSystemPrompt?, cancelActiveTurn?, waitForMemoryTasks? })` | 异步:终止活动生成、清空消息/摘要/轮次,默认保留系统提示词 |
|
|
125
|
+
| 语音识别 | `ai.audio.transcribe` / `transcribeStream` | 完整音频返回 `HaiResult`;持续音频输入用 `AudioInputStream` 流式返回临时文本 |
|
|
126
|
+
| 语音合成 | `ai.audio.synthesize` / `synthesizeStream` | `text` 可为字符串或 `AsyncIterable<string>`(可接 LLM 文本流边生成边合成) |
|
|
100
127
|
| A2A | `ai.a2a.registerExecutor/handleRequest` | 延迟初始化 SDK handler |
|
|
101
128
|
|
|
102
129
|
## LLM + 工具调用
|
|
103
130
|
|
|
104
131
|
```ts
|
|
105
|
-
|
|
106
|
-
|
|
132
|
+
import { z } from 'zod'
|
|
133
|
+
|
|
134
|
+
const registry = ai.tools.createRegistry({
|
|
135
|
+
authorize: ({ toolName, context }) => canExecuteTool(context.objectId, toolName),
|
|
136
|
+
})
|
|
137
|
+
const registered = registry.register(ai.tools.define({
|
|
107
138
|
name: 'get_weather',
|
|
108
139
|
description: '获取天气',
|
|
109
140
|
parameters: z.object({ city: z.string() }),
|
|
110
141
|
handler: async ({ city }) => ({ city, temperature: 20 }),
|
|
111
142
|
}))
|
|
143
|
+
if (!registered.success) return registered
|
|
112
144
|
|
|
113
145
|
const messages: ChatMessage[] = [{ role: 'user', content: '北京天气?' }]
|
|
146
|
+
const objectId = 'user-001'
|
|
114
147
|
let result = await ai.llm.chat({ messages, tools: registry.getDefinitions() })
|
|
115
148
|
|
|
116
149
|
while (result.success && result.data.choices[0]?.finish_reason === 'tool_calls') {
|
|
@@ -118,7 +151,7 @@ while (result.success && result.data.choices[0]?.finish_reason === 'tool_calls')
|
|
|
118
151
|
const toolCalls = assistant.tool_calls ?? []
|
|
119
152
|
messages.push(assistant)
|
|
120
153
|
|
|
121
|
-
const toolMessages = await registry.executeAll(toolCalls, {
|
|
154
|
+
const toolMessages = await registry.executeAll(toolCalls, { objectId })
|
|
122
155
|
if (!toolMessages.success) return toolMessages
|
|
123
156
|
messages.push(...toolMessages.data)
|
|
124
157
|
|
|
@@ -179,7 +212,7 @@ await server.connect(new StreamableHTTPServerTransport({ sessionIdGenerator: cry
|
|
|
179
212
|
|
|
180
213
|
## 记忆、RAG 与知识库
|
|
181
214
|
|
|
182
|
-
`memory.provider` 默认为 `native`(推荐):HAI 原生引擎,复用 vecdb/reldb/LLM/Embedding,`extract` 采用 **Mem0 式批量合并**(一次 LLM 调用对整批事实与相关既有记忆做 ADD/UPDATE/DELETE/NONE,支持 `category`)。`mem0` 则直接使用 `mem0ai/oss` 的 `Memory` 引擎:LLM/Embedder 从 `llm` 配置提取(OpenAI 兼容),向量库从底层 vecdb 后端提取(qdrant/pgvector
|
|
215
|
+
`memory.provider` 默认为 `native`(推荐):HAI 原生引擎,复用 vecdb/reldb/LLM/Embedding,`extract` 采用 **Mem0 式批量合并**(一次 LLM 调用对整批事实与相关既有记忆做 ADD/UPDATE/DELETE/NONE,支持 `category`)。`mem0` 则直接使用 `mem0ai/oss` 的 `Memory` 引擎:LLM/Embedder 从 `llm` 配置提取(OpenAI 兼容),向量库从底层 vecdb 后端提取(qdrant/pgvector 复用)。**mem0 无法映射 lancedb/chroma 等后端时默认 fail-fast**(初始化失败,避免重启后记忆静默丢失);只有显式 `memory.allowEphemeralFallback: true` 才退回 mem0 自带 in-memory 存储。两者对外 `ai.memory.*` API 完全一致。
|
|
183
216
|
|
|
184
217
|
```ts
|
|
185
218
|
const enriched = await ai.memory.injectMemories(messages, { objectId: 'user-001', topK: 5 })
|
|
@@ -225,21 +258,61 @@ await managerResult.data.save()
|
|
|
225
258
|
|
|
226
259
|
### 真实对话状态(Conversation Commit Layer)
|
|
227
260
|
|
|
228
|
-
`turnCommit: 'manual'` 时,`chat` / `chatStream` 不自动写入生成文本,只返回 `turnId`;由调用方提交**实际发生的内容**(TTS
|
|
261
|
+
`turnCommit: 'manual'` 时,`chat` / `chatStream` 不自动写入生成文本,只返回 `turnId`;由调用方提交**实际发生的内容**(TTS 播放、被打断等场景)。`chatStream` 在调用上游模型前就产出 `turn_started`(事件序列 `turn_started → delta* → done`,中途取消 `→ cancelled`),取消时保留 `turnId` 与已生成文本:
|
|
229
262
|
|
|
230
263
|
```ts
|
|
231
264
|
const m = ai.context.createManager({ turnCommit: 'manual', scope }).data
|
|
232
|
-
|
|
265
|
+
const controller = new AbortController()
|
|
266
|
+
for await (const ev of m.chatStream('展开讲讲', { signal: controller.signal })) {
|
|
233
267
|
if (ev.type === 'delta') feedTts(ev.text)
|
|
234
|
-
else if (ev.type === 'done')
|
|
235
|
-
|
|
236
|
-
? await m.interruptTurn(ev.turnId, { text: spokenSoFar }) // 只提交播放出去的部分
|
|
237
|
-
: await m.commitTurn(ev.turnId) // 完整提交
|
|
238
|
-
}
|
|
268
|
+
else if (ev.type === 'done') await m.commitTurn(ev.turnId) // 完整提交
|
|
269
|
+
else if (ev.type === 'cancelled') await m.interruptTurn(ev.turnId, { text: spokenSoFar }) // 只提交播放出去的部分
|
|
239
270
|
}
|
|
240
271
|
```
|
|
241
272
|
|
|
242
273
|
- 只有 `committed` 的内容进入上下文与记忆;`getTurns()` 可观测 `generated` / `committed` / `status`。
|
|
274
|
+
- 主持人抢话时可在 `turn_started` / 迭代过程中随时 `interruptTurn`;轮次进入终态后即便上游流恰好正常结束,`chatStream` 也**不会再产出 `done`**,业务层不会误判为正常完成。
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
## 语音(Audio)
|
|
278
|
+
|
|
279
|
+
`ai.audio` 提供 ASR/TTS,Provider(OpenAI / MiMo / Qwen / 豆包)作为内部实现,凭据未配置时回退平台环境变量。调用方只表达「音频还是文本、完整还是流式」,不感知 WebSocket / SSE / 厂商事件。
|
|
280
|
+
|
|
281
|
+
```yaml
|
|
282
|
+
# ai.init 配置片段
|
|
283
|
+
audio:
|
|
284
|
+
models:
|
|
285
|
+
- { id: asr, provider: qwen, model: qwen3-asr-flash-realtime, operations: [transcribe] }
|
|
286
|
+
- { id: tts, provider: qwen, model: qwen3-tts-flash-realtime, operations: [synthesize] }
|
|
287
|
+
transcribeModel: asr
|
|
288
|
+
synthesizeModel: tts
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
// 完整识别 / 合成(HaiResult)
|
|
293
|
+
const t = await ai.audio.transcribe({ audio: { data: wavBytes, format: 'wav' }, language: 'zh' })
|
|
294
|
+
if (!t.success) return t
|
|
295
|
+
const s = await ai.audio.synthesize({ text: '欢迎', voice: 'Cherry', format: 'pcm16' })
|
|
296
|
+
|
|
297
|
+
// 实时识别:持续音频输入 → 增量文本(chunk.final 标记语句最终态,可直接覆盖临时文本)
|
|
298
|
+
for await (const chunk of ai.audio.transcribeStream({ audio: { chunks: micChunks, format: 'pcm16', sampleRate: 16000 } })) {
|
|
299
|
+
updateTranscript(chunk.text, chunk.final)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 分段合成:稳定 ID 关联文本与音频,支持 AbortSignal 打断
|
|
303
|
+
const controller = new AbortController()
|
|
304
|
+
for await (const event of ai.audio.synthesizeStream({ text: { id: 'seg-1', text: '欢迎。' }, voice: 'Cherry', signal: controller.signal })) {
|
|
305
|
+
if (event.type === 'segment_started')
|
|
306
|
+
prepareDecoder(event.format, event.sampleRate, event.channels) // 真实输出格式来自服务端解析后的 Provider 输出
|
|
307
|
+
else if (event.type === 'audio')
|
|
308
|
+
await player.write(event.data)
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
- 流式方法是 `AsyncIterable`,迭代期间的连接/协议/上游错误会终止迭代(抛出),不返回 `HaiResult`。
|
|
313
|
+
- `segment_started` 携带服务端解析 Provider 后的真实输出参数(`format` / `sampleRate?` / `channels?`);播放器据此解码,不按请求参数猜测格式。
|
|
314
|
+
- 平台不支持的输入方式(如 OpenAI/MiMo 的持续音频输入)会抛 `AUDIO_UNSUPPORTED_INPUT`,不伪装成实时。
|
|
315
|
+
- 浏览器/移动端经 `@h-ai/serv` 统一语音 WebSocket 入口访问;客户端用已登录 HTTP 请求获取短期一次性 ticket,`@h-ai/ai/client` 通过 `audio.getTicket` 建连,不把 IAM access token 放入 URL。浏览器客户端区分正常结束、取消(`AUDIO_CANCELLED`)与 `end` 前异常断连(`AUDIO_CONNECTION_FAILED`);服务端 error 帧保留领域错误码,`synthesize` 不返回未完成的部分音频。
|
|
243
316
|
|
|
244
317
|
|
|
245
318
|
## SvelteKit API 端点模式
|
|
@@ -257,6 +330,8 @@ export const POST = kit.handler(async ({ request }) => {
|
|
|
257
330
|
|
|
258
331
|
- API Key 只从配置 / 环境变量读取,禁止写死。
|
|
259
332
|
- 工具 handler 必须校验输入;用户可见错误走 i18n/错误码。
|
|
333
|
+
- 模型输出、Prompt 和检索内容均不可信;不要把用户内容拼入不可覆盖的系统规则。Zod 只保证参数形状,高权限工具还必须在 handler 内校验身份、租户、资源归属和配额。
|
|
334
|
+
- 只向模型注册允许自动执行的工具;写操作默认要求业务侧确认或幂等键,不能把“模型请求调用”当作授权。
|
|
260
335
|
- 批量导入、批量 embedding 用批量 API,避免 await-in-loop。
|
|
261
336
|
- 文件解析/OCR 失败按 `HaiAIError.FILE_*` 返回,不抛业务异常。
|
|
262
|
-
- A2A 认证失败返回 `A2A_AUTH_FAILED
|
|
337
|
+
- A2A 认证失败返回 `A2A_AUTH_FAILED`;`callRemoteAgent` 只依赖 `ai.init()`,无需注册本地 executor。远端 URL 仅接受 HTTP(S) 且不得内嵌凭据,应用仍须配置 origin 白名单与出口网络策略。不要记录 token、apiKey、私钥、完整 headers 或带 query 的 URL。
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
## 初始化与依赖
|
|
6
6
|
|
|
7
|
+
未初始化 reldb/vecdb 时,`ai.init()` 自动使用进程内临时 Store;两者均已初始化时使用持久化 DB Provider。需要跨进程持久化时必须使用 DB 或自定义 Provider。
|
|
8
|
+
|
|
7
9
|
| 能力 | 是否需要 `ai.init()` | 依赖 |
|
|
8
10
|
| --- | --- | --- |
|
|
9
11
|
| `ai.tools` | 否 | 无 |
|
|
@@ -46,10 +48,12 @@ if (result.success) {
|
|
|
46
48
|
## Tools
|
|
47
49
|
|
|
48
50
|
- `ai.tools.define({ name, description, parameters, handler })`
|
|
49
|
-
- `ai.tools.createRegistry()`
|
|
50
|
-
- `registry.register(tool)` / `registry.
|
|
51
|
+
- `ai.tools.createRegistry({ authorize? })`
|
|
52
|
+
- `registry.register(tool)` / `registry.registerMany(tools)`:返回 `HaiResult<void>`,默认拒绝同名
|
|
53
|
+
- `registry.replace(tool)`:显式替换已存在工具
|
|
54
|
+
- `registry.unregister(name)`
|
|
51
55
|
- `registry.getDefinitions()`:传给 LLM 的工具定义
|
|
52
|
-
- `registry.execute(toolCall)` / `registry.executeAll(toolCalls, { parallel })`
|
|
56
|
+
- `registry.execute(toolCall, { signal, objectId, sessionId, deadline?, timeoutMs?, authorize? })` / `registry.executeAll(toolCalls, { parallel?, ...ctx })`;默认串行;Registry/单次授权均 fail-closed;handler `(input, ctx)` 可响应取消/超时(默认 30s)
|
|
53
57
|
|
|
54
58
|
工具 handler 输入由 Zod schema 约束,外部输入不要绕过 schema。
|
|
55
59
|
|
|
@@ -92,10 +96,10 @@ Embedding OpenAI 客户端按 `apiKey + baseURL + timeout` 缓存;同一 key
|
|
|
92
96
|
| --- | --- |
|
|
93
97
|
| `extract(messages, options?)` | 从对话提取记忆并存储 |
|
|
94
98
|
| `add(entry)` | 手动添加记忆 |
|
|
95
|
-
| `get(memoryId)` / `update(memoryId, updates)` |
|
|
99
|
+
| `get(memoryId, accessScope?)` / `update(memoryId, updates, accessScope?)` | 读取/更新(传 `accessScope: { objectId, scope? }` 做归属校验,不匹配→ `MEMORY_NOT_FOUND`) |
|
|
96
100
|
| `recall(query, options?)` | 检索相关记忆 |
|
|
97
101
|
| `injectMemories(messages, options?)` | 注入 system 记忆上下文 |
|
|
98
|
-
| `remove(memoryId)` / `clear(options?)` |
|
|
102
|
+
| `remove(memoryId, accessScope?)` / `clear(options?)` | 删除(`accessScope` 同上) |
|
|
99
103
|
| `list(options?)` / `listPage(options?)` | 列表/分页 |
|
|
100
104
|
|
|
101
105
|
推荐所有记忆操作带 `objectId`,避免不同用户或 Agent 混写。
|
|
@@ -103,8 +107,8 @@ Embedding OpenAI 客户端按 `apiKey + baseURL + timeout` 缓存;同一 key
|
|
|
103
107
|
Memory 后端通过 `memory.provider` 选择:
|
|
104
108
|
|
|
105
109
|
- `native`(默认):HAI 原生引擎,复用 vecdb/reldb/LLM/Embedding。`extract` 采用 Mem0 式批量合并(ADD/UPDATE/DELETE/NONE + `category`);`maxEntriesPerObject`(单主体配额)/`maxEntriesGlobal`(全局上限)/`recencyDecay`/`embeddingEnabled`/`writebackRelatedTopK` 作用于此后端;淘汰按 `objectId` 分区。
|
|
106
|
-
- `mem0`:直接使用 `mem0ai/oss` 的 `Memory` 引擎(嵌入式)。LLM/Embedder 从 `llm` 配置提取(OpenAI 兼容,场景模型 `extraction` / `embedding`);向量库从底层 vecdb 后端提取(`storeProvider.getVectorBackend()`),qdrant/pgvector
|
|
107
|
-
- 两者对外 API(extract/recall/injectMemories/add/update/get/remove/list/listPage/clear)完全一致;`objectId` 隔离不同主体的记忆,`scope`(key-value)用于业务作用域隔离(recall/list/listPage/clear 均严格过滤)。mem0 后端 `update` 涉及 type/importance/metadata 时会重建记忆并重新分配 `id`。
|
|
110
|
+
- `mem0`:直接使用 `mem0ai/oss` 的 `Memory` 引擎(嵌入式)。LLM/Embedder 从 `llm` 配置提取(OpenAI 兼容,场景模型 `extraction` / `embedding`);向量库从底层 vecdb 后端提取(`storeProvider.getVectorBackend()`),qdrant/pgvector 复用同一后端;无法映射 lancedb/chroma 等后端时**默认 fail-fast**(除非 `memory.allowEphemeralFallback: true` 才退回 mem0 in-memory);历史默认禁用。
|
|
111
|
+
- 两者对外 API(extract/recall/injectMemories/add/update/get/remove/list/listPage/clear)完全一致;`objectId` 隔离不同主体的记忆,`scope`(key-value)用于业务作用域隔离(recall/list/listPage/clear 均严格过滤)。mem0 后端 `extract` 在框架层分类打分后以 `infer:false` 写入(保留 `hai_type`/`hai_importance`),`recall` 支持 `types`/`recencyWeight`,与 native 一致;mem0 后端 `update` 涉及 type/importance/metadata 时会重建记忆并重新分配 `id`。
|
|
108
112
|
|
|
109
113
|
## Retrieval / RAG
|
|
110
114
|
|
|
@@ -163,6 +167,27 @@ const result = await ai.rag.query('核心架构是什么?', {
|
|
|
163
167
|
- `ai.rerank.rerank(request)` / `rerankTexts(query, texts, topN?)`:相关性重排。
|
|
164
168
|
- `ai.reasoning.run(query, options?)` / `runStream(query, options?)`:`react`、`cot`、`plan-execute`。
|
|
165
169
|
|
|
170
|
+
## Audio
|
|
171
|
+
|
|
172
|
+
| 方法 | 返回 | 说明 |
|
|
173
|
+
| --- | --- | --- |
|
|
174
|
+
| `transcribe(request)` | `Promise<HaiResult<TranscriptionResult>>` | 完整音频 → 完整文本 |
|
|
175
|
+
| `transcribeStream(request)` | `AsyncIterable<TranscriptionEvent>` | 完整音频或 `AudioInputStream` → `speech_started` / `{type:'transcript',text,final}` / `speech_stopped`(VAD 平台产出语音起止事件) |
|
|
176
|
+
| `synthesize(request)` | `Promise<HaiResult<SynthesisResult>>` | 完整文本 → 完整音频 |
|
|
177
|
+
| `synthesizeStream(request)` | `AsyncIterable<SynthesisEvent>` | 带 ID 文本段 → `segment_started → audio* → segment_done`,事件均可关联 `segmentId`;`segment_started` 携带服务端解析后的真实 `format` / `sampleRate?` / `channels?` |
|
|
178
|
+
| `getCapabilities({ operation, model? })` | `HaiResult<AudioModelCapabilities>` | 按模型与操作查询 `transcribe` / `synthesize` 能力分支,并拒绝操作不匹配模型 |
|
|
179
|
+
|
|
180
|
+
- 音频类型:`AudioContent { data: Uint8Array, format: 'pcm16'|'wav'|'mp3'|'opus', sampleRate?, channels? }`;`pcm16` 等裸音频必须传 `sampleRate`。
|
|
181
|
+
- 请求可选:识别 `contextHints?: string[]`(热词/提示);合成 `instruction?: string`(自然语言风格指令);均支持 `signal: AbortSignal`。
|
|
182
|
+
- 模型配置:`audio.models: [{ id, provider: 'openai'|'mimo'|'qwen'|'doubao', model, operations, apiKey?, baseUrl?, appKey?, accessKey?, resourceId?, workspaceId? }]`;`operations` 必须明确为识别、合成或两者。
|
|
183
|
+
- 凭据环境变量回退:`HAI_AI_AUDIO_<PROVIDER>_API_KEY` 或 `OPENAI_API_KEY` / `MIMO_API_KEY` / `DASHSCOPE_API_KEY` / `VOLC_API_KEY`(豆包旧版控制台额外 `VOLC_APP_KEY` / `VOLC_ACCESS_KEY`)。
|
|
184
|
+
- 资源上限:`audio.maxAudioBytes`(默 10 MiB)、`audio.maxStreamDurationMs`(默 5 分钟);所有请求支持 `signal: AbortSignal` 打断。
|
|
185
|
+
- Provider 为内部实现,不从根入口导出;不支持的输入方式招 `AUDIO_UNSUPPORTED_INPUT`,不伪装实时。取消 → `AUDIO_CANCELLED`,超时 → `AUDIO_TIMEOUT`,连接失败或 `end` 前异常断连 → `AUDIO_CONNECTION_FAILED`。浏览器客户端(`@h-ai/ai/client`)严格区分正常结束 / 取消 / 异常断连:取消招 `AUDIO_CANCELLED`、`end` 前断连招 `AUDIO_CONNECTION_FAILED`、服务端 error 帧保留其领域错误码,`synthesize` 不把未完成的部分音频当作成功返回。
|
|
186
|
+
|
|
187
|
+
## LLM 结构化输出
|
|
188
|
+
|
|
189
|
+
`ai.llm.generateObject({ schema, messages, model?, systemPrompt?, maxRepairs?, signal? })`:按 Zod schema 约束模型输出(json_schema)并解析为对象,解析/校验失败自动带错误提示重试(默 1 次)。适用于“是否为问题/意图分类/置信度”等需要稳定结构结果的场景,避免手写 `JSON.parse`。
|
|
190
|
+
|
|
166
191
|
## A2A
|
|
167
192
|
|
|
168
193
|
| 方法 | 说明 |
|
|
@@ -171,9 +196,11 @@ const result = await ai.rag.query('核心架构是什么?', {
|
|
|
171
196
|
| `getAgentCard()` | 获取 Agent Card |
|
|
172
197
|
| `handleRequest(body, context?)` | 处理 A2A JSON-RPC 请求 |
|
|
173
198
|
| `listMessages(filter)` | 查询 A2A 消息记录 |
|
|
174
|
-
| `callRemoteAgent(remoteUrl, message, options?)` | 调用远端 Agent |
|
|
199
|
+
| `callRemoteAgent(remoteUrl, message, options?)` | 调用远端 Agent;只依赖 `ai.init()`,不要求本地 executor |
|
|
175
200
|
|
|
176
|
-
A2A
|
|
201
|
+
A2A 服务端 SDK handler 在注册 executor 时延迟创建;远端客户端调用不依赖服务端配置。
|
|
202
|
+
|
|
203
|
+
`callRemoteAgent` 只接受 HTTP(S) 且拒绝 URL 内嵌凭据。该校验不是完整 SSRF 防护:remote URL 若来自外部输入,应用必须先按 origin 白名单过滤,并通过出口代理限制 DNS 重绑定、重定向到私网与云元数据地址。
|
|
177
204
|
|
|
178
205
|
## 错误码速查
|
|
179
206
|
|
|
@@ -182,14 +209,15 @@ A2A 的 SDK handler 延迟创建;注册 executor 或首次处理请求时才
|
|
|
182
209
|
| `hai:ai:000` | `INTERNAL_ERROR` |
|
|
183
210
|
| `hai:ai:010-012` | 初始化:`NOT_INITIALIZED` / `CONFIGURATION_ERROR` / `INIT_IN_PROGRESS` |
|
|
184
211
|
| `hai:ai:020-033` | Rerank / File |
|
|
212
|
+
| `hai:ai:050-059` | Audio:`AUDIO_INVALID_REQUEST` / `MODEL_NOT_FOUND` / `PROVIDER_NOT_FOUND` / `UNSUPPORTED_INPUT` / `UPSTREAM_ERROR` / `PROTOCOL_ERROR` / `CONNECTION_FAILED` / `TIMEOUT` / `INPUT_TOO_LARGE` / `CANCELLED` |
|
|
185
213
|
| `hai:ai:100-107` | LLM / 历史记录 |
|
|
186
214
|
| `hai:ai:200-204` | MCP |
|
|
187
215
|
| `hai:ai:300-302` | Embedding |
|
|
188
|
-
| `hai:ai:400-
|
|
216
|
+
| `hai:ai:400-405` | Tool(含重复注册、授权拒绝) |
|
|
189
217
|
| `hai:ai:500-502` | Reasoning |
|
|
190
218
|
| `hai:ai:600-701` | Retrieval / RAG |
|
|
191
219
|
| `hai:ai:800-805` | Knowledge |
|
|
192
|
-
| `hai:ai:900-
|
|
220
|
+
| `hai:ai:900-905` | Memory |
|
|
193
221
|
| `hai:ai:950-971` | Context / Store / Session |
|
|
194
222
|
| `hai:ai:980-984` | A2A |
|
|
195
223
|
|
|
@@ -201,3 +229,5 @@ A2A 的 SDK handler 延迟创建;注册 executor 或首次处理请求时才
|
|
|
201
229
|
const response = await apiClient.ai.chats.createCompletion({ messages })
|
|
202
230
|
const memories = await apiClient.ai.memories.recall({ query: '偏好', objectId: 'user-001', topK: 5 })
|
|
203
231
|
```
|
|
232
|
+
|
|
233
|
+
语音:`@h-ai/ai/client` 的 `createAIClient({ api, audio: { url, getTicket } })` 提供 `client.audio.transcribe/transcribeStream/synthesize/synthesizeStream`。`getTicket(request)` 接收本次操作摘要(`operation` / `model`),应通过已登录 HTTP 请求签发与本次操作严格绑定的短期、一次性 Audio ticket(推荐 `iam.ticket.issue({ grant })`);IAM access token 不进入 WebSocket URL。
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/api-client 构建多端共用的 oRPC/OpenAPI typed cl
|
|
|
5
5
|
|
|
6
6
|
# hai-api-client
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/api-client 构建多端共用的 oRPC/OpenAPI typed client,通过 apiClient.init() 初始化,支持 Bearer Token 自动管理、401 刷新重试与 contract 嵌套方法调用;当需求涉及客户端 API 请求、Token 管理或多端数据层时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-api-client` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/api-client` 是跨端 typed API client。公共 HTTP API 由 `@h-ai/api-contract` 定义,服务端由 `@h-ai/serv` 挂载,客户端直接调用 `apiClient.<domain>.<group>.<operation>()`。
|
|
9
19
|
|
|
10
20
|
## 使用步骤
|
|
@@ -71,6 +81,10 @@ if (login.success) {
|
|
|
71
81
|
}
|
|
72
82
|
|
|
73
83
|
const me = await apiClient.iam.auth.currentUser()
|
|
84
|
+
if (me.success) {
|
|
85
|
+
// currentUser 返回服务端最新角色/权限;不要把权限快照持久化到 localStorage。
|
|
86
|
+
const { roles, permissions, ...user } = me.data
|
|
87
|
+
}
|
|
74
88
|
const upload = await apiClient.storage.presignedUrls.createUpload({ key: 'avatar.png' })
|
|
75
89
|
const answer = await apiClient.ai.chats.sendMessage({ message: 'hello' })
|
|
76
90
|
```
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/api-contract 定义或扩展 oRPC HTTP API 契约;
|
|
|
5
5
|
|
|
6
6
|
# hai-api-contract
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/api-contract 定义或扩展 oRPC HTTP API 契约;当需求涉及定义新领域 contract、组合应用级 contract、使用内置 IAM/Storage/AI/Payment 契约、编写自定义 procedure 输入输出 Schema 或为 @h-ai/api-client/@h-ai/serv 提供接口真相源时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-api-contract` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/api-contract` 是 hai-framework 的公共 HTTP API 契约包,使用 oRPC contract + Zod v4 作为唯一接口真相源。本包只描述接口边界,不包含任何 procedure 实现。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 以 TDD 方式在应用中创建新功能:先编写测试定义
|
|
|
5
5
|
|
|
6
6
|
# hai-app-create — TDD 驱动的应用功能创建规范
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 以 TDD 方式在应用中创建新功能:先编写测试定义行为,再编码实现直至测试通过;当需求涉及新增页面/路由、API、服务、数据模型、组件时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-app-create` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 明确的功能需求、目标路径、现有实现、仓库规范与验收条件 |
|
|
15
|
+
| 输出 | 最小必要的代码、类型、测试和同步文档,以及实际验证结果 |
|
|
16
|
+
| 限制 | 不为假设需求增加抽象,不绕过生命周期/HaiResult/i18n 约定,不覆盖用户已有改动 |
|
|
17
|
+
|
|
8
18
|
> 面向 AI 助手的应用功能创建指南。**必须遵循 TDD**:先写测试(Red)→ 再实现(Green)→ 再重构(Refactor)。
|
|
9
19
|
> 若目标是纯 API service workspace,优先围绕 `apps/*-contract`、`apps/*-service` 与测试组织改动,而不是套用页面/路由脚手架。
|
|
10
20
|
|
|
@@ -5,6 +5,16 @@ description: 对应用代码进行审查:路由安全 → 认证授权 → i18
|
|
|
5
5
|
|
|
6
6
|
# hai-app-review — 应用代码审查规范
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 对应用代码进行审查:路由安全 → 认证授权 → i18n → 组件使用 → API 端点 / service workspace → 服务层 → 性能,并补充产品体验与交互走查;当需求涉及代码审查、规范化、质量检查时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-app-review` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户指定的审查范围、代码/差异、仓库规范与可复现证据 |
|
|
15
|
+
| 输出 | 按优先级排列的问题、影响、定位和修正建议;仅在用户要求时实施修改 |
|
|
16
|
+
| 限制 | 不把风格偏好当缺陷,不猜测未读取的实现,不在审查请求中擅自发布或改动外部状态 |
|
|
17
|
+
|
|
8
18
|
> 面向 AI 助手的应用代码审查指南。用于审查使用 hai-framework 构建的 SvelteKit 应用、纯 Svelte/Vite 客户端与 API service workspace。本技能也是 TDD Refactor 阶段的执行入口。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 以 TDD 驱动应用开发:先分析需求、生成单元测试
|
|
|
5
5
|
|
|
6
6
|
# hai-app-tests — TDD 驱动的应用测试规范
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 以 TDD 驱动应用开发:先分析需求、生成单元测试(Vitest)与 E2E 测试(Playwright),确认测试全部失败后再编码实现直至测试通过;当需求涉及应用测试、TDD 流程、覆盖率提升、E2E 测试时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-app-tests` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> 面向 AI 助手的 TDD 测试指南。**测试先行**:先写测试定义行为,再写实现让测试通过。涵盖 Vitest 单元测试与 Playwright E2E 测试。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/audit 进行审计日志的记录、查询、清理与
|
|
|
5
5
|
|
|
6
6
|
# @h-ai/audit — 审计日志模块
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/audit 进行审计日志的记录、查询、清理与统计。当需求涉及操作审计、安全事件追踪、用户活动日志时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-audit` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
统一审计日志模块,基于 `@h-ai/reldb` 实现持久化,提供审计日志的记录、分页查询、清理与统计。
|
|
9
19
|
|
|
10
20
|
## 运行环境
|
|
@@ -5,6 +5,16 @@ description: 应用开发入口技能。提供项目架构总览(SSR/SPA/原
|
|
|
5
5
|
|
|
6
6
|
# hai-build — 应用开发入口
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 应用开发入口技能。提供项目架构总览(SSR/SPA/原生 App 多端)、TDD 开发工作流、模块初始化顺序与技能导航。当用户需要了解项目结构、查找正确的技能、或开始新任务时触发。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-build` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户目标、仓库与运行环境上下文、现有配置、授权范围和质量门禁 |
|
|
15
|
+
| 输出 | 与目标匹配的配置/代码/文档或审查结论,以及可复现的验证结果 |
|
|
16
|
+
| 限制 | 不扩张用户授权,不输出或固化密钥,不跳过失败门禁,不假定外部服务状态 |
|
|
17
|
+
|
|
8
18
|
> 本技能是 hai-framework 应用开发的起点。帮助理解项目结构、定位正确的技能、并遵循 **TDD 驱动的标准工作流**。支持 SSR Web、SPA、Android/iOS 原生 App 等多端构建。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/cache 进行内存或 Redis 缓存操作(kv/hash/lis
|
|
|
5
5
|
|
|
6
6
|
# hai-cache
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/cache 进行内存或 Redis 缓存操作(kv/hash/list/set/zset/分布式锁);当需求涉及缓存读写、TTL 管理、集合运算、排行榜、缓存一致性策略或分布式互斥锁时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-cache` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/cache` 提供统一缓存接口,支持 Memory 与 Redis 后端,包含 KV / Hash / List / Set / ZSet / 分布式锁 六类操作。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/capacitor 桥接 Capacitor 原生能力(Token 安全
|
|
|
5
5
|
|
|
6
6
|
# hai-capacitor
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/capacitor 桥接 Capacitor 原生能力(Token 安全存储、设备信息、推送通知、相机、状态栏),构建 Android/iOS 原生应用;当需求涉及原生 App 开发、Capacitor 集成、安全存储或原生设备功能时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-capacitor` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户目标、仓库与运行环境上下文、现有配置、授权范围和质量门禁 |
|
|
15
|
+
| 输出 | 与目标匹配的配置/代码/文档或审查结论,以及可复现的验证结果 |
|
|
16
|
+
| 限制 | 不扩张用户授权,不输出或固化密钥,不跳过失败门禁,不假定外部服务状态 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/capacitor` 是 hai-framework 的 Capacitor 原生桥接模块,封装常用原生能力为统一 API,返回 `HaiResult<T>`。与 `@h-ai/api-client` 配合时,Token 仅存于原生安全存储,不回退到 Web `localStorage`。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 设计和维护 hai-framework 应用仓库的 CI/CD、GitHub Action
|
|
|
5
5
|
|
|
6
6
|
# hai-ci — CI/CD 与质量门禁规范
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 设计和维护 hai-framework 应用仓库的 CI/CD、GitHub Actions、质量门禁、secret scan 与 workflow 安全;当需求涉及 CI、GitHub Actions、required checks、泄漏扫描或 release workflow 编排时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-ci` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户目标、仓库与运行环境上下文、现有配置、授权范围和质量门禁 |
|
|
15
|
+
| 输出 | 与目标匹配的配置/代码/文档或审查结论,以及可复现的验证结果 |
|
|
16
|
+
| 限制 | 不扩张用户授权,不输出或固化密钥,不跳过失败门禁,不假定外部服务状态 |
|
|
17
|
+
|
|
8
18
|
> 面向 AI 助手和团队成员的仓库自动化指南。目标是让每个 PR 都能被机器稳定验证,同时避免把 secrets 暴露给不可信 PR 或第三方 Action。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/core 进行配置加载、日志记录、i18n 国际
|
|
|
5
5
|
|
|
6
6
|
# hai-core
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/core 进行配置加载、日志记录、i18n 国际化、HaiResult 错误处理、Zod 校验错误本地化与模块生命周期管理;当需求涉及 core.init、core.logger、core.config、core.i18n、core.zodValidation、ok/err 或模块初始化模式时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-core` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/core` 是 hai-framework 的基础模块,提供配置管理、结构化日志、国际化、HaiResult 错误模型、Zod 校验错误本地化与模块生命周期工具。所有其他模块均依赖 core。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/crypto 进行加密(非对称/哈希/对称)、密
|
|
|
5
5
|
|
|
6
6
|
# hai-crypto
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/crypto 进行加密(非对称/哈希/对称)、密码哈希与传输加密;当需求涉及加密、解密、签名、验签、哈希、密码存储、密钥管理或 crypto.transport 时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-crypto` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/crypto` 提供非对称加密、哈希、对称加密与密码哈希能力,支持 Node.js 与浏览器双端。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/datapipe 进行文本清洗(HTML/URL/空白移除)
|
|
|
5
5
|
|
|
6
6
|
# hai-datapipe
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/datapipe 进行文本清洗(HTML/URL/空白移除)、多模式分块(句子/段落/Markdown/字符/自定义)和管线组合;当需求涉及文本预处理、文档分块、数据清洗或 RAG 入库前处理时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-datapipe` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/datapipe` 提供文本清洗(clean)、多模式分块(chunk)和可组合管线(pipeline),纯函数模块,无需初始化。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/deploy 进行自动化部署:Vercel 部署 + 基础
|
|
|
5
5
|
|
|
6
6
|
# hai-deploy
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/deploy 进行自动化部署:Vercel 部署 + 基础设施开通(Neon/Upstash/R2/Resend/Aliyun);当需求涉及应用部署、环境配置、凭证管理或云服务开通时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-deploy` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户目标、仓库与运行环境上下文、现有配置、授权范围和质量门禁 |
|
|
15
|
+
| 输出 | 与目标匹配的配置/代码/文档或审查结论,以及可复现的验证结果 |
|
|
16
|
+
| 限制 | 不扩张用户授权,不输出或固化密钥,不跳过失败门禁,不假定外部服务状态 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/deploy` 提供自动化部署能力,将 SvelteKit 应用部署到 Vercel,并自动开通 PostgreSQL (Neon)、Redis (Upstash)、S3 (Cloudflare R2)、邮件 (Resend)、短信 (阿里云) 等基础设施服务。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 管理 hai-framework 与应用仓库之间的依赖、技能模板
|
|
|
5
5
|
|
|
6
6
|
# hai-framework-sync — hai-framework 与应用仓库同步规范
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 管理 hai-framework 与应用仓库之间的依赖、技能模板、Copilot/AGENTS 指令和本地联调同步;当需求涉及 hai-framework 源头修改、skills 同步、framework:use:local、framework:watch、版本漂移或双仓 PR 时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-framework-sync` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户目标、仓库与运行环境上下文、现有配置、授权范围和质量门禁 |
|
|
15
|
+
| 输出 | 与目标匹配的配置/代码/文档或审查结论,以及可复现的验证结果 |
|
|
16
|
+
| 限制 | 不扩张用户授权,不输出或固化密钥,不跳过失败门禁,不假定外部服务状态 |
|
|
17
|
+
|
|
8
18
|
> hai-framework 是能力与 skill 模板源头;应用仓库消费这些能力,并可以有少量项目本地覆盖。同步的目标是减少漂移,而不是把两个仓库混成一个仓库。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/iam 进行身份认证(密码/OTP/LDAP/API Key)、
|
|
|
5
5
|
|
|
6
6
|
# hai-iam
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/iam 进行身份认证(密码/OTP/LDAP/API Key)、统一 Bearer Token 管理(TokenPair/refresh/revoke)与 RBAC 授权;当需求涉及登录、注册、权限检查、角色管理、Token 认证或通过 @h-ai/api-contract 暴露 IAM API 时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-iam` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/iam` 是统一的身份与访问管理模块,支持多种认证策略(密码/OTP/LDAP/API Key)、Bearer Token 管理和 RBAC 授权。依赖 `@h-ai/reldb`(持久化)、`@h-ai/cache`(Token + 权限缓存)、`@h-ai/crypto`(密码哈希)、`@h-ai/audit`(审计日志)。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -145,6 +155,22 @@ interface TokenPair {
|
|
|
145
155
|
- 创建全新的 session,返回新的 TokenPair
|
|
146
156
|
- 旧 refreshToken 立即失效,防止重放攻击
|
|
147
157
|
|
|
158
|
+
### 一次性票据 — `iam.ticket`
|
|
159
|
+
|
|
160
|
+
短期、一次性能力票据,用于无法携带 Bearer Token 的通道(如 WebSocket URL)。密码学安全随机、TTL、原子单次消费、用途绑定。
|
|
161
|
+
|
|
162
|
+
| 方法 | 签名 | 说明 |
|
|
163
|
+
| ---------- | -------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
164
|
+
| `issue` | `({ subjectId, purpose, grant?, ttlMs? }) => Promise<HaiResult<{ ticket, expiresAt }>>` | 签发(默认 30s) |
|
|
165
|
+
| `consume` | `(ticket, { purpose? }?) => Promise<HaiResult<{ subjectId, purpose, grant }>>` | 原子消费(单次有效,用途不符拒绝) |
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
const issued = await iam.ticket.issue({ subjectId, purpose: 'ai-audio', grant: { operation: 'transcribe' } })
|
|
169
|
+
const consumed = await iam.ticket.consume(ticket, { purpose: 'ai-audio' }) // 并发消费仅一个成功
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
错误码:`TICKET_INVALID`(hai:iam:110) / `TICKET_EXPIRED`(hai:iam:111) / `TICKET_ISSUE_FAILED`(hai:iam:112)。
|
|
173
|
+
|
|
148
174
|
### 用户管理 — `iam.user`
|
|
149
175
|
|
|
150
176
|
| 方法 | 签名 | 说明 |
|
|
@@ -312,6 +338,11 @@ if (login.success) {
|
|
|
312
338
|
|
|
313
339
|
// 获取当前用户
|
|
314
340
|
const me = await apiClient.iam.auth.currentUser()
|
|
341
|
+
if (me.success) {
|
|
342
|
+
// 返回 User + 服务端当前会话的 roles/permissions。
|
|
343
|
+
// 身份资料与访问范围可在状态层拆开,但不要持久化权限快照。
|
|
344
|
+
const { roles, permissions, ...user } = me.data
|
|
345
|
+
}
|
|
315
346
|
|
|
316
347
|
// Token 过期时,api-client 自动调用 refreshPath 刷新
|
|
317
348
|
// 刷新失败时,清除 Token 并跳转登录页
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/kit 构建 SvelteKit 请求管道、认证守卫、统
|
|
|
5
5
|
|
|
6
6
|
# hai-kit
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/kit 构建 SvelteKit 请求管道、认证守卫、统一响应、Zod 校验、浏览器端 apiFetch、A2A 与双构建适配;当需求涉及 hooks.server.ts、权限守卫、CORS、限流、同源 transport 或 SvelteKit API endpoint 时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-kit` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/kit` 只负责 SvelteKit 集成:`handle` hook、guard、response、validate、client、auth、crud、A2A。公共跨端 HTTP API 契约统一使用 `@h-ai/api-contract` + `@h-ai/serv`,不要在 kit 中定义业务 API contract。
|
|
9
19
|
|
|
10
20
|
## 使用步骤
|
|
@@ -83,6 +93,8 @@ export const handle = kit.createHandle({
|
|
|
83
93
|
})
|
|
84
94
|
```
|
|
85
95
|
|
|
96
|
+
需要保护会话 Cookie 时配置 `crypto.encryptedCookies`,并通过 `crypto.cookieEncryptionKey` 或 `HAI_KIT_COOKIE_KEY` 提供密钥。缺少密钥会在 `createHandle()` 时失败;加解密错误不会回退到明文 Cookie。
|
|
97
|
+
|
|
86
98
|
```ts
|
|
87
99
|
// routes/+layout.svelte
|
|
88
100
|
<script lang='ts'>
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/payment 接入微信支付、支付宝、Stripe 统一
|
|
|
5
5
|
|
|
6
6
|
# hai-payment
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/payment 接入微信支付、支付宝、Stripe 统一支付;支持创建订单、回调验签、订单查询与退款;当需求涉及支付接入、订单创建、支付回调、退款或客户端调起支付时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-payment` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/payment` 是 hai-framework 的统一支付模块,通过 Provider 模式支持微信支付、支付宝、Stripe。服务端处理订单和回调,客户端调起支付。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 审查 Pull Request 的交付质量、scope、风险、验证方式
|
|
|
5
5
|
|
|
6
6
|
# hai-pr-review — PR 审查与 AI Review 规范
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 审查 Pull Request 的交付质量、scope、风险、验证方式、AI-assisted 说明与合并准备度;当需求涉及 PR review、AI Review 策略、PR 模板、CODEOWNERS 或合并门禁时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-pr-review` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 用户指定的审查范围、代码/差异、仓库规范与可复现证据 |
|
|
15
|
+
| 输出 | 按优先级排列的问题、影响、定位和修正建议;仅在用户要求时实施修改 |
|
|
16
|
+
| 限制 | 不把风格偏好当缺陷,不猜测未读取的实现,不在审查请求中擅自发布或改动外部状态 |
|
|
17
|
+
|
|
8
18
|
> PR 是团队协作和 AI 辅助开发的交付边界。AI 可以帮助发现问题,但不能替代确定性 CI 和人类最终责任。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/reach 进行邮件、短信和 API 回调发送;当
|
|
|
5
5
|
|
|
6
6
|
# hai-reach
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/reach 进行邮件、短信和 API 回调发送;当需求涉及用户触达、消息通知、验证码发送、多渠道模板管理时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-reach` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/reach` 提供统一的用户触达接口,支持同时注册多个 Provider(SMTP 邮件、短信、API 回调),内置模板引擎与免打扰(DND)机制。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -78,6 +88,8 @@ dnd:
|
|
|
78
88
|
end: '08:00'
|
|
79
89
|
```
|
|
80
90
|
|
|
91
|
+
API Provider 只接受 HTTP(S) URL。回调地址若来自不可信输入,业务层必须先做域名 allowlist,并由企业网络出口策略限制内网访问;不要在日志中记录完整 URL、收件人或第三方响应体。
|
|
92
|
+
|
|
81
93
|
### 2. 初始化与关闭
|
|
82
94
|
|
|
83
95
|
```typescript
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/reldb 进行 SQLite/PostgreSQL/MySQL 的初始化、SQ
|
|
|
5
5
|
|
|
6
6
|
# hai-reldb
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/reldb 进行 SQLite/PostgreSQL/MySQL 的初始化、SQL/DDL/CRUD/事务与分页操作;当需求涉及数据库访问、CRUD 仓库、事务处理、分页查询或 HaiReldbError 分支处理时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-reldb` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/reldb` 提供统一的数据库操作接口,支持 SQLite、PostgreSQL、MySQL,包含 DDL、SQL、CRUD 抽象、事务与分页。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/scheduler 进行统一定时任务管理、任务持
|
|
|
5
5
|
|
|
6
6
|
# hai-scheduler
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/scheduler 进行统一定时任务管理、任务持久化、手工触发、触发来源审计、全局生命周期回调与执行日志查询;当需求涉及 cron 调度、JS 函数字符串任务、API 任务、分布式锁或任务事件回调时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-scheduler` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/scheduler` 使用统一任务模型管理 API / JS / Hook 三类执行路径,支持持久化、手工触发来源记录、分布式锁与全局生命周期回调。
|
|
9
19
|
|
|
10
20
|
## 运行环境
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/serv 将 oRPC contract 挂载为最小 HTTP App 抽象
|
|
|
5
5
|
|
|
6
6
|
# hai-serv
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/serv 将 oRPC contract 挂载为最小 HTTP App 抽象;当需求涉及创建 API 服务、装配 procedure、挂载 OpenAPI 文档、配置健康检查、添加认证/权限 pipeline 包装器或切换 Node/Fetch 运行时适配器时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-serv` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/serv` 是 hai-framework 的 API Service 运行时,对外暴露最小 HTTP App 抽象,将 `@h-ai/api-contract` 的领域 contract 挂载成跨端可访问的 HTTP API;Hono 是内部实现细节,应用代码不要直接 import 或暴露 Hono。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -28,6 +38,7 @@ description: 使用 @h-ai/serv 将 oRPC contract 挂载为最小 HTTP App 抽象
|
|
|
28
38
|
- 通过 `config/_serv.yml` 管理 API 前缀、OpenAPI、docs、health、rpc 等 HTTP 挂载配置
|
|
29
39
|
- 启用传输加密:`serv.createApp({ transport: { crypto } })`
|
|
30
40
|
- 高级场景通过 `createApp({ middlewares })` 自定义 HTTP middleware,或通过共享类型自定义 procedure wrapper
|
|
41
|
+
- 为 Audio WebSocket 配置一次性 ticket 校验、IAM/模型/配额授权与并发释放钩子
|
|
31
42
|
|
|
32
43
|
---
|
|
33
44
|
|
|
@@ -80,6 +91,28 @@ serv.listen(app, {
|
|
|
80
91
|
})
|
|
81
92
|
```
|
|
82
93
|
|
|
94
|
+
### 2.1 Audio WebSocket 安全接入
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const app = serv.createApp({
|
|
98
|
+
contract,
|
|
99
|
+
procedures,
|
|
100
|
+
iam,
|
|
101
|
+
audio: {
|
|
102
|
+
ai,
|
|
103
|
+
verifyTicket: consumeAudioTicket, // 校验用途/时效并原子消费,返回 { session, grant? }(推荐 iam.ticket.consume)
|
|
104
|
+
authorize: (session, request, grant) => authorizeAudioRequest(session, request, grant),
|
|
105
|
+
onSessionEnd: (session, request) => releaseAudioConcurrency(session.userId, request.operation),
|
|
106
|
+
},
|
|
107
|
+
})
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- ticket 由已登录 HTTP 请求签发(推荐 `iam.ticket.issue`),短期有效且只能消费一次;连接建立即鉴权(独立预鉴权超时,默认 5s),未鉴权不处理任何业务帧;普通 IAM access token 禁止进入 WebSocket URL。
|
|
111
|
+
- `verifyTicket` 返回 `HaiResult<AudioTicketVerification>`(`{ session, grant? }`);`grant` 承载票据绑定的操作/模型/会话,供 `authorize` 交叉校验 `start` 未越权。
|
|
112
|
+
- 每帧经运行时 Zod 校验并按严格状态机接受(识别只收音频、合成只收文本、`start`/`done` 各一次、`segmentId` 会话内唯一);输入队列、消息积压、发送缓冲均有上限(`preAuthTimeoutMs`/`maxPendingMessages`/`maxSendBufferBytes` 等可调),超限或取消时以领域错误关闭并级联中止上游。
|
|
113
|
+
- `authorize` 返回的 `AuthorizedAudioRequest` 是唯一会传给 `ai.audio` 的模型、音色与格式配置;未提供时客户端的付费参数会被忽略(若票据 `grant.model` 存在则采用之)。
|
|
114
|
+
- IAM 权限、Persona、套餐配额和并发计数属于应用策略;框架提供校验与结束钩子,不硬编码业务权限名或存储。
|
|
115
|
+
|
|
83
116
|
### 3. 扩展应用自有 contract + procedures
|
|
84
117
|
|
|
85
118
|
`apiContract.create({...})` 接受任意 key——除了框架提供的 `iam/storage/ai`,应用可以挂入自己的领域 contract,
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/storage 进行文件存储操作(本地/S3),包
|
|
|
5
5
|
|
|
6
6
|
# hai-storage
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/storage 进行文件存储操作(本地/S3),包括 file/dir/presign 三组能力;当需求涉及文件上传下载、目录批量删除、S3 预签名 URL 或客户端直传时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-storage` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/storage` 提供统一文件存储接口,支持本地文件系统(LocalProvider)和 S3 兼容存储(S3Provider),通过 `storage.file`、`storage.dir`、`storage.presign` 三组接口访问能力。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/ui 构建多端应用界面,包含三层组件架构
|
|
|
5
5
|
|
|
6
6
|
# hai-ui
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/ui 构建多端应用界面,包含三层组件架构(原子/组合/场景)、DaisyUI 样式 + Bits UI headless 交互、移动端组件(SafeArea/BottomNav/PullRefresh/ActionSheet/SwipeCell/InfiniteScroll/AppBar)、Design Token 系统与平台检测;当需求涉及界面、表单、表格、移动端适配或主题切换时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-ui` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/ui` 是基于 Svelte 5 Runes 的多端 UI 组件库,采用 DaisyUI v5 + Tailwind CSS v4 + Bits UI v2,内置 15 个精选 DaisyUI 主题、内置中英文 i18n、自动导入。内置 Shiki 代码高亮、Mermaid 图表渲染、Design Token 系统和 7 个移动端组件。
|
|
9
19
|
|
|
10
20
|
---
|
|
@@ -258,7 +268,7 @@ const p = usePlatform()
|
|
|
258
268
|
| `Spinner` | `size`, `variant` | 加载动画 |
|
|
259
269
|
| `Progress` | `value`, `max`, `striped`, `animated` | 进度条 |
|
|
260
270
|
|
|
261
|
-
### 组合组件(Compounds,
|
|
271
|
+
### 组合组件(Compounds,36 个)
|
|
262
272
|
|
|
263
273
|
由原子组件 + Bits UI headless 交互组合。
|
|
264
274
|
|
|
@@ -275,7 +285,7 @@ const p = usePlatform()
|
|
|
275
285
|
| `Calendar` | `value`, `minValue`, `maxValue` | 独立日历 |
|
|
276
286
|
| `DatePicker` | `value`, `minValue`, `maxValue`, `error` | 日期输入+弹出 |
|
|
277
287
|
| `Tabs` | `items: TabItem[]`, `active`, `type` | 标签页 |
|
|
278
|
-
| `Pagination` | `page`, `total`, `pageSize`, `showTotal`, `showJumper`, `showSizeChanger`, `onchange` | 分页(统一为 shadcn table 风格) |
|
|
288
|
+
| `Pagination` | `page`, `total`, `pageSize`, `showTotal`, `showJumper`, `showSizeChanger`, `showPageInfo`, `showFirstLast`, `onchange` | 分页(统一为 shadcn table 风格) |
|
|
279
289
|
| `Dropdown` | `items: DropdownItem[]`, `trigger` | 下拉菜单 |
|
|
280
290
|
| `Accordion` | `items: AccordionItem[]` | 折叠面板 |
|
|
281
291
|
| `Skeleton` | `variant`, `count`, `animation` | 骨架屏 |
|
|
@@ -375,11 +385,13 @@ const p = usePlatform()
|
|
|
375
385
|
|
|
376
386
|
| 组件 | Props 要点 | 说明 |
|
|
377
387
|
| ------------- | ---------------------------------------------- | -------- |
|
|
378
|
-
| `FileUpload` | `accept`, `maxSize`, `
|
|
379
|
-
| `ImageUpload` | `value`, `
|
|
380
|
-
| `AvatarUpload` | `value`, `
|
|
388
|
+
| `FileUpload` | `accept`, `maxSize`, `uploadHandler`, `autoUpload` | 文件上传 |
|
|
389
|
+
| `ImageUpload` | `value`, `uploadHandler`, `aspectRatio` | 图片上传 |
|
|
390
|
+
| `AvatarUpload` | `value`, `uploadHandler`, `size`, `fallback` | 头像上传 |
|
|
381
391
|
| `FileList` | `files: FileItem[]`, `layout`, `showPreview` | 文件列表 |
|
|
382
392
|
|
|
393
|
+
上传协议属于应用 service:组件通过 `uploadHandler(file, { signal, onProgress })` 注入实现,并接收 `{ url?, response? }`。不要把 presign、认证头或 PUT/POST 细节塞进 UI 组件;图片与头像 handler 必须返回安全的 `url`。未提供 handler 时组件只负责文件选择或本地预览。
|
|
394
|
+
|
|
383
395
|
#### AI 场景组件
|
|
384
396
|
|
|
385
397
|
| 组件 | 说明 |
|
|
@@ -454,6 +466,7 @@ const p = usePlatform()
|
|
|
454
466
|
| `pagination.showSizeChanger` | 每页条数选择器(默认开启) |
|
|
455
467
|
| `pagination.pageSizeOptions` | 每页条数候选项(默认 `[10, 20, 50, 100]`) |
|
|
456
468
|
| `pagination.showJumper` / `pagination.showTotal` | 跳页输入 / 总数(默认开启) |
|
|
469
|
+
| `pagination.showPageInfo` / `pagination.showFirstLast` | 页码文案 / 首页末页按钮(默认开启;紧凑视图可关闭) |
|
|
457
470
|
| `density` | 列表密度:`'normal'`(默认)或 `'compact'`;仅影响列表行、行内操作、分页与创建/编辑/详情表单 |
|
|
458
471
|
|
|
459
472
|
注意:分页栏会始终显示,不再因数据量小而自动隐藏。
|
|
@@ -5,6 +5,16 @@ description: 使用 @h-ai/vecdb 进行向量数据库操作(LanceDB/pgvector/Q
|
|
|
5
5
|
|
|
6
6
|
# hai-vecdb
|
|
7
7
|
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 使用 @h-ai/vecdb 进行向量数据库操作(LanceDB/pgvector/Qdrant/Chroma)的集合管理与向量增删改查;当需求涉及向量存储、相似度搜索、嵌入检索或语义搜索时使用。 |
|
|
13
|
+
| 适用场景 | 当任务与 `hai-vecdb` 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
|
|
14
|
+
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
|
|
15
|
+
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
|
|
16
|
+
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
|
|
17
|
+
|
|
8
18
|
> `@h-ai/vecdb` 提供统一的向量数据库操作接口,支持 LanceDB、pgvector、Qdrant、Chroma,包含集合管理和向量 CRUD/搜索。
|
|
9
19
|
|
|
10
20
|
---
|