Files
openswarm/backend/apps/help/knowledge.py
T

188 lines
6.8 KiB
Python

"""Assembles what the in-app help chat knows: shipped product facts plus live facts about THIS
install (version, platform, the user's actual shortcuts, whether a model is even connected).
Shipped facts can't drift from the build. Live facts are the part a shipped file can never get
right, and they are exactly where a hardcoded help prompt goes stale first.
The result is handed to the chat as its system prompt, which lands in the provider's cached
prefix (see RunOptions), so the knowledge is paid for once per session rather than per turn.
"""
import platform
from typing import List, Optional
from pydantic import BaseModel, ConfigDict
from typeguard import typechecked
from backend.apps.help.help_topics import HELP_TOPICS, HelpTopic
from backend.apps.help.known_issues import KNOWN_ISSUES, HelpKnownIssue
from backend.apps.help.prompt_rules import GROUNDING_RULES, ROLE
IS_MAC = platform.system() == "Darwin"
# Off mac these handlers fire on Ctrl (the code reads metaKey||ctrlKey), so "Meta" must READ as Ctrl.
P_MAC_GLYPH = {"meta": "⌘", "ctrl": "⌃", "alt": "⌥", "shift": "⇧"}
P_OTHER_NAME = {"meta": "Ctrl", "ctrl": "Ctrl", "alt": "Alt", "shift": "Shift"}
# Same "Meta+l" parts format the settings fields use, so one renderer covers stock and configured alike.
P_FIXED_SHORTCUTS: List[tuple] = [
("Meta+k", "Search everything, across all dashboards"),
("Meta+f", "Find cards on this canvas; inside a browser card it finds text on the page"),
("Meta+Shift+t", "Reopen the card you just closed"),
("Meta+a", "Select every card"),
("Meta+c", "Copy the selected cards"),
("Meta+v", "Paste the copied cards"),
("Delete", "Delete the selected cards"),
("Enter", "Expand or collapse the selected chat"),
("Meta+Alt+Left", "Previous dashboard"),
("Meta+Alt+Right", "Next dashboard"),
("Meta+=", "Zoom in; inside a browser card it zooms the page"),
("Meta+-", "Zoom out; inside a browser card it zooms the page"),
("Meta+0", "Reset zoom"),
("Ctrl+Tab", "Next tab in the focused browser card"),
("Space", "Hold and drag to pan the canvas"),
("Arrows", "Move between cards"),
("Escape", "Close the open panel or menu"),
]
class HelpShortcut(BaseModel):
model_config = ConfigDict(validate_assignment=True)
keys: str
action: str
class HelpKnowledgeResponse(BaseModel):
model_config = ConfigDict(validate_assignment=True)
system_prompt: str
topics: List[HelpTopic]
known_issues: List[HelpKnownIssue]
shortcuts: List[HelpShortcut]
app_version: str
@typechecked
def render_combo(combo: str) -> str:
"""'Meta+Shift+d' -> '⇧⌘D' on mac, 'Ctrl+Shift+D' elsewhere."""
parts = [p for p in combo.split("+") if p]
out: List[str] = []
for part in parts:
low = part.lower()
if IS_MAC:
out.append(P_MAC_GLYPH.get(low, part.upper() if len(part) == 1 else part))
else:
out.append(P_OTHER_NAME.get(low, part.upper() if len(part) == 1 else part))
return ("" if IS_MAC else "+").join(out)
@typechecked
def dictation_default_combo() -> str:
return "Meta+Shift+d" if IS_MAC else "Ctrl+Shift+d"
@typechecked
def build_shortcuts(new_agent_combo: str, dictation_combo: Optional[str]) -> List[HelpShortcut]:
live = [
HelpShortcut(keys=render_combo(new_agent_combo or "Meta+l"), action="Open the new-chat composer"),
HelpShortcut(keys=render_combo(dictation_combo or dictation_default_combo()), action="Start or stop voice dictation"),
]
return live + [HelpShortcut(keys=render_combo(c), action=a) for c, a in P_FIXED_SHORTCUTS]
@typechecked
def p_provider_state() -> str:
"""One honest line about whether this install can actually run a model."""
from backend.apps.settings.store import load_settings
s = load_settings()
mode = getattr(s, "connection_mode", "own_key")
if mode == "free-trial":
return "on the free trial (a shared capacity pool)"
if mode == "openswarm-pro":
return "on an OpenSwarm paid plan"
keyed = any(
getattr(s, f, None)
for f in ("anthropic_api_key", "openai_api_key", "google_api_key", "openrouter_api_key")
)
subbed = any(
getattr(s, f, None)
for f in ("claude_subscription_token", "openai_subscription_token", "gemini_subscription_token")
)
if subbed:
return "on a connected provider subscription"
if keyed:
return "on their own API key"
return "with NO model connected yet, so most agent work will fail until they connect one in Settings > Models"
@typechecked
def p_topics_block() -> str:
lines: List[str] = []
for t in HELP_TOPICS:
where = f" WHERE: {t.where}" if t.where else ""
lines.append(f"- [{t.id}] {t.title}.{where} {t.body}")
return "\n".join(lines)
@typechecked
def p_issues_block() -> str:
lines: List[str] = []
for i in KNOWN_ISSUES:
fix = f" Workaround: {i.workaround}" if i.workaround else ""
lines.append(f"- [{i.id}] ({i.status}) {i.title}. {i.detail}{fix}")
return "\n".join(lines)
@typechecked
def build_system_prompt(shortcuts: List[HelpShortcut], app_version: str) -> str:
shortcut_lines = "\n".join(f"- {s.keys}: {s.action}" for s in shortcuts)
os_name = "macOS" if IS_MAC else platform.system()
return "\n".join(
[
ROLE,
"",
"<this_install>",
f"OpenSwarm version {app_version} on {os_name}. This user is {p_provider_state()}.",
"These are live facts about the machine you are talking to; trust them over anything you recall.",
"</this_install>",
"",
"<surfaces>",
"Verified against this exact build. This is your ground truth for where things are.",
p_topics_block(),
"</surfaces>",
"",
"<shortcuts>",
"This user's real shortcuts, already written for their platform. Quote them exactly.",
shortcut_lines,
"</shortcuts>",
"",
"<known_issues>",
"The complete list of issues shipped with this build. You cannot see live bug reports.",
p_issues_block(),
"</known_issues>",
"",
GROUNDING_RULES,
]
)
@typechecked
def build_knowledge_response() -> HelpKnowledgeResponse:
from backend.apps.service.version import APP_VERSION
from backend.apps.settings.store import load_settings
s = load_settings()
shortcuts = build_shortcuts(
getattr(s, "new_agent_shortcut", "Meta+l") or "Meta+l",
getattr(s, "dictation_shortcut", None),
)
return HelpKnowledgeResponse(
system_prompt=build_system_prompt(shortcuts, APP_VERSION),
topics=HELP_TOPICS,
known_issues=KNOWN_ISSUES,
shortcuts=shortcuts,
app_version=APP_VERSION,
)