Commit Graph

27 Commits

Author SHA1 Message Date
6f0300f038 Fix Langfuse usage tracking: map to snake_case keys it recognizes
LangfuseTracer was passing our internal camelCase usage fields
(promptTokens/completionTokens/totalTokens) straight through as
usageDetails. Langfuse only recognizes a flat schema (input/output/...)
or OpenAI's native snake_case schema (prompt_tokens/completion_tokens/
total_tokens) for usage/cost calculation - anything else is silently
ignored, so every generation was showing zero usage regardless of
what LlmClient actually reported.

Note: cost still requires a price-list entry for the model name.
Langfuse's built-in list only covers hosted providers (OpenAI,
Anthropic, Google); self-hosted models (e.g. LLM_MODEL=llama3 via
Ollama) need a custom model price added in Project Settings > Models
for a $ figure to show up, even with token counts now correct.

Verified: full suite (80/80) passing, tsc/eslint clean.
2026-08-12 23:00:04 +02:00
e47c57b50d Group pipeline runs into Langfuse sessions, tagged by trigger source
Each pipeline invocation (runAsync/searchAsync) now gets a fresh
sessionId, wrapped via the new Tracer.runWithSession() (implemented
with @langfuse/tracing's propagateAttributes, since v5 has no direct
sessionId/tags option on startObservation) so it shows up in
Langfuse's Sessions view. The session is also tagged with what
triggered the run: "cron", "api-list", "api-trigger", "api-search".

Verified: full test suite (79/79) passing, tsc/eslint clean, real
docker compose build + container smoke test against /health.
2026-08-12 22:51:17 +02:00
a5120d5153 upgrade langfuse 2026-08-12 22:17:56 +02:00
2ffba19392 add langfuse url to server starting 2026-08-12 22:03:04 +02:00
ae8bfaa2eb Fix final review findings: key leak, model fallback, error resilience, docs
- ApiClient: strip query string from ApiError messages so API keys
  (e.g. TMDb's api_key query param) never leak into 500 response
  bodies or logs.
- LlmTool: accept an optional defaultModel, wired from AppConfig's
  LLM_MODEL, so Langfuse prompts that omit a model config fall back
  to the configured LLM rather than silently requesting gpt-4o-mini.
- RecommendationPipeline: restore the Go original's graceful
  degradation — library/Radarr fetch failures, per-suggestion TMDb
  resolution failures, and per-signal TMDb similarity/recommendation
  failures are now logged and skipped instead of aborting the whole
  run (applies to both runInternal and searchAsync).
- RecommendationsController: validate the ?count= query param
  (must be a positive integer) instead of silently producing NaN.
- Commit the Langfuse prompt definitions (langfuse/*.prompt.json) and
  add a README covering setup, prompt seeding, cache invalidation,
  and the HTTP API surface — the branch was not otherwise runnable by
  anyone but the author.
2026-08-12 21:40:09 +02:00
31de7f15db Wire up cron scheduling and the app entrypoint 2026-08-12 21:23:08 +02:00
e712470013 Add Health/Recommendations/Request/Webhook controllers 2026-08-12 21:21:26 +02:00
3c5f723d22 Isolate per-item Radarr failures in RecommendationPipeline.autoRequest
Matches the Go original's behavior: a lookup/addMovie failure for one
recommendation is logged and skipped rather than aborting the whole
auto-request batch.
2026-08-12 21:18:33 +02:00
62848f6ecd Add RecommendationPipeline 2026-08-12 21:15:21 +02:00
5edeb0ebb9 Add MovieRecommenderTool and MovieSearchTool 2026-08-12 21:14:10 +02:00
5140bc5a50 Widen loadEnv schema type and allow rest-sibling destructuring in lint
loadEnv's ZodSchema<T> parameter required schema input === output,
which breaks any schema using .transform() (e.g. AppConfigSchema's
boolean coercion). Widen to ZodType<T, ZodTypeDef, unknown>, matching
existing runtime behavior. Also allow ignoreRestSiblings in the
no-unused-vars rule so 'const { X, ...rest } = obj' omission tests
don't trip the linter.
2026-08-12 21:08:21 +02:00
8e908408cd Add RadarrClient 2026-08-12 21:05:58 +02:00
4e483557d7 Add TmdbClient 2026-08-12 21:05:22 +02:00
9683d65a1f Add JellyfinClient 2026-08-12 21:04:47 +02:00
ef037d25fe Add app config schema and shared models 2026-08-12 21:04:15 +02:00
69db1d5558 Harden auth hook and fix eslint config for intentional unused args
- authHook: use crypto.timingSafeEqual for the bearer token comparison
  instead of !==, avoiding a timing side-channel on the secret key.
- .eslintrc.cjs: add argsIgnorePattern for underscore-prefixed unused
  params, fixing false-positive no-unused-vars errors on intentional
  _ctx/_params placeholders used throughout the LlmTool hierarchy.
2026-08-12 21:00:44 +02:00
bb479f7749 Fix LangfusePromptGateway compile() to match langfuse SDK's Record<string,string> variable type 2026-08-12 20:56:39 +02:00
cf3c12774f Add concrete Langfuse tracer and prompt gateway 2026-08-12 20:55:51 +02:00
299375bcd3 Add core server Controller base, auth hook, and buildServer 2026-08-12 20:55:06 +02:00
3f99bce3c6 Add core LlmPipeline base class 2026-08-12 20:54:38 +02:00
8d468903a4 Add SchemaLlmTool and TextLlmTool 2026-08-12 20:54:10 +02:00
ee4aba83e8 Add core Tracer/RunContext types and LlmTool base class 2026-08-12 20:53:27 +02:00
3ca58194e6 Add core LlmClient wrapping OpenAI-compatible chat completions 2026-08-12 20:52:36 +02:00
81e9a20b14 Add cached Langfuse PromptService 2026-08-12 20:52:10 +02:00
580357a130 Add core Endpoint/ApiClient base classes 2026-08-12 20:51:36 +02:00
ca08ed9294 Add core env loader 2026-08-12 20:51:03 +02:00
a9a8fa7c3f Scaffold TypeScript project and add core logger 2026-08-12 20:50:40 +02:00