Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bookstack_agent/api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ async def lifespan(application: FastAPI) -> AsyncGenerator[None, None]:
),
token_id=os.environ["BOOKSTACK_TOKEN_ID"],
token_secret=os.environ["BOOKSTACK_TOKEN_SECRET"],
llm_base_url=os.environ.get("LLM_BASE_URL"),
)

# OrderedDict preserves insertion order for LRU-style eviction
Expand Down Expand Up @@ -116,7 +117,7 @@ async def lifespan(application: FastAPI) -> AsyncGenerator[None, None]:

def get_agent() -> BookstackQAAgent:
"""Return the shared BookstackQAAgent."""
agent: BookstackQAAgent = app.state.agent
agent: BookstackQAAgent | None = getattr(app.state, "agent", None)
if agent is None:
raise HTTPException(status_code=503, detail="Agent not initialised")
return agent
Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ packages = ["src/aieng_bot"]
[dependency-groups]
dev = [
"codecov>=2.1.13",
"cryptography>=46.0.7", # Pinning version to address vulnerabilities CVE-2026-26007, CVE-2026-34073, CVE-2026-39892
"pyjwt>=2.13.0", # Pinning version to address vulnerabilities PYSEC-2026-175 PYSEC-2026-177 PYSEC-2026-178 PYSEC-2026-179
"cryptography>=48.0.1", # Pinning version to address vulnerabilities CVE-2026-26007, CVE-2026-34073, CVE-2026-39892, GHSA-537c-gmf6-5ccf
"pyjwt>=2.13.0", # Pinning version to address vulnerabilities CVE-2026-32597, PYSEC-2026-175, PYSEC-2026-176, PYSEC-2026-177, PYSEC-2026-178, PYSEC-2026-179
"mypy>=1.14.1",
"nbqa>=1.9.1",
"pip>=26.1.2", # Pinning version to address vulnerabilities CVE-2026-1703, CVE-2026-6357, PYSEC-2026-196
Expand Down Expand Up @@ -78,10 +78,10 @@ docs = [

bookstack-api = [
"fastapi>=0.115.0",
"starlette>=1.0.1", # Pinning version to address PYSEC-2026-161
"starlette>=1.3.1", # Pinning version to address PYSEC-2026-161, CVE-2026-54282, CVE-2026-54283
"google-cloud-storage>=2.0.0",
"httptools>=0.6.0",
"python-multipart>=0.0.27", # Pinning version to address vulnerabilities CVE-2026-40347, CVE-2026-42561
"python-multipart>=0.0.31", # Pinning version to address vulnerabilities CVE-2026-40347, CVE-2026-42561, CVE-2026-53538, CVE-2026-53539, CVE-2026-53540
"uvicorn[standard]>=0.32.0",
"uvloop>=0.21.0",
]
Expand Down
20 changes: 16 additions & 4 deletions src/aieng_bot/bookstack/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ class BookstackQAAgent:
token_secret : str
BookStack API token secret.
api_key : str, optional
Anthropic API key. Defaults to ``ANTHROPIC_API_KEY`` env var.
API key for the LLM backend. Defaults to ``ANTHROPIC_API_KEY`` env var.
model : str, optional
Claude model name. Defaults to :func:`~aieng_bot.config.get_model_name`.
Model name. Defaults to :func:`~aieng_bot.config.get_model_name`.
llm_base_url : str, optional
Base URL for the LLM backend. Set to point at a gateway (e.g.
``https://proxy.vectorinstitute.ai``) instead of the Anthropic API
directly. Defaults to ``LLM_BASE_URL`` env var, or the Anthropic API
if unset.

"""

Expand All @@ -60,14 +65,21 @@ def __init__(
token_secret: str,
api_key: str | None = None,
model: str | None = None,
llm_base_url: str | None = None,
) -> None:
"""Initialise the agent."""
resolved_key = api_key or os.environ.get("ANTHROPIC_API_KEY")
if not resolved_key:
raise ValueError("ANTHROPIC_API_KEY environment variable not set")

self._sync_client = anthropic.Anthropic(api_key=resolved_key)
self._async_client = anthropic.AsyncAnthropic(api_key=resolved_key)
resolved_llm_base_url = llm_base_url or os.environ.get("LLM_BASE_URL")

self._sync_client = anthropic.Anthropic(
api_key=resolved_key, base_url=resolved_llm_base_url
)
self._async_client = anthropic.AsyncAnthropic(
api_key=resolved_key, base_url=resolved_llm_base_url
)
self.bookstack = BookStackClient(base_url, token_id, token_secret)
self.model = model or get_model_name()

Expand Down
Loading
Loading