This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to branch feat/llmao
in repository https://gitbox.apache.org/repos/asf/sling-tooling-jenkins.git


The following commit(s) were added to refs/heads/feat/llmao by this push:
     new c4e6a6c  chore: log tool output, help troubleshooting
c4e6a6c is described below

commit c4e6a6c37c067d91d020166eafb60c966337845f
Author: Robert Munteanu <[email protected]>
AuthorDate: Mon Oct 12 18:33:35 2026 +0100

    chore: log tool output, help troubleshooting
---
 README.md                                          |  4 ++-
 resources/org/apache/sling/jenkins/llmao/run-pi.sh |  1 +
 .../sling/jenkins/llmao/tool-output-logger.mjs     | 41 ++++++++++++++++++++++
 vars/slingOsgiBundleBuild.groovy                   |  3 +-
 4 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index cb99a79..0aaee61 100644
--- a/README.md
+++ b/README.md
@@ -83,7 +83,9 @@ Provide either an input string or an input file; the library 
has no default task
 
 `llmaoMaxTokens` replaces Pi's default 16,384-token output allowance for this 
custom model. A smaller allowance may help a request fit within the remaining 
PAT quota, but does not reset or increase that quota or cap the total tokens 
used by a multi-step job.
 
-The library runs [Pi](https://pi.dev) in Docker, configured for LLMAO's 
OpenAI-compatible endpoint at `https://llm.apache.org/v1`, with the selected 
model and temperature `0.0`. Pi can read, search, edit, and write project files 
and run shell commands. Extensions, MCP, automatic project instructions, stored 
sessions, and compaction remain disabled.
+The library runs [Pi](https://pi.dev) in Docker, configured for LLMAO's 
OpenAI-compatible endpoint at `https://llm.apache.org/v1`, with the selected 
model and temperature `0.0`. Pi can read, search, edit, and write project files 
and run shell commands. Automatic extensions, MCP, automatic project 
instructions, stored sessions, and compaction remain disabled.
+
+A bundled tool-output logger is explicitly loaded. It writes shell commands 
(up to 2,000 characters), shell-result tails (up to 6,000 characters), and 
errors from other tools to stderr in the Jenkins console. It redacts the 
`LLMAO_PAT` value before truncation and does not log successful file reads, 
prompts, or reasoning. It does not alter tool results or the final 
SUCCESS/FAILURE response on stdout.
 
 Pi retries transient provider/network errors, including HTTP 429 rate limits, 
up to 10 times per failed model turn at one-minute intervals. Retries stay in 
the same Pi session, preserving tool history and edits; provider-level retries 
remain disabled. This polls for quota recovery rather than parsing LLMAO's 
custom reset timestamp, and the existing job/process timeouts still apply.
 
diff --git a/resources/org/apache/sling/jenkins/llmao/run-pi.sh 
b/resources/org/apache/sling/jenkins/llmao/run-pi.sh
index 73a60fa..a964950 100644
--- a/resources/org/apache/sling/jenkins/llmao/run-pi.sh
+++ b/resources/org/apache/sling/jenkins/llmao/run-pi.sh
@@ -43,6 +43,7 @@ exec timeout --kill-after=5s 1500s pi \
     --provider llmao --model "$LLMAO_MODEL" \
     --print --tools read,bash,edit,write,grep,find,ls --no-session \
     --no-extensions --no-mcp --no-skills --no-prompt-templates \
+    --extension /inputs/tool-output-logger.mjs \
     --skill "$HOME/sling-whiteboard/skills" \
     --no-context-files --no-approve \
     --system-prompt /inputs/system-prompt.txt \
diff --git a/resources/org/apache/sling/jenkins/llmao/tool-output-logger.mjs 
b/resources/org/apache/sling/jenkins/llmao/tool-output-logger.mjs
new file mode 100644
index 0000000..0722eb2
--- /dev/null
+++ b/resources/org/apache/sling/jenkins/llmao/tool-output-logger.mjs
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export default function toolOutputLogger(pi) {
+    function log(value, limit = 6000) {
+        let text = String(value ?? '');
+        const secret = process.env.LLMAO_PAT;
+        if (secret) text = text.split(secret).join('[REDACTED]');
+        text = text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
+        if (text.length > limit) text = `[...truncated; last ${limit} 
characters...]\n${text.slice(-limit)}`;
+        process.stderr.write(`[Pi tool] ${text}\n`);
+    }
+
+    pi.on('tool_call', event => {
+        if (event.toolName === 'bash') log(`bash 
command:\n${event.input?.command ?? ''}`, 2000);
+    });
+
+    pi.on('tool_result', event => {
+        if (event.toolName !== 'bash' && !event.isError) return;
+        log(`${event.toolName}: ${event.isError ? 'ERROR' : 
'OK'}${event.input?.path ? ` (${event.input.path})` : ''}`);
+        const output = (event.content ?? []).filter(block => block.type === 
'text').map(block => block.text).join('\n');
+        if (output) log(output);
+        // Return nothing: logging must not change the result seen by the 
model.
+    });
+}
diff --git a/vars/slingOsgiBundleBuild.groovy b/vars/slingOsgiBundleBuild.groovy
index 4806f8b..e30d4fc 100644
--- a/vars/slingOsgiBundleBuild.groovy
+++ b/vars/slingOsgiBundleBuild.groovy
@@ -219,6 +219,7 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
                             }
                             dir('inputs') {
                                 writeFile file: 'run-pi.sh', text: 
libraryResource('org/apache/sling/jenkins/llmao/run-pi.sh')
+                                writeFile file: 'tool-output-logger.mjs', 
text: libraryResource('org/apache/sling/jenkins/llmao/tool-output-logger.mjs')
                                 writeFile file: 'system-prompt.txt', text: 
'You are a coding assistant working on the checked-out project. Follow the 
relevant supplied Apache Sling skills; use update-sling-parent-pom for parent 
POM upgrades. Complete the requested update and its required verification. Do 
not stage, unstage, commit, push, switch branches, or change Git metadata. 
Respond with exactly SUCCESS if the update and verification succeeded, or 
FAILURE otherwise. Do not include pun [...]
                                 writeFile file: 'prompt_input.txt', text: 
contextData, encoding: 'UTF-8'
                                 writeJSON file: 'models.json', json: [
@@ -260,7 +261,7 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
                             set +x
                             docker rm --force "$LLMAO_CONTAINER" >/dev/null 
2>&1 || true
                             rm -f image/Dockerfile inputs/models.json 
inputs/settings.json \\
-                              inputs/system-prompt.txt inputs/prompt_input.txt 
inputs/run-pi.sh
+                              inputs/system-prompt.txt inputs/prompt_input.txt 
inputs/run-pi.sh inputs/tool-output-logger.mjs
                         '''
                     }
                 }

Reply via email to