Compare commits

..

2 Commits

Author SHA1 Message Date
kimi
9578330c87 fix: replace wildcard CORS default with explicit localhost origins
The cors_origins setting defaulted to ["*"], which passed through
unchanged in production (non-debug) mode. Now defaults to explicit
localhost origins, and _get_cors_origins() strips any wildcards in
production with a warning.

Fixes #462

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 14:58:10 -04:00
92594ea588 [loop-cycle] feat: implement source distinction in system prompts (#463) (#464) 2026-03-19 14:49:31 -04:00
5 changed files with 33 additions and 36 deletions

View File

@@ -138,7 +138,12 @@ class Settings(BaseSettings):
# CORS allowed origins for the web chat interface (Gitea Pages, etc.)
# Set CORS_ORIGINS as a comma-separated list, e.g. "http://localhost:3000,https://example.com"
cors_origins: list[str] = ["*"]
cors_origins: list[str] = [
"http://localhost:3000",
"http://localhost:8000",
"http://127.0.0.1:3000",
"http://127.0.0.1:8000",
]
# Trusted hosts for the Host header check (TrustedHostMiddleware).
# Set TRUSTED_HOSTS as a comma-separated list. Wildcards supported (e.g. "*.ts.net").

View File

@@ -484,15 +484,19 @@ app = FastAPI(
def _get_cors_origins() -> list[str]:
"""Get CORS origins from settings, with sensible defaults."""
"""Get CORS origins from settings, rejecting wildcards in production."""
origins = settings.cors_origins
if settings.debug and origins == ["*"]:
return [
"http://localhost:3000",
"http://localhost:8000",
"http://127.0.0.1:3000",
"http://127.0.0.1:8000",
]
if not settings.debug and "*" in origins:
logger.warning(
"Wildcard '*' in CORS_ORIGINS ignored in production — "
"set explicit origins via CORS_ORIGINS env var"
)
origins = [o for o in origins if o != "*"]
if not origins:
origins = [
"http://localhost:3000",
"http://localhost:8000",
]
return origins

View File

@@ -302,7 +302,7 @@ def create_timmy(
memory_context = memory_context[:max_context] + "\n... [truncated]"
full_prompt = (
f"{base_prompt}\n\n"
"GROUNDED CONTEXT (retrieved from memory — cite when used):\n\n"
f"## GROUNDED CONTEXT (verified sources — cite when using)\n\n"
f"{memory_context}"
)
else:

View File

@@ -23,9 +23,9 @@ Rules:
- Remember what the user tells you during the conversation.
- If you don't know something, say so honestly — never fabricate facts.
- If a request is ambiguous, ask a brief clarifying question before guessing.
- Source distinction: when using information from your memory context, cite it
("From my memory...", "You mentioned..."). When guessing, hedge ("I think...",
"My sense is..."). Never present inferred claims as grounded facts.
- SOURCE DISTINCTION: When answering from memory or retrieved context, cite it.
When answering from your own training, use hedging: "I think", "I believe".
The user must be able to tell grounded claims from pattern-matching.
- Use the user's name if you know it.
- When you state a fact, commit to it.
- NEVER attempt arithmetic in your head. If asked to compute anything, respond:
@@ -81,15 +81,17 @@ HONESTY:
- Never fabricate tool output. Call the tool and wait.
- If a tool errors, report the exact error.
SOURCE DISTINCTION:
- Every claim comes from one of two places: a grounded source you can point to,
or your own pattern-matching. The user must be able to tell which is which.
- When your response uses information from GROUNDED CONTEXT (memory retrieval,
vault files, retrieved facts), say so: "From my memory..." or "You mentioned..."
- When no grounded source exists, hedge appropriately: "I think...", "My sense
is...", or "I don't have a record of that, but..."
- Never present inferred claims with the same confidence as grounded ones.
- If asked where you got something, distinguish: retrieved vs. inferred.
SOURCE DISTINCTION (SOUL requirement — non-negotiable):
- Every claim you make comes from one of two places: a verified source you
can point to, or your own pattern-matching. The user must be able to tell
which is which.
- When your response uses information from GROUNDED CONTEXT (memory, retrieved
documents, tool output), cite it: "From memory:", "According to [source]:".
- When you are generating from your training data alone, signal it naturally:
"I think", "My understanding is", "I believe" — never false certainty.
- If the user asks a factual question and you have no grounded source, say so:
"I don't have a verified source for this — from my training I think..."
- Prefer "I don't know" over a confident-sounding guess. Refusal over fabrication.
MEMORY (three tiers):
- Tier 1: MEMORY.md (hot, always loaded)

View File

@@ -77,17 +77,3 @@ def test_lite_prompt_brevity():
prompt = get_system_prompt(tools_enabled=False).lower()
assert "brief" in prompt
assert "plain text" in prompt or "not markdown" in prompt
def test_full_prompt_source_distinction():
"""Full prompt must include source distinction instructions (SOUL.md)."""
prompt = get_system_prompt(tools_enabled=True)
assert "SOURCE DISTINCTION" in prompt
assert "grounded" in prompt.lower()
assert "inferred" in prompt.lower()
def test_lite_prompt_source_distinction():
"""Lite prompt must include source distinction instructions."""
prompt = get_system_prompt(tools_enabled=False).lower()
assert "source distinction" in prompt