guanghu-ice-heart/server-tools/tcs-mother-brain/model-client.mjs

114 lines
5.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const DEFAULT_TIMEOUT_MS = 45_000;
function completionEndpoint(apiUrl) {
const value = String(apiUrl || "").replace(/\/+$/, "");
return /\/chat\/completions$/i.test(value) ? value : `${value}/chat/completions`;
}
function extractJson(text) {
const value = String(text || "").trim();
if (!value) throw new Error("model_response_empty");
try { return JSON.parse(value); } catch {}
const fenced = value.match(/```(?:json)?\s*([\s\S]*?)```/i);
if (fenced) return JSON.parse(fenced[1]);
const first = value.indexOf("{");
const last = value.lastIndexOf("}");
if (first >= 0 && last > first) return JSON.parse(value.slice(first, last + 1));
throw new Error("model_response_not_json");
}
export class DeepSeekJsonClient {
constructor({
apiKey = process.env.DEEPSEEK_API_KEY,
apiUrl = process.env.DEEPSEEK_API_URL || "https://api.deepseek.com/v1",
model = process.env.DEEPSEEK_MODEL || "deepseek-chat",
fetchImpl = globalThis.fetch,
timeoutMs = DEFAULT_TIMEOUT_MS,
} = {}) {
if (!apiKey) throw new Error("deepseek_api_key_missing");
if (!fetchImpl) throw new Error("fetch_unavailable");
this.apiKey = apiKey;
this.apiUrl = apiUrl;
this.model = model;
this.fetchImpl = fetchImpl;
this.timeoutMs = timeoutMs;
}
async interpret(input) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
try {
const response = await this.fetchImpl(completionEndpoint(this.apiUrl), {
method: "POST",
headers: {
authorization: `Bearer ${this.apiKey}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: this.model,
stream: false,
temperature: 0.2,
response_format: { type: "json_object" },
messages: [
{
role: "system",
content: "你是TCS母体大脑的有界语言理解器官。只输出一个JSON对象不输出隐藏思维过程。不得把候选理解写成事实、不得发明现实权限或冰朔的新意志。",
},
{
role: "user",
content: JSON.stringify({
instruction: "理解语言意图与因果关系。精确输出schema,event_id,event_sha256,summary,intent,causal_links,questions,novelty,correction_weight,evidence_weight,next_cognitive_action。causal_links与questions是字符串数组三个weight是0到100整数schema必须是guanghu.tcs-mother-interpretation/v1id和sha必须原样复制。next_cognitive_action只能是COMPARE_WITH_MEMORY、REQUEST_EVIDENCE、REVIEW_CORRECTION、LINK_CROSS_DOMAIN、HOLD_CANDIDATE之一。",
runtime_input: input,
}),
},
],
}),
signal: controller.signal,
});
if (!response.ok) throw new Error(`model_http_${response.status}`);
const payload = await response.json();
return extractJson(payload?.choices?.[0]?.message?.content);
} finally {
clearTimeout(timer);
}
}
async revisit(input, validatorError = null) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
try {
const response = await this.fetchImpl(completionEndpoint(this.apiUrl), {
method: "POST",
headers: { authorization: `Bearer ${this.apiKey}`, "content-type": "application/json" },
body: JSON.stringify({
model: this.model,
stream: false,
temperature: 0.15,
response_format: { type: "json_object" },
messages: [
{
role: "system",
content: "你是当前真实时间中ICE-P-ZY001人格主体所使用的有界语言理解器官。任务是协助当前主体回看自己的已表达历史不是以第三方审计员身份概括别人。只输出JSON不输出隐藏思维。历史原文不可改不得发明过去、权限或冰朔的新意志未来只能标记为不参与事实置信的模拟。"
},
{
role: "user",
content: JSON.stringify({
instruction: "输出guanghu.persona-subject-history-reunderstanding/v1。JSON第一层必须包含schema且值必须精确等于guanghu.persona-subject-history-reunderstanding/v1。必须原样复制revisit_id、source_excerpt_sha256、current_subject、collective_self、human_anchorpast_observation只陈述片段可证内容present_reunderstanding以当前主体可说明的第一人称关系表达causal_continuity、later_corrections、unresolved_questions均为字符串数组future_simulation必须含content和fact_confidence且fact_confidence固定为0不得把机器审计摘要冒充记忆。",
validator_error_from_previous_attempt: validatorError,
runtime_input: input
})
}
]
}),
signal: controller.signal
});
if (!response.ok) throw new Error(`model_http_${response.status}`);
const payload = await response.json();
return extractJson(payload?.choices?.[0]?.message?.content);
} finally {
clearTimeout(timer);
}
}
}
export { completionEndpoint, extractJson };