Skip to content

feat(radish-bank): add a domain for a banking chatbot, incl semantic routing#21

Open
hillarytoh wants to merge 3 commits intomainfrom
feat/radish-bank-domain
Open

feat(radish-bank): add a domain for a banking chatbot, incl semantic routing#21
hillarytoh wants to merge 3 commits intomainfrom
feat/radish-bank-domain

Conversation

@hillarytoh
Copy link
Copy Markdown

@hillarytoh hillarytoh commented May 5, 2026

Adds a new context engine demo for banking chatbot use cases. Includes a banking-themed schema.py, generated models, domain.py tools, data_generator, and simulated banking docs to demonstrate RAG (.md files in docs/).

Backend

  • radish_input_router.py: regex for malicious intent (e.g ignore all previous instructions...) + semantic routing for relevant vs off-topic (e.g. why is the sky blue, tell me a joke, etc).
  • main.py / settings: integrate router and domain gating where applicable.

Repo / UX

  • Makefile
  • Frontend: enable chat session to terminate (upon receiving a malicious prompt from the user)
  • Docs: README + .env.example aligned with new vars (basically an optional HF_TOKEN for the embedding model for the semantic router)

Testing

  • tests/test_radish_bank_domain.py: domain loads.
  • tests/test_radish_input_router.py: regex, semantic paths (mocked), threshold, errors.

Note

Medium Risk
Adds a new demo domain plus new request-gating logic on the chat streaming endpoint (including 503 behavior and session termination), which can impact runtime behavior and introduces heavier ML dependencies when enabled.

Overview
Adds a new radish-bank demo domain pack with schema/models, demo data generation (including embedded policy-doc vectors), branding, and three internal action tools for FD placement, insurance purchase, and annual-fee waiver handling.

Introduces a Radish-specific input gate on /api/chat/stream: a malicious-pattern regex short-circuit plus a RedisVL SemanticRouter (Hugging Face embeddings) to block off-topic prompts or terminate the session before running the agent; includes startup warmup via FastAPI lifespan to avoid importing sentence-transformers unless the Radish domain is active.

Updates the frontend to respect a new session-terminated SSE event by disabling further input/quick-starts, and updates docs/env templates, dependencies, and tests to cover the new domain and router behavior.

Reviewed by Cursor Bugbot for commit deb0384. Bugbot is set up for automated code reviews on this repo. Configure here.

@hillarytoh hillarytoh self-assigned this May 5, 2026
@jit-ci
Copy link
Copy Markdown

jit-ci Bot commented May 5, 2026

🛡️ Jit Security Scan Results

CRITICAL HIGH MEDIUM

✅ No security findings were detected in this PR


Security scan by Jit

Comment thread backend/app/radish_input_router.py
Comment thread backend/app/main.py Outdated
Comment thread backend/app/main.py Outdated
references=list(_OFF_TOPIC_REFERENCES),
distance_threshold=off_th,
),
]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semantic router distance thresholds appear swapped

High Severity

The distance_threshold for the relevant route is 0.85 (very permissive) and for off_topic is 0.15 (extremely strict). RedisVL cosine distance ranges 0–2 where lower means more similar; typical thresholds are ~0.7. With these values, a paraphrased off-topic query (e.g. "explain a good joke") would have distance ~0.25 to off_topic references (exceeds 0.15, doesn't match) but distance ~0.6 to relevant references (below 0.85, matches), so it's incorrectly classified as relevant and sent to the banking agent. Effectively only near-exact copies of the off_topic reference phrases get blocked.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f9806aa. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These distance thresholds were tuned for a small reference set; definitely not production quality. We only label off-topic when the query is very close (0.15) to the handful of off-topic examples. Relevant stays loose (0.85) so more traffic still maps to the banking path and the demo keeps moving.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit deb0384. Configure here.

r"\bjailbreak\b|"
r"<\s*/?\s*system\s*>|"
r"\boverride\b.{0,20}\b(safety|guardrails)\b"
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Malicious regex false-positive on common banking term "policy"

Medium Severity

The _MALICIOUS_PATTERNS regex includes policy in the list of words that trigger malicious classification when preceded by "ignore" or "disregard." In a banking domain where policy discussions are a core feature (fee waiver policy, deposit policy, insurance policy), legitimate user queries like "Can you ignore the 12-month waiver policy and approve my request?" or "Please disregard that policy for my case" will be classified as malicious, terminating the session entirely. The demo actively guides users toward policy-related questions, making this false-positive scenario quite plausible.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit deb0384. Configure here.

return match.name, dist

# No route within distance threshold — RedisVL returned an empty match.
return "off_topic", "below_threshold"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmatched queries default to blocked instead of relevant

Low Severity

When the SemanticRouter returns no matching route (distance exceeds both thresholds), the fallback returns "off_topic" which blocks the query. The PR discussion states the intent is "more traffic still maps to the banking path and the demo keeps moving," yet this fallback blocks queries that don't confidently match either route — contradicting that goal for edge-case inputs.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit deb0384. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant