File size: 6,140 Bytes
d659d2d
 
 
 
9eec184
13fe947
ded41ce
d659d2d
 
 
 
 
9eec184
d659d2d
 
 
 
 
 
13fe947
d659d2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ded41ce
d659d2d
 
 
 
 
 
 
 
 
 
 
 
 
ded41ce
d659d2d
a3e1f0c
d659d2d
 
a3e1f0c
d659d2d
a3e1f0c
d659d2d
36ed450
 
 
 
 
 
 
 
 
902a11f
36ed450
902a11f
36ed450
902a11f
36ed450
d659d2d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9eec184
d659d2d
 
 
 
 
ded41ce
d659d2d
 
 
 
 
 
 
 
 
 
 
 
902a11f
d659d2d
902a11f
 
 
 
d659d2d
902a11f
d659d2d
 
 
 
a3e1f0c
d659d2d
a3e1f0c
d659d2d
a3e1f0c
d659d2d
 
a3e1f0c
d659d2d
 
 
 
 
 
 
 
 
 
 
a3e1f0c
d659d2d
 
 
 
ded41ce
 
 
9eec184
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from __future__ import annotations

from typing import Any

from hackathon_advisor.tools import goal_label
from hackathon_advisor._text import clean as _clean, list_of_dicts as _list_of_dicts, utc_now


def build_field_notes_markdown(session: dict[str, Any], metadata: dict[str, Any]) -> str:
    ideas = _list_of_dicts(session.get("ideas"))
    trace = _list_of_dicts(session.get("trace"))
    profile = session.get("profile") if isinstance(session.get("profile"), dict) else {}
    goals = _goal_labels(session.get("goals"))
    last_plan = [str(step) for step in session.get("last_plan") or []]
    last_artifact = session.get("last_artifact") if isinstance(session.get("last_artifact"), dict) else {}

    lines = [
        "# Hackathon Advisor Field Notes",
        "",
        f"Generated: {utc_now()}",
        "",
        "## Snapshot",
        "",
        f"- Project snapshot: {_clean(metadata.get('snapshot_generated_at'))}",
        f"- Project count: {_clean(metadata.get('project_count', 'unknown'))}",
        f"- Index: {_clean(metadata.get('index_algorithm'))} at {_clean(metadata.get('index_generated_at'))}",
        f"- Digest: `{_clean(metadata.get('snapshot_digest'))}`",
        "",
        "## Builder Context",
        "",
    ]

    if profile:
        for field in ("skills", "time", "preferences", "constraints"):
            value = _clean(profile.get(field))
            if value:
                lines.append(f"- {field.title()}: {value}")
    else:
        lines.append("- No profile notes recorded.")
    lines.append(f"- Goals: {', '.join(goals) if goals else 'No specific goals'}")

    lines.extend(["", "## Idea Board", ""])
    if ideas:
        for index, idea in enumerate(ideas, start=1):
            lines.extend(_idea_section(index, idea))
    else:
        lines.append("No ideas were written.")

    lines.extend(["", "## Build Plan", ""])
    if last_plan:
        for index, step in enumerate(last_plan, start=1):
            lines.append(f"{index}. {_clean(step)}")
    else:
        lines.append("No build plan has been generated yet.")

    lines.extend(["", "## Session Decisions", ""])
    if trace:
        for index, event in enumerate(trace, start=1):
            lines.extend(_decision_section(index, event))
    else:
        lines.append("No session decisions were recorded.")

    wood_map = last_artifact.get("wood_map") if isinstance(last_artifact.get("wood_map"), dict) else {}
    if wood_map:
        lines.extend(["", "## Wood Map", "", _clean(wood_map.get("caption"))])
        for dot in _list_of_dicts(wood_map.get("dots")):
            if dot.get("kind") != "echo":
                continue
            title = _clean(dot.get("title"))
            score = _clean(dot.get("score"))
            url = _clean(dot.get("url"))
            page = _clean(dot.get("page_number")) or "?"
            if url:
                lines.append(f"- Page {page}: [{title}]({url}) - echo score {score}")
            else:
                lines.append(f"- Page {page}: {title} - echo score {score}")

    if last_artifact:
        lines.extend(
            [
                "",
                "## Share Caption",
                "",
                _clean(last_artifact.get("caption") or ""),
            ]
        )

    return "\n".join(lines).rstrip() + "\n"


def _idea_section(index: int, idea: dict[str, Any]) -> list[str]:
    title = _clean(idea.get("title") or f"Idea {index}")
    pitch = _clean(idea.get("pitch"))
    goals = _goal_labels(idea.get("goals"))
    score = idea.get("score") if isinstance(idea.get("score"), dict) else {}
    lines = [
        f"### {index}. {title}",
        "",
        f"- Pitch: {pitch or 'No pitch recorded.'}",
        f"- Goals: {', '.join(goals) if goals else 'No specific goals'}",
    ]
    if score:
        lines.append(f"- Seal: {_clean(score.get('overall'))}/10 - {_clean(score.get('verdict'))}")
        echoes = _list_of_dicts(score.get("echoes"))
        if echoes:
            lines.append("- Closest cited Spaces:")
            for echo in echoes[:4]:
                project = echo.get("project") if isinstance(echo.get("project"), dict) else {}
                title = _clean(project.get("title") or project.get("id") or "Untitled Space")
                url = _clean(project.get("url") or project.get("host") or "")
                matched = ", ".join(str(term) for term in echo.get("matched_terms") or [])
                score_text = _clean(echo.get("score"))
                page = _clean(echo.get("page_number")) or "?"
                if url:
                    lines.append(
                        f"  - Page {page}: [{title}]({url}) - score {score_text}; "
                        f"matched {matched or 'no shared terms'}"
                    )
                else:
                    lines.append(f"  - Page {page}: {title} - score {score_text}; matched {matched or 'no shared terms'}")
    lines.append("")
    return lines


def _decision_section(index: int, event: dict[str, Any]) -> list[str]:
    tools = _list_of_dicts(event.get("tools"))
    action_names = " -> ".join(_clean(tool.get("name")) for tool in tools if tool.get("name")) or "reply"
    lines = [
        f"### Decision {index}",
        "",
        f"- Input: {_clean(event.get('input'))}",
        f"- Advisor actions: {action_names}",
    ]
    verdict = _clean(event.get("verdict"))
    overall = event.get("overall")
    if verdict or overall is not None:
        lines.append(f"- Verdict: {verdict or 'n/a'} {overall if overall is not None else ''}".rstrip())
    response = _clean(event.get("response"))
    if response:
        lines.append(f"- Advisor note: {response}")
    resolution = event.get("tool_resolution") if isinstance(event.get("tool_resolution"), dict) else {}
    call = resolution.get("call") if isinstance(resolution.get("call"), dict) else {}
    if call:
        lines.append(f"- Recorded action: `{_clean(call.get('name'))}`")
    lines.append("")
    return lines


def _goal_labels(value: Any) -> list[str]:
    if not isinstance(value, list):
        return []
    return [goal_label(str(goal)) for goal in value]