@henjicc/ai-sdk 0.6.1 → 0.6.2

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.
Files changed (27) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +16 -3
  3. package/dist/capabilities/client.js +103 -86
  4. package/dist/capabilities/speech-recognition/bailian/realtime/module.js +42 -7
  5. package/dist/capabilities/speech-recognition/bailian/realtime/protocol.js +57 -15
  6. package/dist/capabilities/speech-recognition/volcengine/realtime/module.js +42 -10
  7. package/dist/capabilities/translation/bailian/module.js +41 -13
  8. package/dist/capabilities/translation/bailian/sse.d.ts +1 -1
  9. package/dist/capabilities/translation/bailian/sse.js +82 -54
  10. package/dist/capabilities/types.d.ts +4 -0
  11. package/dist/llm/chat.js +6 -1
  12. package/dist/llm/streaming.js +131 -91
  13. package/dist/protocols/sse-events.d.ts +4 -0
  14. package/dist/protocols/sse-events.js +31 -0
  15. package/docs/consumers.md +119 -107
  16. package/docs/llm-adaptation/README.md +26 -1
  17. package/docs/llm-adaptation//344/276/233/345/272/224/345/225/206//346/231/272/350/260/261GLM.md +3 -1
  18. package/docs/model-adaptation/Fun-ASR-Realtime/Fun-ASR-Realtime_/347/231/276/347/202/274.md +22 -2
  19. package/docs/model-adaptation/Qwen-MT-Flash/Qwen-MT-Flash_/347/231/276/347/202/274.md +24 -3
  20. package/docs/model-adaptation/Qwen-MT-Lite/Qwen-MT-Lite_/347/231/276/347/202/274.md +3 -2
  21. package/docs/model-adaptation/Qwen-MT-Plus/Qwen-MT-Plus_/347/231/276/347/202/274.md +3 -2
  22. package/docs/model-adaptation/Qwen3-ASR-Flash-Realtime/Qwen3-ASR-Flash-Realtime_/347/231/276/347/202/274.md +25 -2
  23. package/docs/model-adaptation/SeedASR-2.0-Realtime/SeedASR-2.0-Realtime_/347/201/253/345/261/261/345/274/225/346/223/216.md +7 -3
  24. package/examples/llm-chat/README.md +1 -1
  25. package/examples/llm-chat/index.ts +1 -1
  26. package/examples/llm-chat/package.json +1 -1
  27. package/package.json +1 -1
@@ -1,3 +1,5 @@
1
+ import { drainSseEvents } from '../protocols/sse-events.js';
2
+ import { AiRuntimeError } from '../runtime/AiRuntimeError.js';
1
3
  import { fetchProvider } from '../providers/provider-fetch.js';
2
4
  import { applyProviderRequestBodyQuirks, resolveProviderExtraAuthHeaders, } from './providerProtocolCore.js';
3
5
  import { applyProviderReasoningRequestBody } from './providerReasoningRequest.js';
@@ -78,7 +80,7 @@ export async function streamOpenAiCompatibleChat(options) {
78
80
  if (!response.body) {
79
81
  throw new Error('LLM streaming response body is empty');
80
82
  }
81
- return await readSseStream(response.body, options.emit);
83
+ return await readSseStream(response.body, options);
82
84
  }
83
85
  export function serializeMessage(message) {
84
86
  const serialized = { role: message.role };
@@ -138,7 +140,8 @@ function serializeContentPart(part) {
138
140
  }
139
141
  return next;
140
142
  }
141
- async function readSseStream(body, emit) {
143
+ async function readSseStream(body, options) {
144
+ const { emit, signal } = options;
142
145
  const reader = body.getReader();
143
146
  const decoder = createUtf8StreamDecoder();
144
147
  let pending = '';
@@ -147,68 +150,84 @@ async function readSseStream(body, emit) {
147
150
  let usage = null;
148
151
  let finishReason = null;
149
152
  const toolCalls = new Map();
150
- let streamDone = false;
151
- while (!streamDone) {
152
- const result = await reader.read();
153
- if (result.done) {
154
- streamDone = true;
155
- continue;
156
- }
157
- pending += decoder.decode(result.value, { stream: true });
158
- const parsed = drainSseEvents(pending);
159
- pending = parsed.remaining;
160
- for (const event of parsed.events) {
161
- const chunk = parseSseData(event);
162
- if (chunk.done) {
163
- return {
164
- output,
165
- reasoningOutput,
166
- usage,
167
- finishReason,
168
- truncated: isOutputTruncated(finishReason),
169
- toolCalls: [...toolCalls.values()],
170
- };
171
- }
172
- usage = chunk.usage ?? usage;
173
- finishReason = chunk.finishReason ?? finishReason;
174
- mergeToolCallDeltas(toolCalls, chunk.toolCalls);
175
- if (chunk.reasoning) {
176
- reasoningOutput += chunk.reasoning;
177
- emit({ type: 'ReasoningToken', data: chunk.reasoning });
153
+ let eof = false;
154
+ let stage = 'read';
155
+ let cancellation;
156
+ const cancelReader = () => {
157
+ // Cleanup may reject on an already errored stream. It must not replace the
158
+ // original protocol/transport failure or delay settlement on a custom host.
159
+ cancellation ??= reader.cancel().catch(() => undefined);
160
+ };
161
+ const checkAbort = () => {
162
+ if (signal.aborted)
163
+ throw Object.assign(new Error('LLM stream cancelled'), { name: 'AbortError' });
164
+ };
165
+ const complete = () => {
166
+ stage = 'completion';
167
+ checkAbort();
168
+ if (!finishReason)
169
+ throw new AiRuntimeError('STREAM_INCOMPLETE', 'Chat stream ended without finish_reason');
170
+ return { output, reasoningOutput, usage, finishReason,
171
+ truncated: isOutputTruncated(finishReason, options.providerId), toolCalls: [...toolCalls.values()] };
172
+ };
173
+ signal.addEventListener('abort', cancelReader, { once: true });
174
+ try {
175
+ checkAbort();
176
+ for (;;) {
177
+ stage = 'read';
178
+ const result = await reader.read();
179
+ checkAbort();
180
+ if (result.done) {
181
+ eof = true;
182
+ // SSE dispatch requires a blank line. Do not manufacture a final event
183
+ // from an unterminated block at EOF.
184
+ return complete();
178
185
  }
179
- if (chunk.content) {
180
- output += chunk.content;
181
- emit({ type: 'Token', data: chunk.content });
186
+ pending += decoder.decode(result.value, { stream: true });
187
+ const parsed = drainSseEvents(pending);
188
+ pending = parsed.remaining;
189
+ for (const event of parsed.events) {
190
+ checkAbort();
191
+ stage = 'parse';
192
+ const chunk = parseSseData(event, options.providerId);
193
+ if (chunk.done)
194
+ return complete();
195
+ if (finishReason && (chunk.content || chunk.reasoning || chunk.toolCalls?.length
196
+ || (chunk.finishReason && chunk.finishReason !== finishReason))) {
197
+ throw new AiRuntimeError('INVALID_STREAM_RESPONSE', 'Chat result changed after finish_reason');
198
+ }
199
+ usage = chunk.usage ?? usage;
200
+ finishReason = chunk.finishReason ?? finishReason;
201
+ mergeToolCallDeltas(toolCalls, chunk.toolCalls);
202
+ stage = 'emit';
203
+ if (chunk.reasoning) {
204
+ reasoningOutput += chunk.reasoning;
205
+ emit({ type: 'ReasoningToken', data: chunk.reasoning });
206
+ checkAbort();
207
+ }
208
+ if (chunk.content) {
209
+ output += chunk.content;
210
+ emit({ type: 'Token', data: chunk.content });
211
+ }
182
212
  }
183
213
  }
184
214
  }
185
- const flushed = decoder.decode();
186
- if (flushed) {
187
- pending += flushed;
188
- }
189
- const parsed = drainSseEvents(`${pending}\n\n`);
190
- for (const event of parsed.events) {
191
- const chunk = parseSseData(event);
192
- usage = chunk.usage ?? usage;
193
- finishReason = chunk.finishReason ?? finishReason;
194
- mergeToolCallDeltas(toolCalls, chunk.toolCalls);
195
- if (chunk.reasoning) {
196
- reasoningOutput += chunk.reasoning;
197
- emit({ type: 'ReasoningToken', data: chunk.reasoning });
198
- }
199
- if (chunk.content) {
200
- output += chunk.content;
201
- emit({ type: 'Token', data: chunk.content });
215
+ catch (error) {
216
+ if (error instanceof AiRuntimeError) {
217
+ throw new AiRuntimeError(error.code, 'Chat streaming response failed', {
218
+ providerId: options.providerId, modelId: options.payload.model,
219
+ protocol: 'openai-chat-sse', stage, receivedFinish: finishReason !== null,
220
+ ...(error.details?.finishReason === 'network_error' ? { finishReason: 'network_error' } : {}),
221
+ });
202
222
  }
223
+ throw error;
224
+ }
225
+ finally {
226
+ signal.removeEventListener('abort', cancelReader);
227
+ if (!eof)
228
+ cancelReader();
229
+ reader.releaseLock();
203
230
  }
204
- return {
205
- output,
206
- reasoningOutput,
207
- usage,
208
- finishReason,
209
- truncated: isOutputTruncated(finishReason),
210
- toolCalls: [...toolCalls.values()],
211
- };
212
231
  }
213
232
  function applyStructuredOutputRequestBody(request, providerId, body) {
214
233
  const output = request.structuredOutput;
@@ -282,47 +301,68 @@ function resolveMaxOutputTokens(request) {
282
301
  function invalidRequest(code, message) {
283
302
  return Object.assign(new Error(message), { code, statusCode: 400 });
284
303
  }
285
- function isOutputTruncated(finishReason) {
286
- return finishReason === 'length' || finishReason === 'max_tokens' || finishReason === 'max_output_tokens';
287
- }
288
- function drainSseEvents(input) {
289
- const events = [];
290
- let remaining = input;
291
- let hasSeparator = true;
292
- while (hasSeparator) {
293
- const separator = findNextSeparator(remaining);
294
- if (!separator) {
295
- hasSeparator = false;
296
- continue;
297
- }
298
- if (separator) {
299
- events.push(remaining.slice(0, separator.index));
300
- remaining = remaining.slice(separator.index + separator.length);
301
- }
302
- }
303
- return { events, remaining };
304
- }
305
- function findNextSeparator(input) {
306
- const crlf = input.indexOf('\r\n\r\n');
307
- const lf = input.indexOf('\n\n');
308
- if (crlf === -1 && lf === -1)
309
- return undefined;
310
- if (crlf !== -1 && (lf === -1 || crlf < lf))
311
- return { index: crlf, length: 4 };
312
- return { index: lf, length: 2 };
304
+ function isOutputTruncated(finishReason, providerId) {
305
+ return finishReason === 'length' || finishReason === 'max_tokens' || finishReason === 'max_output_tokens'
306
+ || (providerId === 'bigmodel' && finishReason === 'model_context_window_exceeded');
313
307
  }
314
- function parseSseData(event) {
308
+ function parseSseData(event, providerId) {
309
+ const eventName = event.split(/\r\n|\r|\n/)
310
+ .filter(line => line.startsWith('event:')).at(-1)?.slice(6).trim();
315
311
  const data = event
316
- .split(/\r?\n/)
317
- .map((line) => line.trim())
312
+ .split(/\r\n|\r|\n/)
318
313
  .filter((line) => line.startsWith('data:'))
319
314
  .map((line) => line.slice(5).trim())
320
315
  .join('\n');
316
+ if (eventName === 'error' && !data)
317
+ throw new AiRuntimeError('PROVIDER_STREAM_ERROR', 'Server error event');
321
318
  if (!data)
322
319
  return { done: false };
323
- if (data === '[DONE]')
320
+ if (data === '[DONE]' && (!eventName || eventName === 'message'))
324
321
  return { done: true };
325
- const json = JSON.parse(data);
322
+ if (eventName && !['message', 'chat.completion.chunk', 'error'].includes(eventName))
323
+ return { done: false };
324
+ let json;
325
+ try {
326
+ json = JSON.parse(data);
327
+ }
328
+ catch {
329
+ if (eventName === 'error')
330
+ throw new AiRuntimeError('PROVIDER_STREAM_ERROR', 'Server error event');
331
+ throw new AiRuntimeError('INVALID_STREAM_RESPONSE', 'Invalid SSE JSON');
332
+ }
333
+ if (eventName === 'error' || (isRecord(json) && json.error != null)) {
334
+ const error = isRecord(json) && isRecord(json.error) ? json.error : json;
335
+ const code = isRecord(error) && typeof error.code === 'string' && /^[\w.-]{1,80}$/.test(error.code)
336
+ ? error.code : 'PROVIDER_STREAM_ERROR';
337
+ throw new AiRuntimeError(code, 'Server error event');
338
+ }
339
+ // BigModel's documented SDK consumer permits status-only chunks without
340
+ // choices. This does not make them completion evidence or allow wrong types.
341
+ const statusOnlyAllowed = providerId === 'bigmodel';
342
+ if (statusOnlyAllowed && isRecord(json) && json.choices === undefined) {
343
+ return { done: false, usage: readUsage(json) };
344
+ }
345
+ if (!isRecord(json) || !Array.isArray(json.choices)) {
346
+ throw new AiRuntimeError('INVALID_STREAM_RESPONSE', 'Chat chunk has no choices array');
347
+ }
348
+ if (json.choices.length === 0) {
349
+ if (!statusOnlyAllowed && !isRecord(json.usage))
350
+ throw new AiRuntimeError('INVALID_STREAM_RESPONSE', 'Empty choices without usage');
351
+ return { done: false, usage: readUsage(json) };
352
+ }
353
+ const first = json.choices[0];
354
+ if (!isRecord(first) || !isRecord(first.delta)
355
+ || (first.finish_reason != null && (typeof first.finish_reason !== 'string' || !first.finish_reason.trim()))) {
356
+ throw new AiRuntimeError('INVALID_STREAM_RESPONSE', 'Invalid Chat choice');
357
+ }
358
+ if (providerId === 'bigmodel' && first.finish_reason === 'network_error') {
359
+ throw new AiRuntimeError('PROVIDER_STREAM_ERROR', 'Model inference failed', { finishReason: 'network_error' });
360
+ }
361
+ for (const field of ['content', 'reasoning_content', 'reasoning']) {
362
+ if (first.delta[field] != null && typeof first.delta[field] !== 'string') {
363
+ throw new AiRuntimeError('INVALID_STREAM_RESPONSE', 'Invalid Chat text delta');
364
+ }
365
+ }
326
366
  const delta = readDelta(json);
327
367
  return {
328
368
  done: false,
@@ -0,0 +1,4 @@
1
+ export declare function drainSseEvents(input: string): {
2
+ events: string[];
3
+ remaining: string;
4
+ };
@@ -0,0 +1,31 @@
1
+ // Dispatch only complete SSE events; an EOF does not imply a blank line.
2
+ export function drainSseEvents(input) {
3
+ const events = [];
4
+ let remaining = input;
5
+ let hasSeparator = true;
6
+ while (hasSeparator) {
7
+ const separator = findNextSeparator(remaining);
8
+ if (!separator) {
9
+ hasSeparator = false;
10
+ continue;
11
+ }
12
+ if (separator) {
13
+ events.push(remaining.slice(0, separator.index));
14
+ remaining = remaining.slice(separator.index + separator.length);
15
+ }
16
+ }
17
+ return { events, remaining };
18
+ }
19
+ function findNextSeparator(input) {
20
+ // CRLF is one line ending, including when it crosses transport chunks.
21
+ const endings = /\r\n|\r|\n/g;
22
+ let previous = null;
23
+ let current;
24
+ while ((current = endings.exec(input)) !== null) {
25
+ if (previous && previous.index + previous[0].length === current.index) {
26
+ return { index: previous.index, length: previous[0].length + current[0].length };
27
+ }
28
+ previous = current;
29
+ }
30
+ return undefined;
31
+ }
package/docs/consumers.md CHANGED
@@ -1,107 +1,119 @@
1
- # SDK 消费项目清单
2
-
3
- 本清单是 `@henjicc/ai-sdk` 消费方的唯一维护入口,用于 SDK 发布后的跨仓升级协调。
4
- 绝对路径仅描述当前开发机上的仓库位置,不进入 SDK 运行时代码、发布包或用户配置。
5
-
6
- 最后核对日期:2026-09-24
7
-
8
- `0.6.0` 已发布:新增 MiMo 2.6、GLM-5.3-FlashX、KIE HappyHorse 1.1、火山 Seedream 5.0 Flash 和百炼 Qwen Audio 3.1 ASR;补齐 MiMo Responses 思考事件与 ASR JSON/说话人解析。SDK 79 个测试文件 / 933 项测试、类型构建、可移植性、49 个公开入口和受限宿主验证通过;痕迹 AI 目录、参数组合、模型发现与旧配置兼容验证通过。MiMo 思考事件、ASR JSON 回退、HappyHorse 图生字段的修复撤销验证均检测到失败,恢复后通过。未执行付费请求。发布提交 `d08ea8fa` 的必需 CI [35904531000](https://github.com/henjicc/Henji-AI/actions/runs/35904531000) 全部通过,npm 网页认证后发布固定候选包;公共索引可读后,隔离配置、缓存与令牌的仓外匿名安装、包校验、新模型请求探针、Vite 49 入口和受限宿主验证全部通过。
9
-
10
- 本轮消费影响:Henji-AI 自动组合新增 generation pack,无需新增助手工具;三个仓内示例精确依赖同步到 `0.6.0`,均在仓外从公共 npm 匿名安装,minimal-node dry-run、llm-chat dry-run / bundle 边界和 form-renderer 构建 / 五类模型表单输出通过。外部 `say-it` 仍需先完成 `0.5.0` 文件上传桥迁移;当前未引入这批模型,不机械升级。`henji-ai-ps` 本机未定位,不声称已完成外部宿主升级。
11
-
12
- - `0.6.0` tarball:[公共 npm 包](https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.6.0.tgz)
13
- - `0.6.0` shasum:`2d02f956d6addc9fb92580cda323bc9d0904607e`
14
- - `0.6.0` integrity:`sha512-GzhWnVkdv2NNZjf0diI9dRBRkc/cH0O5nCjbiQrast54f+ik4Q4LbKjytrMhyMawxaSkCoHVeNQuEUwnCDkcnA==`
15
-
16
- Henji-AI 安装包的 GPT Image 2.5 高分辨率报错归属:宿主智能比例预处理曾忽略联动过滤,将 `smart` 转成 KIE 仅限 1K 的 `27:16`,SDK 在请求前正确拒绝。修复位于应用公共预处理,按当前分辨率/渠道的合法选项匹配;Flare/Sunburst 的 1K/2K/4K 及 APIMart、Grsai 同类筛选已有定向覆盖。无需放宽 SDK 契约或发布 SDK;安装包需随应用更新才包含修复,现有版本可手动选合法比例规避。
17
-
18
- 当前仓内及公共 npm SDK:`0.6.0`(2026-09-24 已发布并完成公共匿名回装)。以下为历史发布证据。
19
-
20
- `0.5.2` 完善轻量 `@henjicc/ai-sdk/llm/streaming`:正式类型支持文本、JSON Object 与 JSON Schema,Chat Completions 的最终请求体写入 `response_format`,OpenAI 输出上限写入 `max_completion_tokens`;结构化输出、思考模式和模型能力的非法组合会在请求前返回结构化错误。流式正文与思考继续分离,保留外部 `AbortSignal`,不设置默认总时限;未显式配置输出上限时不再注入 4096,服务端以 `length` 等原因结束时返回 `truncated: true`。发布前 77 个测试文件 / 909 项测试、可移植性、构建、49 个 Vite 公开入口和受限宿主门禁通过;故意撤销结构化参数、输出上限、OpenAI 字段映射和截断标记后,8 项定向断言失败,恢复后通过。公共索引可读后,已使用隔离 npm 配置和缓存匿名安装精确版本,并从已发布的轻量入口验证最终请求体包含 JSON Schema、思考强度和 24,000 token 上限,SSE 正文/思考事件分离且未截断。
21
-
22
- - `0.5.2` tarball:https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.5.2.tgz
23
- - `0.5.2` shasum:`f1c06ae12c9240b203f3ad310c4eec35b755db13`
24
- - `0.5.2` integrity:`sha512-ljb50njJ0bXWxwNmlgZ1+YDBoBgPiLhoNEDjsbhPbe4pc7aVZGcfvpDLh+zGdx9KsB7g7Xp3mqVM4MLpVQm15g==`
25
-
26
- `0.5.1` 将 Grsai GPT Image 2.5 未指定变体时的默认值从官方公告仍在维护的 Flare 改为 Standard,并同步默认价格;显式选择 Flare / Sunburst 的调用保持兼容。公共 DTO、请求协议、宿主边界和其余模型未变。发布前 77 个测试文件 / 899 项测试、可移植性、构建、49 个 Vite 公开入口和受限宿主门禁通过;公共索引可读后,已在隔离用户 npm 配置的仓外目录匿名安装并完成 ESM 导入。
27
-
28
- - `0.5.1` tarball:https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.5.1.tgz
29
- - `0.5.1` shasum:`40087e680f1b7de63a601d12758acb7280de305f`
30
- - `0.5.1` integrity:`sha512-+L/mAmFU6zgJ0gdsIwy0T1Z9TDOABaxO3HgLsEvMUNbRQhs9K55golF1472EgSJsIDysScnUulFJfBVg0xsNBg==`
31
-
32
- `0.5.0` 发布运行时代码提交 `1333422e`,补充边界回归提交 `da37e4bc`;后者必需 CI `35535140722` 全部成功。12组修复撤销验证均检测到失败,恢复后定向测试通过。固定候选包经仓外回装后发布,公共 registry 匿名安装的 shasum/integrity 与候选包一致;Vite公开入口和无TextEncoder/TextDecoder的受限宿主消费通过。npm网页登录与发布二次验证已完成;发布后等待公共索引可读才执行匿名验证,没有重复发布。
33
-
34
- - tarball:https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.5.0.tgz
35
- - shasum:`1b66a7c54f4f86a01b73fdca68b1c63e53dcbe10`
36
- - integrity:`sha512-MaPS87wDnvGdeAkGZOQHV+q/XPsQv9WZSPKYTYhqYrDhLbGUKS+m6h1sQ2oPM0GVXuZXKsos9BTJH61NSHjzag==`
37
-
38
- 本轮按用户SDK范围交付可安装包及宿主调整依据;未升级或修改外部say-it/Photoshop仓库。say-it必须实现新流式/原生文件上传桥并完成Tauri集成验收后再升级;不能只改10 MiB常量。
39
-
40
- `0.5.0` 文件 ASR:四族九模型已核对。SDK 新增 describe/readChunk + fetchStream 的有界请求体消费,百炼异步 media-ref 必须通过 uploadFile 原生直传 OSS;旧宿主 read 兼容路径不得提升原内存阈值。structured media_too_large 保留实际字节、上限与可得时长。官方 Qwen 编码后10 MB对应原始7,500,000字节,Fun Flash 2,000,000,000字节/5分钟,Groq附件25,000,000,硅基流动50,000,000,百炼临时上传取min(1,000,000,000,凭证MB×1,000,000)。
41
-
42
- 本次完成SDK精确回归、12组修复撤销反向验证、全量发布门禁与真实QuickJS 64 MiB堆探针(50 MB multipart、7.5/12 MB JSON);未执行付费请求。say-it 当前 Host API 虽有分块,适配器仍拼回完整Uint8Array,请求体也仍缓冲,必须接入新契约后才可调整分块总文件上限;原生OSS单独受凭证限制。当前任务交付SDK及宿主调整依据,未改写该外部仓库或声称完成Tauri验收。Henji-AI/Photoshop现有生成媒体读取未迁移到新ASR接口,不机械增加未使用能力。
43
-
44
- 2026-09-14 候选增量:安全网络失败在端点尝试耗尽后按 1/3/8 秒退避,每次失败重新判断重放安全性,取消立即结束退避。SDK 873 项测试、主进程定向测试与类型检查、可移植性及仓外 Vite/受限宿主消费通过;故意移除重试安全复核后,未知提交状态测试失败,恢复后通过。真实 Electron 主进程对本地服务及 KIE 无凭据只读查询,Node 与 Chromium 两栈均得到 HTTP 200;只证明当时连通,不代表付费生成成功,也未复现之前断连的外部原因。宿主增加关联原请求的脱敏 DNS/代理诊断,不更换网络栈。本机 npm 身份仍返回 401,本次候选变更尚未公共发布或同步外部消费者;下方旧候选包校验值仅对应此前版本内容。
45
-
46
- `0.4.2`:共享 transport 将 Node 明确的 TLS 建立前 ECONNRESET 识别为未发送,允许备用端点切换;GET/HEAD 的瞬态断连也允许切换,提交状态不明的写请求仍禁止重放。错误附带脱敏端点、阶段、耗时和提交状态,Henji-AI 生成与继续查询日志保留这些字段。SDK 870 项测试、宿主 7 项定向测试、可移植性、类型构建、仓外 Node ESM / 严格 TypeScript / Vite 49 入口与受限宿主回装通过;故意放行普通 ECONNRESET 重放会被 3 项写请求测试检测,恢复后全量通过。未执行真实付费请求。外部宿主使用不同 transport,需按其错误契约核对影响,不能将 Node 连接前分类视为所有宿主均已实测。
47
-
48
- 修复提交 `5bf36dce` 已推送,CI `34758299265` 已启动。本机 npm 身份检查返回 `401 Unauthorized`,认证恢复且必需 CI 通过前不得发布;未声称完成公共回装或外部消费者升级。候选包 shasum 为 `dafaae4787798c3f22e5615fe8f5d60f4545c0a2`。宿主 Electron 类型检查与重启通过。上一提交 `45bb50b5` 的 CI 已存在两项画布能力引用相等断言失败,与本次网络修复无关,未夹带修改。
49
-
50
- `0.4.1`:修复 KIE GPT Image 2 / 2.5 的视频参考误标签,图片生成、编辑、多图输入及请求契约保持不变。109 个生成模型的跨模态视频标签检查、67 项定向测试、SDK 862 项全量测试、可移植性、类型构建及仓外公开入口/受限宿主回装通过。外部消费者登记版本为 `0.2.8`:say-it 不使用图片模型,不受影响;henji-ai-ps 的 KIE GPT Image 2 标签消费情况需在该项目可访问时核实,尚未升级。
51
-
52
- 修复提交 `ef2be83f` 的必需 CI `34575686946` 已全部通过。正式包与固定候选包 shasum 一致:`32b8dd00f3e320822999b626b8e95a50b6a8ff2f`。发布后在仓外隔离 npm 配置并移除令牌环境变量,已从公共 npm 匿名安装精确版本;Node ESM、严格 TypeScript、49 个 Vite 入口及无 TextEncoder/TextDecoder 的受限宿主验证通过。仓内 workspace 与三个示例 manifest 已锁定 `0.4.1`;未执行真实付费生成或外部消费项目升级。
53
-
54
- - `0.4.1` tarball:`https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.4.1.tgz`
55
- - `0.4.1` integrity:`sha512-HtOoOlJWGR6m15wIvqI2VMJFk+ijHntXl2oZAqEA6Ri12gWqaa3JhPthisTj+epO7GwGcuGX4gW3a8qIDd4vAw==`
56
-
57
- `0.4.0`:新增硅基流动聊天预设与分类模型发现,提交 `a678dab6` 已推送,必需 CI `34565921443` 全部通过。SDK 861 项测试、宿主配置 15 项测试、类型构建、49 个公开入口及受限宿主候选包回装通过;未执行真实付费推理。移除服务端分类参数的断牙验证使 4 项测试失败,恢复后全量通过。
58
-
59
- 账号网页二次验证已完成,正式包与候选包校验值一致。已在仓外隔离 npm 配置并移除令牌环境变量,从公共 npm 匿名安装精确版本:Node ESM、严格 TypeScript、Vite 49 个入口及无 TextEncoder/TextDecoder 的受限宿主验证通过,包含硅基流动动态模型发现。仓内 workspace 与三个示例 manifest 已锁定 `0.4.0`;现有外部消费者未新增硅基流动聊天使用,暂不升级。
60
-
61
- - tarball:`https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.4.0.tgz`
62
- - shasum:`29a267d8a9f8375ac08b5af94569939473ab6a17`
63
- - integrity:`sha512-4D2gHakuo7Fhhh3a987qrObqJd78k8mIhXPL9dgE3A5uywBi4ebHj7U4XVLUcbjv/HO34wH/+8kFlE5JMOGD0g==`
64
-
65
- `0.3.0` 已发布:新增四家 GPT Image 2.5 pack、五家文本 embedding / 四家 rerank,DeepSeek 官方默认模型更新为 `deepseek-flash`。发布提交 `a2dc5bc4` 的必需 CI 门禁全部通过(运行 `34532267703`),SDK 全量 839 项测试和候选包回装通过。正式包已在隔离 npm 配置、无用户令牌的仓外环境从公共 npm 安装,标准 Vite 48 个入口与受限宿主验证通过;正式包校验值与候选包一致。未运行真实付费模型请求。
66
-
67
- Henji-AI workspace 与三个仓内示例 manifest 均锁定 `0.4.0`;下表原有示例运行记录仅代表 `0.2.8` 历史证据,本次未完成三个示例的独立全套回装复验。`say-it` 已在 `D:/VibeCode/说吧` 定位,仍锁定公共 npm `0.2.8`,实际按需使用 ASR、translation 与 LLM modules,未使用本次新增硅基流动聊天能力,无需机械升级;未运行其真实宿主验收。`henji-ai-ps` 的下表路径为另一台开发机记录,本机未定位该路径,不声称本次完成外部升级。
68
-
69
- ## 判定口径
70
-
71
- - **消费者**:package manifest / lockfile 声明 SDK,或源码、构建入口实际导入 SDK。
72
- - **内部消费验证面**:位于 SDK 主仓库内,但有独立 manifest 和可运行构建的示例;它们不是外部仓库,仍需跟随发布版本验证。
73
- - **非消费者证据**:README、任务交接、迁移记录中的文字引用,以及没有进入实际构建的声明,不单独算消费者。
74
- - 扫描范围为 `/Users/henji/Documents/VibeCode` 下一级项目,排除了 `.git`、`node_modules`、`dist`、`target`、`build`、`coverage` 和缓存目录。
75
-
76
- ## 独立宿主
77
-
78
- | 仓库 / 开发路径 | 宿主类型 | 当前精确版本 | SDK 入口与构建方式 | 凭据 / transport 责任 | 需同步的变更类型 | 验证命令 | 同步证据与边界 | 最后核对 |
79
- |---|---|---|---|---|---|---|---|---|
80
- | `Henji-AI`<br>`D:/VibeCode/Henji-AI` | Electron 42 主进程 + React/Vite;SDK 主开发、首发验证宿主 | workspace 源码与公共 npm 均为 `0.6.0` | 包根、`provider-packs/*`、`tool-packs/*`;根构建先执行 `build:sdk`,再构建 Electron | Electron 主进程注入 HTTP transport、凭据、媒体读取、日志、trace、取消与落盘;渲染层不直接持有密钥 | 公共类型/目录、provider preset、凭据坐标、transport、媒体、包导出、LLM/生成执行协议 | SDK 发布门禁、相关宿主 Vitest、渲染层/主进程类型检查与模型 i18n | `d08ea8fa`;必需 CI `35904531000` 成功,SDK 933 项测试、公开入口及受限宿主验证通过;公共包匿名安装及校验值一致,未执行付费请求 | 2026-09-24 |
81
- | `henji-ai-ps`<br>`/Users/henji/Documents/VibeCode/henji-ai-ps` | Photoshop UXP 插件 + React/Vite IIFE(pnpm) | manifest/lock 均精确锁定公共 npm `0.2.8`;lock integrity 与上方正式产物一致 | `generation/core`、单模型/供应商 pack、LLM streaming;Vite 构建与 UXP smoke bundle | UXP 宿主注入受限 `fetch`、provider 凭据、媒体编码读取和脱敏日志;SDK 不读取 Node/文件系统 | 生成 pack/exports、受限环境可移植性、RuntimeContext、凭据 scope、媒体与流式 LLM;不因版本同步自动引入 GLM | `pnpm typecheck:uxp-smoke && pnpm check:uxp-sdk && pnpm smoke:uxp:build && pnpm check:uxp-smoke`;完整 `pnpm check` | `e509716`;无用户 npm 凭据的 frozen lock 安装通过;Node 22 下四项门禁通过,正式产品仍仅 39 个 generation/erase packs,网络调用与受限环境风险均为 0 | 2026-08-31 |
82
- | `say-it`<br>`/Users/henji/Documents/VibeCode/say-it` | Tauri 2 + Rust 管理 QuickJS;WebView 不运行 SDK | manifest/lock 均精确锁定公共 npm `0.2.8`;resolved、shasum、integrity 与上方正式产物一致 | 按需打包 capability、Bailian/火山实时 ASR、SiliconFlow/Groq 文件 ASR、translation、LLM modules 为相互隔离 IIFE;Rust 加载 bundle | Rust Host API 注入 HTTP 字节流、WS、media-ref、CredentialStore、日志/trace、Abort/timeout/cancel;QuickJS/插件/WebView 不直取密钥 | capability/LLM 协议、按需 exports、descriptor source/坐标、QuickJS 可移植性、bundle 隔离;不因版本同步自动增加未采用模型 | `npm run sdk-runtime:typecheck && npm run sdk-runtime:build`;`npm run test:ui`;Rust 定向/全量测试;`npm run ui:build` | SDK 迁移提交 `5eb4c8b`,0.2.8 基础验证 `df3107e`,Rust→QuickJS 可选字段省略修复 `9e70d32`;QuickJS multipart 内存修复 `3f00ea9` 属宿主传输实现问题,改为原生二进制句柄且保持 64 MiB 沙箱上限,10 MiB 音频边界回归、重定向/资源清理测试、SDK Runtime 类型检查与构建通过 | 2026-09-01 |
83
-
84
- ## SDK 仓内消费验证面
85
-
86
- 这些目录是可独立安装、构建的真实示例,但与 SDK 同属 `Henji-AI` 仓库,不重复算外部仓库。
87
- 它们的 manifest 均精确声明公共 npm `0.6.0`,仓内不维护锁文件;本次在仓外临时副本重新安装并验证,未使用 workspace 或本地源码替代正式包。
88
-
89
- | 路径 | 用途 / 入口 | 当前版本 | 宿主责任 | 验证命令 | 同步证据 | 最后核对 |
90
- |---|---|---|---|---|---|---|
91
- | `D:/VibeCode/Henji-AI/packages/ai-sdk/examples/minimal-node` | `generation` + `runtime` 按需入口;完整 generation catalog、KIE dry-run/live 闸门,不带 LLM/BigModel | `0.6.0`(精确 manifest,仓内无 lock) | Node transport、环境凭据、文件媒体读取、日志 | 在目录内 `npm install && npm run dry-run` | 公共 npm 匿名安装、类型构建与 dry-run 通过,模型网络调用为 0 | 2026-09-24 |
92
- | `D:/VibeCode/Henji-AI/packages/ai-sdk/examples/llm-chat` | `llm/streaming` 按需入口;OpenAI-compatible SSE 对话,不带 generation、BigModel preset/models/pricing、Groq 或 LLM modules(保留通用身份解析所需 profiles) | `0.6.0`(精确 manifest,仓内无 lock) | Node transport、环境凭据、流事件与取消 | 在目录内 `npm install && npm run dry-run && npm run check:bundle` | 公共 npm 匿名安装、类型构建、dry-run 和 bundle 边界检查通过 | 2026-09-24 |
93
- | `D:/VibeCode/Henji-AI/packages/ai-sdk/examples/form-renderer` | `generation` + `catalog` + `runtime` 按需入口;完整 generation catalog/参数契约与最小 renderer,不带 LLM/BigModel | `0.6.0`(精确 manifest,仓内无 lock) | 零网络 RuntimeContext;仅目录与 renderer | 在目录内 `npm install && npm run build && npm start` | 公共 npm 匿名安装、类型构建与五类代表模型表单输出通过 | 2026-09-24 |
94
-
95
- ## 非消费者证据
96
-
97
- - `Henji-AI`、`henji-ai-ps`、`say-it` 的 README、任务文件和交接文档含历史版本或迁移描述;它们用于追溯,不形成额外消费者。
98
- - `/Users/henji/Documents/VibeCode` 下的 `ai-roundtable`、`fast-install`、`henji`、`henji-dev`、`henjicc.github.io`、`mySkills`、`test` 未发现 `@henjicc/ai-sdk` 的 manifest、lockfile、源码 import 或构建脚本引用。
99
- - SDK 自身的测试、fixture、导出检查和发布脚本属于生产者验证,不作为独立消费项目。
100
-
101
- ## 发布后维护规则
102
-
103
- 1. SDK 必须先在 `Henji-AI` 完成精确测试、全量/可移植性/包验证与远端回装,再发布。
104
- 2. 发布后按变更影响逐个同步本清单中的实际消费者;外部消费者必须精确锁版本并核对 lock integrity,再回写 commit、验证状态、边界和日期。
105
- 3. 只升级消费项目实际使用的按需入口。新增 provider/model 不等于所有宿主都要增加对应 bundle 或业务入口。
106
- 4. 涉及 provider 身份、endpoint profile、credentialId、transport、media 或协议事件时,逐项检查表中宿主责任边界,禁止在消费方复制 SDK 执行内核。
107
- 5. 消费项目升级完成后,将验证结果写入对应任务交接;本清单只维护稳定事实,不复制每次执行日志。
1
+ # SDK 消费项目清单
2
+
3
+ 本清单是 `@henjicc/ai-sdk` 消费方的唯一维护入口,用于 SDK 发布后的跨仓升级协调。
4
+ 绝对路径仅描述当前开发机上的仓库位置,不进入 SDK 运行时代码、发布包或用户配置。
5
+
6
+ 最后核对日期:2026-09-24
7
+
8
+ `0.6.2` 候选验证中,尚未发布:聊天/翻译流终态、百炼/火山实时 ASR、共享会话终止与脱敏诊断已完成修复及撤销修复后的失败验证。SDK 83 文件 / 1023 项测试、可移植性、构建、49 个公开入口、严格类型和受限宿主门禁通过,Henji-AI 8 项相关宿主测试与主进程类型检查通过。下一步验证固定候选包并等待对应发布提交的必需 CI;未执行本轮真实付费请求。Henji-AI workspace 和 llm-chat 示例准备使用 `0.6.2`,minimal-node/form-renderer 保持 `0.6.0`。说吧当前仍为 `0.6.1`,本次不修改外部仓库;Photoshop 未在本机验证,不能声称已升级。
9
+
10
+ `0.6.1` 已发布:修复百炼 Fun Duplex 实时识别将无句首标记的空中间帧误判为 `invalid_response`;缺失 text、空 final 和无最终结果仍明确失败。发布源码提交 `6dd90b22` 的必需 CI [35917044506](https://github.com/henjicc/Henji-AI/actions/runs/35917044506) 全部成功;SDK 79 文件 / 933 项测试、可移植性、类型构建、49 个公开入口和受限宿主验证通过。两项事件序列回归撤销修复后失败、恢复后通过;合成语音最小真实请求成功。固定候选包发布后,隔离配置、缓存和令牌的仓外匿名回装及 Vite / 受限宿主验证通过。
11
+
12
+ - `0.6.1` tarball:[公共 npm 包](https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.6.1.tgz)
13
+ - `0.6.1` shasum:`48a48e4692dd30695393b0c7f7432b994ede5ef1`
14
+ - `0.6.1` integrity:`sha512-0gY7crODwieU82r5XOgrmKVQIzLdJqFf8gAjsz8xv0wIpJe4aL8SeBM59qVVVSGpjckaVqzFe9NryhA/hjQw8Q==`
15
+
16
+ 外部 `say-it` 已在 `D:/VibeCode/说吧` 完成公共 npm `0.6.1` 精确升级,提交 `18bad6d`;manifest、lock、bundle 版本与完整性校验一致。QuickJS/WS 空中间帧回归、SDK 宿主 35 项本地测试、runtime 类型检查通过;另有听写 48 项、历史 12 项、历史 UI 6 项及前端类型检查/构建通过。开发桌面应用已重启,实际麦克风交互由用户验证。当前宿主已含流式/原生文件上传桥,不再受下方旧版迁移待办限制。三个仓内示例仅消费 generation/LLM,保持已验证的 `0.6.0`;Photoshop 未消费此次 ASR 修复,不机械升级。
17
+
18
+ 以下 `0.6.0` 及更早记录用于追溯历史发布。
19
+
20
+ `0.6.0` 已发布:新增 MiMo 2.6、GLM-5.3-FlashX、KIE HappyHorse 1.1、火山 Seedream 5.0 Flash 和百炼 Qwen Audio 3.1 ASR;补齐 MiMo Responses 思考事件与 ASR JSON/说话人解析。SDK 79 个测试文件 / 933 项测试、类型构建、可移植性、49 个公开入口和受限宿主验证通过;痕迹 AI 目录、参数组合、模型发现与旧配置兼容验证通过。MiMo 思考事件、ASR JSON 回退、HappyHorse 图生字段的修复撤销验证均检测到失败,恢复后通过。未执行付费请求。发布提交 `d08ea8fa` 的必需 CI [35904531000](https://github.com/henjicc/Henji-AI/actions/runs/35904531000) 全部通过,npm 网页认证后发布固定候选包;公共索引可读后,隔离配置、缓存与令牌的仓外匿名安装、包校验、新模型请求探针、Vite 49 入口和受限宿主验证全部通过。
21
+
22
+ 本轮消费影响:Henji-AI 自动组合新增 generation pack,无需新增助手工具;三个仓内示例精确依赖同步到 `0.6.0`,均在仓外从公共 npm 匿名安装,minimal-node dry-run、llm-chat dry-run / bundle 边界和 form-renderer 构建 / 五类模型表单输出通过。外部 `say-it` 仍需先完成 `0.5.0` 文件上传桥迁移;当前未引入这批模型,不机械升级。`henji-ai-ps` 本机未定位,不声称已完成外部宿主升级。
23
+
24
+ - `0.6.0` tarball:[公共 npm 包](https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.6.0.tgz)
25
+ - `0.6.0` shasum:`2d02f956d6addc9fb92580cda323bc9d0904607e`
26
+ - `0.6.0` integrity:`sha512-GzhWnVkdv2NNZjf0diI9dRBRkc/cH0O5nCjbiQrast54f+ik4Q4LbKjytrMhyMawxaSkCoHVeNQuEUwnCDkcnA==`
27
+
28
+ Henji-AI 安装包的 GPT Image 2.5 高分辨率报错归属:宿主智能比例预处理曾忽略联动过滤,将 `smart` 转成 KIE 仅限 1K 的 `27:16`,SDK 在请求前正确拒绝。修复位于应用公共预处理,按当前分辨率/渠道的合法选项匹配;Flare/Sunburst 的 1K/2K/4K 及 APIMart、Grsai 同类筛选已有定向覆盖。无需放宽 SDK 契约或发布 SDK;安装包需随应用更新才包含修复,现有版本可手动选合法比例规避。
29
+
30
+ 当前仓内 SDK:`0.6.2` 候选;公共 npm 仍为 `0.6.1`(已发布并完成公共匿名回装)。以下为历史发布证据。
31
+
32
+ `0.5.2` 完善轻量 `@henjicc/ai-sdk/llm/streaming`:正式类型支持文本、JSON Object 与 JSON Schema,Chat Completions 的最终请求体写入 `response_format`,OpenAI 输出上限写入 `max_completion_tokens`;结构化输出、思考模式和模型能力的非法组合会在请求前返回结构化错误。流式正文与思考继续分离,保留外部 `AbortSignal`,不设置默认总时限;未显式配置输出上限时不再注入 4096,服务端以 `length` 等原因结束时返回 `truncated: true`。发布前 77 个测试文件 / 909 项测试、可移植性、构建、49 个 Vite 公开入口和受限宿主门禁通过;故意撤销结构化参数、输出上限、OpenAI 字段映射和截断标记后,8 项定向断言失败,恢复后通过。公共索引可读后,已使用隔离 npm 配置和缓存匿名安装精确版本,并从已发布的轻量入口验证最终请求体包含 JSON Schema、思考强度和 24,000 token 上限,SSE 正文/思考事件分离且未截断。
33
+
34
+ - `0.5.2` tarball:https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.5.2.tgz
35
+ - `0.5.2` shasum:`f1c06ae12c9240b203f3ad310c4eec35b755db13`
36
+ - `0.5.2` integrity:`sha512-ljb50njJ0bXWxwNmlgZ1+YDBoBgPiLhoNEDjsbhPbe4pc7aVZGcfvpDLh+zGdx9KsB7g7Xp3mqVM4MLpVQm15g==`
37
+
38
+ `0.5.1` 将 Grsai GPT Image 2.5 未指定变体时的默认值从官方公告仍在维护的 Flare 改为 Standard,并同步默认价格;显式选择 Flare / Sunburst 的调用保持兼容。公共 DTO、请求协议、宿主边界和其余模型未变。发布前 77 个测试文件 / 899 项测试、可移植性、构建、49 个 Vite 公开入口和受限宿主门禁通过;公共索引可读后,已在隔离用户 npm 配置的仓外目录匿名安装并完成 ESM 导入。
39
+
40
+ - `0.5.1` tarball:https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.5.1.tgz
41
+ - `0.5.1` shasum:`40087e680f1b7de63a601d12758acb7280de305f`
42
+ - `0.5.1` integrity:`sha512-+L/mAmFU6zgJ0gdsIwy0T1Z9TDOABaxO3HgLsEvMUNbRQhs9K55golF1472EgSJsIDysScnUulFJfBVg0xsNBg==`
43
+
44
+ `0.5.0` 发布运行时代码提交 `1333422e`,补充边界回归提交 `da37e4bc`;后者必需 CI `35535140722` 全部成功。12组修复撤销验证均检测到失败,恢复后定向测试通过。固定候选包经仓外回装后发布,公共 registry 匿名安装的 shasum/integrity 与候选包一致;Vite公开入口和无TextEncoder/TextDecoder的受限宿主消费通过。npm网页登录与发布二次验证已完成;发布后等待公共索引可读才执行匿名验证,没有重复发布。
45
+
46
+ - tarball:https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.5.0.tgz
47
+ - shasum:`1b66a7c54f4f86a01b73fdca68b1c63e53dcbe10`
48
+ - integrity:`sha512-MaPS87wDnvGdeAkGZOQHV+q/XPsQv9WZSPKYTYhqYrDhLbGUKS+m6h1sQ2oPM0GVXuZXKsos9BTJH61NSHjzag==`
49
+
50
+ 本轮按用户SDK范围交付可安装包及宿主调整依据;未升级或修改外部say-it/Photoshop仓库。say-it必须实现新流式/原生文件上传桥并完成Tauri集成验收后再升级;不能只改10 MiB常量。
51
+
52
+ `0.5.0` 文件 ASR:四族九模型已核对。SDK 新增 describe/readChunk + fetchStream 的有界请求体消费,百炼异步 media-ref 必须通过 uploadFile 原生直传 OSS;旧宿主 read 兼容路径不得提升原内存阈值。structured media_too_large 保留实际字节、上限与可得时长。官方 Qwen 编码后10 MB对应原始7,500,000字节,Fun Flash 2,000,000,000字节/5分钟,Groq附件25,000,000,硅基流动50,000,000,百炼临时上传取min(1,000,000,000,凭证MB×1,000,000)。
53
+
54
+ 本次完成SDK精确回归、12组修复撤销反向验证、全量发布门禁与真实QuickJS 64 MiB堆探针(50 MB multipart、7.5/12 MB JSON);未执行付费请求。say-it 当前 Host API 虽有分块,适配器仍拼回完整Uint8Array,请求体也仍缓冲,必须接入新契约后才可调整分块总文件上限;原生OSS单独受凭证限制。当前任务交付SDK及宿主调整依据,未改写该外部仓库或声称完成Tauri验收。Henji-AI/Photoshop现有生成媒体读取未迁移到新ASR接口,不机械增加未使用能力。
55
+
56
+ 2026-09-14 候选增量:安全网络失败在端点尝试耗尽后按 1/3/8 秒退避,每次失败重新判断重放安全性,取消立即结束退避。SDK 873 项测试、主进程定向测试与类型检查、可移植性及仓外 Vite/受限宿主消费通过;故意移除重试安全复核后,未知提交状态测试失败,恢复后通过。真实 Electron 主进程对本地服务及 KIE 无凭据只读查询,Node 与 Chromium 两栈均得到 HTTP 200;只证明当时连通,不代表付费生成成功,也未复现之前断连的外部原因。宿主增加关联原请求的脱敏 DNS/代理诊断,不更换网络栈。本机 npm 身份仍返回 401,本次候选变更尚未公共发布或同步外部消费者;下方旧候选包校验值仅对应此前版本内容。
57
+
58
+ `0.4.2`:共享 transport 将 Node 明确的 TLS 建立前 ECONNRESET 识别为未发送,允许备用端点切换;GET/HEAD 的瞬态断连也允许切换,提交状态不明的写请求仍禁止重放。错误附带脱敏端点、阶段、耗时和提交状态,Henji-AI 生成与继续查询日志保留这些字段。SDK 870 项测试、宿主 7 项定向测试、可移植性、类型构建、仓外 Node ESM / 严格 TypeScript / Vite 49 入口与受限宿主回装通过;故意放行普通 ECONNRESET 重放会被 3 项写请求测试检测,恢复后全量通过。未执行真实付费请求。外部宿主使用不同 transport,需按其错误契约核对影响,不能将 Node 连接前分类视为所有宿主均已实测。
59
+
60
+ 修复提交 `5bf36dce` 已推送,CI `34758299265` 已启动。本机 npm 身份检查返回 `401 Unauthorized`,认证恢复且必需 CI 通过前不得发布;未声称完成公共回装或外部消费者升级。候选包 shasum 为 `dafaae4787798c3f22e5615fe8f5d60f4545c0a2`。宿主 Electron 类型检查与重启通过。上一提交 `45bb50b5` 的 CI 已存在两项画布能力引用相等断言失败,与本次网络修复无关,未夹带修改。
61
+
62
+ `0.4.1`:修复 KIE GPT Image 2 / 2.5 的视频参考误标签,图片生成、编辑、多图输入及请求契约保持不变。109 个生成模型的跨模态视频标签检查、67 项定向测试、SDK 862 项全量测试、可移植性、类型构建及仓外公开入口/受限宿主回装通过。外部消费者登记版本为 `0.2.8`:say-it 不使用图片模型,不受影响;henji-ai-ps 的 KIE GPT Image 2 标签消费情况需在该项目可访问时核实,尚未升级。
63
+
64
+ 修复提交 `ef2be83f` 的必需 CI `34575686946` 已全部通过。正式包与固定候选包 shasum 一致:`32b8dd00f3e320822999b626b8e95a50b6a8ff2f`。发布后在仓外隔离 npm 配置并移除令牌环境变量,已从公共 npm 匿名安装精确版本;Node ESM、严格 TypeScript、49 个 Vite 入口及无 TextEncoder/TextDecoder 的受限宿主验证通过。仓内 workspace 与三个示例 manifest 已锁定 `0.4.1`;未执行真实付费生成或外部消费项目升级。
65
+
66
+ - `0.4.1` tarball:`https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.4.1.tgz`
67
+ - `0.4.1` integrity:`sha512-HtOoOlJWGR6m15wIvqI2VMJFk+ijHntXl2oZAqEA6Ri12gWqaa3JhPthisTj+epO7GwGcuGX4gW3a8qIDd4vAw==`
68
+
69
+ `0.4.0`:新增硅基流动聊天预设与分类模型发现,提交 `a678dab6` 已推送,必需 CI `34565921443` 全部通过。SDK 861 项测试、宿主配置 15 项测试、类型构建、49 个公开入口及受限宿主候选包回装通过;未执行真实付费推理。移除服务端分类参数的断牙验证使 4 项测试失败,恢复后全量通过。
70
+
71
+ 账号网页二次验证已完成,正式包与候选包校验值一致。已在仓外隔离 npm 配置并移除令牌环境变量,从公共 npm 匿名安装精确版本:Node ESM、严格 TypeScript、Vite 49 个入口及无 TextEncoder/TextDecoder 的受限宿主验证通过,包含硅基流动动态模型发现。仓内 workspace 与三个示例 manifest 已锁定 `0.4.0`;现有外部消费者未新增硅基流动聊天使用,暂不升级。
72
+
73
+ - tarball:`https://registry.npmjs.org/@henjicc/ai-sdk/-/ai-sdk-0.4.0.tgz`
74
+ - shasum:`29a267d8a9f8375ac08b5af94569939473ab6a17`
75
+ - integrity:`sha512-4D2gHakuo7Fhhh3a987qrObqJd78k8mIhXPL9dgE3A5uywBi4ebHj7U4XVLUcbjv/HO34wH/+8kFlE5JMOGD0g==`
76
+
77
+ `0.3.0` 已发布:新增四家 GPT Image 2.5 pack、五家文本 embedding / 四家 rerank,DeepSeek 官方默认模型更新为 `deepseek-flash`。发布提交 `a2dc5bc4` 的必需 CI 门禁全部通过(运行 `34532267703`),SDK 全量 839 项测试和候选包回装通过。正式包已在隔离 npm 配置、无用户令牌的仓外环境从公共 npm 安装,标准 Vite 48 个入口与受限宿主验证通过;正式包校验值与候选包一致。未运行真实付费模型请求。
78
+
79
+ Henji-AI workspace 与三个仓内示例 manifest 均锁定 `0.4.0`;下表原有示例运行记录仅代表 `0.2.8` 历史证据,本次未完成三个示例的独立全套回装复验。`say-it` 已在 `D:/VibeCode/说吧` 定位,仍锁定公共 npm `0.2.8`,实际按需使用 ASR、translation 与 LLM modules,未使用本次新增硅基流动聊天能力,无需机械升级;未运行其真实宿主验收。`henji-ai-ps` 的下表路径为另一台开发机记录,本机未定位该路径,不声称本次完成外部升级。
80
+
81
+ ## 判定口径
82
+
83
+ - **消费者**:package manifest / lockfile 声明 SDK,或源码、构建入口实际导入 SDK。
84
+ - **内部消费验证面**:位于 SDK 主仓库内,但有独立 manifest 和可运行构建的示例;它们不是外部仓库,仍需跟随发布版本验证。
85
+ - **非消费者证据**:README、任务交接、迁移记录中的文字引用,以及没有进入实际构建的声明,不单独算消费者。
86
+ - 扫描范围为 `/Users/henji/Documents/VibeCode` 下一级项目,排除了 `.git`、`node_modules`、`dist`、`target`、`build`、`coverage` 和缓存目录。
87
+
88
+ ## 独立宿主
89
+
90
+ | 仓库 / 开发路径 | 宿主类型 | 当前精确版本 | SDK 入口与构建方式 | 凭据 / transport 责任 | 需同步的变更类型 | 验证命令 | 同步证据与边界 | 最后核对 |
91
+ |---|---|---|---|---|---|---|---|---|
92
+ | `Henji-AI`<br>`D:/VibeCode/Henji-AI` | Electron 42 主进程 + React/Vite;SDK 主开发、首发验证宿主 | workspace 源码 `0.6.2` 候选;公共 npm `0.6.1` | 包根、`provider-packs/*`、`tool-packs/*`;根构建先执行 `build:sdk`,再构建 Electron | Electron 主进程注入 HTTP transport、凭据、媒体读取、日志、trace、取消与落盘;渲染层不直接持有密钥 | 公共类型/目录、provider preset、凭据坐标、transport、媒体、包导出、LLM/生成执行协议 | SDK 发布门禁、相关宿主 Vitest、渲染层/主进程类型检查与模型 i18n | `6dd90b22`;必需 CI `35917044506` 成功,SDK 933 项测试、公开入口及受限宿主验证通过;公共包匿名回装通过,合成语音最小真实请求成功 | 2026-09-24 |
93
+ | `henji-ai-ps`<br>`/Users/henji/Documents/VibeCode/henji-ai-ps` | Photoshop UXP 插件 + React/Vite IIFE(pnpm) | manifest/lock 均精确锁定公共 npm `0.2.8`;lock integrity 与上方正式产物一致 | `generation/core`、单模型/供应商 pack、LLM streaming;Vite 构建与 UXP smoke bundle | UXP 宿主注入受限 `fetch`、provider 凭据、媒体编码读取和脱敏日志;SDK 不读取 Node/文件系统 | 生成 pack/exports、受限环境可移植性、RuntimeContext、凭据 scope、媒体与流式 LLM;不因版本同步自动引入 GLM | `pnpm typecheck:uxp-smoke && pnpm check:uxp-sdk && pnpm smoke:uxp:build && pnpm check:uxp-smoke`;完整 `pnpm check` | `e509716`;无用户 npm 凭据的 frozen lock 安装通过;Node 22 下四项门禁通过,正式产品仍仅 39 个 generation/erase packs,网络调用与受限环境风险均为 0 | 2026-08-31 |
94
+ | `say-it`<br>`D:/VibeCode/说吧` | Tauri 2 + Rust 管理 QuickJS;WebView 不运行 SDK | manifest/lock 精确锁定公共 npm `0.6.1`;bundle 版本、resolved、shasum、integrity 一致 | 按需打包 capability、Bailian/火山实时 ASR、SiliconFlow/Groq 文件 ASR、translation、LLM modules 为相互隔离 IIFE;Rust 加载 bundle | Rust Host API 注入 HTTP 字节流、WS、media-ref、CredentialStore、日志/trace、Abort/timeout/cancel;QuickJS/插件/WebView 不直取密钥 | capability/LLM 协议、按需 exports、descriptor source/坐标、QuickJS 可移植性、bundle 隔离;不因版本同步自动增加未采用模型 | `npm run sdk-runtime:typecheck && npm run sdk-runtime:build`;`npm run test:ui`;Rust 定向/全量测试;`npm run ui:build` | `18bad6d`;QuickJS/WS 空中间帧回归及 35 项 SDK 宿主本地测试通过,runtime 类型检查通过;听写/历史/UI 定向回归与前端类型构建通过,桌面开发应用已重启,实际麦克风交互待用户验证 | 2026-09-24 |
95
+
96
+ ## SDK 仓内消费验证面
97
+
98
+ 这些目录是可独立安装、构建的真实示例,但与 SDK 同属 `Henji-AI` 仓库,不重复算外部仓库。
99
+ 示例 manifest 使用精确版本,仓内不维护锁文件。llm-chat 准备升级到 `0.6.2`,其余两个示例保持 `0.6.0`;下表正式消费证据仍对应已发布版本,候选验证不冒充公共 npm 安装。
100
+
101
+ | 路径 | 用途 / 入口 | 当前版本 | 宿主责任 | 验证命令 | 同步证据 | 最后核对 |
102
+ |---|---|---|---|---|---|---|
103
+ | `D:/VibeCode/Henji-AI/packages/ai-sdk/examples/minimal-node` | `generation` + `runtime` 按需入口;完整 generation catalog、KIE dry-run/live 闸门,不带 LLM/BigModel | `0.6.0`(精确 manifest,仓内无 lock) | Node transport、环境凭据、文件媒体读取、日志 | 在目录内 `npm install && npm run dry-run` | 公共 npm 匿名安装、类型构建与 dry-run 通过,模型网络调用为 0 | 2026-09-24 |
104
+ | `D:/VibeCode/Henji-AI/packages/ai-sdk/examples/llm-chat` | `llm/streaming` 按需入口;OpenAI-compatible SSE 对话,不带 generation、BigModel preset/models/pricing、Groq 或 LLM modules(保留通用身份解析所需 profiles) | `0.6.2` 候选(上次公共验证为 `0.6.0`) | Node transport、环境凭据、流事件与取消 | 在目录内 `npm install && npm run dry-run && npm run check:bundle` | 公共 npm 匿名安装、类型构建、dry-run 和 bundle 边界检查通过 | 2026-09-24 |
105
+ | `D:/VibeCode/Henji-AI/packages/ai-sdk/examples/form-renderer` | `generation` + `catalog` + `runtime` 按需入口;完整 generation catalog/参数契约与最小 renderer,不带 LLM/BigModel | `0.6.0`(精确 manifest,仓内无 lock) | 零网络 RuntimeContext;仅目录与 renderer | 在目录内 `npm install && npm run build && npm start` | 公共 npm 匿名安装、类型构建与五类代表模型表单输出通过 | 2026-09-24 |
106
+
107
+ ## 非消费者证据
108
+
109
+ - `Henji-AI`、`henji-ai-ps`、`say-it` 的 README、任务文件和交接文档含历史版本或迁移描述;它们用于追溯,不形成额外消费者。
110
+ - `/Users/henji/Documents/VibeCode` 下的 `ai-roundtable`、`fast-install`、`henji`、`henji-dev`、`henjicc.github.io`、`mySkills`、`test` 未发现 `@henjicc/ai-sdk` 的 manifest、lockfile、源码 import 或构建脚本引用。
111
+ - SDK 自身的测试、fixture、导出检查和发布脚本属于生产者验证,不作为独立消费项目。
112
+
113
+ ## 发布后维护规则
114
+
115
+ 1. SDK 必须先在 `Henji-AI` 完成精确测试、全量/可移植性/包验证与远端回装,再发布。
116
+ 2. 发布后按变更影响逐个同步本清单中的实际消费者;外部消费者必须精确锁版本并核对 lock integrity,再回写 commit、验证状态、边界和日期。
117
+ 3. 只升级消费项目实际使用的按需入口。新增 provider/model 不等于所有宿主都要增加对应 bundle 或业务入口。
118
+ 4. 涉及 provider 身份、endpoint profile、credentialId、transport、media 或协议事件时,逐项检查表中宿主责任边界,禁止在消费方复制 SDK 执行内核。
119
+ 5. 消费项目升级完成后,将验证结果写入对应任务交接;本清单只维护稳定事实,不复制每次执行日志。