File size: 2,814 Bytes
526950e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
"""ContextPack assembler.

Composes deterministic packs from retrieval results:
- course_constitution: all course_meta records (always loaded)
- topic: retrieval top-K
- module: full topic content (intent-driven)

assessment_safe is enforced upstream (catalog only contains student_access=True
records by construction in sub-project #1's _student_visible_files).
"""
from __future__ import annotations
from dataclasses import dataclass, field

from scripts.lib.catalog_loader import Catalog
from scripts.lib.ranker import RetrievalResult


_ASSESSMENT_KINDS = {"question", "slide_answer"}
_MODULE_INTENTS = {"summarize", "explain"}


@dataclass
class ContextPack:
    course_constitution: list[dict] = field(default_factory=list)
    topic: list[RetrievalResult] = field(default_factory=list)
    module: list[dict] = field(default_factory=list)
    has_assessment_content: bool = False
    has_redacted_tier: bool = False


def assemble(
    *,
    intent: str,
    retrieved: list[RetrievalResult],
    catalog: Catalog,
    mode: str = "tutor",
) -> ContextPack:
    """Compose a ContextPack from an intent + retrieval results + mode.

    In review mode the module block is expanded whenever the dominant-topic
    threshold is met, regardless of intent — faculty queries about a concept
    consistently want every occurrence across the term, not the intent-driven
    subset that's right for student tutoring.
    """
    by_doc_id = {r["doc_id"]: r for r in catalog.records}

    constitution = [r for r in catalog.records if r.get("kind") == "course_meta"]

    topic = list(retrieved)

    module: list[dict] = []
    module_eligible = mode == "review" or intent in _MODULE_INTENTS
    if module_eligible and len(retrieved) >= 2:
        # Find the topic with the most retrieved records
        topic_counts: dict[str, int] = {}
        for r in retrieved:
            rec = by_doc_id.get(r.doc_id, {})
            t = rec.get("topic", "")
            if t:
                topic_counts[t] = topic_counts.get(t, 0) + 1
        if topic_counts:
            dominant_topic = max(topic_counts, key=lambda k: topic_counts[k])
            if topic_counts[dominant_topic] >= 2:
                module = [
                    rec for rec in catalog.records
                    if rec.get("topic") == dominant_topic
                ]

    has_assessment = any(
        by_doc_id.get(r.doc_id, {}).get("kind") in _ASSESSMENT_KINDS
        for r in retrieved
    )
    has_redacted = any(
        by_doc_id.get(r.doc_id, {}).get("privacy_tier") == "redacted_classroom_speech"
        for r in retrieved
    )

    return ContextPack(
        course_constitution=constitution,
        topic=topic,
        module=module,
        has_assessment_content=has_assessment,
        has_redacted_tier=has_redacted,
    )