utils¶
Shared utilities — LLM calls, RAG retrieval, slugification, error handling.
add_monitor_hook(hook)
¶
Register a monitoring callback for LLM calls.
The hook is called after every successful LLM API response with (request_body, response_data) arguments. Useful for observability, logging, or analytics integration. Exceptions raised by hooks are silently caught to avoid disrupting the main flow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hook
|
Callable accepting (request_body: dict, response_data: dict). |
required |
call_llm(messages, *, temperature=None, max_tokens=None, response_format=None, timeout=None, tools=None, api_key=None, thinking=None, reasoning_effort=None)
¶
Synchronous LLM API call to DeepSeek.
Sends a chat completion request and returns the full JSON response. Supports optional tool definitions, response format constraints (e.g., json_object), configurable temperature/max_tokens, and thinking-mode overrides.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[dict]
|
List of message dicts in OpenAI-compatible format. |
required |
temperature
|
float | None
|
Sampling temperature. Defaults to LLM_TEMPERATURE. Ignored by the API when thinking mode is enabled. |
None
|
max_tokens
|
int | None
|
Maximum tokens in response. Defaults to LLM_MAX_TOKENS. In thinking mode this budget covers reasoning + content. |
None
|
response_format
|
dict | None
|
Optional format constraint dict (e.g., {"type": "json_object"}). |
None
|
timeout
|
int | None
|
Request timeout in seconds. Defaults to LLM_TIMEOUT. |
None
|
tools
|
list | None
|
Optional list of tool/function definitions. |
None
|
api_key
|
str | None
|
Optional per-user API key. Falls back to global DEEPSEEK_API_KEY. |
None
|
thinking
|
bool | None
|
Override LLM_THINKING_ENABLED for this call. |
None
|
reasoning_effort
|
str | None
|
Override LLM_REASONING_EFFORT ("low"/"high"/"max"). |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
Full JSON response dict from the LLM API. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
On timeout, connection error, HTTP error, or empty/invalid response from the API. |
call_llm_stream(messages, *, temperature=None, max_tokens=None, timeout=None, tools=None, api_key=None, thinking=None, reasoning_effort=None, http_client=None)
async
¶
Stream tokens from the DeepSeek API via httpx.AsyncClient.stream().
Sends a chat completion request with streaming enabled. Parses SSE chunks from the response, yielding TokenEvent for each content delta, StatusEvent when reasoning (chain-of-thought) deltas arrive, ToolCallEvent when finish_reason='tool_calls' is detected, and TruncatedEvent when finish_reason='length' cuts the reply short.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[dict]
|
List of message dicts (role + content) forming the conversation context. |
required |
temperature
|
float | None
|
Sampling temperature (defaults to LLM_TEMPERATURE). |
None
|
max_tokens
|
int | None
|
Max completion tokens (defaults to LLM_MAX_TOKENS). In thinking mode this budget covers reasoning + content. |
None
|
timeout
|
int | None
|
Request timeout in seconds (defaults to LLM_TIMEOUT). |
None
|
tools
|
list | None
|
Optional list of tool schema dicts for function calling. |
None
|
api_key
|
str | None
|
Optional per-user API key override. |
None
|
thinking
|
bool | None
|
Override LLM_THINKING_ENABLED for this call. |
None
|
reasoning_effort
|
str | None
|
Override LLM_REASONING_EFFORT ("low"/"high"/"max"). |
None
|
http_client
|
'httpx.AsyncClient | None'
|
Optional shared httpx.AsyncClient for connection reuse. When provided, avoids TLS handshake per call. |
None
|
Yields:
| Type | Description |
|---|---|
AsyncGenerator
|
TokenEvent for each content delta, StatusEvent for reasoning |
AsyncGenerator
|
liveness, ToolCallEvent for tool call finish reasons, and |
AsyncGenerator
|
TruncatedEvent when finish_reason='length' (max_tokens cut |
AsyncGenerator
|
the reply short). |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
On timeout, connection error, or HTTP error from the LLM API. |
call_llm_text(messages, **kwargs)
¶
Convenience wrapper for call_llm() that extracts only the text content.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[dict]
|
List of message dicts in OpenAI-compatible format. |
required |
**kwargs
|
Passed through to call_llm() (temperature, max_tokens, etc.). |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
The text content from the first choice's message, or empty string |
str
|
if no content was returned. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
Propagated from call_llm() on API errors. |
count_messages_tokens(messages)
¶
Count total tokens across a list of chat messages.
Sums token counts for message content strings and for tool call function arguments and names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
list[dict]
|
List of message dicts with "content" and optional "tool_calls" keys (OpenAI-compatible format). |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total estimated token count for all messages combined. |
count_tokens(text)
¶
Count tokens in a text string using tiktoken.
Falls back to a rough estimate (chars / 4) if tiktoken is unavailable or encoding fails.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text string to count tokens for. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Estimated token count as an integer. |
rag_retrieve(embedder, kb, query, top_k=TOP_K)
¶
Retrieve top-k relevant chunks from the knowledge base.
Delegates to KnowledgeBase.query() which handles embedding, cosine similarity, and the Python 3.15 JIT pre-allocation workaround.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embedder
|
Fitted Embedder instance (unused — kept for API compat). |
required | |
kb
|
KnowledgeBase instance with loaded vectors and chunks. |
required | |
query
|
str
|
The search query string. |
required |
top_k
|
int
|
Number of results to return. Defaults to TOP_K config value. |
TOP_K
|
Returns:
| Type | Description |
|---|---|
list
|
List of ChunkResult objects sorted by descending similarity score. |
rag_retrieve_md(embedder, kb, query, top_k=TOP_K)
¶
Retrieve top-k chunks and format them as markdown.
Combines rag_retrieve() with markdown formatting for use in prompts or reports. Each chunk is rendered as a markdown section with source and score. Content is truncated to 500 characters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embedder
|
Fitted Embedder instance. |
required | |
kb
|
KnowledgeBase instance with loaded vectors and chunks. |
required | |
query
|
str
|
The search query string. |
required |
top_k
|
int
|
Number of results to return. Defaults to TOP_K. |
TOP_K
|
Returns:
| Type | Description |
|---|---|
str
|
Markdown-formatted string with retrieved chunk sections. |
safe_json_loads(text, context='')
¶
Parse JSON with a descriptive error message on failure.
Wraps json.loads() and converts ValueError/TypeError into RuntimeError with context information for debugging tool call argument parsing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
JSON string to parse. |
required |
context
|
str
|
Optional label for error messages (e.g., tool name). |
''
|
Returns:
| Type | Description |
|---|---|
dict
|
Parsed dictionary from the JSON string. |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If the text is not valid JSON, with context and truncated argument text in the error message. |
sanitize_text(text)
¶
Sanitize text by encoding to UTF-8 and decoding back.
This is a safety measure for text that may contain characters incompatible with Unicode. Uses "replace" error handling to substitute problematic bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input string that may contain non-UTF-8 data. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Clean UTF-8 string with any invalid bytes replaced. |
set_verbose(enabled)
¶
Enable or disable verbose logging for LLM requests/responses.
When enabled, prints request body summaries and response metadata to stdout via _print_llm_request() and _print_llm_response().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
bool
|
True to enable verbose output, False to disable. |
required |
slugify(text, max_len=40)
¶
Create a URL-safe slug from arbitrary text.
Lowercases the text, replaces non-alphanumeric characters with underscores, collapses consecutive underscores, and strips leading/trailing underscores.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input text to slugify. |
required |
max_len
|
int
|
Maximum length of the output slug. Defaults to 40. |
40
|
Returns:
| Type | Description |
|---|---|
str
|
URL-safe slug string containing only [a-z0-9_-]. |