@paypol-protocol/aps-1 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,337 @@
1
+ # APS-1: Agent Payment Standard v1.0
2
+
3
+ > The open protocol standard for AI agent payments on blockchain.
4
+
5
+ **APS-1** defines how AI agents discover, negotiate, escrow, execute, verify, and settle payments - providing a universal interface for the AI agent economy.
6
+
7
+ ## Why APS-1?
8
+
9
+ Today, every AI agent platform has its own payment mechanism. APS-1 standardizes this into a single protocol that works across frameworks (OpenAI, Anthropic, LangChain, CrewAI, MCP, Eliza) and chains.
10
+
11
+ | Before APS-1 | After APS-1 |
12
+ |---|---|
13
+ | Every platform = custom integration | One standard, every framework |
14
+ | Trust the agent blindly | Verifiable execution proofs |
15
+ | Pay upfront, hope for the best | Escrow-protected payments |
16
+ | No reputation portability | On-chain reputation scores |
17
+
18
+ ## Protocol Overview
19
+
20
+ APS-1 defines a 6-phase lifecycle for agent payments:
21
+
22
+ ```
23
+ ┌─────────────────────────────────────────────────────┐
24
+ │ APS-1 Protocol Flow │
25
+ │ │
26
+ │ 1. DISCOVER ──→ GET /manifest │
27
+ │ Returns APS1Manifest │
28
+ │ │
29
+ │ 2. NEGOTIATE ──→ POST /negotiate (optional) │
30
+ │ Price negotiation messages │
31
+ │ │
32
+ │ 3. ESCROW ──→ Lock funds on-chain │
33
+ │ NexusV2 | StreamV1 | Direct │
34
+ │ │
35
+ │ 4. EXECUTE ──→ POST /execute │
36
+ │ Send APS1ExecutionEnvelope │
37
+ │ Receive APS1Result │
38
+ │ │
39
+ │ 5. VERIFY ──→ AIProofRegistry verification │
40
+ │ planHash vs resultHash matching │
41
+ │ │
42
+ │ 6. SETTLE ──→ Release escrow payment │
43
+ │ Agent payout - platform fee │
44
+ └─────────────────────────────────────────────────────┘
45
+ ```
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ npm install @paypol-protocol/aps-1
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ ### Build an APS-1 Agent
56
+
57
+ ```typescript
58
+ import { APS1Agent } from '@paypol-protocol/aps-1';
59
+
60
+ const agent = new APS1Agent({
61
+ id: 'data-analyzer',
62
+ name: 'Data Analyzer',
63
+ description: 'Analyzes on-chain data and generates reports',
64
+ category: 'analytics',
65
+ version: '1.0.0',
66
+ pricing: { basePrice: 5, currency: 'USD', negotiable: true, minPrice: 2 },
67
+ capabilities: ['analyze-transactions', 'generate-report', 'trend-detection'],
68
+ walletAddress: '0xYourAgentWallet',
69
+ });
70
+
71
+ agent.onExecute(async (envelope) => {
72
+ // Your agent logic here
73
+ const analysis = await analyzeData(envelope.prompt, envelope.payload);
74
+
75
+ return {
76
+ status: 'success',
77
+ result: analysis,
78
+ onChain: {
79
+ executed: true,
80
+ transactions: [{ hash: '0x...', blockNumber: 1234, gasUsed: '21000', explorerUrl: '...' }],
81
+ network: 'Tempo L1 Moderato',
82
+ chainId: 42431,
83
+ },
84
+ };
85
+ });
86
+
87
+ // Optional: support price negotiation
88
+ agent.onNegotiate(async (message) => {
89
+ if (message.type === 'propose' && message.price >= 3) {
90
+ return { type: 'accept', jobId: message.jobId, price: message.price, currency: 'USD', timestamp: new Date().toISOString() };
91
+ }
92
+ return { type: 'counter', jobId: message.jobId, price: 4, currency: 'USD', message: 'Minimum $4 for this task', timestamp: new Date().toISOString() };
93
+ });
94
+
95
+ agent.listen(3002);
96
+ ```
97
+
98
+ ### Hire an APS-1 Agent
99
+
100
+ ```typescript
101
+ import { APS1Client } from '@paypol-protocol/aps-1';
102
+
103
+ const client = new APS1Client({
104
+ agentServiceUrl: 'https://paypol.xyz',
105
+ });
106
+
107
+ // Discover available agents
108
+ const agents = await client.listAgents();
109
+ const analytics = await client.searchAgents({ category: 'analytics', maxPrice: 10 });
110
+
111
+ // Execute a job
112
+ const result = await client.execute(
113
+ 'data-analyzer',
114
+ 'Analyze top 100 transactions on Tempo L1 this week',
115
+ '0xMyWallet',
116
+ );
117
+
118
+ console.log(result.status); // 'success'
119
+ console.log(result.result); // { analysis: ... }
120
+ ```
121
+
122
+ ### Validate APS-1 Data
123
+
124
+ ```typescript
125
+ import { validateManifest, validateResult } from '@paypol-protocol/aps-1';
126
+
127
+ // Validate a manifest
128
+ const manifestCheck = validateManifest(someData);
129
+ if (!manifestCheck.success) {
130
+ console.error('Invalid manifest:', manifestCheck.errors);
131
+ }
132
+
133
+ // Validate a result
134
+ const resultCheck = validateResult(someResult);
135
+ if (resultCheck.success) {
136
+ console.log('Valid result:', resultCheck.data);
137
+ }
138
+ ```
139
+
140
+ ## Specification
141
+
142
+ ### Phase 1: Discovery
143
+
144
+ Every APS-1 agent MUST serve a manifest at `GET /manifest`:
145
+
146
+ ```json
147
+ {
148
+ "aps": "1.0",
149
+ "id": "data-analyzer",
150
+ "name": "Data Analyzer",
151
+ "description": "Analyzes on-chain data and generates reports",
152
+ "category": "analytics",
153
+ "version": "1.0.0",
154
+ "pricing": {
155
+ "basePrice": 5.00,
156
+ "currency": "USD",
157
+ "negotiable": true,
158
+ "minPrice": 2.00
159
+ },
160
+ "capabilities": ["analyze-transactions", "generate-report"],
161
+ "paymentMethods": ["nexus-escrow", "stream-milestone", "direct-transfer"],
162
+ "supportedTokens": [
163
+ { "symbol": "AlphaUSD", "address": "0x20c0...0001", "decimals": 6 }
164
+ ],
165
+ "proofEnabled": true,
166
+ "walletAddress": "0xAgentWallet",
167
+ "endpoints": {
168
+ "manifest": "https://agent.example.com/manifest",
169
+ "execute": "https://agent.example.com/execute",
170
+ "negotiate": "https://agent.example.com/negotiate",
171
+ "status": "https://agent.example.com/status",
172
+ "health": "https://agent.example.com/health"
173
+ }
174
+ }
175
+ ```
176
+
177
+ ### Phase 2: Negotiation (Optional)
178
+
179
+ If `pricing.negotiable` is `true`, clients MAY negotiate price via `POST /negotiate`:
180
+
181
+ ```json
182
+ // Client proposes
183
+ { "type": "propose", "jobId": "job-123", "price": 3.00, "currency": "USD" }
184
+
185
+ // Agent counters
186
+ { "type": "counter", "jobId": "job-123", "price": 4.00, "currency": "USD", "message": "Minimum $4" }
187
+
188
+ // Client accepts
189
+ { "type": "accept", "jobId": "job-123", "price": 4.00, "currency": "USD" }
190
+ ```
191
+
192
+ ### Phase 3: Escrow
193
+
194
+ Before execution, the client locks funds using one of three methods:
195
+
196
+ | Method | Contract | Use Case |
197
+ |--------|----------|----------|
198
+ | `nexus-escrow` | NexusV2 | Single job with dispute resolution |
199
+ | `stream-milestone` | PayPolStreamV1 | Multi-milestone projects |
200
+ | `direct-transfer` | ERC20 transfer | Trusted agents, small amounts |
201
+
202
+ ### Phase 4: Execution
203
+
204
+ Client sends an `APS1ExecutionEnvelope` to `POST /execute`:
205
+
206
+ ```json
207
+ {
208
+ "jobId": "job-123",
209
+ "agentId": "data-analyzer",
210
+ "prompt": "Analyze top 100 transactions",
211
+ "callerWallet": "0xClientWallet",
212
+ "escrow": {
213
+ "contractAddress": "0x6A467Cd4156093bB528e448C04366586a1052Fab",
214
+ "onChainId": 42,
215
+ "txHash": "0xabc...",
216
+ "method": "nexus-escrow"
217
+ },
218
+ "proof": {
219
+ "planHash": "0xdef...",
220
+ "commitmentId": "proof-42",
221
+ "commitTxHash": "0x789..."
222
+ },
223
+ "timestamp": "2025-01-15T10:30:00Z"
224
+ }
225
+ ```
226
+
227
+ Agent returns an `APS1Result`:
228
+
229
+ ```json
230
+ {
231
+ "jobId": "job-123",
232
+ "agentId": "data-analyzer",
233
+ "status": "success",
234
+ "result": { "analysis": "...", "topTransactions": [...] },
235
+ "onChain": {
236
+ "executed": true,
237
+ "transactions": [
238
+ { "hash": "0x...", "blockNumber": 54321, "gasUsed": "150000", "explorerUrl": "https://explore.tempo.xyz/tx/0x..." }
239
+ ],
240
+ "network": "Tempo L1 Moderato",
241
+ "chainId": 42431
242
+ },
243
+ "proof": {
244
+ "resultHash": "0xabc...",
245
+ "verifyTxHash": "0xdef...",
246
+ "matched": true
247
+ },
248
+ "executionTimeMs": 4520,
249
+ "timestamp": "2025-01-15T10:30:04Z"
250
+ }
251
+ ```
252
+
253
+ ### Phase 5: Verification
254
+
255
+ If `proofEnabled` is `true`, the agent's execution is verified via `AIProofRegistry`:
256
+
257
+ 1. **Commit**: Before execution, agent commits `planHash` on-chain
258
+ 2. **Execute**: Agent performs the work
259
+ 3. **Verify**: After execution, agent submits `resultHash` for verification
260
+ 4. **Match**: `planHash === resultHash` → proof of honest execution
261
+
262
+ ### Phase 6: Settlement
263
+
264
+ After successful execution and verification:
265
+
266
+ - **Success**: Escrow releases payment to agent (minus platform fee)
267
+ - **Failure**: Client can dispute via NexusV2 judge mechanism
268
+ - **Timeout**: If agent doesn't deliver within deadline, client gets refund
269
+
270
+ ```json
271
+ {
272
+ "jobId": "job-123",
273
+ "type": "settle",
274
+ "agentPayout": "4600000",
275
+ "platformFee": "400000",
276
+ "txHash": "0x...",
277
+ "timestamp": "2025-01-15T10:31:00Z"
278
+ }
279
+ ```
280
+
281
+ ## Protocol Constants
282
+
283
+ | Constant | Value | Description |
284
+ |----------|-------|-------------|
285
+ | `APS1_VERSION` | `1.0` | Protocol version |
286
+ | `APS1_CHAIN_ID` | `42431` | Tempo L1 Moderato |
287
+ | `APS1_PLATFORM_FEE_BPS` | `800` | 8% platform fee |
288
+ | `APS1_NETWORK` | `Tempo L1 Moderato` | Network name |
289
+
290
+ ## Smart Contracts
291
+
292
+ | Contract | Address | Purpose |
293
+ |----------|---------|---------|
294
+ | NexusV2 | `0x6A467Cd4156093bB528e448C04366586a1052Fab` | Escrow + dispute |
295
+ | PayPolStreamV1 | `0x4fE37c46E3D442129c2319de3D24c21A6cbfa36C` | Milestone streams |
296
+ | AIProofRegistry | `0x8fDB8E871c9eaF2955009566F41490Bbb128a014` | Execution proofs |
297
+ | ReputationRegistry | `0x9332c1B2bb94C96DA2D729423f345c76dB3494D0` | Agent reputation |
298
+ | ShieldVaultV2 | `0x3B4b47971B61cB502DD97eAD9cAF0552ffae0055` | Privacy payments |
299
+ | MultisendV2 | `0x25f4d3f12C579002681a52821F3a6251c46D4575` | Batch payments |
300
+
301
+ ## Supported Tokens
302
+
303
+ | Token | Address | Decimals |
304
+ |-------|---------|----------|
305
+ | AlphaUSD | `0x20c0000000000000000000000000000000000001` | 6 |
306
+ | pathUSD | `0x20c0000000000000000000000000000000000000` | 6 |
307
+ | BetaUSD | `0x20c0000000000000000000000000000000000002` | 6 |
308
+ | ThetaUSD | `0x20c0000000000000000000000000000000000003` | 6 |
309
+
310
+ ## Framework Compatibility
311
+
312
+ APS-1 is framework-agnostic. Use the `paypol-sdk` adapters:
313
+
314
+ ```typescript
315
+ // OpenAI function-calling
316
+ import { toOpenAITools } from 'paypol-sdk/openai';
317
+
318
+ // Anthropic tool-use
319
+ import { toAnthropicTools } from 'paypol-sdk/anthropic';
320
+
321
+ // LangChain
322
+ import { PayPolToolkit } from 'paypol-sdk/langchain';
323
+
324
+ // CrewAI
325
+ import { PayPolCrewAITool } from 'paypol-sdk/crewai';
326
+
327
+ // MCP
328
+ import { PayPolMCPServer } from 'paypol-sdk/mcp';
329
+ ```
330
+
331
+ ## Contributing
332
+
333
+ Want to build APS-1 compliant agents? See the [Contributing Guide](../../CONTRIBUTING.md).
334
+
335
+ ## License
336
+
337
+ MIT
@@ -0,0 +1,88 @@
1
+ /**
2
+ * APS-1 Reference Agent
3
+ *
4
+ * An Express-based agent server that implements the full APS-1 protocol.
5
+ * Extends the standard PayPolAgent pattern with:
6
+ * - APS-1 manifest endpoint
7
+ * - Optional negotiation endpoint
8
+ * - Job status tracking
9
+ * - Structured APS-1 result format
10
+ *
11
+ * Usage:
12
+ * const agent = new APS1Agent({
13
+ * id: 'my-agent',
14
+ * name: 'My Agent',
15
+ * description: 'Does amazing things',
16
+ * category: 'analytics',
17
+ * version: '1.0.0',
18
+ * pricing: { basePrice: 5, currency: 'USD', negotiable: false },
19
+ * capabilities: ['analyze', 'report'],
20
+ * walletAddress: '0x...',
21
+ * });
22
+ *
23
+ * agent.onExecute(async (envelope) => {
24
+ * return { status: 'success', result: { ... } };
25
+ * });
26
+ *
27
+ * agent.listen(3002);
28
+ */
29
+ import express from 'express';
30
+ import type { APS1Manifest, APS1ExecutionEnvelope, APS1Result, APS1NegotiationMessage, APS1Category, APS1Pricing, APS1PaymentMethod, APS1TokenConfig } from './types';
31
+ export interface APS1AgentConfig {
32
+ /** Unique agent ID (kebab-case) */
33
+ id: string;
34
+ /** Human-readable agent name */
35
+ name: string;
36
+ /** What the agent does */
37
+ description: string;
38
+ /** Agent category */
39
+ category: APS1Category;
40
+ /** Semantic version */
41
+ version: string;
42
+ /** Pricing configuration */
43
+ pricing: APS1Pricing;
44
+ /** List of capabilities */
45
+ capabilities: string[];
46
+ /** Agent's wallet address on Tempo L1 */
47
+ walletAddress: string;
48
+ /** Accepted payment methods (default: all) */
49
+ paymentMethods?: APS1PaymentMethod[];
50
+ /** Accepted tokens (default: APS1_DEFAULT_TOKENS) */
51
+ supportedTokens?: APS1TokenConfig[];
52
+ /** Whether AIProofRegistry is used (default: true) */
53
+ proofEnabled?: boolean;
54
+ /** Optional metadata */
55
+ metadata?: Record<string, unknown>;
56
+ }
57
+ export type APS1ExecuteHandler = (envelope: APS1ExecutionEnvelope) => Promise<Partial<APS1Result>>;
58
+ export type APS1NegotiateHandler = (message: APS1NegotiationMessage) => Promise<APS1NegotiationMessage>;
59
+ export declare class APS1Agent {
60
+ private config;
61
+ private app;
62
+ private executeHandler?;
63
+ private negotiateHandler?;
64
+ private baseUrl;
65
+ /** In-memory job status tracking */
66
+ private jobs;
67
+ constructor(config: APS1AgentConfig);
68
+ /**
69
+ * Register the handler called for every APS-1 execution envelope.
70
+ * Return a partial APS1Result - jobId, agentId, executionTimeMs, timestamp
71
+ * are filled in automatically.
72
+ */
73
+ onExecute(handler: APS1ExecuteHandler): this;
74
+ /**
75
+ * Register an optional negotiation handler.
76
+ * If not registered, the /negotiate endpoint will return 404.
77
+ */
78
+ onNegotiate(handler: APS1NegotiateHandler): this;
79
+ /** Start the HTTP server. */
80
+ listen(port: number, cb?: () => void): void;
81
+ /** Generate the APS-1 manifest. */
82
+ toManifest(): APS1Manifest;
83
+ /** Get a tracked job result by ID. */
84
+ getJob(jobId: string): APS1Result | undefined;
85
+ /** Access the underlying Express app (for custom middleware). */
86
+ getExpressApp(): express.Application;
87
+ private _registerRoutes;
88
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * APS-1 Reference Agent
3
+ *
4
+ * An Express-based agent server that implements the full APS-1 protocol.
5
+ * Extends the standard PayPolAgent pattern with:
6
+ * - APS-1 manifest endpoint
7
+ * - Optional negotiation endpoint
8
+ * - Job status tracking
9
+ * - Structured APS-1 result format
10
+ *
11
+ * Usage:
12
+ * const agent = new APS1Agent({
13
+ * id: 'my-agent',
14
+ * name: 'My Agent',
15
+ * description: 'Does amazing things',
16
+ * category: 'analytics',
17
+ * version: '1.0.0',
18
+ * pricing: { basePrice: 5, currency: 'USD', negotiable: false },
19
+ * capabilities: ['analyze', 'report'],
20
+ * walletAddress: '0x...',
21
+ * });
22
+ *
23
+ * agent.onExecute(async (envelope) => {
24
+ * return { status: 'success', result: { ... } };
25
+ * });
26
+ *
27
+ * agent.listen(3002);
28
+ */
29
+ import express from 'express';
30
+ import { APS1_VERSION, APS1_DEFAULT_TOKENS, APS1_NETWORK, APS1_CHAIN_ID, } from './types';
31
+ // ── APS-1 Agent Server ──────────────────────────────────
32
+ export class APS1Agent {
33
+ config;
34
+ app = express();
35
+ executeHandler;
36
+ negotiateHandler;
37
+ baseUrl = '';
38
+ /** In-memory job status tracking */
39
+ jobs = new Map();
40
+ constructor(config) {
41
+ this.config = config;
42
+ this.app.use(express.json());
43
+ this._registerRoutes();
44
+ }
45
+ // ── Public API ──────────────────────────────────────
46
+ /**
47
+ * Register the handler called for every APS-1 execution envelope.
48
+ * Return a partial APS1Result - jobId, agentId, executionTimeMs, timestamp
49
+ * are filled in automatically.
50
+ */
51
+ onExecute(handler) {
52
+ this.executeHandler = handler;
53
+ return this;
54
+ }
55
+ /**
56
+ * Register an optional negotiation handler.
57
+ * If not registered, the /negotiate endpoint will return 404.
58
+ */
59
+ onNegotiate(handler) {
60
+ this.negotiateHandler = handler;
61
+ return this;
62
+ }
63
+ /** Start the HTTP server. */
64
+ listen(port, cb) {
65
+ this.baseUrl = `http://localhost:${port}`;
66
+ this.app.listen(port, () => {
67
+ console.log(`[APS-1] ${this.config.name} listening on port ${port}`);
68
+ console.log(`[APS-1] Manifest: ${this.baseUrl}/manifest`);
69
+ console.log(`[APS-1] Execute: POST ${this.baseUrl}/execute`);
70
+ cb?.();
71
+ });
72
+ }
73
+ /** Generate the APS-1 manifest. */
74
+ toManifest() {
75
+ const base = this.baseUrl || 'http://localhost:3000';
76
+ return {
77
+ aps: '1.0',
78
+ id: this.config.id,
79
+ name: this.config.name,
80
+ description: this.config.description,
81
+ category: this.config.category,
82
+ version: this.config.version,
83
+ pricing: this.config.pricing,
84
+ capabilities: this.config.capabilities,
85
+ paymentMethods: this.config.paymentMethods ?? ['nexus-escrow', 'stream-milestone', 'direct-transfer'],
86
+ supportedTokens: this.config.supportedTokens ?? APS1_DEFAULT_TOKENS,
87
+ proofEnabled: this.config.proofEnabled ?? true,
88
+ walletAddress: this.config.walletAddress,
89
+ endpoints: {
90
+ manifest: `${base}/manifest`,
91
+ execute: `${base}/execute`,
92
+ negotiate: this.negotiateHandler ? `${base}/negotiate` : undefined,
93
+ status: `${base}/status`,
94
+ health: `${base}/health`,
95
+ },
96
+ metadata: this.config.metadata,
97
+ };
98
+ }
99
+ /** Get a tracked job result by ID. */
100
+ getJob(jobId) {
101
+ return this.jobs.get(jobId);
102
+ }
103
+ /** Access the underlying Express app (for custom middleware). */
104
+ getExpressApp() {
105
+ return this.app;
106
+ }
107
+ // ── Routes ──────────────────────────────────────────
108
+ _registerRoutes() {
109
+ // GET /manifest - APS-1 manifest
110
+ this.app.get('/manifest', (_req, res) => {
111
+ res.json(this.toManifest());
112
+ });
113
+ // POST /execute - APS-1 execution
114
+ this.app.post('/execute', async (req, res) => {
115
+ if (!this.executeHandler) {
116
+ return res.status(501).json({
117
+ error: 'No execute handler registered',
118
+ aps: APS1_VERSION,
119
+ });
120
+ }
121
+ const jobId = req.body.jobId ?? `aps1-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
122
+ const envelope = {
123
+ jobId,
124
+ agentId: this.config.id,
125
+ prompt: req.body.prompt ?? '',
126
+ payload: req.body.payload,
127
+ callerWallet: req.body.callerWallet ?? '',
128
+ escrow: req.body.escrow,
129
+ proof: req.body.proof,
130
+ timestamp: new Date().toISOString(),
131
+ };
132
+ const start = Date.now();
133
+ try {
134
+ const partial = await this.executeHandler(envelope);
135
+ const result = {
136
+ jobId,
137
+ agentId: this.config.id,
138
+ status: partial.status ?? 'success',
139
+ result: partial.result,
140
+ error: partial.error,
141
+ onChain: partial.onChain ?? {
142
+ executed: false,
143
+ transactions: [],
144
+ network: APS1_NETWORK,
145
+ chainId: APS1_CHAIN_ID,
146
+ },
147
+ proof: partial.proof,
148
+ executionTimeMs: Date.now() - start,
149
+ timestamp: new Date().toISOString(),
150
+ };
151
+ // Track the job
152
+ this.jobs.set(jobId, result);
153
+ res.json(result);
154
+ }
155
+ catch (err) {
156
+ const errorResult = {
157
+ jobId,
158
+ agentId: this.config.id,
159
+ status: 'error',
160
+ error: err.message ?? String(err),
161
+ executionTimeMs: Date.now() - start,
162
+ timestamp: new Date().toISOString(),
163
+ };
164
+ this.jobs.set(jobId, errorResult);
165
+ res.status(500).json(errorResult);
166
+ }
167
+ });
168
+ // POST /negotiate - optional price negotiation
169
+ this.app.post('/negotiate', async (req, res) => {
170
+ if (!this.negotiateHandler) {
171
+ return res.status(404).json({
172
+ error: 'This agent does not support negotiation',
173
+ aps: APS1_VERSION,
174
+ });
175
+ }
176
+ try {
177
+ const message = {
178
+ type: req.body.type,
179
+ jobId: req.body.jobId,
180
+ price: req.body.price,
181
+ currency: req.body.currency ?? 'USD',
182
+ message: req.body.message,
183
+ timestamp: new Date().toISOString(),
184
+ };
185
+ const response = await this.negotiateHandler(message);
186
+ res.json(response);
187
+ }
188
+ catch (err) {
189
+ res.status(500).json({
190
+ error: err.message ?? String(err),
191
+ aps: APS1_VERSION,
192
+ });
193
+ }
194
+ });
195
+ // GET /status/:jobId - job status
196
+ this.app.get('/status/:jobId', (req, res) => {
197
+ const job = this.jobs.get(req.params.jobId);
198
+ if (!job) {
199
+ return res.status(404).json({
200
+ error: 'Job not found',
201
+ aps: APS1_VERSION,
202
+ });
203
+ }
204
+ res.json(job);
205
+ });
206
+ // GET /health - health check
207
+ this.app.get('/health', (_req, res) => {
208
+ res.json({
209
+ status: 'ok',
210
+ aps: APS1_VERSION,
211
+ agent: this.config.id,
212
+ name: this.config.name,
213
+ version: this.config.version,
214
+ uptime: process.uptime(),
215
+ });
216
+ });
217
+ }
218
+ }