feat: refresh goal loop lesson

This commit is contained in:
Haoran
2026-07-31 21:44:10 +08:00
parent 13dc5396bb
commit 2ad77cee19
8 changed files with 1815 additions and 780 deletions

View File

@@ -1,109 +1,76 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 540" font-family="system-ui, -apple-system, sans-serif">
<defs>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#22c55e"/>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto">
<path d="M0 0L10 5L0 10Z" fill="#16a34a"/>
</marker>
<marker id="arrow-gray" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#888888"/>
<marker id="arrow-gray" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto">
<path d="M0 0L10 5L0 10Z" fill="#737373"/>
</marker>
</defs>
<!-- Background -->
<rect width="960" height="540" rx="8" fill="#ffffff"/>
<text x="480" y="32" text-anchor="middle" fill="#171717" font-size="20" font-weight="700">Goal Loop</text>
<text x="480" y="53" text-anchor="middle" fill="#737373" font-size="11.5">the return boundary checks the active condition before the turn can end</text>
<!-- Title -->
<text x="480" y="30" text-anchor="middle" fill="#1a1a1a" font-size="19" font-weight="700">Goal Loop — the host-owned turn-completion gate</text>
<text x="480" y="50" text-anchor="middle" fill="#888888" font-size="12">after every turn an evaluator judges trusted evidence and blocks the stop until the goal is met</text>
<rect x="24" y="76" width="912" height="426" rx="8" fill="#ffffff" stroke="#d4d4d4" stroke-width="1.5" stroke-dasharray="6 4"/>
<text x="44" y="100" fill="#171717" font-size="13" font-weight="700">Agent session</text>
<!-- ===== Main loop container ===== -->
<rect x="20" y="66" width="920" height="156" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="40" y="86" fill="#1a1a1a" font-size="13" font-weight="700">Main loop — the turn boundary</text>
<rect x="52" y="150" width="142" height="58" rx="6" fill="#ffffff" stroke="#171717" stroke-width="1.5"/>
<text x="123" y="173" text-anchor="middle" fill="#171717" font-size="12" font-weight="700" font-family="monospace">messages[]</text>
<text x="123" y="192" text-anchor="middle" fill="#737373" font-size="9">conversation and tool results</text>
<!-- loop-back over the top: continuation -> messages[] -->
<path d="M 910 350 L 910 104 L 101 104 L 101 130" fill="none" stroke="#22c55e" stroke-width="1.5" stroke-dasharray="6,3" marker-end="url(#arrow-green)"/>
<text x="500" y="99" text-anchor="middle" fill="#22c55e" font-size="10" font-weight="600">continuation -&gt; transcript[] (next turn)</text>
<circle cx="101" cy="130" r="3" fill="#22c55e"/>
<line x1="194" y1="179" x2="230" y2="179" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="232" y="150" width="132" height="58" rx="6" fill="#ffffff" stroke="#171717" stroke-width="1.5"/>
<text x="298" y="173" text-anchor="middle" fill="#171717" font-size="12" font-weight="700">Worker model</text>
<text x="298" y="192" text-anchor="middle" fill="#737373" font-size="9">tools and actions</text>
<!-- transcript[] -->
<rect x="40" y="130" width="122" height="52" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="101" y="152" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700" font-family="monospace">transcript[]</text>
<text x="101" y="169" text-anchor="middle" fill="#888888" font-size="9">messages + origins</text>
<line x1="162" y1="156" x2="180" y2="156" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<line x1="364" y1="179" x2="400" y2="179" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="402" y="150" width="132" height="58" rx="6" fill="#ffffff" stroke="#171717" stroke-width="1.5"/>
<text x="468" y="173" text-anchor="middle" fill="#171717" font-size="11.5" font-weight="700">no tool_use</text>
<text x="468" y="192" text-anchor="middle" fill="#737373" font-size="9">worker proposes a stop</text>
<!-- turn (LLM) -->
<rect x="182" y="130" width="108" height="52" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="236" y="152" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">turn (LLM)</text>
<text x="236" y="169" text-anchor="middle" fill="#888888" font-size="9">may emit tool_use</text>
<line x1="290" y1="156" x2="308" y2="156" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<line x1="534" y1="179" x2="574" y2="179" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow-green)"/>
<!-- no tool_use -->
<rect x="310" y="130" width="118" height="52" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="369" y="152" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">no tool_use</text>
<text x="369" y="169" text-anchor="middle" fill="#888888" font-size="9">(wants to stop)</text>
<line x1="428" y1="156" x2="446" y2="156" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="576" y="112" width="324" height="278" rx="8" fill="#f8fdf9" stroke="#171717" stroke-width="2"/>
<text x="596" y="138" fill="#171717" font-size="13" font-weight="700">Goal gate</text>
<text x="880" y="138" text-anchor="end" fill="#737373" font-size="9">GoalController</text>
<!-- goal gate (emphasis: thicker border) -->
<rect x="448" y="124" width="170" height="64" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="2.4"/>
<text x="533" y="146" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">goal gate</text>
<text x="533" y="163" text-anchor="middle" fill="#888888" font-size="9.5" font-family="monospace">evaluate_after_turn()</text>
<text x="533" y="177" text-anchor="middle" fill="#888888" font-size="8.5">after every turn</text>
<rect x="600" y="156" width="276" height="48" rx="6" fill="#ffffff" stroke="#737373" stroke-width="1.2"/>
<text x="738" y="176" text-anchor="middle" fill="#171717" font-size="11.5" font-weight="700">Stop-hook checks</text>
<text x="738" y="192" text-anchor="middle" fill="#737373" font-size="9">active goal · background work</text>
<!-- gate -> return (stop): gray -->
<line x1="618" y1="156" x2="664" y2="156" stroke="#888888" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<text x="641" y="148" text-anchor="middle" fill="#888888" font-size="8.5">completed</text>
<text x="641" y="178" text-anchor="middle" fill="#888888" font-size="8.5">/ blocked</text>
<line x1="738" y1="204" x2="738" y2="292" stroke="#16a34a" stroke-width="1.8" marker-end="url(#arrow-green)"/>
<!-- return -->
<rect x="666" y="130" width="120" height="52" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="726" y="152" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">return</text>
<text x="726" y="169" text-anchor="middle" fill="#888888" font-size="9">turn ends</text>
<rect x="600" y="228" width="126" height="48" rx="6" fill="#ffffff" stroke="#a3a3a3" stroke-width="1.2"/>
<text x="663" y="248" text-anchor="middle" fill="#171717" font-size="10.5" font-weight="700">Goal condition</text>
<text x="663" y="264" text-anchor="middle" fill="#737373" font-size="8.5">checkable end state</text>
<!-- ===== gate consults: evaluator -> evidence ===== -->
<!-- gate -> evaluator (judge) -->
<line x1="500" y1="188" x2="500" y2="248" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="510" y="222" fill="#22c55e" font-size="9" font-weight="600">judge</text>
<rect x="750" y="228" width="126" height="48" rx="6" fill="#ffffff" stroke="#a3a3a3" stroke-width="1.2"/>
<text x="813" y="248" text-anchor="middle" fill="#171717" font-size="10.5" font-weight="700">Conversation</text>
<text x="813" y="264" text-anchor="middle" fill="#737373" font-size="8.5">reported evidence</text>
<rect x="416" y="250" width="168" height="50" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="500" y="272" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">evaluator</text>
<text x="500" y="289" text-anchor="middle" fill="#888888" font-size="9">separate small / fast model</text>
<path d="M663 276V284H700V292" fill="none" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<path d="M813 276V284H776V292" fill="none" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<!-- evaluator -> evidence (reads) -->
<line x1="500" y1="300" x2="500" y2="338" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="510" y="324" fill="#22c55e" font-size="9" font-weight="600">reads</text>
<rect x="650" y="292" width="176" height="52" rx="6" fill="#ffffff" stroke="#171717" stroke-width="1.5"/>
<text x="738" y="313" text-anchor="middle" fill="#171717" font-size="11.5" font-weight="700">Evaluator</text>
<text x="738" y="331" text-anchor="middle" fill="#737373" font-size="9">tool-free model call</text>
<!-- evidence trust boundary container -->
<rect x="40" y="340" width="606" height="156" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="60" y="361" fill="#1a1a1a" font-size="12" font-weight="700">evidence window</text>
<text x="188" y="361" fill="#888888" font-size="10" font-family="monospace">= transcript[start_index:] · trust boundary</text>
<line x1="738" y1="344" x2="738" y2="356" stroke="#737373" stroke-width="1.5"/>
<path d="M738 356L750 368L738 380L726 368Z" fill="#ffffff" stroke="#737373" stroke-width="1.3"/>
<!-- trusted -->
<rect x="62" y="376" width="270" height="104" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="197" y="399" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">counts as evidence</text>
<text x="197" y="424" text-anchor="middle" fill="#1a1a1a" font-size="11" font-family="monospace">task-notification</text>
<text x="197" y="446" text-anchor="middle" fill="#1a1a1a" font-size="11" font-family="monospace">monitor-line</text>
<text x="197" y="468" text-anchor="middle" fill="#888888" font-size="8.5">trusted async origins</text>
<path d="M726 368H650V404H516V420" fill="none" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="682" y="360" text-anchor="middle" fill="#16a34a" font-size="9" font-weight="600">block + reason</text>
<rect x="330" y="422" width="372" height="50" rx="6" fill="#ffffff" stroke="#171717" stroke-width="1.5"/>
<text x="516" y="443" text-anchor="middle" fill="#171717" font-size="11.5" font-weight="700">append the evaluator reason to messages[]</text>
<text x="516" y="460" text-anchor="middle" fill="#737373" font-size="9">continue in the same while loop</text>
<!-- untrusted -->
<rect x="354" y="376" width="270" height="104" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="489" y="399" text-anchor="middle" fill="#888888" font-size="11" font-weight="700">filtered out</text>
<text x="489" y="421" text-anchor="middle" fill="#888888" font-size="10">/goal command text</text>
<text x="489" y="439" text-anchor="middle" fill="#888888" font-size="10">continuation reminder</text>
<text x="489" y="457" text-anchor="middle" fill="#888888" font-size="10">plain user / assistant</text>
<text x="489" y="475" text-anchor="middle" fill="#888888" font-size="8.5">model can't self-satisfy</text>
<path d="M330 447H123V208" fill="none" stroke="#16a34a" stroke-width="1.5" stroke-dasharray="6 4" marker-end="url(#arrow-green)"/>
<!-- ===== continuing -> CommandQueue -> loop back ===== -->
<!-- gate -> CommandQueue (continuing) -->
<path d="M 600 188 L 600 230 L 786 230 L 786 322" fill="none" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="700" y="223" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">continuing</text>
<path d="M750 368H841V430" fill="none" stroke="#737373" stroke-width="1.5" marker-end="url(#arrow-gray)"/>
<text x="806" y="360" text-anchor="middle" fill="#737373" font-size="8.5">allow / terminal</text>
<rect x="768" y="432" width="146" height="40" rx="6" fill="#f5f5f5" stroke="#a3a3a3" stroke-width="1.3"/>
<text x="841" y="456" text-anchor="middle" fill="#171717" font-size="11.5" font-weight="700">return to user</text>
<!-- CommandQueue (mutable: dashed black) -->
<rect x="696" y="324" width="180" height="56" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="786" y="347" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">CommandQueue</text>
<text x="786" y="364" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">continuation (active-goal)</text>
<!-- CommandQueue -> loop back (up the right edge, joins the over-top path) -->
<line x1="876" y1="350" x2="908" y2="350" stroke="#22c55e" stroke-width="1.5" stroke-dasharray="6,3"/>
<!-- ===== Bottom note ===== -->
<text x="480" y="520" text-anchor="middle" fill="#888888" font-size="10">The model proposes stop; the goal gate decides against trusted evidence only, not the model's own say-so.</text>
<text x="480" y="525" text-anchor="middle" fill="#737373" font-size="10">The evaluator is part of the gate; it reads evidence already present in the conversation and never runs tools.</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB