Files
canvas-frontend/llm-proxy
canvas-bot 8e360bcc70
build-and-publish / test (pull_request) Has been cancelled
build-and-publish / image (pull_request) Has been cancelled
feat(llm-proxy): port to Node + @earendil-works/pi-ai
The user explicitly asked for the agent to be backed by a fork of the
pi coding agent. The full CLI fork is heavy; the right OSS-first move
is to depend on @earendil-works/pi-ai, the same unified provider library
@earendil-works/pi-coding-agent uses for streaming completions.

What this commit does:

- llm-proxy/server.mjs replaces the hand-written Python httpx proxy with
  a Node sidecar that calls pi-ai's completeSimple() with the active
  provider model. Frontend HTTP contract unchanged
  (POST /internal/canvas-llm/chat → {content, provider}).
- Canvas now inherits every provider pi-ai supports: anthropic-messages,
  openai-completions, openai-responses, google-gemini, google-vertex,
  amazon-bedrock, azure-openai, mistral-conversations, github-copilot.
- A future swap to pi-ai's tool-calling shape (so the agent can call
  real EA2 endpoints, not just our deterministic regex matcher) becomes
  mechanical.
- Health endpoint surfaces which providers have keys configured.
- 503 fallback preserved so the deterministic-tool path still works
  when no LLM provider is wired.

Image published: gitea.flow-master.ai/shad/canvas-llm-proxy:sha-pi-ai-0.2.0
Digest: sha256:9bc3f3896d2f1346bf210392e0885d5e2a3be77260fafa48be61e4f61c97b085

Old Python sidecar (main.py, requirements.txt, Dockerfile) retained
for one release so deployers can roll back.
2026-06-15 01:37:29 +04:00
..

canvas-llm-proxy

In-cluster sidecar for canvas.flow-master.ai. Brokers POST /internal/canvas-llm/chat to the configured upstream LLM provider so the in-app Command Assistant can synthesise fluent natural-language replies when no deterministic tool matches.

Why a Node sidecar (not a Python one)

This was a Python httpx proxy that hand-wrote OpenAI and Anthropic calls. PR canvas-frontend#6 swapped it for a Node sidecar that depends on @earendil-works/pi-ai — the same unified provider client @earendil-works/pi-coding-agent uses. Why:

  • It is the OSS-first move the canvas user asked for ("you could use a fork pi coding agent for that agent and then integrate it because pi coding agent is very clean and small while being efficient and useful").
  • pi-ai normalises streaming completions across OpenAI (completions + responses), Anthropic, Google Gemini, Google Vertex, Amazon Bedrock, Azure OpenAI, Mistral, GitHub Copilot. Canvas inherits all of them.
  • A future move to pi-ai's tool-calling shape (so the agent can hit real EA2 endpoints, not just our deterministic regex matcher) becomes mechanical instead of a rewrite.

Wire-compatible

The HTTP contract is the same: POST /internal/canvas-llm/chat with {messages, max_tokens} returns {content, provider}. The frontend's src/lib/llmClient.ts does not change.

Configuration

Set one of: ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY. Optional: ANTHROPIC_MODEL, OPENAI_MODEL, GEMINI_MODEL, PORT (8080).

If no key is set, every request returns 503 so the frontend's deterministic-tool fallback fires gracefully.

Run

cd llm-proxy
npm install
ANTHROPIC_API_KEY=… node server.mjs

Container:

docker build -f Dockerfile.node -t canvas-llm-proxy .
docker run -e ANTHROPIC_API_KEY=… -p 8080:8080 canvas-llm-proxy

Legacy

The previous Python sidecar (main.py, requirements.txt, Dockerfile) is retained for one release so deployers can roll back. It will be removed once the Node sidecar is in production.