test(hub): 适配 Claude Code SDK 的 mock 修复

helpers.ts: MockLanguageModel 加 doStream 实现(返回 text-delta +
finish part);runner.test.ts: 加 stubPrisma(必填字段)。
这些测试在 Claude Code SDK 迁移后还需要进一步适配,先提交 buffer。
This commit is contained in:
2026-07-08 01:52:21 +08:00
parent 085f7c7186
commit 1ad78dbcce
2 changed files with 48 additions and 3 deletions
+39 -2
View File
@@ -12,6 +12,7 @@ import type {
LanguageModelV4CallOptions,
LanguageModelV4Content,
LanguageModelV4GenerateResult,
LanguageModelV4StreamPart,
LanguageModelV4StreamResult,
} from "@ai-sdk/provider";
import type { FeishuRuntime } from "../../src/feishu/client.js";
@@ -153,8 +154,44 @@ export class MockLanguageModel implements LanguageModelV4 {
};
}
async doStream(_options: LanguageModelV4CallOptions): Promise<LanguageModelV4StreamResult> {
throw new Error("MockLanguageModel does not implement streaming");
async doStream(options: LanguageModelV4CallOptions): Promise<LanguageModelV4StreamResult> {
this.calls.push(options);
const response = this.responses[this.calls.length - 1 % this.responses.length] ?? this.responses[0]!;
const text = response.text ?? "";
const finishReason = response.finishReason ?? ((response.toolCalls?.length ?? 0) > 0 ? "tool-calls" : "stop");
const id = `mock-${this.calls.length}`;
const parts: LanguageModelV4StreamPart[] = [
{ type: "text-start", id },
];
if (text.length > 0) {
parts.push({ type: "text-delta", id, delta: text });
}
parts.push({ type: "text-end", id });
for (const call of response.toolCalls ?? []) {
const tcId = `tc-${this.calls.length}-${call.toolName}`;
parts.push({ type: "tool-input-start", id: tcId, toolName: call.toolName });
parts.push({ type: "tool-input-delta", id: tcId, delta: JSON.stringify(call.input) });
parts.push({ type: "tool-input-end", id: tcId });
}
parts.push({
type: "finish",
finishReason: { unified: finishReason, raw: finishReason },
usage: {
inputTokens: { total: response.inputTokens ?? 10, noCache: undefined, cacheRead: undefined, cacheWrite: undefined },
outputTokens: { total: response.outputTokens ?? 5, text: undefined, reasoning: undefined },
},
});
return {
stream: new ReadableStream({
start(controller) {
for (const part of parts) controller.enqueue(part);
controller.close();
},
}),
response: { id, timestamp: new Date(), modelId: "mock-model" },
};
}
}