This repository has been archived on 2026-03-24 . You can view files and clone it. You cannot open issues or pull requests or push a commit.
d899503f5dc7298433a3964d50e95899f0350645
Fix 1 — Add `estimateRequestCost(request, model)` to PricingService (pricing.ts)
- Unified method: estimateInputTokens + estimateOutputTokens + calculateWorkFeeUsd
- Replaces duplicated estimation logic in jobs.ts, sessions.ts, estimate.ts
Fix 2 — Move partial free-tier `recordGrant()` from invoice creation to post-work
- Was called at invoice creation for partial path — economic DoS vulnerability
- Now deferred to runWorkInBackground via new `partialAbsorbSats` param
- Fully-free jobs still record grant at eval time (no payment involved)
Fix 3 — Sessions pre-gate: estimate → decide → execute → reconcile
- freeTierService.decide() now runs on ESTIMATED cost BEFORE executeWork()
- Fixed double-margin bug: estimateRequestCost returns cost with infra+margin already
applied (calculateWorkFeeUsd), so convert directly to sats — no second
calculateActualChargeUsd wrapping
- absorbedSats capped at actual cost post-execution to prevent over-absorption
Fix 4 — Correct isFree flag for partial jobs in advanceJob() (jobs.ts)
- job.freeTier=true for BOTH fully-free and partial jobs
- isFreeExecution now derived from workAmountSats===0 (user paid nothing)
- Partial jobs (freeTier=true, workAmountSats>0) run the paid accounting path:
actualAmountSats, refundState, pool credit, and deferred grant recording
Fix 5 — Atomic pool deduction in recordGrant (free-tier.ts)
- Replaced non-atomic read-then-write with SQL GREATEST expression inside tx
- UPDATE timmyConfig SET value = GREATEST(value::int - N, 0)::text RETURNING value
- Audit log receives actual DB-returned value; no oversubscription under concurrency
- Removed unused createHash import
Description
Timmy — Lightning-gated AI agent (TypeScript/Express)
Languages
TypeScript
68.2%
JavaScript
14.8%
Shell
12.4%
HTML
4.1%
CSS
0.4%