sketch: add debug handler to dump conversation history as JSON

Add HTTP debug endpoint /debug/conversation-history to dump agent conversation
history as pretty-printed JSON for debugging purposes.

Sometimes, you just want to see what went on.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s6c9e876db9b3aa5ck
diff --git a/loop/agent_test.go b/loop/agent_test.go
index ea93dc6..0d0e6ab 100644
--- a/loop/agent_test.go
+++ b/loop/agent_test.go
@@ -266,6 +266,7 @@
 	overBudgetFunc               func() error
 	getIDFunc                    func() string
 	subConvoWithHistoryFunc      func() *conversation.Convo
+	debugJSONFunc                func() ([]byte, error)
 }
 
 func (m *MockConvoInterface) SendMessage(message llm.Message) (*llm.Response, error) {
@@ -344,6 +345,13 @@
 	return nil
 }
 
+func (m *MockConvoInterface) DebugJSON() ([]byte, error) {
+	if m.debugJSONFunc != nil {
+		return m.debugJSONFunc()
+	}
+	return []byte(`[{"role": "user", "content": [{"type": "text", "text": "mock conversation"}]}]`), nil
+}
+
 // TestAgentProcessTurnWithNilResponseNilError tests the scenario where Agent.processTurn receives
 // a nil value for initialResp and nil error from processUserMessage.
 // This test verifies that the implementation properly handles this edge case.
@@ -529,6 +537,10 @@
 	return nil
 }
 
+func (m *mockConvoInterface) DebugJSON() ([]byte, error) {
+	return []byte(`[{"role": "user", "content": [{"type": "text", "text": "mock conversation"}]}]`), nil
+}
+
 func TestAgentProcessTurnStateTransitions(t *testing.T) {
 	// Create a mock ConvoInterface for testing
 	mockConvo := &mockConvoInterface{}