返回 CodeWhale
context.rs
根目录 / crates / tui / src / diagnostics_reports / context.rs
1 //! Single portable formatter for the authoritative context source map and prompt schema.
2 //! Pressure and route-source verification are already classified by the host
3 //! and skipped by serde, so JSON retains its original public schema.
4
5 use codewhale_command_contract::facets::{DebugPromptContext, DebugPromptSourceMap};
6 use std::fmt::Write as _;
7
8 pub fn format_context_report(report: &DebugPromptSourceMap) -> String {
9 let mut out = String::new();
10 let _ = writeln!(out, "Context Source Map");
11 let _ = writeln!(
12 out,
13 "Estimated active context: {} tokens",
14 report.active_context_estimated_tokens
15 );
16 write_overflow_guard_line(&mut out, report);
17 match (report.context_window_tokens, report.budget_used_percent) {
18 (Some(window), Some(percent)) => {
19 let source = report
20 .context_window_source
21 .as_deref()
22 .unwrap_or("fallback");
23 // An unverified rung is a guess about the window printed on this
24 // same line; it must not claim a fixed 128K default the capability
25 // matrix may not hold. A label from no known rung is no evidence
26 // either, so it reads the same way.
27 let source_label = if report.context_window_verified {
28 source.to_string()
29 } else {
30 format!(
31 "{source} (unverified — nothing describes this model, so this window is a guess)"
32 )
33 };
34 let _ = writeln!(
35 out,
36 "Window: {window} tokens ({percent:.1}% used, {}; source: {})",
37 report.pressure_label.as_str(),
38 source_label
39 );
40 }
41 _ => {
42 let _ = writeln!(out, "Window: unknown");
43 }
44 }
45 // #5134: the source label says where the window came from but not how to
46 // change it. Name the key here so the report answers the question it
47 // provokes.
48 let _ = writeln!(
49 out,
50 "Change the window: set `context_window` on the active `[providers.<name>]` table in config.toml (docs/CONFIGURATION.md, \"Context length\")."
51 );
52 let _ = writeln!(
53 out,
54 "Source-entry total: {} tokens",
55 report.total_estimated_tokens
56 );
57 let _ = writeln!(
58 out,
59 "Manage standing law: /constitution (status/preview), /constitution repo (repo-local law), /setup report (readiness)."
60 );
61 let _ = writeln!(out);
62 let _ = writeln!(out, "Sources:");
63 for entry in &report.entries {
64 let path = entry
65 .source_path
66 .as_deref()
67 .map(|path| format!(" [{path}]"))
68 .unwrap_or_default();
69 let tier = entry
70 .authority_tier
71 .map(|tier| format!(", tier {tier}"))
72 .unwrap_or_default();
73 let omitted = entry
74 .truncation_reason
75 .as_deref()
76 .map(|reason| format!(" - {reason}"))
77 .unwrap_or_default();
78 let _ = writeln!(
79 out,
80 "- {:?}: {}{} - {} tokens ({:?}{}){}",
81 entry.source_kind,
82 entry.label,
83 path,
84 entry.estimated_tokens,
85 entry.counting_confidence,
86 tier,
87 omitted
88 );
89 }
90 let _ = writeln!(out);
91 let _ = write!(out, "{}", report.note);
92 out
93 }
94
95 /// Secondary line: the inflated overflow-guard figure, labeled so nobody
96 /// reads it as the pressure the meter and the compaction gate act on.
97 fn write_overflow_guard_line(out: &mut String, report: &DebugPromptSourceMap) {
98 if let Some(guard) = report.overflow_guard_estimated_tokens {
99 let _ = writeln!(
100 out,
101 "Overflow guard: {guard} tokens (conservative 1.5x estimate that blocks oversized requests; not the pressure the meter and auto-compaction read)"
102 );
103 }
104 }
105
106 pub fn format_context_summary(report: &DebugPromptSourceMap) -> String {
107 let mut entries = report.entries.clone();
108 entries.sort_by_key(|entry| std::cmp::Reverse(entry.estimated_tokens));
109 let top = entries
110 .iter()
111 .take(5)
112 .map(|entry| format!("{} ({})", entry.label, entry.estimated_tokens))
113 .collect::<Vec<_>>()
114 .join(", ");
115
116 let mut out = String::new();
117 let _ = writeln!(out, "Context Summary");
118 let _ = writeln!(out, "Pressure: {}", report.pressure_label.as_str());
119 let _ = writeln!(
120 out,
121 "Estimated active context: {} tokens",
122 report.active_context_estimated_tokens
123 );
124 if let Some(percent) = report.budget_used_percent {
125 let _ = writeln!(out, "Budget used: {percent:.1}%");
126 }
127 write_overflow_guard_line(&mut out, report);
128 let _ = write!(out, "Top sources: {top}");
129 out
130 }
131
132 pub fn context_report_json(report: &DebugPromptSourceMap) -> String {
133 serde_json::to_string_pretty(report).unwrap_or_else(|err| {
134 format!("{{\"error\":\"failed to serialize context report: {err}\"}}")
135 })
136 }
137
138 #[must_use]
139 pub fn prompt_context_json(context: &DebugPromptContext) -> String {
140 serde_json::to_string_pretty(context).unwrap_or_else(|error| {
141 format!(r#"{{"error":"failed to serialize prompt context: {error}"}}"#)
142 })
143 }
144
144 lines RUST