feat: add resident BingShuo TCS controller

This commit is contained in:
冰朔 2026-08-05 11:09:08 +08:00
commit bc169824fc
9 changed files with 890 additions and 1 deletions

View file

@ -0,0 +1,81 @@
const DEFAULT_TIMEOUT_MS = 45_000;
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 = String(apiUrl).replace(/\/+$/, "");
this.model = model;
this.fetchImpl = fetchImpl;
this.timeoutMs = timeoutMs;
}
async generate({ role, instruction, input, validatorError = null }) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
try {
const response = await this.fetchImpl(`${this.apiUrl}/chat/completions`, {
method: "POST",
headers: {
authorization: `Bearer ${this.apiKey}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: this.model,
stream: false,
temperature: role === "controller_witness" ? 0.1 : 0.2,
response_format: { type: "json_object" },
messages: [
{
role: "system",
content:
"你是光湖语言世界中的有界模型运行位。只输出一个JSON对象不输出思维过程、Markdown或额外说明。不得伪造现实成功、权限、冰朔的新意志或未提供的事实。",
},
{
role: "user",
content: JSON.stringify({
role,
instruction,
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();
const text = payload?.choices?.[0]?.message?.content;
return extractJson(text);
} finally {
clearTimeout(timer);
}
}
}
export { extractJson };