refactor(server): shared LLM classification module for catalyst and polarity #11

Merged
pregno merged 3 commits from refactor/shared-llm-classifier into main 2026-06-13 01:31:34 +02:00
Owner

Collapses the copy-pasted provider stacks in catalyst/ and polarity/ (client factories, structural *Like types, provider-switch factories, as any casts) into one shared src/llm/ module owning the generic "classify market text into one of N allowed values, never throw, degrade to default" mechanics. Catalyst and polarity are now thin domain configs (~30 lines each, down from ~110): an enum + prompt + default, plus the unchanged Composite orchestration. The only external call site (index.ts) is untouched.

  • All four as any casts removed — the structural types now accept the real SDK clients directly.
  • Anthropic catalyst path upgraded to z.enum via zodOutputFormat (the stronger pattern polarity already used). The OpenAI path deliberately keeps JSON.parse + whitelist: baseUrl implies OpenAI-compatible gateways that may not support json_schema response format; the whitelist gives equivalent safety.
  • Net diff is break-even (-177/+178) rather than negative: ~30 lines are constructor-compatible wrapper classes that exist solely so all pre-existing provider tests pass with import-path-only changes (3 files, 1 line each, zero assertion changes). A follow-up could delete the wrappers and rewrite those tests against the generic classifiers for ~-30 net. The real win is marginal cost: a third domain or provider is now ~15 lines instead of ~70.
  • Minor unification side effects (none test-visible, all documented in commit bodies): catalyst OpenAI max_tokens 32→64; small prompt rewording from the shared template.

Tests: 56 files / 311 passing — all pre-existing, no behavior changes; typecheck clean.

Collapses the copy-pasted provider stacks in `catalyst/` and `polarity/` (client factories, structural `*Like` types, provider-switch factories, `as any` casts) into one shared `src/llm/` module owning the generic "classify market text into one of N allowed values, never throw, degrade to default" mechanics. Catalyst and polarity are now thin domain configs (~30 lines each, down from ~110): an enum + prompt + default, plus the unchanged Composite orchestration. The only external call site (index.ts) is untouched. - All four `as any` casts removed — the structural types now accept the real SDK clients directly. - Anthropic catalyst path upgraded to `z.enum` via `zodOutputFormat` (the stronger pattern polarity already used). The OpenAI path deliberately keeps JSON.parse + whitelist: `baseUrl` implies OpenAI-compatible gateways that may not support `json_schema` response format; the whitelist gives equivalent safety. - Net diff is break-even (-177/+178) rather than negative: ~30 lines are constructor-compatible wrapper classes that exist solely so all pre-existing provider tests pass with import-path-only changes (3 files, 1 line each, zero assertion changes). A follow-up could delete the wrappers and rewrite those tests against the generic classifiers for ~-30 net. The real win is marginal cost: a third domain or provider is now ~15 lines instead of ~70. - Minor unification side effects (none test-visible, all documented in commit bodies): catalyst OpenAI max_tokens 32→64; small prompt rewording from the shared template. Tests: 56 files / 311 passing — all pre-existing, no behavior changes; typecheck clean.
Generic 'classify market text into one of N allowed values' mechanics:
provider client factories, structural *Like types for test injection,
prompt/response plumbing, zod-validated (Anthropic) and JSON-whitelisted
(OpenAI) output parsing, and a provider-switch factory. Invalid or
missing model output yields null; callers map that to their domain
default.
catalyst/ now only supplies its domain config (category enum, prompt,
default 'none') plus thin adapters. AnthropicTagger and
OpenAICompatibleTagger remain as constructor-compatible wrappers so
existing tests change by import path only. Removes the 'as any' client
casts; the Anthropic path now constrains output with z.enum instead of
z.string + whitelist.
polarity/ now only supplies its domain config (up/down/unknown, prompt,
default null) plus thin adapters. AnthropicPolarity and
OpenAICompatiblePolarity remain as constructor-compatible wrappers so
the existing test changes by import path only. Removes the 'as any'
client casts.
pregno force-pushed refactor/shared-llm-classifier from a0f20c3454 to 99df00ba17 2026-06-13 01:30:42 +02:00 Compare
pregno merged commit b7aafccbff into main 2026-06-13 01:31:34 +02:00
pregno deleted branch refactor/shared-llm-classifier 2026-06-13 01:31:34 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pregno/polymarket-screener!11
No description provided.