prompt_context
Async context builder for system-prompt template variables.
Gathers runtime data from the incoming message, platform adapter,
bot configuration, and (optionally) Redis to produce the full
dictionary that PromptRenderer feeds into
the Jinja2 template.
- async prompt_context.resolve_public_ip_once()[source]
Resolve and cache the host’s outbound public IPv4 exactly once.
Memoizes the result on the
ConfigSingletonso the inference worker pays the network cost a single time at bootstrap rather than on every prompt build; later calls short-circuit on the cached value. This matters because the IP feeds the (whitelist-gated)bot_ipfield of the system prompt and must never block the message hot path.Makes one outbound HTTP GET to
api.ipify.orgviahttpxunder a 3-second timeout, mutatingConfigSingleton.PUBLIC_IPandConfigSingleton.IP_RESOLVED. On any failure it logs, raises an observabilityWARNINGalert, and falls back to127.0.0.1while still marking resolution complete so it is not retried per message. Called byPromptContextBuilder._build_public_ips()(lazily, if not yet resolved) and exercised directly by the whitelisting test suite.- Returns:
The resolved public IPv4 address, or
"127.0.0.1"on failure.- Return type:
- prompt_context.build_whitelisted_prompt_context(channel_id, user_name, raw_vector)[source]
Build the user/environment context block, gating secrets by whitelist.
Assembles the
userandenvironmentsub-dicts that feed the system prompt, parsing valence/arousal out of a heterogeneous raw_vector (list, tuple, or dict keyed by name or index). Sensitive fields — the bot’s public IP, real limbic resonance, and a secret-metadata-access flag — are only populated when the channel passes_is_channel_in_whitelist()againstSTAR_CONTEXT_CHANNEL_WHITELIST; otherwise they are redacted to safe defaults. This is the choke point that keeps host secrets out of prompts rendered for untrusted channels.Reads the
STAR_CONTEXT_CHANNEL_WHITELISTenvironment variable andConfigSingleton.PUBLIC_IP, and emitswhitelisted_context_injectedorcontext_redactedobservability counters as a side effect. Called byPromptContextBuilder._build_runtime()(which merges the result into the runtime context) and directly by the whitelisting test suite.- Parameters:
channel_id (
str) – Channel the prompt is being built for; decides whether secrets are injected.user_name (
str) – Display name of the interacting user.raw_vector (
list[float] |dict[str,Any] |None) – Optional limbic vector from which valence (index/key 0) and arousal (index/key 1) are extracted; malformed values are logged and treated as0.0.
- Returns:
A nested
{"user": ..., "environment": ...}context dict, with sensitive fields either populated or redacted.- Return type:
- async prompt_context.fetch_git_metadata_async(project_root)[source]
Resolve the current commit hash and ref decoration via async
git.Shells out to
git log -1 --format=%h%din a non-blockingasyncio.create_subprocess_exec()so the event loop is never blocked, parsing the short hash and any ref decoration (branch/tag) into a small metadata dict. The result drives the self-awarenessrelease_tagshown in the system prompt, so it must degrade gracefully rather than raise. A 3-secondasyncio.wait_for()timeout bounds the call, and any timeout or error is logged and folded into a static fallback.Touches the filesystem only by reading the git repository at project_root; no Redis, network, or other side effects. Called by
PromptContextBuilder._build_git_metadata()and exercised by the prompt-context safeguard and whitelisting tests.
- prompt_context.resolve_skills_corpus_roots(cfg)[source]
Resolve the configured Agent Skills corpus roots to absolute paths.
Normalizes each entry of
cfg.skills_corpus_rootsso the system prompt can advertise unambiguous on-disk locations for skill files: relative segments are joined to the current working directory and resolved, while unresolvable paths fall back to their original string. Surfacing absolute roots is what lets the model (and theactivate_skilltool) locateSKILL.mddirectories reliably on this deployment.Reads
cfg.skills_corpus_rootsand the process working directory and touches the filesystem only viapathlib.Path.resolve()(which may stat paths); no other side effects. Called byPromptContextBuilder._build_skills_storage_paths().
- prompt_context.format_mention(user_id, platform)[source]
Format a user mention appropriate for platform.
Produces the platform-native ping syntax so the rendered system prompt can reference the bot and owner in a form the user’s client will linkify. Discord wraps the snowflake as
<@USER_ID>; Matrix user IDs (@user:server) are already display-ready and returned verbatim. Pure string formatting with no I/O or side effects.Called by
PromptContextBuilder._build_runtime()for both thebot_mentionandowner_mentiontemplate variables.
- prompt_context.invalidate_self_json_cache()[source]
Invalidate the process-level
prompts/self.jsoncache.Resets the module-global
_self_json_cachetoNoneso the next_load_self_json()call re-reads the persona blob from disk. This is how an in-place edit to the bot’s self description (via themodify_self_jsontool) becomes visible without restarting the worker.Mutates module global state only — no Redis, network, or filesystem access — and logs the invalidation. Called by
tools/modify_self_json.pyafter it writes the file, and by the SWORD adversarial test suite.- Return type:
- Returns:
None
- class prompt_context.PromptContextBuilder(config, kg_manager=None, threadweave_manager=None, status_manager=None, message_cache=None, task_manager=None, conversation_manager=None, openrouter_client=None, persona_pref_manager=None, sword_graph_manager=None)[source]
Bases:
objectBuild the template-variable dict consumed by the system prompt.
- Parameters:
config (
Config) – The globalConfiginstance (providesmodel,redis_url, etc.).kg_manager (
KnowledgeGraphManager|None) – OptionalKnowledgeGraphManagerfor injecting knowledge graph context into the system prompt.Nonewhen Redis is not configured.threadweave_manager (ThreadweaveManager | None)
status_manager (Any | None)
message_cache (MessageCache | None)
task_manager (TaskManager | None)
conversation_manager (ConversationManager | None)
openrouter_client (Any | None)
persona_pref_manager (Any | None)
sword_graph_manager (Any | None)
- __init__(config, kg_manager=None, threadweave_manager=None, status_manager=None, message_cache=None, task_manager=None, conversation_manager=None, openrouter_client=None, persona_pref_manager=None, sword_graph_manager=None)[source]
Initialize the instance.
- Parameters:
config (
Config) – Bot configuration object.kg_manager (
KnowledgeGraphManager|None) – The kg manager value.threadweave_manager (
ThreadweaveManager|None) – The threadweave manager value.message_cache (
MessageCache|None) – The message cache value.task_manager (
TaskManager|None) – The task manager value.conversation_manager (
ConversationManager|None) – The conversation manager value.openrouter_client (
Any|None) – Shared OpenRouterClient for embedding connection pooling.persona_pref_manager (
Any|None) – PersonaPreferenceManager instance.sword_graph_manager (
Any|None) – SWORD graph manager instance.
- Return type:
None
- all_adapters: list[PlatformAdapter]
- async build(msg, platform, query_embedding=None)[source]
Collect every context section and return a merged dict.
Sections that depend on Redis silently return empty values when Redis is not configured. Sections that depend on Discord- specific data gracefully degrade on other platforms.
- Return type:
- Parameters:
msg (IncomingMessage)
platform (PlatformAdapter)
query_embedding (ndarray | None)
- build_minimal(msg, platform)[source]
Return a context dict using only synchronous, I/O-free sections.
Guarantees every unconditional template variable is present so the Jinja2 renderer never receives a bare
Undefinedobject. Used as the fallback when the full asyncbuild()call times out or raises an unexpected exception.- Return type:
- Parameters:
msg (IncomingMessage)
platform (PlatformAdapter)