Files
ozan a81a450e7e feat: monorepo consolidation — merge CLI, bot, admin, team-tool, website, docs, runner, proxy
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.
2026-05-22 04:55:50 +00:00

88 lines
2.2 KiB
TypeScript

/**
* Langfuse client — LLM observability.
*
* Pushes traces, spans, and generations to self-hosted Langfuse.
* Wraps every LLM call (Nova Lite, Claude, Ollama) with tracing.
*
* Usage:
* import { langfuse, traceAgent } from "@/lib/langfuse";
* const trace = traceAgent("singularity", "process-message", { space, user });
* const gen = trace.generation({ model, input, output, tokens });
* trace.update({ output: result });
*/
import { Langfuse } from "langfuse";
// Self-hosted Langfuse on Lightsail :3100
// Falls back gracefully if Langfuse is not running
const langfuse = new Langfuse({
publicKey: process.env.LANGFUSE_PUBLIC_KEY || "pk-tinqs-agents",
secretKey: process.env.LANGFUSE_SECRET_KEY || "sk-tinqs-agents-secret",
baseUrl: process.env.LANGFUSE_BASE_URL || "http://localhost:3100",
enabled: process.env.LANGFUSE_ENABLED !== "false",
});
// Flush on process exit
if (typeof process !== "undefined") {
process.on("beforeExit", async () => {
await langfuse.shutdownAsync();
});
}
/**
* Create a trace for an agent action.
*/
function traceAgent(
agentName: string,
action: string,
metadata?: Record<string, unknown>
) {
return langfuse.trace({
name: `${agentName}/${action}`,
userId: agentName,
metadata: {
...metadata,
machine: metadata?.machine || "unknown",
timestamp: new Date().toISOString(),
},
});
}
/**
* Log a generation (LLM call) to Langfuse.
* Call this instead of just logInference — it feeds both Langfuse + Postgres.
*/
function logGeneration(
trace: ReturnType<typeof langfuse.trace>,
opts: {
name: string;
model: string;
input: string;
output: string;
tokensIn: number;
tokensOut: number;
latencyMs: number;
costUsd?: number;
metadata?: Record<string, unknown>;
}
) {
return trace.generation({
name: opts.name,
model: opts.model,
input: opts.input,
output: opts.output,
usage: {
input: opts.tokensIn,
output: opts.tokensOut,
total: opts.tokensIn + opts.tokensOut,
},
metadata: {
latency_ms: opts.latencyMs,
cost_usd: opts.costUsd,
...opts.metadata,
},
});
}
export { langfuse, traceAgent, logGeneration };