Metadata-Version: 2.5
Name: agentship-service
Version: 0.0.2
Summary: AgentShip runtime service — the REST/SSE/WS surface over an agent, with pluggable auth adapters and tenant isolation. The irreducible in-app core a gateway cannot replace.
License-Expression: Apache-2.0
Requires-Python: >=3.13
Requires-Dist: agentship-core==0.0.2
Requires-Dist: fastapi>=0.115
Requires-Dist: sse-starlette>=2.1
Provides-Extra: a2a
Requires-Dist: a2a-sdk<2,>=1.1; extra == 'a2a'
Provides-Extra: serve
Requires-Dist: uvicorn[standard]>=0.30; extra == 'serve'
Description-Content-Type: text/markdown

# agentship-service

The AgentShip **runtime service** — the REST / SSE / WebSocket surface that turns a built
agent into an HTTP API, with pluggable authentication adapters and, above all, **tenant
isolation**.

This is the part of the stack a gateway *cannot* replace. A gateway (agentgateway) routes
requests and can authenticate them at the edge; but only the app can guarantee that every
stored read and write is scoped to the authenticated tenant. That guarantee lives here.

```python
from agentship.auth import ApiKeyAuthProvider, EnvApiKeyStore
from agentship_service import create_app

app = create_app(auth=ApiKeyAuthProvider(EnvApiKeyStore()))
```

## Integrations (we wire, we don't reinvent)

- **Streaming** — `/v1 …:stream` and A2A `message/stream` frame Server-Sent Events with
  [`sse-starlette`](https://github.com/sysid/sse-starlette)'s `EventSourceResponse`, which owns
  the wire encoding, keepalive comments, and client-disconnect cancellation. We only shape each
  `StreamEvent` into its event/data fields.
- **Auth** — `agentship.auth` ships pluggable providers; the optional OIDC path
  (`JwtAuthProvider`) delegates JWKS fetching, key-id resolution, and rotation to PyJWT's
  `PyJWKClient`. Tenant isolation on every read/write is the part that stays here.
- **A2A** — we speak the protocol with our own thin Pydantic wire models rather than pull in the
  protobuf-first `a2a-sdk`. A drift guard under the `agentship-service[a2a]` extra
  (`tests/test_a2a_conformance.py`) validates every AgentCard / Message / status frame against
  `a2a-sdk`'s own schema, so we cannot drift from the spec. See
  [`docs/decisions/0001-integrate-not-invent.md`](../../docs/decisions/0001-integrate-not-invent.md).

See `agentship serve` for the one-command server, and the phase-04 spec for the full
endpoint contract.
