Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
f5fa210
feat: add generic OpenAI-compatible DeepSeek V4 routing
erinepshovel-code Sep 8, 2026
dd8ab62
chore(provider): remove obsolete transport import
erinepshovel-code Sep 8, 2026
9488c2f
fix(provider): close compatible routing review gaps
erinepshovel-code Sep 8, 2026
6db4f6e
fix(catalog): enforce resolved model tier on presets
erinepshovel-code Sep 8, 2026
9a3a8b7
test(provider): cover exact review regressions
erinepshovel-code Sep 8, 2026
5491892
fix(provider): fingerprint semantic tool repeats
erinepshovel-code Sep 9, 2026
d0d7329
fix(providers): preserve routed reasoning state
erinepshovel-code Sep 9, 2026
0c6978d
fix(providers): harden stateless fan-out paths
erinepshovel-code Sep 9, 2026
2ab72d0
fix(providers): isolate fan-out routing context
erinepshovel-code Sep 9, 2026
2a981ae
fix(routing): preserve explicit model pins
erinepshovel-code Sep 9, 2026
d9e8139
fix(providers): close final review boundaries
erinepshovel-code Sep 9, 2026
11278b7
fix: close exact-head provider review findings
erinepshovel-code Sep 9, 2026
d40e4f7
fix: retain role routing for auto chat turns
erinepshovel-code Sep 9, 2026
d8eb1d2
repair auto routing gates and provenance
erinepshovel-code Sep 9, 2026
301959e
bind routed model identity through approval
erinepshovel-code Sep 9, 2026
2f18a94
add shared compatible-provider approval gate
erinepshovel-code Sep 9, 2026
efe9401
bind effective compatible-provider transport identity
erinepshovel-code Sep 9, 2026
259a50b
align OpenAI role policy with registered models
erinepshovel-code Sep 9, 2026
153c7e2
test compatible-provider approval preflight
erinepshovel-code Sep 9, 2026
2e4f3b4
test policy ownership and effective transport owner
erinepshovel-code Sep 9, 2026
86f06c7
bind repair witnesses into executable contract check
erinepshovel-code Sep 9, 2026
3880653
regenerate a0 msdmd collection
erinepshovel-code Sep 9, 2026
123cada
add PCEA-named shared approval gate
erinepshovel-code Sep 10, 2026
3e530c8
add approval dispatch and routed-owner witnesses
erinepshovel-code Sep 10, 2026
d98abb8
load PCEA approval service
erinepshovel-code Sep 10, 2026
c50b61b
route legacy OpenAI through concrete owner
erinepshovel-code Sep 10, 2026
838a4a1
scope explicit gate clearance to model call
erinepshovel-code Sep 10, 2026
4b893ae
bind approved replay context through transport
erinepshovel-code Sep 10, 2026
c504629
enforce approval scope at concrete tool dispatch
erinepshovel-code Sep 10, 2026
378f6cd
pin every resolved model through approval replay
erinepshovel-code Sep 10, 2026
32857b0
bind approval repair witnesses to executable check
erinepshovel-code Sep 10, 2026
9944495
refresh wheel source manifest
erinepshovel-code Sep 10, 2026
67df871
remove non-PCEA approval service path
erinepshovel-code Sep 10, 2026
4507065
regenerate a0 msdmd collection
erinepshovel-code Sep 10, 2026
48f322f
Clamp standalone reasoning effort to provider floor
erinepshovel-code Sep 10, 2026
a4254ce
Replace Boolean approval clearance with exact scopes
erinepshovel-code Sep 10, 2026
1fdda63
Surface exact-scope tool approval denials
erinepshovel-code Sep 10, 2026
254b99e
Bind current-turn approvals to tool scopes
erinepshovel-code Sep 10, 2026
251be40
Gate and capture every tool-capable transport
erinepshovel-code Sep 10, 2026
eef5374
Remove Boolean approval bypass and clamp effort floor
erinepshovel-code Sep 10, 2026
c5a9243
Propagate scoped tool approval denials
erinepshovel-code Sep 10, 2026
19bc985
Propagate Gemini tool approval denials
erinepshovel-code Sep 10, 2026
71a8d01
Persist deterministic scope-bound gate continuations
erinepshovel-code Sep 10, 2026
36a0746
Test standalone reasoning floor
erinepshovel-code Sep 10, 2026
7f8ce52
Test current-turn and scope-bound approvals
erinepshovel-code Sep 10, 2026
ff2ab4f
Verify centralized pending gate continuations
erinepshovel-code Sep 10, 2026
15f2581
Extend executable approval repair witnesses
erinepshovel-code Sep 10, 2026
c64ce3d
Regenerate module metadata for scope-bound approvals
erinepshovel-code Sep 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,34 @@
REGISTRY: us-central1-docker.pkg.dev

jobs:
provider-contracts:
name: Provider adapter contracts
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v5

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'

- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
with:
version: "0.11.18"
enable-cache: true

- name: Install Python dependencies
run: uv sync --frozen

- name: Run provider contracts
run: |
uv run pytest -q tests/test_open_comp_prov_v0.0.0alpha.py tests/test_open_comp_rout_v0.0.0alpha.py tests/test_aone_open_comp_adap_v0.0.0alpha.py tests/test_a0_package.py
uv run python -m python.tests.contract_runner --only check_openai_compatible_registry_wiring --only check_openai_compatible_repair_regressions

check-console-tabs:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
name: Console tab regression guard
runs-on: ubuntu-latest

Expand Down Expand Up @@ -125,7 +152,7 @@

deploy:
name: Build, push, deploy
needs: [check-console-tabs, deployment-readiness]
needs: [provider-contracts, check-console-tabs, deployment-readiness]
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && vars.GCP_DEPLOY_ENABLED == 'true'
runs-on: ubuntu-latest
permissions:
Expand Down Expand Up @@ -170,4 +197,4 @@
--max-instances=10 \
--memory=512Mi \
--cpu=1 \
--set-secrets="DATABASE_URL=a0p-database-url:latest,SESSION_SECRET=a0p-session-secret:latest,XAI_API_KEY=a0p-xai-api-key:latest,STRIPE_SECRET_KEY=a0p-stripe-secret-key:latest,STRIPE_WEBHOOK_SECRET=a0p-stripe-webhook-secret:latest"
--set-secrets="DATABASE_URL=a0p-database-url:latest,SESSION_SECRET=a0p-session-secret:latest,XAI_API_KEY=a0p-xai-api-key:latest,DEEPSEEK_API_KEY=a0p-deepseek-api-key:latest,STRIPE_SECRET_KEY=a0p-stripe-secret-key:latest,STRIPE_WEBHOOK_SECRET=a0p-stripe-webhook-secret:latest"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ playwright-report/
# Local secrets
.env
.venv/
.skill-lib/
.state/
android/keystore/
android/keystore.properties
Expand Down
8 changes: 6 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ Naming convention: `{name}.py` = self-contained module; `{name}_api.py` = thin d

### Key Python Services & Engines

- `python/services/inference.py` — Orchestrates LLM calls across registered energy providers (Grok / Gemini / Claude / OpenAI-style); resolves role, normalizes reasoning effort, injects tier-specific `prompt_context`.
- `python/services/inference.py` — Orchestrates LLM calls across registered energy providers (Grok / Gemini / Claude / OpenAI-compatible); resolves role, normalizes reasoning effort, injects tier-specific `prompt_context`.
- `python/services/providers/open_comp_prov_v0.0.0alpha.py` — Generic Responses/Chat Completions transport; endpoints, credential env names, models, and provider quirks stay in `python/config/providers.json`.
- `a0/prov_regi_v0.0.0alpha.py` + `a0/adapters/open_comp_adap_v0.0.0alpha.py` — Standalone/Termux provider selection from that same registry; `A0_PROVIDER` is explicit and fail-closed.
- `python/services/heartbeat.py` — Periodic tick: audit snapshots, memory checkpoints, PCNA propagation, sub-agent cleanup.
- `python/services/tool_executor.py` — Tool invocation with approval gates.
- `python/engine/ptcna_state.py` — durable Platonic-Agent adapter over the exactly pinned producer-owned PTCNA pipeline and UCNS receipt.
Expand Down Expand Up @@ -171,7 +173,7 @@ Auth is handled entirely by Express. Tiers (Free → Seeker → Operator → Pat

| Workflow | Trigger | Does |
|----------|---------|------|
| `.github/workflows/deploy.yml` | push/PR to `main` | Boots Postgres + Python backend, runs console-tab guard; on push to `main`, builds Docker image and deploys to Cloud Run (`a0p`, us-central1) |
| `.github/workflows/deploy.yml` | push/PR to `main` | Runs provider contracts, boots Postgres + Python for the console-tab guard; on push to `main`, builds and deploys to Cloud Run (`a0p`, us-central1) |
| `.github/workflows/clean-build-check.yml` | push/PR to `main` | Builds with `REPL_ID` unset and fails if any `@replit` reference leaks into the client bundle |

---
Expand All @@ -185,6 +187,8 @@ SESSION_SECRET # Express session encryption (no fallback in prod)
INTERNAL_API_SECRET # Express→Python shared secret (start-dev.sh generates a per-run value)
DATABASE_URL # PostgreSQL connection string
XAI_API_KEY # Grok energy provider
DEEPSEEK_API_KEY # DeepSeek V4 Flash/Pro; also used by standalone a0
A0_PROVIDER # Optional standalone provider id (e.g. deepseek-pro)
STRIPE_SECRET_KEY # Stripe billing
STRIPE_WEBHOOK_SECRET # Stripe webhook validation
ADMIN_USER_ID # User ID allowed to write prompt contexts
Expand Down
12 changes: 7 additions & 5 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,15 @@ values.
echo -n "postgres://..." | gcloud secrets create a0p-database-url --data-file=-
echo -n "your-session-secret" | gcloud secrets create a0p-session-secret --data-file=-
echo -n "xai-key" | gcloud secrets create a0p-xai-api-key --data-file=-
echo -n "deepseek-key" | gcloud secrets create a0p-deepseek-api-key --data-file=-
echo -n "sk_live_..." | gcloud secrets create a0p-stripe-secret-key --data-file=-
echo -n "whsec_..." | gcloud secrets create a0p-stripe-webhook-secret --data-file=-
```

Grant the service account access to each secret:

```bash
for SECRET in a0p-database-url a0p-session-secret a0p-xai-api-key a0p-stripe-secret-key a0p-stripe-webhook-secret; do
for SECRET in a0p-database-url a0p-session-secret a0p-xai-api-key a0p-deepseek-api-key a0p-stripe-secret-key a0p-stripe-webhook-secret; do
gcloud secrets add-iam-policy-binding $SECRET \
--member="serviceAccount:$SA" \
--role="roles/secretmanager.secretAccessor"
Expand All @@ -107,8 +108,9 @@ Replit Auth (OIDC) will not work outside Replit. Before going live on Cloud Run

## Pre-deploy checks

Every push runs the **Console tab regression guard** (`scripts/check-console-tabs.mjs`)
as a separate CI job before the build/deploy job. The guard spins up an ephemeral
Every push runs the provider adapter contracts and the **Console tab regression
guard** (`scripts/check-console-tabs.mjs`) as separate CI jobs before the
build/deploy job. The guard spins up an ephemeral
Postgres + Python backend in the runner, fetches `/api/v1/ui/structure`, and fails
the build if either:

Expand All @@ -117,8 +119,7 @@ the build if either:
2. `CUSTOM_TAB_RENDERERS` registers a `tab_id` that the API no longer returns
(an orphan / dead entry).

The deploy job has `needs: check-console-tabs`, so a failure here blocks the
deploy entirely.
The deploy job needs both gates, so either failure blocks deployment entirely.

To run the same check locally against a running dev server:

Expand Down Expand Up @@ -153,5 +154,6 @@ docker run -p 5000:5000 \
-e DATABASE_URL="..." \
-e SESSION_SECRET="..." \
-e XAI_API_KEY="..." \
-e DEEPSEEK_API_KEY="..." \
a0p:local
```
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

## The Agent

ZFAE (`a0(zeta fun alpha echo)`) is the single persistent agent running on the instrument. Large language models (GPT-5 mini, Gemini 2.5 Flash, Claude Sonnet 4.5, Grok 4 Fast) are treated as **energy providers** — they supply computational energy for each response but are not the agent itself.
ZFAE (`a0(zeta fun alpha echo)`) is the single persistent agent running on the instrument. Large language models (GPT-5 mini, Gemini 2.5 Flash, Claude Sonnet 4.5, Grok 4 Fast, DeepSeek V4) are treated as **energy providers** — they supply computational energy for each response but are not the agent itself.

Sub-agents (`a0(zeta{n})`) can be spawned to fork the PCNA instance, execute in parallel, and merge results back into the primary agent.

Expand Down Expand Up @@ -86,6 +86,21 @@ bash scripts/start-dev.sh

In development `scripts/start-dev.sh` generates a shared `INTERNAL_API_SECRET` automatically.

### Standalone a0 / Termux with DeepSeek

The standalone `run.sh` runtime reads the same `python/config/providers.json`
registry as the FastAPI service. With a DeepSeek key present it auto-selects
V4 Flash through the generic `openai-compatible` adapter. Pin V4 Pro explicitly:

```bash
export DEEPSEEK_API_KEY="..."
export A0_PROVIDER=deepseek-pro # omit for deepseek-v4-flash
printf '%s\n' '{"task_id":"ds1","input":{"text":"hello"},"tools_allowed":["none"],"mode":"analyze","hmmm":["direct model turn"]}' | ./run.sh
```

Provider configuration contains only the credential environment-variable name;
keys remain in the process environment and are never written to source.

### Useful commands

```bash
Expand Down Expand Up @@ -118,6 +133,7 @@ npx playwright test
| `ANTHROPIC_API_KEY` | Claude Sonnet 4.5 |
| `GEMINI_API_KEY` | Gemini 2.5 Flash |
| `OPENAI_API_KEY` | GPT-5 mini |
| `DEEPSEEK_API_KEY` | DeepSeek V4 Flash/Pro through the OpenAI-compatible adapter |
| `STRIPE_SECRET_KEY` | Stripe (donations + EDCMbone explainer) |
| `STRIPE_PUBLISHABLE_KEY` | Stripe embedded checkout |
| `STRIPE_WEBHOOK_SECRET` | Stripe webhook HMAC |
Expand Down
33 changes: 30 additions & 3 deletions a0/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# 0:1 0:0 0:0
# a0 package
# 0:1 0:0 0:0
# 21:1 0:0 0:0
"""a0 package and stable exports for versioned PCEA service modules."""

from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
import sys


def _load_versioned_module(public_name: str, filename: str):
qualified_name = f"{__name__}.{public_name}"
existing = sys.modules.get(qualified_name)
if existing is not None:
return existing
spec = spec_from_file_location(qualified_name, Path(__file__).with_name(filename))
if spec is None or spec.loader is None:
raise ImportError(f"cannot load {qualified_name} from {filename}")
module = module_from_spec(spec)
sys.modules[qualified_name] = module
spec.loader.exec_module(module)
return module


provider_registry = _load_versioned_module(
"provider_registry", "prov_regi_v0.0.0alpha.py"
)
load_provider_registry = provider_registry.load_provider_registry
resolve_openai_compatible_provider = provider_registry.resolve_openai_compatible_provider

__all__ = ["load_provider_registry", "resolve_openai_compatible_provider"]
# 21:1 0:0 0:0
35 changes: 32 additions & 3 deletions a0/adapters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,35 @@
# 3:0 0:0 0:2
# 27:0 0:0 0:3
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
import sys

from .claude_agent_adapter import ClaudeAgentAdapter
from .subagents import ALL_SUBAGENTS, MODE_SUBAGENTS

__all__ = ["ClaudeAgentAdapter", "ALL_SUBAGENTS", "MODE_SUBAGENTS"]
# 3:0 0:0 0:2

def _load_versioned_module(public_name: str, filename: str):
qualified_name = f"{__name__}.{public_name}"
existing = sys.modules.get(qualified_name)
if existing is not None:
return existing
spec = spec_from_file_location(qualified_name, Path(__file__).with_name(filename))
if spec is None or spec.loader is None:
raise ImportError(f"cannot load {qualified_name} from {filename}")
module = module_from_spec(spec)
sys.modules[qualified_name] = module
spec.loader.exec_module(module)
return module


openai_compatible_adapter = _load_versioned_module(
"openai_compatible_adapter", "open_comp_adap_v0.0.0alpha.py"
)
OpenAICompatibleAdapter = openai_compatible_adapter.OpenAICompatibleAdapter

__all__ = [
"ClaudeAgentAdapter",
"OpenAICompatibleAdapter",
"ALL_SUBAGENTS",
"MODE_SUBAGENTS",
]
# 27:0 0:0 0:3
Loading
Loading