@h-ai/cli 0.1.0-alpha.40 → 0.1.0-alpha.42

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/cli",
3
3
  "type": "module",
4
- "version": "0.1.0-alpha.40",
4
+ "version": "0.1.0-alpha.42",
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.40"
37
+ "@h-ai/core": "0.1.0-alpha.42"
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.40",
3
+ "version": "0.1.0-alpha.42",
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,11 +1,11 @@
1
1
  ---
2
2
  name: hai-ai
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 客户端时使用。"
3
+ description: "Use when: using @h-ai/ai for LLM calls, tools, MCP, streaming, memory/context, RAG, image generation, text-to-image, GPT Image, Gemini Image, Qwen Image, Seedream, 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、Audio 与 A2A 能力。
8
+ `@h-ai/ai` 统一提供 LLM、工具、MCP、Embedding、Memory、Retrieval/RAG、Knowledge、Context、File、Rerank、Image、Audio 与 A2A 能力。
9
9
 
10
10
  > 详细 API 表、错误码与长示例见同目录 `reference.md`。只有需要完整契约或边界用例时再读取,避免把长参考塞进上下文。
11
11
 
@@ -13,7 +13,7 @@ description: "Use when: using @h-ai/ai for LLM calls, tools, MCP, streaming, mem
13
13
 
14
14
  | 项目 | 契约 |
15
15
  | --- | --- |
16
- | 能力 | LLM/流式生成、结构化 Tool、MCP、Embedding、Memory、RAG/Knowledge、Context、Audio、A2A |
16
+ | 能力 | LLM/流式生成、结构化 Tool、MCP、Embedding、Memory、RAG/Knowledge、Context、Image、Audio、A2A |
17
17
  | 适用场景 | 服务端 AI 对话、Agent 工具链、知识问答、长期记忆、语音交互和 Agent-to-Agent;浏览器通过 client/API 代理 |
18
18
  | 输入 | `AIConfigInput`、消息/文本/音频、Zod Tool schema、`objectId/sessionId/scope`、`AbortSignal` |
19
19
  | 输出 | 领域操作返回 `HaiResult<T>`;流式 API 返回 `AsyncIterable`;Tool 返回 `ToolMessage`;客户端传输可能抛异常 |
@@ -22,7 +22,7 @@ description: "Use when: using @h-ai/ai for LLM calls, tools, MCP, streaming, mem
22
22
  ## 使用边界
23
23
 
24
24
  - `ai.tools`、`ai.stream` 是纯函数能力,无需 `ai.init()`。
25
- - `ai.llm`、`ai.embedding`、`ai.memory`、`ai.retrieval`、`ai.rag`、`ai.knowledge`、`ai.context`、`ai.audio`、`ai.a2a` 需要先 `await ai.init(...)`。
25
+ - `ai.llm`、`ai.embedding`、`ai.memory`、`ai.retrieval`、`ai.rag`、`ai.knowledge`、`ai.context`、`ai.image`、`ai.audio`、`ai.a2a` 需要先 `await ai.init(...)`。
26
26
  - 未初始化 reldb/vecdb 时,`ai.init()` 使用进程内临时 Store,适合 LLM-only 与本地原型;数据在 `ai.close()` 或进程退出后丢失。
27
27
  - reldb 与 vecdb 均已初始化时自动使用持久化 DB Provider;生产 Memory/Context/Persona/Knowledge 应使用该路径或自定义 `AIStoreProvider`。
28
28
  - 浏览器端不要直接调用 Node-only 能力;通过 `@h-ai/api-client` 或应用自定义 API/SSE endpoint 代理。
@@ -124,6 +124,7 @@ memory:
124
124
  | Context 重置 | `await manager.reset({ preserveSystemPrompt?, cancelActiveTurn?, waitForMemoryTasks? })` | 异步:终止活动生成、清空消息/摘要/轮次,默认保留系统提示词 |
125
125
  | 语音识别 | `ai.audio.transcribe` / `transcribeStream` | 完整音频返回 `HaiResult`;持续音频输入用 `AudioInputStream` 流式返回临时文本 |
126
126
  | 语音合成 | `ai.audio.synthesize` / `synthesizeStream` | `text` 可为字符串或 `AsyncIterable<string>`(可接 LLM 文本流边生成边合成) |
127
+ | 图片生成 | `ai.image.generate({ prompt, size?, model?, referenceImages? })` | 可选参考图使用字节 + MIME;Provider 协议和临时 URL 下载由模块内部处理 |
127
128
  | A2A | `ai.a2a.registerExecutor/handleRequest` | 延迟初始化 SDK handler |
128
129
 
129
130
  ## LLM + 工具调用
@@ -316,6 +317,38 @@ for await (const event of ai.audio.synthesizeStream({ text: { id: 'seg-1', text:
316
317
  - 平台不支持的输入方式(如 OpenAI/MiMo 的持续音频输入)会抛 `AUDIO_UNSUPPORTED_INPUT`,不伪装成实时。
317
318
  - 浏览器/移动端经 `@h-ai/serv` 统一语音 WebSocket 入口访问;客户端用已登录 HTTP 请求获取短期一次性 ticket,`@h-ai/ai/client` 通过 `audio.getTicket` 建连,不把 IAM access token 放入 URL。浏览器客户端区分正常结束、取消(`AUDIO_CANCELLED`)与 `end` 前异常断连(`AUDIO_CONNECTION_FAILED`);服务端 error 帧保留领域错误码,`synthesize` 不返回未完成的部分音频。
318
319
 
320
+ ## 文生图(Image)
321
+
322
+ `ai.image` 只暴露稳定的提示词、模型别名、像素尺寸、可选参考图和图片字节;OpenAI、Google、Qwen、Seedream 与 Pollinations 的请求结构、鉴权、响应解析和临时 URL 下载均封装在内部 Provider。
323
+
324
+ ```yaml
325
+ image:
326
+ models:
327
+ - { id: free, provider: pollinations, model: zimage }
328
+ - { id: openai, provider: openai, model: gpt-image-2 }
329
+ - { id: google, provider: google, model: gemini-3.1-flash-image-preview }
330
+ - { id: qwen, provider: qwen, model: qwen-image-2.0-pro }
331
+ - { id: seedream, provider: seedream, model: doubao-seedream-5-0-260128 }
332
+ generateModel: free
333
+ ```
334
+
335
+ ```ts
336
+ const image = await ai.image.generate({
337
+ prompt: '水墨风格的未来城市,清晨薄雾',
338
+ size: { width: 1024, height: 1024 },
339
+ referenceImages: [{ data: referenceBytes, mimeType: 'image/png' }],
340
+ })
341
+ if (!image.success) return image
342
+ await saveImage(image.data.images[0].data, image.data.images[0].mimeType)
343
+ ```
344
+
345
+ - `Pollinations` 提供可免费起步的开发额度,但仍需 API key;不要把“免费额度”描述为匿名或无限调用。
346
+ - 应用应通过 `core.init({ configDir: './config' })` 加载 `_core.yml` / `_ai.yml`,再以 `core.config.validate('ai', AIConfigSchema)` 校验并传给 `ai.init`;不要在启动代码中重复拼装模型、端点和超时,也不要传入 `logging` 覆盖 `_core.yml`。
347
+ - Pollinations 的 HTTP 402 表示账户余额或该 API Key 的预算耗尽;401 是密钥无效,403 是权限或模型访问被拒。诊断日志记录厂商、模型、状态、上游错误码和请求 ID,不记录密钥、提示词或图片内容。
348
+ - Qwen 等返回的临时图片 URL 会在 Provider 内立即下载,公共结果不泄漏易过期 URL。
349
+ - 参考图统一使用 `{ data: Uint8Array, mimeType: 'image/...' }`;不要把厂商 URL、multipart 或 Base64 结构泄漏到业务层。
350
+ - Provider 请求/响应格式变更时,先更新契约测试,再修改实现。
351
+
319
352
 
320
353
  ## SvelteKit API 端点模式
321
354
 
@@ -184,6 +184,19 @@ const result = await ai.rag.query('核心架构是什么?', {
184
184
  - 资源上限:`audio.maxAudioBytes`(默 10 MiB)、`audio.maxStreamDurationMs`(默 5 分钟);所有请求支持 `signal: AbortSignal` 打断。
185
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
186
 
187
+ ## Image
188
+
189
+ | 方法 | 返回 | 说明 |
190
+ | --- | --- | --- |
191
+ | `generate(request)` | `Promise<HaiResult<GenerateImageResult>>` | 文本提示词 → 一张或多张已下载的图片字节 |
192
+
193
+ - 请求:`GenerateImageRequest { prompt, model?, size?: { width, height }, referenceImages?: ReferenceImage[], signal? }`;`ReferenceImage` 为 `{ data: Uint8Array, mimeType: string }`。
194
+ - 返回:`GenerateImageResult { images: Array<{ data: Uint8Array, mimeType, width?, height? }> }`。
195
+ - 模型配置:`image.models: [{ id, provider: 'openai'|'google'|'qwen'|'seedream'|'pollinations', model, apiKey?, baseUrl?, workspaceId?, timeout? }]`;`image.generateModel` 选择默认模型别名。
196
+ - 凭据优先使用模型项 `apiKey`,否则回退 `HAI_AI_IMAGE_<PROVIDER>_API_KEY` 或厂商标准环境变量。
197
+ - 厂商差异由内部 Provider 消化:OpenAI/Pollinations 的 multipart edits、Google `inlineData`、Qwen/Seedream 的 Data URL 参考图,以及各家 Base64、临时 URL 或二进制响应均归一为图片字节。
198
+ - Google 只接受其文档列出的宽高比;Qwen/Seedream 还可能对总像素与边长有限制。业务应提供厂商支持的尺寸预设,不要假设任意像素组合都可用。
199
+
187
200
  ## LLM 结构化输出
188
201
 
189
202
  `ai.llm.generateObject({ schema, messages, model?, systemPrompt?, maxRepairs?, signal? })`:按 Zod schema 约束模型输出(json_schema)并解析为对象,解析/校验失败自动带错误提示重试(默 1 次)。适用于“是否为问题/意图分类/置信度”等需要稳定结构结果的场景,避免手写 `JSON.parse`。
@@ -210,6 +223,7 @@ A2A 服务端 SDK handler 在注册 executor 时延迟创建;远端客户端
210
223
  | `hai:ai:010-012` | 初始化:`NOT_INITIALIZED` / `CONFIGURATION_ERROR` / `INIT_IN_PROGRESS` |
211
224
  | `hai:ai:020-033` | Rerank / File |
212
225
  | `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` |
226
+ | `hai:ai:060-065` | Image:`IMAGE_INVALID_REQUEST` / `MODEL_NOT_FOUND` / `PROVIDER_NOT_FOUND` / `UPSTREAM_ERROR` / `PROTOCOL_ERROR` / `CANCELLED` |
213
227
  | `hai:ai:100-107` | LLM / 历史记录 |
214
228
  | `hai:ai:200-204` | MCP |
215
229
  | `hai:ai:300-302` | Embedding |
@@ -179,7 +179,7 @@ const consumed = await iam.ticket.consume(ticket, { purpose: 'ai-audio' }) //
179
179
  | `getUser` | `(id, options?) => Promise<HaiResult<User \| null>>` | 获取用户(可选 include: ['roles']) |
180
180
  | `getCurrentUser` | `(token) => Promise<HaiResult<User>>` | 通过令牌获取当前用户 |
181
181
  | `updateCurrentUser` | `(token, data: UpdateCurrentUserInput) => Promise<HaiResult<User>>` | 当前用户修改个人资料(白名单字段) |
182
- | `listUsers` | `(options?: ListUsersOptions) => Promise<HaiResult<PaginatedResult<User>>>` | 用户列表(分页 + 搜索 + 过滤) |
182
+ | `listUsers` | `(options?: ListUsersOptions) => Promise<HaiResult<PaginatedResult<User>>>` | 用户列表(分页 + 搜索 + 过滤 + 白名单排序) |
183
183
  | `updateUser` | `(id, data) => Promise<HaiResult<User>>` | 更新用户信息 |
184
184
  | `deleteUser` | `(id) => Promise<HaiResult<void>>` | 删除用户(自动清除会话) |
185
185
  | `changePassword` | `(id, old, new) => Promise<HaiResult<void>>` | 修改密码(自动清除会话) |
@@ -468,8 +468,13 @@ const p = usePlatform()
468
468
  | `pagination.showJumper` / `pagination.showTotal` | 跳页输入 / 总数(默认开启) |
469
469
  | `pagination.showPageInfo` / `pagination.showFirstLast` | 页码文案 / 首页末页按钮(默认开启;紧凑视图可关闭) |
470
470
  | `density` | 列表密度:`'normal'`(默认)或 `'compact'`;仅影响列表行、行内操作、分页与创建/编辑/详情表单 |
471
+ | `toolbarStyle` | `'toolbar'`(图标弹层,默认)或 `'filter-bar'`(平铺筛选栏) |
472
+ | `showHeader` / `toolbarLeading` | 关闭默认页头并在工具栏左侧放置标题或说明 |
473
+ | `toolbarActions` | 工具栏业务操作 snippet |
474
+ | `card` | 卡片列表项渲染 snippet;仍复用分页和独立滚动容器 |
475
+ | `sortableColumns` | 可执行服务端排序的列;为空时使用全部列表列 |
471
476
 
472
- 注意:分页栏会始终显示,不再因数据量小而自动隐藏。
477
+ 注意:`CrudPage` 会占满父级可用高度;表格无论是否有数据都会撑满剩余空间,仅数据区滚动,表头和分页栏固定。
473
478
 
474
479
  ### CrudPage 推荐用法
475
480
 
@@ -481,6 +486,7 @@ const p = usePlatform()
481
486
  form={{ variant: 'modal', modalSize: 'lg' }}
482
487
  pagination={{ showSizeChanger: true, showJumper: true, pageSizeOptions: [10, 20, 50] }}
483
488
  density='compact'
489
+ sortableColumns={[{ key: 'createdAt', label: '创建时间' }]}
484
490
  {nav}
485
491
  />
486
492
  ```