feat: Story 8 - Collapsible tool outputs + autonomous coding improvements

Implemented Story 8: Collapsible Tool Outputs
- Tool outputs now render in <details>/<summary> elements, collapsed by default
- Summary shows tool name with key argument (e.g., ▶ read_file(src/main.rs))
- Added arrow rotation animation and scrollable content (max 300px)
- Enhanced tool_calls display to show arguments inline
- Added CSS styling for dark theme consistency

Fixed: LLM autonomous coding behavior
- Strengthened system prompt with explicit examples and directives
- Implemented triple-reinforcement system (primary prompt + reminder + message prefixes)
- Improved tool descriptions to be more explicit and action-oriented
- Increased MAX_TURNS from 10 to 30 for complex agentic workflows
- Added debug logging for Ollama requests/responses
- Result: GPT-OSS (gpt-oss:20b) now successfully uses write_file autonomously

Documentation improvements
- Created MODEL_SELECTION.md guide with recommendations
- Updated PERSONA.md spec to emphasize autonomous agent behavior
- Updated UI_UX.md spec with collapsible tool output requirements
- Updated SDSW workflow: LLM archives stories and performs squash merge

Cleanup
- Removed unused ToolTester.tsx component
This commit is contained in:
Dave
2025-12-25 15:18:12 +00:00
parent c493da2f2a
commit 990441dfc1
17 changed files with 471 additions and 172 deletions

View File

@@ -299,20 +299,40 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
{msg.role === "user" ? (
msg.content
) : msg.role === "tool" ? (
<div>
<strong
<details style={{ cursor: "pointer" }}>
<summary
style={{
display: "block",
marginBottom: "4px",
color: "#aaa",
fontSize: "0.9em",
marginBottom: "8px",
listStyle: "none",
display: "flex",
alignItems: "center",
gap: "6px",
}}
>
<span style={{ fontSize: "0.8em" }}></span>
<span>
Tool Output
{msg.tool_call_id && ` (${msg.tool_call_id})`}
</span>
</summary>
<pre
style={{
maxHeight: "300px",
overflow: "auto",
margin: 0,
padding: "8px",
background: "#1a1a1a",
borderRadius: "4px",
fontSize: "0.85em",
whiteSpace: "pre-wrap",
wordBreak: "break-word",
}}
>
Tool Output
</strong>
<div style={{ maxHeight: "300px", overflow: "auto" }}>
{msg.content}
</div>
</div>
</pre>
</details>
) : (
<div className="markdown-body">
{/* Assuming global CSS handles standard markdown styling now */}
@@ -332,28 +352,47 @@ export function Chat({ projectPath, onCloseProject }: ChatProps) {
gap: "8px",
}}
>
{msg.tool_calls.map((tc, i) => (
<div
key={i}
style={{
display: "flex",
alignItems: "center",
gap: "8px",
fontFamily: "monospace",
}}
>
<span style={{ color: "#888" }}>Running:</span>
<span
{msg.tool_calls.map((tc, i) => {
// Parse arguments to extract key info
let argsSummary = "";
try {
const args = JSON.parse(tc.function.arguments);
const firstKey = Object.keys(args)[0];
if (firstKey && args[firstKey]) {
argsSummary = String(args[firstKey]);
// Truncate if too long
if (argsSummary.length > 50) {
argsSummary = argsSummary.substring(0, 47) + "...";
}
}
} catch (e) {
// If parsing fails, just show empty
}
return (
<div
key={i}
style={{
background: "#333",
padding: "2px 6px",
borderRadius: "4px",
display: "flex",
alignItems: "center",
gap: "8px",
fontFamily: "monospace",
}}
>
{tc.function.name}
</span>
</div>
))}
<span style={{ color: "#888" }}></span>
<span
style={{
background: "#333",
padding: "2px 6px",
borderRadius: "4px",
}}
>
{tc.function.name}
{argsSummary && `(${argsSummary})`}
</span>
</div>
);
})}
</div>
)}
</div>