a81a450e7e
Merged into tinqs/studio: - cmd/tinqs-cli/ — tinqs-cli (Go binary, from bot/cli) - cmd/tea/ — Gitea CLI tool (from tinqs/cli-tea) - services/bot/ — Bot service (from tinqs-ltd/bot on git.arikigame.com) - services/admin/ — Admin panel (from tinqs/admin) - services/team-tool/ — Team Tool (from tinqs/team-tool) - services/proxy/ — tinqs-proxy (from bot/proxy) - web/landing/ — tinqs.com website (from tinqs/website) - web/docs/ — Platform docs (from tinqs/docs) - web/blog/ — Blog (placeholder) - runner/ — Ephemeral CI runner (from tinqs/runner) All source repos will be deleted after verification.
60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
/**
|
|
* Reasoning-content cache for the DeepSeek inference proxy.
|
|
*
|
|
* DeepSeek's thinking-mode tool-call API requires that `reasoning_content`
|
|
* from the assistant's previous turn be sent back on every continuation:
|
|
* https://api-docs.deepseek.com/guides/thinking_mode#tool-calls
|
|
*
|
|
* Cursor (and a latent path in Tinqs IDE) strip that field when replaying
|
|
* history. This module caches reasoning_content as it streams in from
|
|
* DeepSeek, keyed by signatures of the assistant message + its tool_calls,
|
|
* so the request transform can inject it back when the client omits it.
|
|
*
|
|
* Pure key-derivation helpers live in lib/reasoning-keys.ts (testable
|
|
* without Redis). This file wraps them with ioredis-backed storage.
|
|
*/
|
|
import { redis } from "./db";
|
|
import { type AssistantMessage, reasoningKeys } from "./reasoning-keys";
|
|
|
|
export {
|
|
type AssistantMessage,
|
|
type ToolCall,
|
|
type ToolCallFn,
|
|
messageSignature,
|
|
normalizeToolCall,
|
|
reasoningKeys,
|
|
toolCallSignature,
|
|
userScope,
|
|
} from "./reasoning-keys";
|
|
|
|
const DEFAULT_TTL_SECONDS = 30 * 24 * 60 * 60; // 30 days, matches Python default
|
|
|
|
/** Look up cached reasoning_content for an assistant message in this scope. */
|
|
export async function lookupReasoning(
|
|
scope: string,
|
|
msg: AssistantMessage,
|
|
): Promise<string | null> {
|
|
if (!redis) return null;
|
|
for (const key of reasoningKeys(scope, msg)) {
|
|
const v = await redis.get(key);
|
|
if (typeof v === "string" && v.length > 0) return v;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** Cache reasoning_content under every alias key for this assistant message. */
|
|
export async function storeReasoning(
|
|
scope: string,
|
|
msg: AssistantMessage,
|
|
reasoning: string,
|
|
ttlSeconds = DEFAULT_TTL_SECONDS,
|
|
): Promise<number> {
|
|
if (!redis) return 0;
|
|
if (typeof reasoning !== "string" || reasoning.length === 0) return 0;
|
|
const keys = reasoningKeys(scope, msg);
|
|
const pipe = redis.pipeline();
|
|
for (const k of keys) pipe.set(k, reasoning, "EX", ttlSeconds);
|
|
await pipe.exec();
|
|
return keys.length;
|
|
}
|