Task #3: MVP API — payment-gated jobs + demo endpoint
OpenAPI spec (lib/api-spec/openapi.yaml)
- Added POST /jobs, GET /jobs/{id}, GET /demo endpoints
- Added schemas: CreateJobRequest, CreateJobResponse, JobStatusResponse,
InvoiceInfo, JobState, DemoResponse, ErrorResponse
- Ran codegen: generated CreateJobBody, GetJobResponse, RunDemoQueryParams etc.
Jobs router (artifacts/api-server/src/routes/jobs.ts)
- POST /jobs: validates body, creates LNbits eval invoice, inserts job +
invoice in a DB transaction, returns { jobId, evalInvoice }
- GET /jobs/🆔 fetches job, calls advanceJob() helper, returns state-
appropriate payload (eval/work invoice, reason, result, errorMessage)
- advanceJob() state machine:
- awaiting_eval_payment: checks LNbits, atomically marks paid + advances
state via optimistic WHERE state='awaiting_eval_payment'; runs
AgentService.evaluateRequest, branches to awaiting_work_payment or rejected
- awaiting_work_payment: same pattern for work invoice, runs
AgentService.executeWork, advances to complete
- Any agent/LNbits error transitions job to failed
Demo router (artifacts/api-server/src/routes/demo.ts)
- GET /demo?request=...: in-memory rate limiter (5 req/hour per IP)
- Explicit guard for missing request param (coerce.string() workaround)
- Calls AgentService.executeWork directly, returns { result }
Dev router (artifacts/api-server/src/routes/dev.ts)
- POST /dev/stub/pay/:paymentHash: marks stub invoice paid in-memory
- Only mounted when NODE_ENV !== 'production'
Route index updated to mount all three routers
replit.md: documented full curl flow with all 6 steps, demo endpoint,
and dev stub-pay trigger
End-to-end verified with curl:
- Full flow: create → eval pay → evaluating → work pay → executing → complete
- Error cases: 400 on missing body/param, 404 on unknown job
This commit is contained in:
@@ -14,3 +14,60 @@ import * as zod from "zod";
|
||||
export const HealthCheckResponse = zod.object({
|
||||
status: zod.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Accepts a request, creates a job row, and issues an eval fee Lightning invoice.
|
||||
* @summary Create a new agent job
|
||||
*/
|
||||
|
||||
export const CreateJobBody = zod.object({
|
||||
request: zod.string().min(1),
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns current job state. Automatically advances the state machine when a pending invoice is found to be paid.
|
||||
* @summary Get job status
|
||||
*/
|
||||
export const GetJobParams = zod.object({
|
||||
id: zod.coerce.string(),
|
||||
});
|
||||
|
||||
export const GetJobResponse = zod.object({
|
||||
jobId: zod.string(),
|
||||
state: zod.enum([
|
||||
"awaiting_eval_payment",
|
||||
"evaluating",
|
||||
"rejected",
|
||||
"awaiting_work_payment",
|
||||
"executing",
|
||||
"complete",
|
||||
"failed",
|
||||
]),
|
||||
evalInvoice: zod
|
||||
.object({
|
||||
paymentRequest: zod.string(),
|
||||
amountSats: zod.number(),
|
||||
})
|
||||
.optional(),
|
||||
workInvoice: zod
|
||||
.object({
|
||||
paymentRequest: zod.string(),
|
||||
amountSats: zod.number(),
|
||||
})
|
||||
.optional(),
|
||||
reason: zod.string().optional(),
|
||||
result: zod.string().optional(),
|
||||
errorMessage: zod.string().optional(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Runs the agent without payment. Limited to 5 requests per IP per hour.
|
||||
* @summary Free demo (rate-limited)
|
||||
*/
|
||||
export const RunDemoQueryParams = zod.object({
|
||||
request: zod.coerce.string(),
|
||||
});
|
||||
|
||||
export const RunDemoResponse = zod.object({
|
||||
result: zod.string(),
|
||||
});
|
||||
|
||||
12
lib/api-zod/src/generated/types/createJobRequest.ts
Normal file
12
lib/api-zod/src/generated/types/createJobRequest.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface CreateJobRequest {
|
||||
/** @minLength 1 */
|
||||
request: string;
|
||||
}
|
||||
13
lib/api-zod/src/generated/types/createJobResponse.ts
Normal file
13
lib/api-zod/src/generated/types/createJobResponse.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { InvoiceInfo } from "./invoiceInfo";
|
||||
|
||||
export interface CreateJobResponse {
|
||||
jobId: string;
|
||||
evalInvoice: InvoiceInfo;
|
||||
}
|
||||
11
lib/api-zod/src/generated/types/demoResponse.ts
Normal file
11
lib/api-zod/src/generated/types/demoResponse.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface DemoResponse {
|
||||
result: string;
|
||||
}
|
||||
11
lib/api-zod/src/generated/types/errorResponse.ts
Normal file
11
lib/api-zod/src/generated/types/errorResponse.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface ErrorResponse {
|
||||
error: string;
|
||||
}
|
||||
@@ -6,4 +6,12 @@
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export * from "./createJobRequest";
|
||||
export * from "./createJobResponse";
|
||||
export * from "./demoResponse";
|
||||
export * from "./errorResponse";
|
||||
export * from "./healthStatus";
|
||||
export * from "./invoiceInfo";
|
||||
export * from "./jobState";
|
||||
export * from "./jobStatusResponse";
|
||||
export * from "./runDemoParams";
|
||||
|
||||
12
lib/api-zod/src/generated/types/invoiceInfo.ts
Normal file
12
lib/api-zod/src/generated/types/invoiceInfo.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export interface InvoiceInfo {
|
||||
paymentRequest: string;
|
||||
amountSats: number;
|
||||
}
|
||||
19
lib/api-zod/src/generated/types/jobState.ts
Normal file
19
lib/api-zod/src/generated/types/jobState.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type JobState = (typeof JobState)[keyof typeof JobState];
|
||||
|
||||
export const JobState = {
|
||||
awaiting_eval_payment: "awaiting_eval_payment",
|
||||
evaluating: "evaluating",
|
||||
rejected: "rejected",
|
||||
awaiting_work_payment: "awaiting_work_payment",
|
||||
executing: "executing",
|
||||
complete: "complete",
|
||||
failed: "failed",
|
||||
} as const;
|
||||
19
lib/api-zod/src/generated/types/jobStatusResponse.ts
Normal file
19
lib/api-zod/src/generated/types/jobStatusResponse.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
import type { InvoiceInfo } from "./invoiceInfo";
|
||||
import type { JobState } from "./jobState";
|
||||
|
||||
export interface JobStatusResponse {
|
||||
jobId: string;
|
||||
state: JobState;
|
||||
evalInvoice?: InvoiceInfo;
|
||||
workInvoice?: InvoiceInfo;
|
||||
reason?: string;
|
||||
result?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
11
lib/api-zod/src/generated/types/runDemoParams.ts
Normal file
11
lib/api-zod/src/generated/types/runDemoParams.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Generated by orval v8.5.3 🍺
|
||||
* Do not edit manually.
|
||||
* Api
|
||||
* API specification
|
||||
* OpenAPI spec version: 0.1.0
|
||||
*/
|
||||
|
||||
export type RunDemoParams = {
|
||||
request: string;
|
||||
};
|
||||
Reference in New Issue
Block a user