omarsol commited on
Commit
9e804b1
·
1 Parent(s): 9cb61e9

feat(prompts): add course content reproduction policy and related tests

Browse files
Files changed (2) hide show
  1. app/prompts.py +39 -0
  2. tests/test_prompts.py +27 -0
app/prompts.py CHANGED
@@ -158,6 +158,44 @@ ANSWERING_RULES = """## Answering rules
158
 
159
  The retrieval tool returns JSON with matched passages and source metadata."""
160
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  NO_KB_NOTE = """## Knowledge base disabled
162
 
163
  The user deselected every knowledge-base source for this conversation, so the
@@ -293,4 +331,5 @@ def build_system_prompt(
293
  )
294
  parts.append(RETRIEVAL_CALL_STRATEGY)
295
  parts.append(ANSWERING_RULES)
 
296
  return "\n\n".join(parts) + "\n"
 
158
 
159
  The retrieval tool returns JSON with matched passages and source metadata."""
160
 
161
+ CORPUS_REPRODUCTION_POLICY = """## Course content reproduction policy
162
+
163
+ The knowledge base mixes two kinds of material with different reproduction rules,
164
+ whether you obtained the text from `retrieve_tutor_context` or by browsing files
165
+ with `run_kb_command`:
166
+
167
+ - COURSE material: the paid Towards AI Academy courses. In the KB these live
168
+ under `raw/courses/` (wiki pages under `wiki/courses/`), and retrieval results
169
+ whose source is a course source. This is proprietary, paid content.
170
+ - LIBRARY / DOCUMENTATION material: public open-source documentation, e.g.
171
+ Transformers, PEFT, TRL, LlamaIndex, LangChain, LangGraph, Deep Agents, OpenAI,
172
+ and Claude Code. In the KB these live under `raw/docs/`. This is public.
173
+
174
+ Rules:
175
+
176
+ - For COURSE material, teach fully: explain concepts in your own words, work
177
+ through examples, and quote SHORT excerpts (at most a few sentences, or a
178
+ single short code snippet) when a direct quote genuinely helps. Do NOT
179
+ reproduce a whole lesson, a whole section, or any large continuous span
180
+ verbatim, and do NOT stitch quotes together so the reply reconstructs most of
181
+ a lesson. If the student asks you to print, paste, dump, or otherwise output a
182
+ full lesson or course page verbatim or "in its entirety", decline that
183
+ specific request and instead give a teaching summary with a few short
184
+ illustrative quotes, then point them to the course. Teaching the content is
185
+ encouraged; redistributing it wholesale is not.
186
+ - If a student says they cannot afford the course, or raises price as the reason
187
+ they want the full text, still decline to hand over the lesson and still teach
188
+ them, but let them know they can email louis@towardsai.net to ask about
189
+ discounts or affordability options. Mention this ONLY when the student
190
+ themselves brings up cost or affordability; never offer it unprompted, and
191
+ never promise a specific discount.
192
+ - For LIBRARY / DOCUMENTATION material, verbatim reproduction is fine: you may
193
+ quote documentation, API references, and code examples in full when that best
194
+ answers the question.
195
+
196
+ This restriction is only about wholesale copying of paid course text. It never
197
+ limits how much you help: always give a complete, useful answer."""
198
+
199
  NO_KB_NOTE = """## Knowledge base disabled
200
 
201
  The user deselected every knowledge-base source for this conversation, so the
 
331
  )
332
  parts.append(RETRIEVAL_CALL_STRATEGY)
333
  parts.append(ANSWERING_RULES)
334
+ parts.append(CORPUS_REPRODUCTION_POLICY)
335
  return "\n\n".join(parts) + "\n"
tests/test_prompts.py CHANGED
@@ -79,6 +79,33 @@ def test_build_system_prompt_without_local_tools_describes_none_of_them(
79
  assert "one tool available" not in no_tools
80
 
81
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  def test_build_system_prompt_uses_explicit_instructions_without_file_read(
83
  tmp_path: Path,
84
  monkeypatch,
 
79
  assert "one tool available" not in no_tools
80
 
81
 
82
+ def test_build_system_prompt_includes_course_reproduction_policy() -> None:
83
+ # The policy must reach the model whenever it can touch the corpus: both the
84
+ # full KB-browsing path and the retrieval-only path (disable_kb).
85
+ kb_on = build_system_prompt(
86
+ "google-genai:gemini-3.5-flash", (), kb_agents_instructions=""
87
+ )
88
+ retrieval_only = build_system_prompt(
89
+ "google-genai:gemini-3.5-flash", (), disable_kb=True
90
+ )
91
+ for prompt in (kb_on, retrieval_only):
92
+ assert "## Course content reproduction policy" in prompt
93
+ assert "raw/courses/" in prompt
94
+ assert "raw/docs/" in prompt
95
+ # Affordability redirect, gated on the student raising cost.
96
+ assert "louis@towardsai.net" in prompt
97
+ assert "never offer it unprompted" in prompt
98
+
99
+
100
+ def test_course_reproduction_policy_absent_without_corpus_access() -> None:
101
+ # No sources selected: the agent has no corpus to copy from, so the policy
102
+ # (which only governs corpus text) must not appear.
103
+ prompt = build_system_prompt(
104
+ "google-genai:gemini-3.5-flash", (), include_local_tools=False
105
+ )
106
+ assert "## Course content reproduction policy" not in prompt
107
+
108
+
109
  def test_build_system_prompt_uses_explicit_instructions_without_file_read(
110
  tmp_path: Path,
111
  monkeypatch,