feat: 结构化 observation 替代 statusDetail,API 层动态构造 detail
- CheckResult: statusDetail -> observation (持久化) + detail (API 动态派生) - 存储: status_detail 列 -> observation TEXT (JSON) - CheckerDefinition: 新增 buildDetail(observation) 方法 - 各 checker 返回结构化 observation,API 层通过 registry 调用 buildDetail - HTTP: bodyPreview 在 status/header 失败时也提前采集 - UDP: observation 包含 durationMs,未响应归为 error failure - CMD: 超时/输出超限时保留已收集 observation - TCP: connectTimeMs 仅含连接建立耗时,不含 banner 等待 - 新增 buildDetail 单测和 mapCheckResult 覆盖测试 - 同步 openspec 主规范,归档 checker-observation 变更
This commit is contained in:
@@ -4,11 +4,15 @@ import type {
|
||||
LlmCheckObservation,
|
||||
LlmHttpMetadata,
|
||||
LlmMode,
|
||||
LlmPersistedHttpMetadata,
|
||||
LlmPersistedObservation,
|
||||
LlmProvider,
|
||||
LlmStreamObservation,
|
||||
LlmUsageObservation,
|
||||
} from "./types";
|
||||
|
||||
import { LLM_HEADERS_MAX, LLM_OUTPUT_PREVIEW_MAX } from "./types";
|
||||
|
||||
export function buildObservationFromApiCallError(
|
||||
error: APICallError,
|
||||
provider: LlmProvider,
|
||||
@@ -129,3 +133,42 @@ export async function buildObservationFromStreamText(
|
||||
warnings,
|
||||
};
|
||||
}
|
||||
|
||||
export function toPersistedObservation(obs: LlmCheckObservation): LlmPersistedObservation {
|
||||
const outputText = obs.outputText;
|
||||
const outputPreview =
|
||||
outputText !== null
|
||||
? outputText.length <= LLM_OUTPUT_PREVIEW_MAX
|
||||
? outputText
|
||||
: outputText.slice(0, LLM_OUTPUT_PREVIEW_MAX)
|
||||
: null;
|
||||
const outputLength = outputText !== null ? outputText.length : null;
|
||||
|
||||
const http: LlmPersistedHttpMetadata | null = obs.http
|
||||
? {
|
||||
headers: truncateHeaders(obs.http.headers, LLM_HEADERS_MAX),
|
||||
status: obs.http.status,
|
||||
statusText: obs.http.statusText,
|
||||
}
|
||||
: null;
|
||||
|
||||
return {
|
||||
finishReason: obs.finishReason,
|
||||
http,
|
||||
mode: obs.mode,
|
||||
model: obs.model,
|
||||
outputLength,
|
||||
outputPreview,
|
||||
provider: obs.provider,
|
||||
rawFinishReason: obs.rawFinishReason,
|
||||
stream: obs.stream,
|
||||
usage: obs.usage,
|
||||
warnings: obs.warnings,
|
||||
};
|
||||
}
|
||||
|
||||
function truncateHeaders(headers: Record<string, string>, maxCount: number): Record<string, string> {
|
||||
const entries = Object.entries(headers);
|
||||
if (entries.length <= maxCount) return headers;
|
||||
return Object.fromEntries(entries.slice(0, maxCount));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user