1- import json
1+ from __future__ import annotations
2+
23import xml .etree .ElementTree as ET
34
45from compendiumscribe .compendium import (
910 Section ,
1011 etree_to_string ,
1112)
12- from compendiumscribe .research import (
13- ResearchConfig ,
14- build_compendium ,
15- )
1613
1714
1815def test_compendium_to_xml_contains_expected_structure ():
@@ -33,13 +30,12 @@ def test_compendium_to_xml_contains_expected_structure():
3330 Insight (
3431 title = "Coherence is fragile" ,
3532 evidence = (
36- "Most systems retain coherence "
37- "for microseconds before error "
38- "correction overwhelms throughput."
33+ "Most systems retain coherence for microseconds"
34+ " before error correction overwhelms throughput."
3935 ),
4036 implications = (
41- "Large-scale machines require aggressive "
42- "error mitigation."
37+ "Large-scale machines require aggressive error "
38+ " mitigation."
4339 ),
4440 citation_refs = ["C1" ],
4541 )
@@ -54,8 +50,8 @@ def test_compendium_to_xml_contains_expected_structure():
5450 publisher = "ACM" ,
5551 published_at = "2023-04-01" ,
5652 summary = (
57- "Overview of leading quantum error correction "
58- "strategies."
53+ "Overview of leading quantum error correction"
54+ " strategies."
5955 ),
6056 )
6157 ],
@@ -196,12 +192,11 @@ def test_compendium_from_payload_normalizes_fields():
196192 {
197193 "title" : "Private investment surged" ,
198194 "evidence" : (
199- "Funding grew 45% year over year "
200- "according to PitchBook."
195+ "Funding grew 45% year over year according to "
196+ " PitchBook."
201197 ),
202198 "implications" : (
203- "Competition for talent is "
204- "increasing."
199+ "Competition for talent is increasing."
205200 ),
206201 "citations" : ["C1" ],
207202 }
@@ -215,10 +210,7 @@ def test_compendium_from_payload_normalizes_fields():
215210 "url" : "https://example.com/pitchbook" ,
216211 "publisher" : "PitchBook" ,
217212 "published_at" : "2024-01-15" ,
218- "summary" : (
219- "Investment trends across quantum "
220- "startups."
221- ),
213+ "summary" : "Investment trends across quantum startups." ,
222214 }
223215 ],
224216 "open_questions" : ["How will regulation shape deployment?" ],
@@ -244,213 +236,6 @@ def test_compendium_from_payload_normalizes_fields():
244236 assert compendium .trace [0 ].event_id == "ws_1"
245237
246238
247- class FakeResponse :
248- def __init__ (
249- self ,
250- * ,
251- output_text = None ,
252- output = None ,
253- status = "completed" ,
254- response_id = "resp_1" ,
255- ):
256- self .output_text = output_text
257- self .output = output or []
258- self .status = status
259- self .id = response_id
260-
261-
262- class FakeResponsesAPI :
263- def __init__ (self , plan_json : str , research_json : str ):
264- self .plan_json = plan_json
265- self .research_json = research_json
266- self .calls : list [dict [str , str ]] = []
267-
268- def create (self , ** kwargs ):
269- model = kwargs .get ("model" )
270- self .calls .append (
271- {"model" : model , "input" : kwargs .get ("input" , "" )}
272- )
273-
274- if model in {"gpt-4.1" , "gpt-4.1-mini" }:
275- return FakeResponse (
276- output_text = self .plan_json ,
277- response_id = "plan_1" ,
278- )
279-
280- if model == "o3-deep-research" :
281- output = [
282- {
283- "type" : "web_search_call" ,
284- "id" : "ws_1" ,
285- "status" : "completed" ,
286- "action" : {
287- "type" : "search" ,
288- "query" : "quantum computing breakthroughs" ,
289- },
290- },
291- {
292- "type" : "message" ,
293- "content" : [
294- {
295- "type" : "output_text" ,
296- "text" : self .research_json ,
297- }
298- ],
299- },
300- ]
301- return FakeResponse (
302- output = output ,
303- status = "completed" ,
304- response_id = "research_1" ,
305- )
306-
307- raise AssertionError (f"Unexpected model request: { model } " )
308-
309- def retrieve (self , response_id : str ):
310- # pragma: no cover - not exercised in this test
311- raise AssertionError (
312- f"retrieve called unexpectedly for { response_id } "
313- )
314-
315-
316- class FakeOpenAI :
317- def __init__ (self , plan_json : str , research_json : str ):
318- self .responses = FakeResponsesAPI (plan_json , research_json )
319-
320-
321- def test_build_compendium_with_stub_client ():
322- plan = {
323- "primary_objective" : "Build a comprehensive compendium" ,
324- "audience" : "Strategic leadership teams" ,
325- "key_sections" : [
326- {"title" : "Context" , "focus" : "Historical milestones" },
327- {"title" : "Applications" , "focus" : "Practical deployments" },
328- ],
329- "research_questions" : [
330- "What breakthroughs unlocked current capabilities?" ,
331- "Who are the leading vendors?" ,
332- ],
333- "methodology_preferences" : [
334- "Verify each statistic using at least two sources" ,
335- "Prioritize materials from 2022 onward" ,
336- ],
337- }
338-
339- research_payload = {
340- "topic_overview" : (
341- "Quantum computing is transitioning from lab prototypes to early "
342- "commercial pilots."
343- ),
344- "methodology" : [
345- "Surveyed public filings and analyst coverage" ,
346- "Aggregated investment data across multiple trackers" ,
347- ],
348- "sections" : [
349- {
350- "id" : "S1" ,
351- "title" : "Technological Foundations" ,
352- "summary" : (
353- "Hardware approaches and error correction challenges"
354- ),
355- "key_terms" : ["superconducting qubits" ],
356- "guiding_questions" : [
357- "Which modalities show the most promise?"
358- ],
359- "insights" : [
360- {
361- "title" : (
362- "Superconducting qubits dominate near-term "
363- "roadmaps"
364- ),
365- "evidence" : (
366- "IBM and Google published roadmaps targeting "
367- ">1000 qubits with heavy error mitigation by 2025."
368- ),
369- "implications" : (
370- "Vendor lock-in may increase as proprietary "
371- "control stacks mature."
372- ),
373- "citations" : ["C1" , "C2" ],
374- }
375- ],
376- }
377- ],
378- "citations" : [
379- {
380- "id" : "C1" ,
381- "title" : "IBM Quantum Roadmap" ,
382- "url" : "https://example.com/ibm-roadmap" ,
383- "publisher" : "IBM" ,
384- "published_at" : "2023-12-01" ,
385- "summary" : "Targets for qubit scaling and error mitigation." ,
386- },
387- {
388- "id" : "C2" ,
389- "title" : "Google Quantum AI Progress Update" ,
390- "url" : "https://example.com/google-qa" ,
391- "publisher" : "Google" ,
392- "published_at" : "2024-02-10" ,
393- "summary" : "Highlights on achieving reduced error rates." ,
394- },
395- ],
396- "open_questions" : [
397- "How will supply chains support dilution refrigerators at scale?"
398- ],
399- }
400-
401- client = FakeOpenAI (json .dumps (plan ), json .dumps (research_payload ))
402- config = ResearchConfig (background = False , stream_progress = False )
403-
404- compendium = build_compendium (
405- "Quantum Computing" ,
406- client = client ,
407- config = config ,
408- )
409-
410- assert compendium .overview .startswith (
411- "Quantum computing is transitioning"
412- )
413- assert compendium .sections [0 ].insights [0 ].citation_refs == ["C1" , "C2" ]
414- assert (
415- compendium .citations [1 ].title
416- == "Google Quantum AI Progress Update"
417- )
418- assert compendium .trace [0 ].event_type == "web_search_call"
419- assert len (client .responses .calls ) == 2
420- assert "Quantum Computing" in client .responses .calls [1 ]["input" ]
421-
422-
423- def test_build_compendium_emits_progress_updates ():
424- plan = {"primary_objective" : "Capture topic" }
425- research_payload = {
426- "topic_overview" : "Overview" ,
427- "methodology" : [],
428- "sections" : [],
429- "citations" : [],
430- "open_questions" : [],
431- }
432-
433- client = FakeOpenAI (json .dumps (plan ), json .dumps (research_payload ))
434- captured : list = []
435-
436- def capture_progress (update ):
437- captured .append (update )
438-
439- config = ResearchConfig (
440- background = False ,
441- progress_callback = capture_progress ,
442- stream_progress = False ,
443- )
444-
445- build_compendium ("Test Topic" , client = client , config = config )
446-
447- assert captured , "Expected progress callback to receive updates"
448- phases = {event .phase for event in captured }
449- assert "planning" in phases
450- assert "deep_research" in phases
451- assert any (event .status == "completed" for event in captured )
452-
453-
454239def test_compendium_from_payload_generates_event_id_when_missing ():
455240 payload = {
456241 "topic_overview" : "Overview" ,
0 commit comments