@tiny-fish/hermes 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +38 -0
- package/README.md +102 -0
- package/__init__.py +10 -0
- package/package.json +33 -0
- package/plugin.yaml +13 -0
- package/pyproject.toml +66 -0
- package/tinyfish_hermes/__init__.py +113 -0
- package/tinyfish_hermes/browser_provider.py +133 -0
- package/tinyfish_hermes/config.py +164 -0
- package/tinyfish_hermes/credit_policy.py +128 -0
- package/tinyfish_hermes/normalize.py +110 -0
- package/tinyfish_hermes/provider.py +163 -0
- package/tinyfish_hermes/rest_client.py +276 -0
- package/tinyfish_hermes/routing_context.py +70 -0
- package/tinyfish_hermes/setup_cli.py +695 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Once-per-context TinyFish tool-routing guidance for Hermes turns."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping, Sequence
|
|
6
|
+
from typing import Any
|
|
7
|
+
from urllib.parse import urlparse
|
|
8
|
+
|
|
9
|
+
from .config import load_config, routing_context_enabled
|
|
10
|
+
|
|
11
|
+
ROUTING_CONTEXT_MARKER = '<tinyfish-routing-context version="1">'
|
|
12
|
+
ROUTING_GUIDANCE = f"""{ROUTING_CONTEXT_MARKER}
|
|
13
|
+
TinyFish tool-routing guidance:
|
|
14
|
+
- For ordinary web discovery or reading a page, use Hermes `web_search` or `web_extract`; the `tinyfish` provider serves both directly over the TinyFish REST APIs.
|
|
15
|
+
- When the request needs TinyFish-specific controls the generic schemas cannot express—domain/date/language/location/purpose/pagination filters, output formats, link or image extraction, cache TTL, or per-URL timeouts—use the native `search` or `fetch_content` tool registered by the `tinyfish` MCP server, commonly exposed as `mcp__tinyfish__search` and `mcp__tinyfish__fetch_content`.
|
|
16
|
+
- Infer the choice from the user's plain language. Do not ask them to choose MCP versus the provider, and do not persist per-request controls as configuration. If a required native tool is unavailable, use the generic provider only when it can preserve the requested constraints; otherwise explain which control is unavailable rather than silently dropping it."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def tinyfish_mcp_configured(config: dict[str, Any]) -> bool:
|
|
20
|
+
servers = config.get("mcp_servers") or {}
|
|
21
|
+
if not isinstance(servers, dict):
|
|
22
|
+
return False
|
|
23
|
+
tinyfish = servers.get("tinyfish") or {}
|
|
24
|
+
if not isinstance(tinyfish, dict):
|
|
25
|
+
return False
|
|
26
|
+
# Any auth mode counts: the first-party MCP entry uses an API-key header, not OAuth.
|
|
27
|
+
parsed = urlparse(str(tinyfish.get("url") or ""))
|
|
28
|
+
return (
|
|
29
|
+
parsed.scheme == "https"
|
|
30
|
+
and (parsed.hostname or "").lower() == "agent.tinyfish.ai"
|
|
31
|
+
and parsed.path.rstrip("/") == "/mcp"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _contains_routing_marker(value: object) -> bool:
|
|
36
|
+
if isinstance(value, str):
|
|
37
|
+
return ROUTING_CONTEXT_MARKER in value
|
|
38
|
+
if isinstance(value, Mapping):
|
|
39
|
+
return any(_contains_routing_marker(item) for item in value.values())
|
|
40
|
+
if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)):
|
|
41
|
+
return any(_contains_routing_marker(item) for item in value)
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def routing_guidance_present(conversation_history: object) -> bool:
|
|
46
|
+
"""Return whether Hermes already carries this routing version in context."""
|
|
47
|
+
|
|
48
|
+
if not isinstance(conversation_history, Sequence) or isinstance(
|
|
49
|
+
conversation_history, (str, bytes, bytearray)
|
|
50
|
+
):
|
|
51
|
+
return False
|
|
52
|
+
for message in conversation_history:
|
|
53
|
+
if not isinstance(message, Mapping):
|
|
54
|
+
continue
|
|
55
|
+
if _contains_routing_marker(message.get("api_content")):
|
|
56
|
+
return True
|
|
57
|
+
if _contains_routing_marker(message.get("content")):
|
|
58
|
+
return True
|
|
59
|
+
return False
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def routing_context_hook(**kwargs: Any) -> dict[str, str] | None:
|
|
63
|
+
"""Hermes ``pre_llm_call`` hook injecting versioned routing guidance once."""
|
|
64
|
+
|
|
65
|
+
config = load_config()
|
|
66
|
+
if not routing_context_enabled(config) or not tinyfish_mcp_configured(config):
|
|
67
|
+
return None
|
|
68
|
+
if routing_guidance_present(kwargs.get("conversation_history")):
|
|
69
|
+
return None
|
|
70
|
+
return {"context": ROUTING_GUIDANCE}
|