Found wiring spritzer in as fountain's local data plane (INTENTIUS/fountain-ops#34). Provisioning works beautifully; the turn does not complete, and it stops at one endpoint.
What happens
fountain provisions a sprite, writes files into its filesystem, starts a turn — and then tries to reattach to any existing runtime session. That call fails:
[warning] list_sessions failed during reattach:
{:api_error, 426, "WebSocket protocol violation: Connection header \"\" does not contain Upgrade\n"}
and the turn is abandoned:
event: stage reattach started {"sprite_name":"fountain-c816d477-e62ef95e"}
event: stage reattach interrupted {"reason":"list_sessions_failed","outcome":"turn_orphaned"}
Reproducible on every conversation, including immediately after a fresh app rollout, on spritzer 0.4.1.
The cause
fountain issues a plain HTTP request against the exec path. spritzer serves GET /v1/sprites/{id}/exec as a control WebSocket only, so the request is rejected with 426 Upgrade Required before any command runs.
The real Sprites API evidently accepts a non-upgraded request on that path (or exposes a separate one for listing sessions) — fountain is a real client and this is what it does.
What I am reasonably confident about, and what I am not
Confident: the 426 is spritzer's, it is the first thing that fails, and it is what orphans the turn. The health endpoint lists GET /v1/sprites/{id}/exec (control WebSocket) and nothing else on that path.
Not confident: exactly which request shape fountain sends, or whether the real API answers it on the same path or a different one. Worth reading Sprites.list_sessions in the Elixir SDK against the upstream API docs before choosing a fix — the answer decides whether this is a missing endpoint or a missing non-WebSocket mode on an existing one.
Why it is worth fixing
Everything up to this point already works, which is what makes it frustrating rather than fundamental. spritzer accepts the create, and fountain writes a real payload into the sprite filesystem — its skill doc and a /home/sprite/.env with a scoped token and conversation id. The emulator is one endpoint away from carrying a fountain conversation to a completed turn.
That is the difference between "the local deployment provisions a sandbox" and "the local deployment runs a conversation", and it is the last thing standing between fountain-ops and an offline loop a beginner can watch work end to end.
Not asking for an agent runtime — the echo-back interpreter is fine and the caveats are documented downstream. Just for the turn to be able to finish.
Found wiring spritzer in as fountain's local data plane (INTENTIUS/fountain-ops#34). Provisioning works beautifully; the turn does not complete, and it stops at one endpoint.
What happens
fountain provisions a sprite, writes files into its filesystem, starts a turn — and then tries to reattach to any existing runtime session. That call fails:
and the turn is abandoned:
Reproducible on every conversation, including immediately after a fresh app rollout, on spritzer 0.4.1.
The cause
fountain issues a plain HTTP request against the exec path. spritzer serves
GET /v1/sprites/{id}/execas a control WebSocket only, so the request is rejected with426 Upgrade Requiredbefore any command runs.The real Sprites API evidently accepts a non-upgraded request on that path (or exposes a separate one for listing sessions) — fountain is a real client and this is what it does.
What I am reasonably confident about, and what I am not
Confident: the 426 is spritzer's, it is the first thing that fails, and it is what orphans the turn. The health endpoint lists
GET /v1/sprites/{id}/exec (control WebSocket)and nothing else on that path.Not confident: exactly which request shape fountain sends, or whether the real API answers it on the same path or a different one. Worth reading
Sprites.list_sessionsin the Elixir SDK against the upstream API docs before choosing a fix — the answer decides whether this is a missing endpoint or a missing non-WebSocket mode on an existing one.Why it is worth fixing
Everything up to this point already works, which is what makes it frustrating rather than fundamental. spritzer accepts the create, and fountain writes a real payload into the sprite filesystem — its skill doc and a
/home/sprite/.envwith a scoped token and conversation id. The emulator is one endpoint away from carrying a fountain conversation to a completed turn.That is the difference between "the local deployment provisions a sandbox" and "the local deployment runs a conversation", and it is the last thing standing between fountain-ops and an offline loop a beginner can watch work end to end.
Not asking for an agent runtime — the echo-back interpreter is fine and the caveats are documented downstream. Just for the turn to be able to finish.