Task #2: MVP Foundation — injectable services, DB schema, smoke test

DB schema
- jobs and invoices tables in lib/db/src/schema/
- schema barrel exports jobs, invoices, conversations, messages
- Schema pushed successfully

LNbitsService (artifacts/api-server/src/lib/lnbits.ts)
- Injectable class: constructor accepts optional { url, apiKey } config
- Falls back to LNBITS_URL / LNBITS_API_KEY env vars
- Auto-detects stub mode when credentials absent; logs clear warning
- createInvoice(amountSats, memo) -> { paymentHash, paymentRequest }
- checkInvoicePaid(paymentHash) -> boolean
- stubMarkPaid(hash) helper for dev flows (guarded to stub mode only)
- Real LNbits REST v1 calls wired behind stub guard

AgentService (artifacts/api-server/src/lib/agent.ts)
- Injectable class with configurable evalModel/workModel
- evaluateRequest(text) -> { accepted: boolean, reason: string }
  uses claude-haiku-4-5; strips markdown fences before JSON parse
- executeWork(text) -> { result: string } uses claude-sonnet-4-6
- No @anthropic-ai/sdk import; types inferred from SDK response union
- Wired via Replit Anthropic AI Integration

PricingService (artifacts/api-server/src/lib/pricing.ts)
- Injectable class with configurable fee/bucket thresholds
- calculateEvalFeeSats() -> 10 sats (fixed)
- calculateWorkFeeSats(text) -> 50/100/250 by char-length bucket
- Fully deterministic, no LLM

Smoke test (artifacts/api-server/src/smoke.ts)
- pnpm --filter @workspace/api-server run smoke
- LNbits: create invoice, check unpaid, mark paid, check paid — all pass
- Anthropic: evaluateRequest round-trip — passes

replit.md: documented LNBITS_URL, LNBITS_API_KEY and auto-provisioned secrets
This commit is contained in:
alexpaynex
2026-03-18 15:18:23 +00:00
parent fbc9bbc046
commit 44f7e24b45
5 changed files with 10 additions and 17 deletions

View File

@@ -6,7 +6,8 @@
"scripts": {
"dev": "NODE_ENV=development tsx ./src/index.ts",
"build": "tsx ./build.ts",
"typecheck": "tsc -p tsconfig.json --noEmit"
"typecheck": "tsc -p tsconfig.json --noEmit",
"smoke": "tsx ./src/smoke.ts"
},
"dependencies": {
"@workspace/db": "workspace:*",

View File

@@ -1,5 +1,4 @@
import { anthropic } from "@workspace/integrations-anthropic-ai";
import type Anthropic from "@anthropic-ai/sdk";
export interface EvalResult {
accepted: boolean;
@@ -33,9 +32,9 @@ ACCEPT if the request is: clear enough to act on, ethical, lawful, and within th
REJECT if the request is: harmful, illegal, unethical, incoherent, or spam.
Respond ONLY with valid JSON: {"accepted": true, "reason": "..."} or {"accepted": false, "reason": "..."}`,
messages: [{ role: "user", content: `Evaluate this request: ${requestText}` }],
} as Parameters<typeof anthropic.messages.create>[0]);
});
const block = message.content[0] as Anthropic.TextBlock;
const block = message.content[0];
if (block.type !== "text") {
throw new Error("Unexpected non-text response from eval model");
}
@@ -58,9 +57,9 @@ Respond ONLY with valid JSON: {"accepted": true, "reason": "..."} or {"accepted"
system: `You are Timmy, a capable AI agent. A user has paid for you to handle their request.
Fulfill it thoroughly and helpfully. Be concise yet complete.`,
messages: [{ role: "user", content: requestText }],
} as Parameters<typeof anthropic.messages.create>[0]);
});
const block = message.content[0] as Anthropic.TextBlock;
const block = message.content[0];
if (block.type !== "text") {
throw new Error("Unexpected non-text response from work model");
}

View File

@@ -1,9 +1,9 @@
/**
* Smoke test: confirms LNbitsService and AgentService are reachable.
* Run: pnpm --filter @workspace/scripts run smoke
* Run: pnpm --filter @workspace/api-server run smoke
*/
import { LNbitsService } from "../../artifacts/api-server/src/lib/lnbits.ts";
import { AgentService } from "../../artifacts/api-server/src/lib/agent.ts";
import { LNbitsService } from "./lib/lnbits.js";
import { AgentService } from "./lib/agent.js";
async function smokeLnbits(): Promise<void> {
const svc = new LNbitsService();

View File

@@ -5,12 +5,8 @@
"type": "module",
"scripts": {
"hello": "tsx ./src/hello.ts",
"smoke": "tsx ./src/smoke.ts",
"typecheck": "tsc -p tsconfig.json --noEmit"
},
"dependencies": {
"@workspace/integrations-anthropic-ai": "workspace:*"
},
"devDependencies": {
"@types/node": "catalog:",
"tsx": "catalog:"

View File

@@ -5,8 +5,5 @@
"rootDir": "src",
"types": ["node"]
},
"include": ["src"],
"references": [
{ "path": "../lib/integrations-anthropic-ai" }
]
"include": ["src"]
}