6ede33ccdb
Build and Push Docker Images / create_manifest (web, surfsense-web, , cpu) (push) Has been cancelled
Build and Push Docker Images / finalize_release (push) Has been cancelled
Obsidian Plugin Lint / lint (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_web, cpu, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-24.04-arm, linux/arm64, arm64, , runner, false, cpu) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_web, cpu, ./surfsense_web/Dockerfile, web, surfsense-web, ubuntu-latest, linux/amd64, amd64, , runner, false, cpu) (push) Has been cancelled
Build and Push Docker Images / compute_version (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cpu, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, , production, false, cpu) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cpu, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, , production, false, cpu) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu126, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, -cuda126, production, true, cuda126) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu126, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, -cuda126, production, true, cuda126) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu128, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-24.04-arm, linux/arm64, arm64, -cuda, production, true, cuda) (push) Has been cancelled
Build and Push Docker Images / build (./surfsense_backend, cu128, ./surfsense_backend/Dockerfile, backend, surfsense-backend, ubuntu-latest, linux/amd64, amd64, -cuda, production, true, cuda) (push) Has been cancelled
Build and Push Docker Images / verify_digests (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend, , cpu) (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend, -cuda, cuda) (push) Has been cancelled
Build and Push Docker Images / create_manifest (backend, surfsense-backend, -cuda126, cuda126) (push) Has been cancelled
73 lines
2.4 KiB
Python
73 lines
2.4 KiB
Python
"""Shape tool results into the format the caller asked for.
|
|
|
|
Tools default to Markdown (readable for the model and the human watching), and
|
|
can return raw JSON when a caller wants to post-process the data. Large payloads
|
|
are clipped so a single call can't blow the context window.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Annotated, Any, Literal
|
|
|
|
from pydantic import Field
|
|
|
|
ResponseFormat = Literal["markdown", "json"]
|
|
|
|
# Shared parameter type for every tool: same name, same semantics everywhere.
|
|
ResponseFormatParam = Annotated[
|
|
ResponseFormat,
|
|
Field(
|
|
description="'markdown' (default, human-readable) or 'json' "
|
|
"(raw data for post-processing)."
|
|
),
|
|
]
|
|
|
|
DEFAULT_CLIP_CHARS = 20_000
|
|
ITEM_FIELD_CLIP_CHARS = 1_500
|
|
|
|
# Fields that duplicate another field verbatim (e.g. Reddit's 'html' mirrors
|
|
# 'body') and only bloat inline results. The full record stays in the run.
|
|
_REDUNDANT_ITEM_FIELDS = frozenset({"html"})
|
|
|
|
|
|
def compact_items(result: Any, field_limit: int = ITEM_FIELD_CLIP_CHARS) -> Any:
|
|
"""Shrink a scraper result for inline return.
|
|
|
|
Drops redundant fields and clips overlong strings per field, so a response
|
|
keeps every item as an excerpt instead of a few items in full. The
|
|
untruncated result remains retrievable via its stored run.
|
|
"""
|
|
if isinstance(result, dict) and isinstance(result.get("items"), list):
|
|
return {
|
|
**result,
|
|
"items": [_compact_item(item, field_limit) for item in result["items"]],
|
|
}
|
|
return result
|
|
|
|
|
|
def _compact_item(item: Any, field_limit: int) -> Any:
|
|
# ponytail: compacts top-level string fields only; nested structures pass
|
|
# through untouched. Upgrade path is a recursive walk if a platform nests
|
|
# long text.
|
|
if not isinstance(item, dict):
|
|
return item
|
|
return {
|
|
key: clip(value, field_limit) if isinstance(value, str) else value
|
|
for key, value in item.items()
|
|
if key not in _REDUNDANT_ITEM_FIELDS
|
|
}
|
|
|
|
|
|
def to_json(payload: Any) -> str:
|
|
"""Pretty-print a payload as JSON, tolerating non-serializable values."""
|
|
return json.dumps(payload, indent=2, ensure_ascii=False, default=str)
|
|
|
|
|
|
def clip(text: str, limit: int = DEFAULT_CLIP_CHARS) -> str:
|
|
"""Trim overlong text, leaving a visible marker of how much was dropped."""
|
|
if len(text) <= limit:
|
|
return text
|
|
dropped = len(text) - limit
|
|
return f"{text[:limit]}\n\n… [{dropped} more characters truncated]"
|