152 lines
4.6 KiB
Plaintext
152 lines
4.6 KiB
Plaintext
---
|
|
title: "Python API"
|
|
slug: "python-api"
|
|
description: "Drive the OpenSRE agent in-process from your own Python code"
|
|
---
|
|
|
|
Use this when your Python code runs on the same machine as OpenSRE and you want
|
|
agent answers without shelling out to the CLI. To call OpenSRE over the network
|
|
instead, use the [HTTP API](/api).
|
|
|
|
## Prerequisites
|
|
|
|
The standalone CLI installer does not expose an importable package, so embed
|
|
from a source checkout:
|
|
|
|
```bash
|
|
git clone https://github.com/Tracer-Cloud/opensre.git
|
|
cd opensre && make install
|
|
```
|
|
|
|
Configure a provider once (`opensre onboard`) — the session API reuses the same
|
|
config and credentials as the CLI. Run your script inside the checkout's
|
|
environment with `uv run python your_script.py`.
|
|
|
|
Register adapters before the first turn (tools and investigation):
|
|
|
|
```python
|
|
from bootstrap.process import EMBEDDED_PROFILE, configure_process
|
|
|
|
configure_process(EMBEDDED_PROFILE)
|
|
```
|
|
|
|
## One API — chat and investigate
|
|
|
|
Every surface uses the same two verbs:
|
|
|
|
```python
|
|
from core.agent_harness import AgentSession
|
|
|
|
session = AgentSession.start()
|
|
result = session.chat("why is checkout-api slow?")
|
|
if result.answered:
|
|
print(result.primary_response_text)
|
|
|
|
report = session.investigate({"alert_name": "HighLatency", "severity": "warning"})
|
|
print(report.report)
|
|
```
|
|
|
|
`AgentSession.start()` resolves the environment, opens a session, and attaches
|
|
an agent with the standard ports — the same tools and prompts the interactive
|
|
shell uses. `investigate` does not require an attached chat agent; it uses the
|
|
payload runner installed by `configure_process`.
|
|
|
|
Always check `result.answered` before trusting chat text: when a turn fails (for
|
|
example the LLM provider is unreachable), the error message itself lands in
|
|
`result.primary_response_text`.
|
|
|
|
### Internal seams (not for hosts)
|
|
|
|
Chat hosts terminate at `dispatch_chat_turn` → `run_turn`. Investigation
|
|
terminates at the installed payload runner (`run_investigation_payload`). Do not
|
|
invent parallel public entrypoints.
|
|
|
|
## A conversation
|
|
|
|
Each `chat` call is one turn in the same session, so follow-ups see earlier
|
|
context:
|
|
|
|
```python
|
|
session.chat("list unresolved Sentry issues from the last 24 hours")
|
|
result = session.chat("which of those affect checkout?")
|
|
```
|
|
|
|
To resume a previous session instead of starting a new one, pass its ID:
|
|
|
|
```python
|
|
from core.agent_harness import AgentSession, SessionConfig
|
|
|
|
session = AgentSession.start(SessionConfig(session_id="abc123"))
|
|
```
|
|
|
|
## Your own grounding context
|
|
|
|
The agent builds its prompts from the session by default. To ground it your own
|
|
way — a different system prompt, your own retrieved context — pass a provider:
|
|
|
|
```python
|
|
from core.agent_harness import AgentSession, SessionConfig
|
|
|
|
session = AgentSession.start(SessionConfig(prompts=my_provider))
|
|
```
|
|
|
|
Omit it and the built-in provider applies
|
|
(`core.agent_harness.DefaultPromptContextProvider`). A custom provider must
|
|
satisfy `core.agent_harness.ports.PromptContextProvider`. The same `prompts=`
|
|
argument is accepted by `build_default_headless_agent` on the custom-ports path
|
|
below.
|
|
|
|
## Custom output and ports
|
|
|
|
`start()` buffers all output. To capture tool progress yourself — stream to a
|
|
websocket, collect for a report — build the agent explicitly and pass your own
|
|
sink:
|
|
|
|
```python
|
|
from core.agent_harness import (
|
|
AgentSession,
|
|
BufferOutputSink,
|
|
SessionConfig,
|
|
build_default_headless_agent,
|
|
)
|
|
|
|
session = AgentSession(SessionConfig())
|
|
startup = session.startup()
|
|
sink = BufferOutputSink()
|
|
agent = build_default_headless_agent(
|
|
session=startup.session,
|
|
output=sink,
|
|
prompts=my_provider, # optional — same port as SessionConfig.prompts
|
|
)
|
|
session.attach_agent(agent)
|
|
|
|
session.chat("summarize open incidents")
|
|
print(sink.lines) # rendered output lines
|
|
print(sink.streamed) # streamed answer chunks
|
|
```
|
|
|
|
Any object implementing the `OutputSink` protocol
|
|
(`core.agent_harness.ports.OutputSink`: `print`, `render_response_header`,
|
|
`render_error`, `stream`) works in place of `BufferOutputSink`.
|
|
`build_default_headless_agent` also accepts a custom logger, prompt surface,
|
|
and tool observers — see its docstring for the full port list.
|
|
|
|
## Your own tools
|
|
|
|
Register a package before the first tool lookup:
|
|
|
|
```python
|
|
from tools.registry import register_external_tool_package
|
|
import my_agent_tools
|
|
|
|
register_external_tool_package(my_agent_tools)
|
|
```
|
|
|
|
Two gotchas:
|
|
|
|
1. Declare tools with `surfaces=("action",)` (or include `"action"`). The
|
|
`@tool` default is `("investigation",)` only — the chat/Python-API action
|
|
loop will not see investigation-only tools.
|
|
2. Tools may live in the package's `__init__.py` or in submodules; both are
|
|
scanned after registration.
|