Metadata-Version: 2.4
Name: vedika-agent-sdk
Version: 0.2.0
Summary: Python client for the Vedika agent harness.
Author: XALEN Technology Private Limited
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/vedika-io/vedika-kit
Project-URL: Source, https://github.com/vedika-io/vedika-kit/tree/main/packages/agent-sdk-py
Project-URL: Issues, https://github.com/vedika-io/vedika-kit/issues
Keywords: vedika,agent,sdk,streaming,ui-message-stream
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<1,>=0.27
Provides-Extra: test
Requires-Dist: pytest>=7.4; extra == "test"
Requires-Dist: pytest-asyncio>=0.23; extra == "test"
Dynamic: license-file

# vedika-agent-sdk

Python client for the Vedika agent harness. Streams turns over the UI Message
Stream v1 wire, resumes with `Last-Event-ID`, and surfaces typed errors.

This client is **server-side only**: it authenticates with your tenant key
(`vk_live_...` or `vk_ent_...`), which must never reach a browser or app.

## Install

```bash
pip install vedika-agent-sdk
```

Python 3.10 or newer. `httpx` is installed with it and backs the default
transport.

## Quickstart (10 lines)

```python
import asyncio
from vedika_agent import create_agent

async def main():
    agent = create_agent("https://harness.example.com", api_key="...")
    thread = await agent.threads.create()
    turn = await agent.threads.send_turn(thread.id, {"kind": "text", "text": "Show my kundli for 1990-06-15."})
    async for chunk in turn:
        if chunk.type == "text-delta":
            print(chunk.delta, end="")
        if chunk.type == "data-vedika-artifact" and chunk.data.kind == "kundli":
            print("kundli ready:", chunk.data.id)
    await turn.done()

asyncio.run(main())
```

## Exchanging your key for a browser token

A browser gets a short-lived `vt_` token from your backend, never your key.
Register the page's exact origin first (`PUT /api/v1/admin/embed/origins`, with an admin session token, not your
tenant key).

```python
import os
import httpx

# Your backend only. Never run this in a browser.
response = httpx.post(
    f"{os.environ['VEDIKA_HARNESS_URL']}/api/v1/embed/tokens",
    headers={"authorization": f"Bearer {os.environ['VEDIKA_TENANT_KEY']}"},
    json={"end_user": "visitor:abc", "origin": "https://shop.example", "ttl_s": 600},
)
response.raise_for_status()  # 201
minted = response.json()  # token, tenant_id, expires_in_seconds
```

The token lives at most 15 minutes. To put the chat on a page, see
`mountWidget` in `@vedika-io/embed-loader`.

## API

### `create_agent(base_url, api_key, *, default_headers=None, transport=None)`

Returns a `VedikaAgent` with a `.threads` namespace.

- `await agent.threads.create(opts=None)` — `POST /api/v1/agent/threads`. Returns a `Thread`.
- `await agent.threads.send_turn(thread_id, input, opts=None)` — `POST /threads/{id}/turns` with `Accept: text/event-stream`. Returns a `Turn` you can iterate.
- `await agent.threads.resume_turn(turn_id, *, last_event_id)` — `GET /turns/{id}/events` with `Last-Event-ID`.
- `await agent.threads.cancel_turn(turn_id)` — `POST /turns/{id}/cancel`.

### `Turn`

- `async for chunk in turn` — async iterator over every chunk.
- `await turn.done()` — resolves on `finish` / `abort`, raises on `error`.
- `await turn.cancel()` — calls the cancel endpoint.
- `await turn.message_id()` — resolves to the `start.messageId` when seen.

### Chunk allowlist

`start`, `start-step`, `finish-step`, `reset-step`, `text-start` / `-delta` /
`-end`, `data-vedika-artifact`, `data-vedika-stage`, `data-vedika-tool-call`,
`data-vedika-tool-result`, `message-metadata`, `source-document`, `finish`,
`abort`, `error`. Anything else raises `ProtocolError`.

### Errors

`VedikaAgentError`, `AuthenticationError`, `NotFoundError`, `RateLimitError`
(with `retry_after_seconds`), `InvalidRequestError`, `ServerError`,
`TurnCancelledError`, `StreamError`, `ProtocolError`. Use
`is_vedika_agent_error(e)` to discriminate.

## Memory toggles

Pass `memory=MemoryToggles(old_memory=..., sensitive_info=...)` to
`send_turn`. They are sent as `x-vedika-memory-old` and
`x-vedika-memory-sensitive` request headers.

## Idempotency

Every `create` and `send_turn` carries an `Idempotency-Key` header. A fresh
UUID v4 is generated when you don't pass one; pass your own to retry safely.

## Version warnings

The server can tell the SDK that it is older than the minimum supported
version (the `X-Harness-Min-Sdk` response header). When that happens the SDK
emits one `UserWarning` per process through the standard `warnings` module,
naming the version to upgrade to, and keeps working. Nothing breaks: calls,
retries and errors behave exactly as before.

## Testing

```bash
pip install -e ".[test]"
pytest
```

Most tests inject a `FakeTransport` that speaks the documented wire. A few
run the default `httpx` transport against a local server to prove that a turn
streams chunk by chunk.

## Changelog

- **0.2.0**: fixes the default transport, which failed with `httpx.StreamConsumed`
  and buffered the whole turn before yielding anything. `httpx` is now a declared
  dependency (0.1.0 declared none, so the default transport could not run after
  `pip install`). License metadata uses an SPDX expression.
- **0.1.0**: first version.

## Licence

Apache-2.0. See `LICENSE`.
