From 7918c9d422962d8dec4fb9fa410a51daa6d6ebe7 Mon Sep 17 00:00:00 2001
From: Arun Isaac
Date: Wed, 22 Jul 2026 00:27:06 +0100
Subject: Add tracing.
This will aid debugging and let users report issues more precisely and
reproducibly.
---
bin/kaagum | 24 +++++++++++++++++++-----
kaagum/tea.scm | 13 +++++++++----
kaagum/trace.scm | 32 ++++++++++++++++++++++++++++++++
kaagum/web.scm | 8 +++++++-
4 files changed, 67 insertions(+), 10 deletions(-)
create mode 100644 kaagum/trace.scm
diff --git a/bin/kaagum b/bin/kaagum
index 138e62c..9d5353d 100755
--- a/bin/kaagum
+++ b/bin/kaagum
@@ -21,6 +21,7 @@ exec guile --no-auto-compile -e main -s "$0" "$@"
;;; along with kaagum. If not, see .
(use-modules (rnrs io ports)
+ (srfi srfi-26)
(srfi srfi-37)
(ice-9 match)
(kaagum config)
@@ -28,6 +29,7 @@ exec guile --no-auto-compile -e main -s "$0" "$@"
(kaagum tea)
(kaagum tools base)
(kaagum tools forges)
+ (kaagum trace)
(kaagum utils))
(define (invalid-option opt name arg result)
@@ -47,6 +49,9 @@ exec guile --no-auto-compile -e main -s "$0" "$@"
(option (list #\k "api-key-command") #t #f
(lambda (opt name arg result)
(acons 'api-key-command arg result)))
+ (option (list "trace-file") #t #f
+ (lambda (opt name arg result)
+ (acons 'trace-file arg result)))
(option (list #\v "version") #f #f
(lambda (opt name arg result)
(acons 'version #t result)))
@@ -67,6 +72,8 @@ Run kaagum AI agent.
--model=MODEL LLM model name to start new sessions with
(default: \"anthropic/claude-opus-4.6\")
+ --trace-file=FILE trace out all interactions in FILE
+
--version print version and exit
--help print this help and exit
"
@@ -105,8 +112,15 @@ Run kaagum AI agent.
(exit #t))
(unless (assq-ref args 'api-key-command)
(die "--api-key-command not specified"))
- (run-tea-loop (assq-ref args 'api-base-uri)
- (get-api-key (assq-ref args 'api-key-command))
- (assq-ref args 'model)
- (append %base-tools
- %forge-tools))))))
+ (let ((thunk (cut run-tea-loop
+ (assq-ref args 'api-base-uri)
+ (get-api-key (assq-ref args 'api-key-command))
+ (assq-ref args 'model)
+ (append %base-tools
+ %forge-tools))))
+ (if (assq-ref args 'trace-file)
+ (call-with-output-file (assq-ref args 'trace-file)
+ (lambda (trace-port)
+ (parameterize ((%trace-port trace-port))
+ (thunk))))
+ (thunk)))))))
diff --git a/kaagum/tea.scm b/kaagum/tea.scm
index 6e750c0..1ac674e 100644
--- a/kaagum/tea.scm
+++ b/kaagum/tea.scm
@@ -34,6 +34,7 @@
#:use-module (kaagum openai)
#:use-module (kaagum records)
#:use-module (kaagum tools)
+ #:use-module (kaagum trace)
#:use-module (kaagum utils)
#:export (run-tea-loop))
@@ -957,7 +958,9 @@ in @code{tea-loop}."
(define* (tea-loop state llm-base-uri llm-api-key models tools
#:optional (events (let ((line (get-line (current-input-port))))
(and (not (eof-object? line))
- (list (acp-message (json-string->scm line)))))))
+ (begin
+ (trace 'acp "<- ~a" line)
+ (list (acp-message (json-string->scm line))))))))
"Run a @acronym{TEA, The Elm Architecture} loop starting with @var{state}.
@var{llm-base-uri}, @var{llm-api-key} and @var{tools} are the same as in
@@ -986,9 +989,11 @@ in @code{tea-loop}."
(cond
;; Send message to client, and return the state unchanged.
((acp-message? effect)
- (display (scm->json-string (focus acp-message-json effect)))
- (newline)
- (flush-output-port (current-output-port))
+ (let ((json-message (scm->json-string (focus acp-message-json effect))))
+ (display json-message)
+ (newline)
+ (flush-output-port (current-output-port))
+ (trace 'acp "-> ~a" json-message))
(list))
;; Send request to LLM, handle the response, and return the new state.
((llm-request? effect)
diff --git a/kaagum/trace.scm b/kaagum/trace.scm
new file mode 100644
index 0000000..2c2c4ed
--- /dev/null
+++ b/kaagum/trace.scm
@@ -0,0 +1,32 @@
+;;; kaagum --- Tiny, security-focused AI agent in Guile
+;;; Copyright © 2026 Arun Isaac
+;;;
+;;; This file is part of kaagum.
+;;;
+;;; kaagum is free software: you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; kaagum is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with kaagum. If not, see .
+
+(define-module (kaagum trace)
+ #:export (%trace-port
+ trace))
+
+(define %trace-port
+ (make-parameter #f))
+
+(define (trace subsystem message . args)
+ "Print out tracing @var{message} with @var{args} for @var{subsystem}."
+ (when (%trace-port)
+ (display subsystem (%trace-port))
+ (display ": " (%trace-port))
+ (apply format (%trace-port) message args)
+ (newline (%trace-port))))
diff --git a/kaagum/web.scm b/kaagum/web.scm
index ce29bdd..db6f33a 100644
--- a/kaagum/web.scm
+++ b/kaagum/web.scm
@@ -22,6 +22,7 @@
#:use-module (web client)
#:use-module (web http)
#:use-module (web response)
+ #:use-module (kaagum trace)
#:use-module (json)
#:export (uri-join
json-request
@@ -40,6 +41,9 @@
(define* (json-request method url #:key (headers '()) body)
"Send a HTTP @var{method} request to @var{url} with @var{body} and
additional @var{headers}. Return JSON response."
+ (if body
+ (trace 'web "-> ~a ~a ~a" method url body)
+ (trace 'web "-> ~a ~a" method url))
(let-values (((response body)
(http-request url
#:method method
@@ -51,7 +55,9 @@ additional @var{headers}. Return JSON response."
(set-port-encoding! body "UTF-8")
(case (quotient (response-code response)
100)
- ((2) (json->scm body))
+ ((2) (let ((result (json->scm body)))
+ (trace 'web "<- ~a ~a" (response-code response) (scm->json-string result))
+ result))
((4)
(raise-exception
(condition (make-violation)
--
cgit 1.4.1