نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی

مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت.
تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
This commit is contained in:
mjalmoudy94
2026-10-13 00:39:28 +03:30
commit 717e53a7ce
185 changed files with 39910 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
# `@agy/ai-runtime`
Drains the queue of tasks nobody has run yet, through the real run engine.
```bash
pnpm --filter @agy/ai-runtime run # one pass, then exit
pnpm --filter @agy/ai-runtime dev # poll every 30s
```
## Why it exists
The API can start a run inline — that is what the «اجرا» button does. But a
platform that *only* runs work on the request thread has two problems: a slow
model call holds a connection open, and a task created by anything other than a
button press (an automation, a seed script, a future integration) never runs at
all. This worker is the second driver.
## What it does
1. Find tasks in `new` or `triaged` state, oldest first.
2. Re-read each through `WorkforceService.get_task_or_404` — so the tenant check
and the "already closed" guard both apply. **The worker gets no privileged
bypass.**
3. Hand it to `WorkforceService.start_run` — the exact call the router makes.
4. Record the outcome and continue. One poisoned task must not block the queue
behind it.
Model routing, usage accounting, the run timeline and the artifact are all the
service's business; the worker owns none of it.
## Idempotency
A task that has been run is no longer in `new`/`triaged`, so a second pass finds
nothing. Re-running a completed task would double-bill the customer, which is
why the query filters on state rather than on "has a run".
## Implementation
`apps/api/app/workers/ai_runtime.py`. Tests:
`apps/api/tests/test_workers.py`.
## Extracting this into its own process
```bash
DATABASE_URL=... python -m app.workers ai-runtime --loop --interval 30
```
Note that the run engine currently executes inline within the worker process. To
make runs *asynchronous* for the customer (return `queued`, complete later), the
next step is to have the API enqueue and this worker claim, rather than having
the API call `start_run` directly. The port boundary for that already exists.
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@agy/ai-runtime",
"version": "0.1.0",
"private": true,
"description": "AI runtime worker — drains queued tasks through the run engine.",
"scripts": {
"once": "cd ../../apps/api && .venv/bin/python -m app.workers ai-runtime",
"dev": "cd ../../apps/api && .venv/bin/python -m app.workers ai-runtime --loop --interval 30",
"lint": "cd ../../apps/api && .venv/bin/python -m ruff check app/workers"
}
}
+39
View File
@@ -0,0 +1,39 @@
# `@agy/billing-worker`
Rolls the **usage ledger** into draft invoices — one invoice per organization
per billing period.
```bash
pnpm --filter @agy/billing-worker run # one pass, then exit (cron shape)
pnpm --filter @agy/billing-worker dev # long-running loop
```
## What it does
For every organization, for the requested period:
1. Skip the organization if the period already has an invoice (**idempotent** —
a cron job that fires twice must not bill twice).
2. Otherwise sum the usage ledger for the period.
3. Skip if the total is zero — no `$0` drafts littering the table.
4. Otherwise create a `draft` invoice carrying the ledger's total.
## What it deliberately does **not** do
- **It never invents an amount.** The ledger is the source of truth; the worker
only snapshots it. See `docs/architecture/overview.md` §8.
- **It never moves money.** Charging a card is `BillingService.settle_payment`,
behind an authenticated API call — not a background job.
## Implementation
`apps/api/app/workers/billing.py`. The service wiring comes from
`apps/api/app/application/container.py`, so this worker and the API compose
services identically. Tests: `apps/api/tests/test_workers.py`.
## Extracting this into its own process
The worker already opens its own database sessions and holds no request state,
so extraction is a deployment change, not a code change: run
`python -m app.workers billing --loop` as its own process with the same
`DATABASE_URL`, and point the cron/loop interval at your billing cycle.
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@agy/billing-worker",
"version": "0.1.0",
"private": true,
"description": "Billing worker — rolls the usage ledger into draft invoices, once per period.",
"scripts": {
"once": "cd ../../apps/api && .venv/bin/python -m app.workers billing",
"dev": "cd ../../apps/api && .venv/bin/python -m app.workers billing --loop",
"lint": "cd ../../apps/api && .venv/bin/python -m ruff check app/workers"
}
}
+43
View File
@@ -0,0 +1,43 @@
# `@agy/sandbox-gateway`
Housekeeping for the only sanctioned path for running untrusted code.
```bash
pnpm --filter @agy/sandbox-gateway run # one pass, then exit
pnpm --filter @agy/sandbox-gateway dev # poll every 10 minutes
```
## What it does
1. **Reaps idle sessions.** A sandbox session nobody has touched for hours is
still consuming CPU and disk on the provider. The worker stops it.
2. **Audits the stop.** It writes a `sandbox.reap` audit event, because "the
platform killed my sandbox" must be answerable from the audit log. A session
whose workspace has vanished is still stopped — just recorded without an
organization.
3. **Reports the safety envelope** at startup: which provider is live, the
command timeout, the output cap and the default egress policy. An operator
should be able to see the limits without reading the source.
## What it deliberately does **not** do
**It never executes a command.** The only command path is
`SandboxService.run_command`, reachable from the API under a tenant check. This
worker only *stops* things.
## Implementation
`apps/api/app/workers/sandbox_gateway.py`; the state change itself lives in
`SandboxService.reap_idle_sessions`, which is explicitly **not** tenant-scoped
and therefore not reachable from any tenant-scoped route. Tests:
`apps/api/tests/test_workers.py`.
## Extracting this into its own process
```bash
DATABASE_URL=... python -m app.workers sandbox-gateway --loop --interval 600
```
When a real provider (`SANDBOX_PROVIDER=daytona|e2b`) is configured, this is the
process that should own provider-side teardown, so that a crash of the API does
not leak sandboxes.
+11
View File
@@ -0,0 +1,11 @@
{
"name": "@agy/sandbox-gateway",
"version": "0.1.0",
"private": true,
"description": "Sandbox gateway worker — stops idle sandbox sessions and audits the stop.",
"scripts": {
"once": "cd ../../apps/api && .venv/bin/python -m app.workers sandbox-gateway",
"dev": "cd ../../apps/api && .venv/bin/python -m app.workers sandbox-gateway --loop --interval 600",
"lint": "cd ../../apps/api && .venv/bin/python -m ruff check app/workers"
}
}