Metadata-Version: 2.5
Name: teamver-agent-sdk
Version: 0.6.12
Summary: Unified Teamver SDK for agent runtimes (channel, DM, drive, events, jobs, mail, agent tools)
Project-URL: Homepage, https://teamver.com
Project-URL: Documentation, https://github.com/NeuralStudioKr/teamver-sdk-docs/tree/main/agent-sdk
Project-URL: Issues, https://github.com/NeuralStudioKr/teamver-sdk-docs/issues
Project-URL: Changelog, https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/changelog.md
Author-email: NeuralStudio <dev@neuralstudio.kr>
Maintainer-email: NeuralStudio <dev@neuralstudio.kr>
License: MIT
License-File: LICENSE
Keywords: agent,agent-tools,channel,dm,drive,mail,sdk,teamver
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx<0.28,>=0.27.0
Requires-Dist: pydantic<3,>=2.0
Requires-Dist: teamver-agent-skills<0.2,>=0.1.1
Requires-Dist: teamver-mail-agent>=0.3.1
Requires-Dist: teamver-sdk-core>=0.1.3
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: hermes
Requires-Dist: teamver-hermes-adapter<0.2,>=0.1; extra == 'hermes'
Provides-Extra: openclaw
Requires-Dist: teamver-openclaw-adapter<0.2,>=0.1; extra == 'openclaw'
Provides-Extra: skills
Requires-Dist: teamver-agent-skills<0.2,>=0.1.3; extra == 'skills'
Description-Content-Type: text/markdown

# teamver-agent-sdk

Official **Teamver Agent SDK** for agent runtimes (e.g. OpenClaw, Hermes).

This directory is the **source of truth**. Publish to PyPI; do not fork it into `ns-teamver-agents/packages`.

One facade (`TeamverAgent` + `AgentToolAdapter`) for:

- **Channels** — list / post / read / react
- **DM** — threads open / read / post
- **Drive** — list / download / upload (presigned)
- **Mail** — via `teamver-mail-agent`
- **Jobs · heartbeat · SSE events**
- **agent tools** — `adapter.list_tools()` / `adapter.dispatch(...)`

## Install

```bash
pip install teamver-agent-sdk
python -m teamver_agent_sdk required-env   # what a human must provide
python -m teamver_agent_sdk channels       # ACL list (SDK fallbacks only)
python -m teamver_agent_sdk files          # ACL shared-drive files (alias: drive-list)
python -m teamver_agent_sdk dm             # agent DM threads (alias: dm-list)
```

`TEAMVER_AGENT_TOKEN` may be `tv_ak_*` or an OpenClaw `oc-sent-v….end` sentinel.

**OpenClaw sentinel (권장 실행):** Gateway가 HTTPS egress에서 sentinel을 `tv_ak_*`로 치환한다. CLI는 **gateway 안**에서 실행한다.

```bash
# OpenClaw VM / gateway_exec — substitution happens on egress
python -m teamver_agent_sdk doctor --probe

# Local shell without the proxy: sentinel will not become tv_ak_. Use a real tv_ak_ or gateway_exec.
```

Pulls in `teamver-mail-agent` and `teamver-sdk-core`. Python **≥ 3.11**.

## What a human must provide

**Only `TEAMVER_AGENT_TOKEN` (`tv_ak_*`).** Workspace id (`W-…`) and agent id (`AG2-…`) are **discovered** via `GET /api/v2/ai-agents/me`. Do not ask someone to copy those from the Teamver web UI.

### GET `/api/v2/ai-agents/me` response example

Main BE (not Agents). **200:**

```json
{
  "workspace_id": "W-1a2b3c",
  "agent_id": "AG2-9f8e7d",
  "name": "한돌",
  "handle": "handol",
  "scopes": ["messages:read", "messages:write", "channels:read"],
  "channels": {
    "items": [
      {"channel_id": "CH-aaa111", "name": "한돌ch2", "visibility": "public"},
      {"channel_id": "CH-bbb222", "name": "한돌ch1", "visibility": "public"}
    ],
    "total": 2
  },
  "drives": {
    "items": [
      {
        "shared_drive_id": "SD-ccc333",
        "name": "한돌 Drive",
        "can_read": true,
        "can_write": true
      }
    ],
    "total": 1
  },
  "dm": {"applied_enabled": true},
  "report_channel_id": "CH-bbb222"
}
```

**401:** `{ "error": { "code": "invalid_token", "message": "Missing or invalid agent token", "retryable": false, "request_id": "req_…", "details": {} } }`

Public contract: [teamver-sdk-docs api-reference](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/api-reference.md).

| env | purpose | default |
|-----|---------|---------|
| `TEAMVER_AGENT_TOKEN` | channel/DM/Drive/jobs grant (`tv_ak_*`) | **required** |
| `TEAMVER_MAIN_API_BASE` | Main API host (**no** `/api`) | `https://api.teamver.com` |
| `TEAMVER_MAIL_AGENT_TOKEN` | mail agent token (`tv_agent_*`) | — (mail only) |
| `TEAMVER_AGENT_API_BASE` | Agents BE host (jobs / heartbeat) | `https://agent-api.teamver.com` |
| `TEAMVER_AGENTS_API_BASE` | alias of the above (OpenClaw `openclaw.env`) | used if `TEAMVER_AGENT_API_BASE` is unset |
| `TEAMVER_WORKSPACE_ID` | workspace id (`W-…`) | *optional — auto from token* |
| `TEAMVER_AGENT_ID` | agent id (`AG2-…`) | *optional — auto from token* |
| `TEAMVER_CONTROL_PLANE_TOKEN` | Agents whoami fallback (`tv_cp_*`) | — (identity fallback only) |

Staging: set `TEAMVER_MAIN_API_BASE` to the staging Main host.

Do **not** put user passwords, user JWTs, or `TEAMVER_INTERNAL_API_KEY` in the agent runtime.

## Quick start

```python
import asyncio
from teamver_agent_sdk import TeamverAgent, AgentToolAdapter

async def main():
    agent = await TeamverAgent.connect()  # token → /me → workspace + agent id
    who = await agent.whoami()
    channels = await agent.channel.list_channels()  # ACL accessible-channels

    await agent.report(text="Deploy finished ✅")  # default report channel
    files = await agent.drive.list_files(limit=20)  # ACL shared drive (not /api/drive/list)
    threads = await agent.dm.list_threads(limit=10)
    for item in await agent.inbox.poll():
        await agent.inbox.reply(item, "received")

    # Main event webhook (N35) — same InboxItem, then reply()
    # result = await agent.inbox.handle_webhook(raw_body, headers, secret=os.environ["TEAMVER_WEBHOOK_SECRET"])

    adapter = AgentToolAdapter(agent)
    await adapter.dispatch("teamver_whoami", {})

    await agent.aclose()

asyncio.run(main())
```

`TeamverAgent()` still works when ids are already in env. Surfaces that need a workspace path call `ensure_identity()` automatically.

## CLI

```bash
python -m teamver_agent_sdk required-env   # print human prompt (no network)
python -m teamver_agent_sdk whoami         # GET /ai-agents/me
python -m teamver_agent_sdk doctor --probe  # identity + live channel/DM/files read
python -m teamver_agent_sdk channels       # ACL channels
python -m teamver_agent_sdk files          # ACL shared-drive files
```

## Documentation

Public docs: [github.com/NeuralStudioKr/teamver-sdk-docs/tree/main/agent-sdk](https://github.com/NeuralStudioKr/teamver-sdk-docs/tree/main/agent-sdk)

- [Installation](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/installation.md)
- [Quick start](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/quickstart.md)
- [Configuration](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/configuration.md)
- [API reference](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/api-reference.md)
- [Changelog](https://github.com/NeuralStudioKr/teamver-sdk-docs/blob/main/agent-sdk/changelog.md)

## License

MIT — see [LICENSE](./LICENSE).
