Metadata-Version: 2.5
Name: insideai
Version: 0.2.0
Summary: Python client for the InsideAI API
Project-URL: Homepage, https://insideai.cpcyber.com
Author: CPCyber
License: MIT
License-File: LICENSE
Keywords: ai,chat,cpcyber,insideai
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: responses>=0.25; extra == 'dev'
Description-Content-Type: text/markdown

# insideai

Python client for the [InsideAI](https://insideai.cpcyber.com) API.

```bash
pip install insideai
```

## Quickstart

```python
import os

from insideai import InsideAI, create_chat, wait_for_chat

iai = InsideAI(api_key=os.environ["INSIDEAI_API_KEY"])

chat = create_chat(iai, "Summarize last quarter's findings.")
print(wait_for_chat(iai, chat["id"])["answer_text"])
```

`InsideAI(...)` holds your key, base URL and a pooled HTTP session. Build it once and pass it as the
first argument to everything else.

InsideAI answers asynchronously, so `create_chat` returns straight away. `wait_for_chat` polls for
you; call `get_chat` yourself if you would rather drive the loop (a job queue, a webhook, a UI that
shows progress).

## Examples

Complete, runnable scripts ship in the source distribution under `examples/`, and are the fastest
way to see the shape of an integration:

| Example | Shows |
|---|---|
| `examples/ask_a_question.py` | The smallest end-to-end call: ask, wait, print. |
| `examples/act_as_a_user.py` | Asking on behalf of one of your own users, and confirming act-as took effect before you do. |
| `examples/run_a_library_prompt.py` | Looking a prompt up by `safe_name` so its text stays editable in InsideAI. |
| `examples/continue_a_conversation.py` | Follow-up questions in one thread. |
| `examples/embed_session_endpoint.py` | The one backend endpoint embedded chat needs — and why it mints for the signed-in user only. |

```bash
export INSIDEAI_API_KEY=iaiak_…
python examples/ask_a_question.py "What changed this week?"
```

## API keys

Keys never expire and are revoked from the InsideAI admin UI. They come in two kinds:

- **Client-wide** — acts as your organization's API service account, and may act as any member of your
  org by passing `act_as=<their email>`.
- **User-specific** — always acts as one person. Passing `act_as` to one of these is an error rather
  than a silent no-op, so a misconfigured integration fails loudly.

```python
me(iai)  # the service account
me(iai, act_as="alice@example.com")  # Alice, with Alice's permissions
```

Acting as someone means exactly that: their org, their permissions, their row-level access, and
anything created shows up in their own InsideAI history. You can only act as an active member of the
key's organization.

**Never send a key to a browser.** For embedded chat, mint a one-time code server-side with
`embed_session` and hand that to the frontend — see
`examples/embed_session_endpoint.py` and
[`@cpcyber/insideai`](https://www.npmjs.com/package/@cpcyber/insideai).

## Functions

Every function takes the client first and an optional `act_as=`.

| Function | Returns |
|---|---|
| `me(iai)` | `{"email", "display_name", "client", "acting_as", "key"}` |
| `prompts(iai, safe_name=None)` | Visible prompt-library prompts, fully paged. `safe_name` is the stable slug to key config off, and filtering on it returns at most one. |
| `create_chat(iai, ask, conversation=None, project=None)` | The new chat. InsideAI answers asynchronously — poll it. Omit `conversation` to start a new thread. |
| `get_chat(iai, chat_id)` | `{"id", "ask", "answer_text", "answer_blocks", "done", "ts_asked", "ts_answered", "conversation", "eta"}` |
| `wait_for_chat(iai, chat_id, interval=2, timeout=120)` | The same chat once `done`. Raises `InsideAITimeoutError` rather than handing back a half-answered one. |
| `chats(iai, conversation=None)` | Every chat the acting user can see. |
| `embed_session(iai, email=None)` | `{"enabled", "code", "chat_url", "mini_url", "expires_in"}` for mounting embedded chat. |

`answer_text` is the answer flattened to plain text. `answer_blocks` is the original display-block
list (`{display, params}`) if you want to render charts and images yourself.

## Errors

`InsideAIError` for anything that isn't a 2xx, carrying `.status` and `.payload`. Two subclasses are
worth catching on their own: `InsideAIAuthError` for 401/403 — a rejected key never becomes valid on
a retry — and `InsideAITimeoutError` when `wait_for_chat` gives up on a chat that is still being
answered. GETs retry twice on connection failures and 502/503/504; nothing else is retried, since a
4xx is an answer.

```python
from insideai import InsideAIAuthError, InsideAIError

try:
    chat = create_chat(iai, "hello")
except InsideAIAuthError:
    ...  # key revoked, or acting as someone you may not
except InsideAIError as exc:
    log.warning("InsideAI %s: %s", exc.status, exc.payload)
```

## Other environments

`base_url` defaults to production. Point it elsewhere if InsideAI gave you a different endpoint:

```python
iai = InsideAI(api_key=..., base_url="https://your-insideai-endpoint/")
```

## Layout

Import everything from the package root — `from insideai import create_chat` — which is the surface
this package keeps stable. Underneath:

| Module | What it owns |
|---|---|
| `client.py` | `InsideAI()`: the key, the base URL, the pooled session and its retry policy. |
| `api.py` | Everything that knows about HTTP — URL building, the act-as header, pagination, turning a failure into an exception. The endpoint modules never touch `requests`. |
| `endpoints/` | One module per `/api/v1/` resource: `chats.py`, `prompts.py`, `identity.py`, `embed.py`. Each knows its path and its arguments, nothing more. |
| `errors.py` | The exception classes, and the mapping from a status code onto one. |
| `constants.py` | The strings both halves share: default base URL, API prefix, auth scheme, act-as header. |
