patchr 0.1.0__py3-none-any.whl

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.
Files changed (116) hide show
  1. apps/__init__.py +2 -0
  2. apps/api/__init__.py +2 -0
  3. apps/api/main.py +652 -0
  4. apps/benchmarks/__init__.py +1 -0
  5. apps/benchmarks/main.py +20 -0
  6. apps/sandbox/__init__.py +1 -0
  7. apps/sandbox/main.py +20 -0
  8. apps/worker/__init__.py +2 -0
  9. apps/worker/main.py +15 -0
  10. apps/worker/verify.py +14 -0
  11. patchr/__init__.py +12 -0
  12. patchr/sdk/__init__.py +20 -0
  13. patchr/sdk/client.py +12 -0
  14. patchr-0.1.0.dist-info/METADATA +137 -0
  15. patchr-0.1.0.dist-info/RECORD +116 -0
  16. patchr-0.1.0.dist-info/WHEEL +5 -0
  17. patchr-0.1.0.dist-info/entry_points.txt +5 -0
  18. patchr-0.1.0.dist-info/licenses/LICENSE +17 -0
  19. patchr-0.1.0.dist-info/top_level.txt +3 -0
  20. picux/__init__.py +6 -0
  21. picux/agents/__init__.py +5 -0
  22. picux/agents/registry.py +204 -0
  23. picux/api/__init__.py +5 -0
  24. picux/api/service.py +5075 -0
  25. picux/audit/__init__.py +31 -0
  26. picux/audit/activity.py +97 -0
  27. picux/audit/observability.py +55 -0
  28. picux/audit/verification/__init__.py +21 -0
  29. picux/audit/verification/ledger.py +633 -0
  30. picux/benchmarks/__init__.py +5 -0
  31. picux/benchmarks/local.py +286 -0
  32. picux/config.py +140 -0
  33. picux/contracts/__init__.py +22 -0
  34. picux/contracts/handshake.py +122 -0
  35. picux/contracts/integration.py +385 -0
  36. picux/contracts/openapi.py +187 -0
  37. picux/contracts/protocol_map.py +152 -0
  38. picux/contracts/routes.py +980 -0
  39. picux/contracts/schema_catalog.py +125 -0
  40. picux/core/__init__.py +17 -0
  41. picux/core/models.py +148 -0
  42. picux/core/router.py +131 -0
  43. picux/core/runtime.py +42 -0
  44. picux/core/state_machine.py +38 -0
  45. picux/domains/__init__.py +2 -0
  46. picux/domains/bridge/HostRun.py +1104 -0
  47. picux/domains/bridge/__init__.py +6 -0
  48. picux/domains/bridge/engine.py +345 -0
  49. picux/domains/hunt/__init__.py +6 -0
  50. picux/domains/hunt/engine.py +307 -0
  51. picux/domains/hunt/models.py +88 -0
  52. picux/domains/pay/__init__.py +16 -0
  53. picux/domains/pay/adapters.py +607 -0
  54. picux/domains/pay/engine.py +950 -0
  55. picux/domains/pay/models.py +95 -0
  56. picux/domains/proxy/__init__.py +5 -0
  57. picux/domains/proxy/engine.py +466 -0
  58. picux/domains/resolve/__init__.py +5 -0
  59. picux/domains/resolve/engine.py +546 -0
  60. picux/orchestrator/__init__.py +3 -0
  61. picux/orchestrator/engine.py +2840 -0
  62. picux/portals/__init__.py +17 -0
  63. picux/portals/templates.py +272 -0
  64. picux/protocols/__init__.py +1 -0
  65. picux/protocols/a2a/__init__.py +6 -0
  66. picux/protocols/a2a/client.py +51 -0
  67. picux/protocols/a2a/envelope.py +132 -0
  68. picux/protocols/mcp/__init__.py +7 -0
  69. picux/protocols/mcp/client.py +69 -0
  70. picux/protocols/mcp/contract.py +67 -0
  71. picux/protocols/mcp/server.py +76 -0
  72. picux/sandbox/__init__.py +6 -0
  73. picux/sandbox/midnight_arbitrage.py +215 -0
  74. picux/sandbox/models.py +90 -0
  75. picux/sdk/__init__.py +13 -0
  76. picux/sdk/client.py +768 -0
  77. picux/sdk/external.py +245 -0
  78. picux/security/__init__.py +18 -0
  79. picux/security/auth.py +86 -0
  80. picux/security/config_validator.py +58 -0
  81. picux/security/policy.py +158 -0
  82. picux/security/secrets.py +144 -0
  83. picux/signals/__init__.py +1 -0
  84. picux/signals/community/__init__.py +24 -0
  85. picux/signals/community/adapters/__init__.py +7 -0
  86. picux/signals/community/adapters/reddit.py +37 -0
  87. picux/signals/community/adapters/shopify.py +23 -0
  88. picux/signals/community/adapters/web.py +23 -0
  89. picux/signals/community/disambiguation.py +51 -0
  90. picux/signals/community/intake.py +227 -0
  91. picux/signals/community/models.py +102 -0
  92. picux/signals/community/rules.py +91 -0
  93. picux/signals/community/scoring.py +64 -0
  94. picux/storage/__init__.py +41 -0
  95. picux/storage/agents.py +50 -0
  96. picux/storage/cases.py +440 -0
  97. picux/storage/channels.py +476 -0
  98. picux/storage/connectors.py +411 -0
  99. picux/storage/envelopes.py +137 -0
  100. picux/storage/escrows.py +168 -0
  101. picux/storage/events.py +989 -0
  102. picux/storage/keyspace.py +60 -0
  103. picux/storage/mandates.py +107 -0
  104. picux/storage/portals.py +222 -0
  105. picux/storage/postgres.py +2049 -0
  106. picux/storage/providers.py +148 -0
  107. picux/storage/proxy.py +231 -0
  108. picux/storage/receipts.py +131 -0
  109. picux/storage/signals.py +147 -0
  110. picux/storage/tasks.py +179 -0
  111. picux/tools/__init__.py +11 -0
  112. picux/tools/shared.py +2048 -0
  113. picux/verification/__init__.py +5 -0
  114. picux/verification/rollout.py +183 -0
  115. picux/workflows/__init__.py +5 -0
  116. picux/workflows/templates.py +74 -0
apps/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ """Picux application entrypoints."""
2
+
apps/api/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ """Picux API application."""
2
+
apps/api/main.py ADDED
@@ -0,0 +1,652 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import json
5
+ import queue
6
+ import threading
7
+ from http.server import BaseHTTPRequestHandler, HTTPServer
8
+ from typing import Any
9
+
10
+ from picux.api import PicuxApiService
11
+
12
+
13
+ service = PicuxApiService()
14
+
15
+
16
+ try:
17
+ from fastapi import FastAPI, Request
18
+ from fastapi.responses import JSONResponse, StreamingResponse
19
+ except Exception: # pragma: no cover - optional dependency
20
+ FastAPI = None
21
+ Request = None
22
+ JSONResponse = None
23
+ StreamingResponse = None
24
+
25
+
26
+ def _json_response(payload: dict[str, Any]) -> bytes:
27
+ return json.dumps(payload, ensure_ascii=True, sort_keys=True).encode("utf-8")
28
+
29
+
30
+ def _ndjson_event(payload: dict[str, Any]) -> bytes:
31
+ return json.dumps(payload, ensure_ascii=True, sort_keys=True).encode("utf-8") + b"\n"
32
+
33
+
34
+ def _log_orchestrator(result: dict[str, Any]) -> None:
35
+ print(
36
+ "[picux:orchestrator]",
37
+ json.dumps(
38
+ {
39
+ "status": result.get("status"),
40
+ "route": result.get("route", []),
41
+ "request": str(result.get("request", ""))[:180],
42
+ "traceCount": len(result.get("trace", [])) if isinstance(result.get("trace"), list) else 0,
43
+ },
44
+ ensure_ascii=True,
45
+ sort_keys=True,
46
+ ),
47
+ )
48
+ trace = result.get("trace", [])
49
+ if not isinstance(trace, list):
50
+ return
51
+ for event in trace[:30]:
52
+ if not isinstance(event, dict):
53
+ continue
54
+ print(
55
+ "[picux:orchestrator:trace]",
56
+ json.dumps(
57
+ {
58
+ "seq": event.get("seq"),
59
+ "phase": event.get("phase"),
60
+ "name": event.get("name"),
61
+ "status": event.get("status"),
62
+ "msg": event.get("msg"),
63
+ "data": event.get("data", {}),
64
+ },
65
+ ensure_ascii=True,
66
+ sort_keys=True,
67
+ ),
68
+ )
69
+
70
+
71
+ async def _read_json_body(receive: Any) -> dict[str, Any]:
72
+ chunks: list[bytes] = []
73
+ more = True
74
+ while more:
75
+ message = await receive()
76
+ chunks.append(message.get("body", b""))
77
+ more = bool(message.get("more_body", False))
78
+ if not chunks:
79
+ return {}
80
+ try:
81
+ payload = json.loads(b"".join(chunks).decode("utf-8") or "{}")
82
+ except Exception:
83
+ return {}
84
+ return payload if isinstance(payload, dict) else {}
85
+
86
+
87
+ if FastAPI is not None:
88
+ app = FastAPI(title="Picux Protocol API", version="0.1.0")
89
+
90
+ def _contract_openapi() -> dict[str, Any]:
91
+ return service.handle("GET", "/openapi.json")[1]
92
+
93
+ app.openapi = _contract_openapi # type: ignore[method-assign]
94
+
95
+ async def _fastapi_payload(request: Request) -> dict[str, Any]:
96
+ if request.method != "POST":
97
+ return {}
98
+ try:
99
+ payload = await request.json()
100
+ except Exception:
101
+ return {}
102
+ return payload if isinstance(payload, dict) else {}
103
+
104
+ @app.middleware("http")
105
+ async def authMiddleware(request: Request, call_next: Any) -> Any:
106
+ status, result = service.authorize(request.method, request.url.path, dict(request.headers))
107
+ if status >= 400:
108
+ return JSONResponse(status_code=status, content=result)
109
+ return await call_next(request)
110
+
111
+ @app.get("/healthz")
112
+ def healthz() -> dict[str, object]:
113
+ return service.handle("GET", "/healthz")[1]
114
+
115
+ @app.get("/runtime")
116
+ def runtimeSummary() -> dict[str, object]:
117
+ return service.handle("GET", "/runtime")[1]
118
+
119
+ @app.get("/v1/status")
120
+ def apiStatus() -> dict[str, object]:
121
+ return service.handle("GET", "/v1/status")[1]
122
+
123
+ @app.get("/openapi.json")
124
+ def openapiJson() -> dict[str, object]:
125
+ return service.handle("GET", "/openapi.json")[1]
126
+
127
+ @app.get("/v1/contract")
128
+ def contractSummary() -> dict[str, object]:
129
+ return service.handle("GET", "/v1/contract")[1]
130
+
131
+ @app.get("/v1/manifest")
132
+ def integrationManifest() -> dict[str, object]:
133
+ return service.handle("GET", "/v1/manifest")[1]
134
+
135
+ @app.get("/v1/protocol-map")
136
+ def protocolMap() -> dict[str, object]:
137
+ return service.handle("GET", "/v1/protocol-map")[1]
138
+
139
+ @app.post("/v1/handshake")
140
+ def integrationHandshake(payload: dict[str, Any]) -> Any:
141
+ status, result = service.handle("POST", "/v1/handshake", payload)
142
+ return JSONResponse(status_code=status, content=result)
143
+
144
+ @app.get("/v1/schemas")
145
+ def schemaList() -> dict[str, object]:
146
+ return service.handle("GET", "/v1/schemas")[1]
147
+
148
+ @app.get("/v1/schemas/{schemaId}")
149
+ def schemaGet(schemaId: str) -> dict[str, object]:
150
+ return service.handle("GET", f"/v1/schemas/{schemaId}")[1]
151
+
152
+ @app.get("/v1/a2a/contract")
153
+ def a2aContract() -> dict[str, object]:
154
+ return service.handle("GET", "/v1/a2a/contract")[1]
155
+
156
+ @app.get("/v1/a2a/envelopes")
157
+ def a2aEnvelopeList() -> dict[str, object]:
158
+ return service.handle("GET", "/v1/a2a/envelopes")[1]
159
+
160
+ @app.get("/v1/a2a/envelopes/{msgId}")
161
+ def a2aEnvelopeGet(msgId: str) -> dict[str, object]:
162
+ return service.handle("GET", f"/v1/a2a/envelopes/{msgId}")[1]
163
+
164
+ @app.get("/v1/bridge/connectors/ready")
165
+ def bridgeReadyConnectors() -> dict[str, object]:
166
+ return service.handle("GET", "/v1/bridge/connectors/ready")[1]
167
+
168
+ @app.get("/v1/bridge/connectors")
169
+ def bridgeConnectorList(request: Request) -> dict[str, object]:
170
+ return service.handle("GET", str(request.url))[1]
171
+
172
+ @app.get("/v1/bridge/connectors/{connectorId}")
173
+ def bridgeConnectorGet(connectorId: str) -> dict[str, object]:
174
+ return service.handle("GET", f"/v1/bridge/connectors/{connectorId}")[1]
175
+
176
+ @app.get("/v1/events")
177
+ def eventList(request: Request) -> dict[str, object]:
178
+ return service.handle("GET", str(request.url))[1]
179
+
180
+ @app.get("/v1/events/{eventId}")
181
+ def eventGet(eventId: str) -> dict[str, object]:
182
+ return service.handle("GET", f"/v1/events/{eventId}")[1]
183
+
184
+ @app.get("/v1/event-subscriptions")
185
+ def eventSubscriptionList(request: Request) -> dict[str, object]:
186
+ return service.handle("GET", str(request.url))[1]
187
+
188
+ @app.get("/v1/event-subscriptions/{subId}")
189
+ def eventSubscriptionGet(subId: str) -> dict[str, object]:
190
+ return service.handle("GET", f"/v1/event-subscriptions/{subId}")[1]
191
+
192
+ @app.get("/v1/event-deliveries")
193
+ def eventDeliveryList(request: Request) -> dict[str, object]:
194
+ return service.handle("GET", str(request.url))[1]
195
+
196
+ @app.get("/v1/event-deliveries/stats")
197
+ def eventDeliveryStats(request: Request) -> dict[str, object]:
198
+ return service.handle("GET", str(request.url))[1]
199
+
200
+ @app.get("/v1/event-deliveries/ready")
201
+ def eventDeliveryReady(request: Request) -> dict[str, object]:
202
+ return service.handle("GET", str(request.url))[1]
203
+
204
+ @app.get("/v1/event-deliveries/{deliveryId}")
205
+ def eventDeliveryGet(deliveryId: str) -> dict[str, object]:
206
+ return service.handle("GET", f"/v1/event-deliveries/{deliveryId}")[1]
207
+
208
+ @app.get("/v1/event-deliveries/{deliveryId}/chain")
209
+ def eventDeliveryChain(deliveryId: str, request: Request) -> dict[str, object]:
210
+ return service.handle("GET", str(request.url))[1]
211
+
212
+ @app.post("/mcp")
213
+ def mcpRpc(payload: dict[str, Any]) -> dict[str, object]:
214
+ return service.handle("POST", "/mcp", payload)[1]
215
+
216
+ @app.post("/v1/tools/nlp")
217
+ def toolNlp(payload: dict[str, Any]) -> dict[str, object]:
218
+ return service.handle("POST", "/v1/tools/nlp", payload)[1]
219
+
220
+ @app.post("/v1/tools/imageReader")
221
+ def toolImageReader(payload: dict[str, Any]) -> dict[str, object]:
222
+ return service.handle("POST", "/v1/tools/imageReader", payload)[1]
223
+
224
+ @app.post("/v1/tools/browserReader")
225
+ def toolBrowserReader(payload: dict[str, Any]) -> dict[str, object]:
226
+ return service.handle("POST", "/v1/tools/browserReader", payload)[1]
227
+
228
+ @app.get("/v1/signals/community/entities")
229
+ def communitySignalEntities() -> dict[str, object]:
230
+ return service.handle("GET", "/v1/signals/community/entities")[1]
231
+
232
+ @app.get("/v1/signals/community")
233
+ def communitySignalList(request: Request) -> dict[str, object]:
234
+ return service.handle("GET", str(request.url))[1]
235
+
236
+ @app.get("/v1/signals/community/{signalId}")
237
+ def communitySignalGet(signalId: str) -> dict[str, object]:
238
+ return service.handle("GET", f"/v1/signals/community/{signalId}")[1]
239
+
240
+ @app.get("/v1/agents")
241
+ def agentList() -> dict[str, object]:
242
+ return service.handle("GET", "/v1/agents")[1]
243
+
244
+ @app.get("/v1/tasks")
245
+ def taskList() -> dict[str, object]:
246
+ return service.handle("GET", "/v1/tasks")[1]
247
+
248
+ @app.get("/v1/tasks/{taskId}")
249
+ def taskGet(taskId: str) -> dict[str, object]:
250
+ return service.handle("GET", f"/v1/tasks/{taskId}")[1]
251
+
252
+ @app.get("/v1/mandates")
253
+ def mandateList() -> dict[str, object]:
254
+ return service.handle("GET", "/v1/mandates")[1]
255
+
256
+ @app.get("/v1/mandates/{mandateId}")
257
+ def mandateGet(mandateId: str) -> dict[str, object]:
258
+ return service.handle("GET", f"/v1/mandates/{mandateId}")[1]
259
+
260
+ @app.get("/v1/pay/escrows")
261
+ def escrowList() -> dict[str, object]:
262
+ return service.handle("GET", "/v1/pay/escrows")[1]
263
+
264
+ @app.get("/v1/pay/escrows/{escrowId}")
265
+ def escrowGet(escrowId: str) -> dict[str, object]:
266
+ return service.handle("GET", f"/v1/pay/escrows/{escrowId}")[1]
267
+
268
+ @app.get("/v1/agents/{agentId}")
269
+ def agentGet(agentId: str) -> dict[str, object]:
270
+ return service.handle("GET", f"/v1/agents/{agentId}")[1]
271
+
272
+ @app.get("/v1/receipts")
273
+ def receiptList() -> dict[str, object]:
274
+ return service.handle("GET", "/v1/receipts")[1]
275
+
276
+ @app.get("/v1/receipts/{receiptId}")
277
+ def receiptGet(receiptId: str) -> dict[str, object]:
278
+ return service.handle("GET", f"/v1/receipts/{receiptId}")[1]
279
+
280
+ @app.get("/v1/audit/pov")
281
+ def auditPovList() -> dict[str, object]:
282
+ return service.handle("GET", "/v1/audit/pov")[1]
283
+
284
+ @app.get("/v1/audit/pov/{povId}")
285
+ def auditPovGet(povId: str) -> dict[str, object]:
286
+ return service.handle("GET", f"/v1/audit/pov/{povId}")[1]
287
+
288
+ @app.get("/v1/audit/evidence")
289
+ def auditEvidenceList() -> dict[str, object]:
290
+ return service.handle("GET", "/v1/audit/evidence")[1]
291
+
292
+ @app.get("/v1/audit/evidence/{artifactId}")
293
+ def auditEvidenceGet(artifactId: str) -> dict[str, object]:
294
+ return service.handle("GET", f"/v1/audit/evidence/{artifactId}")[1]
295
+
296
+ @app.post("/v1/tasks")
297
+ def taskCreate(payload: dict[str, Any]) -> dict[str, object]:
298
+ return service.handle("POST", "/v1/tasks", payload)[1]
299
+
300
+ @app.post("/v1/tasks/{taskId}/update")
301
+ def taskUpdate(taskId: str, payload: dict[str, Any]) -> dict[str, object]:
302
+ return service.handle("POST", f"/v1/tasks/{taskId}/update", payload)[1]
303
+
304
+ @app.post("/v1/agents")
305
+ def agentRegister(payload: dict[str, Any]) -> dict[str, object]:
306
+ return service.handle("POST", "/v1/agents", payload)[1]
307
+
308
+ @app.post("/v1/agents/match")
309
+ def agentMatch(payload: dict[str, Any]) -> dict[str, object]:
310
+ return service.handle("POST", "/v1/agents/match", payload)[1]
311
+
312
+ @app.post("/v1/agents/delegate")
313
+ def agentDelegate(payload: dict[str, Any]) -> dict[str, object]:
314
+ return service.handle("POST", "/v1/agents/delegate", payload)[1]
315
+
316
+ @app.post("/v1/bridge/connectors")
317
+ def bridgeConnectorRegister(payload: dict[str, Any]) -> Any:
318
+ status, result = service.handle("POST", "/v1/bridge/connectors", payload)
319
+ return JSONResponse(status_code=status, content=result)
320
+
321
+ @app.post("/v1/bridge/connectors/ready/install")
322
+ def bridgeReadyConnectorInstall(payload: dict[str, Any]) -> dict[str, object]:
323
+ return service.handle("POST", "/v1/bridge/connectors/ready/install", payload)[1]
324
+
325
+ @app.post("/v1/bridge/connectors/match")
326
+ def bridgeConnectorMatch(payload: dict[str, Any]) -> Any:
327
+ status, result = service.handle("POST", "/v1/bridge/connectors/match", payload)
328
+ return JSONResponse(status_code=status, content=result)
329
+
330
+ @app.post("/v1/a2a/envelopes")
331
+ def a2aEnvelopeCreate(payload: dict[str, Any]) -> dict[str, object]:
332
+ return service.handle("POST", "/v1/a2a/envelopes", payload)[1]
333
+
334
+ @app.post("/v1/a2a/envelopes/{msgId}/update")
335
+ def a2aEnvelopeUpdate(msgId: str, payload: dict[str, Any]) -> dict[str, object]:
336
+ return service.handle("POST", f"/v1/a2a/envelopes/{msgId}/update", payload)[1]
337
+
338
+ @app.post("/v1/events")
339
+ def eventRecord(payload: dict[str, Any]) -> Any:
340
+ status, result = service.handle("POST", "/v1/events", payload)
341
+ return JSONResponse(status_code=status, content=result)
342
+
343
+ @app.post("/v1/event-subscriptions")
344
+ def eventSubscriptionCreate(payload: dict[str, Any]) -> Any:
345
+ status, result = service.handle("POST", "/v1/event-subscriptions", payload)
346
+ return JSONResponse(status_code=status, content=result)
347
+
348
+ @app.post("/v1/event-subscriptions/{subId}/update")
349
+ def eventSubscriptionUpdate(subId: str, payload: dict[str, Any]) -> Any:
350
+ status, result = service.handle("POST", f"/v1/event-subscriptions/{subId}/update", payload)
351
+ return JSONResponse(status_code=status, content=result)
352
+
353
+ @app.post("/v1/event-deliveries")
354
+ def eventDeliveryCreate(payload: dict[str, Any]) -> Any:
355
+ status, result = service.handle("POST", "/v1/event-deliveries", payload)
356
+ return JSONResponse(status_code=status, content=result)
357
+
358
+ @app.post("/v1/event-deliveries/claim")
359
+ def eventDeliveryClaim(payload: dict[str, Any]) -> Any:
360
+ status, result = service.handle("POST", "/v1/event-deliveries/claim", payload)
361
+ return JSONResponse(status_code=status, content=result)
362
+
363
+ @app.post("/v1/event-deliveries/claimBatch")
364
+ def eventDeliveryClaimBatch(payload: dict[str, Any]) -> Any:
365
+ status, result = service.handle("POST", "/v1/event-deliveries/claimBatch", payload)
366
+ return JSONResponse(status_code=status, content=result)
367
+
368
+ @app.post("/v1/event-deliveries/sweep")
369
+ def eventDeliverySweep(payload: dict[str, Any]) -> Any:
370
+ status, result = service.handle("POST", "/v1/event-deliveries/sweep", payload)
371
+ return JSONResponse(status_code=status, content=result)
372
+
373
+ @app.post("/v1/event-deliveries/{deliveryId}/retry")
374
+ def eventDeliveryRetry(deliveryId: str, payload: dict[str, Any]) -> Any:
375
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/retry", payload)
376
+ return JSONResponse(status_code=status, content=result)
377
+
378
+ @app.post("/v1/event-deliveries/{deliveryId}/fail")
379
+ def eventDeliveryFail(deliveryId: str, payload: dict[str, Any]) -> Any:
380
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/fail", payload)
381
+ return JSONResponse(status_code=status, content=result)
382
+
383
+ @app.post("/v1/event-deliveries/{deliveryId}/complete")
384
+ def eventDeliveryComplete(deliveryId: str, payload: dict[str, Any]) -> Any:
385
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/complete", payload)
386
+ return JSONResponse(status_code=status, content=result)
387
+
388
+ @app.post("/v1/event-deliveries/{deliveryId}/cancel")
389
+ def eventDeliveryCancel(deliveryId: str, payload: dict[str, Any]) -> Any:
390
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/cancel", payload)
391
+ return JSONResponse(status_code=status, content=result)
392
+
393
+ @app.post("/v1/event-deliveries/{deliveryId}/lease")
394
+ def eventDeliveryLease(deliveryId: str, payload: dict[str, Any]) -> Any:
395
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/lease", payload)
396
+ return JSONResponse(status_code=status, content=result)
397
+
398
+ @app.post("/v1/event-deliveries/{deliveryId}/release")
399
+ def eventDeliveryRelease(deliveryId: str, payload: dict[str, Any]) -> Any:
400
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/release", payload)
401
+ return JSONResponse(status_code=status, content=result)
402
+
403
+ @app.post("/v1/event-deliveries/{deliveryId}/update")
404
+ def eventDeliveryUpdate(deliveryId: str, payload: dict[str, Any]) -> Any:
405
+ status, result = service.handle("POST", f"/v1/event-deliveries/{deliveryId}/update", payload)
406
+ return JSONResponse(status_code=status, content=result)
407
+
408
+ @app.post("/v1/events/{eventId}/ack")
409
+ def eventAck(eventId: str, payload: dict[str, Any]) -> Any:
410
+ status, result = service.handle("POST", f"/v1/events/{eventId}/ack", payload)
411
+ return JSONResponse(status_code=status, content=result)
412
+
413
+ @app.post("/v1/hunt/discover")
414
+ def huntDiscover(payload: dict[str, Any]) -> dict[str, object]:
415
+ return service.handle("POST", "/v1/hunt/discover", payload)[1]
416
+
417
+ @app.post("/v1/orchestrator/run")
418
+ def orchestratorRun(payload: dict[str, Any]) -> dict[str, object]:
419
+ if payload.get("stream") and StreamingResponse is not None:
420
+ return StreamingResponse(_orchestrator_stream(payload), media_type="application/x-ndjson") # type: ignore[return-value]
421
+ result = service.handle("POST", "/v1/orchestrator/run", payload)[1]
422
+ _log_orchestrator(result)
423
+ return result
424
+
425
+ @app.post("/v1/benchmarks/local")
426
+ def benchmarkLocal(payload: dict[str, Any]) -> dict[str, object]:
427
+ return service.handle("POST", "/v1/benchmarks/local", payload)[1]
428
+
429
+ @app.post("/v1/tasks/{taskId}/resolve")
430
+ def taskResolve(taskId: str, payload: dict[str, Any]) -> dict[str, object]:
431
+ return service.handle("POST", f"/v1/tasks/{taskId}/resolve", payload)[1]
432
+
433
+ @app.post("/v1/mandates")
434
+ def mandateCreate(payload: dict[str, Any]) -> dict[str, object]:
435
+ return service.handle("POST", "/v1/mandates", payload)[1]
436
+
437
+ @app.post("/v1/mandates/{mandateId}/verify")
438
+ def mandateVerify(mandateId: str, payload: dict[str, Any]) -> dict[str, object]:
439
+ return service.handle("POST", f"/v1/mandates/{mandateId}/verify", payload)[1]
440
+
441
+ @app.post("/v1/pay/escrows")
442
+ def escrowCreate(payload: dict[str, Any]) -> dict[str, object]:
443
+ return service.handle("POST", "/v1/pay/escrows", payload)[1]
444
+
445
+ @app.post("/v1/pay/escrows/{escrowId}/update")
446
+ def escrowUpdate(escrowId: str, payload: dict[str, Any]) -> dict[str, object]:
447
+ return service.handle("POST", f"/v1/pay/escrows/{escrowId}/update", payload)[1]
448
+
449
+ @app.post("/v1/pay/settle")
450
+ def paySettle(payload: dict[str, Any]) -> dict[str, object]:
451
+ return service.handle("POST", "/v1/pay/settle", payload)[1]
452
+
453
+ @app.post("/v1/audit/evidence")
454
+ def auditEvidence(payload: dict[str, Any]) -> dict[str, object]:
455
+ return service.handle("POST", "/v1/audit/evidence", payload)[1]
456
+
457
+ @app.post("/v1/audit/pov")
458
+ def auditPov(payload: dict[str, Any]) -> dict[str, object]:
459
+ return service.handle("POST", "/v1/audit/pov", payload)[1]
460
+
461
+ @app.post("/v1/audit/receipts/verify")
462
+ def auditReceiptVerify(payload: dict[str, Any]) -> dict[str, object]:
463
+ return service.handle("POST", "/v1/audit/receipts/verify", payload)[1]
464
+
465
+ @app.post("/v1/audit/chain/verify")
466
+ def auditChainVerify(payload: dict[str, Any]) -> dict[str, object]:
467
+ return service.handle("POST", "/v1/audit/chain/verify", payload)[1]
468
+
469
+ @app.post("/v1/signals/community")
470
+ def communitySignal(payload: dict[str, Any]) -> dict[str, object]:
471
+ return service.handle("POST", "/v1/signals/community", payload)[1]
472
+
473
+ @app.post("/v1/signals/community/analyze")
474
+ def communitySignalAnalyze(payload: dict[str, Any]) -> dict[str, object]:
475
+ return service.handle("POST", "/v1/signals/community/analyze", payload)[1]
476
+
477
+ @app.post("/v1/signals/community/launch-task")
478
+ def communitySignalLaunchTask(payload: dict[str, Any]) -> dict[str, object]:
479
+ return service.handle("POST", "/v1/signals/community/launch-task", payload)[1]
480
+
481
+ @app.api_route("/{path:path}", methods=["GET", "POST"])
482
+ async def contractFallback(path: str, request: Request) -> Any:
483
+ target = str(request.url)
484
+ payload = await _fastapi_payload(request)
485
+ status, result = service.handle(request.method, target, payload, headers=dict(request.headers))
486
+ if request.method == "POST" and request.url.path == "/v1/orchestrator/run":
487
+ _log_orchestrator(result)
488
+ return JSONResponse(status_code=status, content=result)
489
+
490
+ else:
491
+
492
+ async def app(scope: dict[str, Any], receive: Any, send: Any) -> None:
493
+ if scope.get("type") != "http":
494
+ return
495
+ path = scope.get("path", "")
496
+ query = scope.get("query_string", b"").decode("latin1")
497
+ target = f"{path}?{query}" if query else path
498
+ method = scope.get("method", "GET")
499
+ if method == "POST":
500
+ payload = await _read_json_body(receive)
501
+ else:
502
+ payload = {}
503
+ if method == "POST" and path == "/v1/orchestrator/run" and payload.get("stream"):
504
+ await send(
505
+ {
506
+ "type": "http.response.start",
507
+ "status": 200,
508
+ "headers": [(b"content-type", b"application/x-ndjson")],
509
+ }
510
+ )
511
+
512
+ def emit(event: dict[str, Any]) -> None:
513
+ events.put(event)
514
+
515
+ def run() -> None:
516
+ try:
517
+ result = service.runOrchestrator(payload, onEvent=emit)
518
+ _log_orchestrator(result)
519
+ events.put({"type": "final", "result": result})
520
+ except Exception as exc:
521
+ events.put({"type": "error", "error": str(exc)[:500]})
522
+ finally:
523
+ events.put(None)
524
+
525
+ events: "queue.Queue[dict[str, Any] | None]" = queue.Queue()
526
+ threading.Thread(target=run, daemon=True).start()
527
+ while True:
528
+ event = await asyncio.to_thread(events.get)
529
+ if event is None:
530
+ break
531
+ await send({"type": "http.response.body", "body": _ndjson_event(event), "more_body": True})
532
+ await send({"type": "http.response.body", "body": b"", "more_body": False})
533
+ return
534
+ status, result = service.handle(method, target, payload, headers=_scope_headers(scope))
535
+ if method == "POST" and path == "/v1/orchestrator/run":
536
+ _log_orchestrator(result)
537
+ body = _json_response(result)
538
+ await send(
539
+ {
540
+ "type": "http.response.start",
541
+ "status": status,
542
+ "headers": [(b"content-type", b"application/json")],
543
+ }
544
+ )
545
+ await send({"type": "http.response.body", "body": body})
546
+
547
+
548
+ class _LocalHandler(BaseHTTPRequestHandler):
549
+ def do_GET(self) -> None:
550
+ status, payload = service.handle("GET", self.path, headers=dict(self.headers.items()))
551
+ body = _json_response(payload)
552
+ self.send_response(status)
553
+ self.send_header("Content-Type", "application/json")
554
+ self.send_header("Content-Length", str(len(body)))
555
+ self.end_headers()
556
+ self.wfile.write(body)
557
+
558
+ def do_POST(self) -> None:
559
+ length = int(self.headers.get("Content-Length", "0") or "0")
560
+ try:
561
+ payload = json.loads(self.rfile.read(length).decode("utf-8") or "{}")
562
+ except Exception:
563
+ payload = {}
564
+ payload = payload if isinstance(payload, dict) else {}
565
+ if self.path.split("?", 1)[0] == "/v1/orchestrator/run" and payload.get("stream"):
566
+ self._stream_orchestrator(payload)
567
+ return
568
+ status, result = service.handle(
569
+ "POST",
570
+ self.path,
571
+ payload,
572
+ headers=dict(self.headers.items()),
573
+ )
574
+ if self.path.split("?", 1)[0] == "/v1/orchestrator/run":
575
+ _log_orchestrator(result)
576
+ body = _json_response(result)
577
+ self.send_response(status)
578
+ self.send_header("Content-Type", "application/json")
579
+ self.send_header("Content-Length", str(len(body)))
580
+ self.end_headers()
581
+ self.wfile.write(body)
582
+
583
+ def log_message(self, format: str, *args: Any) -> None:
584
+ return
585
+
586
+ def _stream_orchestrator(self, payload: dict[str, Any]) -> None:
587
+ self.send_response(200)
588
+ self.send_header("Content-Type", "application/x-ndjson")
589
+ self.send_header("Cache-Control", "no-cache")
590
+ self.end_headers()
591
+ closed = False
592
+
593
+ def emit(event: dict[str, Any]) -> None:
594
+ nonlocal closed
595
+ if closed:
596
+ return
597
+ try:
598
+ self.wfile.write(_ndjson_event(event))
599
+ self.wfile.flush()
600
+ except (BrokenPipeError, ConnectionResetError):
601
+ closed = True
602
+
603
+ try:
604
+ result = service.runOrchestrator(payload, onEvent=emit)
605
+ if not closed:
606
+ _log_orchestrator(result)
607
+ emit({"type": "final", "result": result})
608
+ except Exception as exc:
609
+ if not closed:
610
+ emit({"type": "error", "error": str(exc)[:500]})
611
+
612
+
613
+ def _orchestrator_stream(payload: dict[str, Any]):
614
+ events: "queue.Queue[dict[str, Any] | None]" = queue.Queue()
615
+
616
+ def emit(event: dict[str, Any]) -> None:
617
+ events.put(event)
618
+
619
+ def run() -> None:
620
+ try:
621
+ result = service.runOrchestrator(payload, onEvent=emit)
622
+ _log_orchestrator(result)
623
+ events.put({"type": "final", "result": result})
624
+ except Exception as exc:
625
+ events.put({"type": "error", "error": str(exc)[:500]})
626
+ finally:
627
+ events.put(None)
628
+
629
+ threading.Thread(target=run, daemon=True).start()
630
+ while True:
631
+ event = events.get()
632
+ if event is None:
633
+ break
634
+ yield _ndjson_event(event)
635
+
636
+
637
+ def main() -> None:
638
+ service.runtime.assertBootable()
639
+ server = HTTPServer(("127.0.0.1", 8088), _LocalHandler)
640
+ print("Picux API scaffold listening on http://127.0.0.1:8088")
641
+ server.serve_forever()
642
+
643
+
644
+ def _scope_headers(scope: dict[str, Any]) -> dict[str, str]:
645
+ headers: dict[str, str] = {}
646
+ for key, value in scope.get("headers", []):
647
+ headers[key.decode("latin1")] = value.decode("latin1")
648
+ return headers
649
+
650
+
651
+ if __name__ == "__main__":
652
+ main()
@@ -0,0 +1 @@
1
+ """Benchmark command entrypoints."""
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+
6
+ from picux.benchmarks import LocalBenchmark
7
+
8
+
9
+ def main() -> None:
10
+ parser = argparse.ArgumentParser(description="Run Picux local protocol benchmarks.")
11
+ parser.add_argument("--iterations", type=int, default=100)
12
+ parser.add_argument("--pretty", action="store_true")
13
+ args = parser.parse_args()
14
+
15
+ report = LocalBenchmark(iterations=args.iterations).run()
16
+ print(json.dumps(report, ensure_ascii=True, sort_keys=True, indent=2 if args.pretty else None))
17
+
18
+
19
+ if __name__ == "__main__":
20
+ main()