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 c995d2a chore: adjust phases for clarity
c995d2a is described below
commit c995d2ab3f1812704e26dbe9468d7de599c48865
Author: Robert Munteanu <[email protected]>
AuthorDate: Wed Oct 14 09:29:39 2026 +0100
chore: adjust phases for clarity
---
README.md | 12 +++++++-
vars/slingOsgiBundleBuild.groovy | 61 +++++++++++++++++++++-------------------
2 files changed, 43 insertions(+), 30 deletions(-)
diff --git a/README.md b/README.md
index 3cd92b8..c7071bf 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,16 @@ When the branch job related to the modified `Jenkinsfile` is
built, it will use
`slingOsgiBundleBuild(llmaoOnly: true)` runs a separate Pi automation job, not
the normal Maven matrix, SonarCloud analysis, deployment, or normal build
notifications. Pi can run Maven as part of verifying its requested changes.
Projects using `slingOsgiBundleBuild()` without this argument continue to build
as before; they do not call LLMAO.
+The dedicated job's stages reflect the local agent workflow:
+
+1. **Checkout and Load Configuration** — check out the project and resolve
module settings and library arguments.
+2. **Configure Job** — apply scheduling, retention, and concurrency settings,
then read and validate the task input.
+3. **Build Pi Image** — build or reuse the cached Docker image, without
binding credentials.
+4. **Prepare Pi Task** — write the prompts, model settings, runtime script,
and bundled extensions outside the checkout.
+5. **Run Pi Task** — run the agent, including skill loading, LLMAO requests,
project edits, verification, and diff output. An unsuccessful task fails this
stage.
+6. **Publish Token Usage** — stop any remaining container and summarize and
archive observed usage, also after build or task failures.
+7. **Clean Up** — remove generated runtime inputs and temporary reports,
leaving project edits untouched.
+
### A separate scheduled job
1. Create a **dedicated Pipeline job** for the project, for example
`<project>-llmao`. This library does not create that job automatically.
@@ -199,7 +209,7 @@ In the Pi TUI, invoke the relevant skill explicitly when
desired, for example `/
### Per-build token usage
-LLMAO builds that reach the submission stage publish a console summary, add
the observed total to their build description (for example, `LLMAO: SUCCESS |
18420 tokens`), and archive `llmao-usage.json`. Normal non-LLMAO builds are
unaffected. No model prices or monetary cost estimates are configured.
+LLMAO builds that reach the image-build stage publish a console summary, add
the observed total to their build description (for example, `LLMAO: SUCCESS |
18420 tokens`), and archive `llmao-usage.json`. Normal non-LLMAO builds are
unaffected. No model prices or monetary cost estimates are configured.
A dedicated Pi extension collects gateway-reported usage across all model
responses, including tool-calling turns and any usage reported on failed or
retried turns. The report contains:
diff --git a/vars/slingOsgiBundleBuild.groovy b/vars/slingOsgiBundleBuild.groovy
index 90006ce..3bd83f4 100644
--- a/vars/slingOsgiBundleBuild.groovy
+++ b/vars/slingOsgiBundleBuild.groovy
@@ -155,7 +155,7 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
node(globalConfig.mainNodeLabel) {
timeout(time: 30, unit: 'MINUTES') {
- stage('Init') {
+ stage('Checkout and Load Configuration') {
checkout scm
if ( fileExists('.sling-module.json') ) {
def overrides = readJSON(file: '.sling-module.json',
returnPojo: true).jenkins ?: [:]
@@ -173,6 +173,7 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
error('llmaoMaxTokens must be a positive integer.')
}
+ def contextData
stage('Configure Job') {
def jobTriggers = []
// Standalone Pipeline jobs have no BRANCH_NAME. Feature
branches
@@ -184,10 +185,6 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
buildDiscarder(logRotator(numToKeepStr: '10')),
disableConcurrentBuilds()
])
- }
-
- def contextData
- stage('Prepare LLMAO Input') {
contextData = llmaoConfig.llmaoInputFile ?
readFile(file: llmaoConfig.llmaoInputFile, encoding:
'UTF-8').trim() :
llmaoConfig.llmaoInput.trim()
@@ -213,13 +210,15 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
"LLMAO_REPORT_DIR=${pwd()}/${reportDirectory}"
]) {
try {
- stage('Submit to LLMAO') {
+ stage('Build Pi Image') {
// Build before binding credentials or capturing
stdout. Docker
// reuses the cached layers on subsequent runs on
this executor.
dir('image') {
writeFile file: 'Dockerfile', text:
libraryResource('org/apache/sling/jenkins/llmao/Dockerfile')
sh 'docker build --tag "$LLMAO_IMAGE" .'
}
+ }
+ stage('Prepare Pi Task') {
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')
@@ -252,44 +251,48 @@ def runLlmaoOnlyBuild(def globalConfig, Map params) {
cacheWarming: 'off'
]
}
+ }
+ stage('Run Pi Task') {
withCredentials([string(credentialsId:
'llmao-pat', variable: 'LLMAO_PAT')]) {
updateStatus = sh(
script:
libraryResource('org/apache/sling/jenkins/llmao/run-docker.sh'),
returnStatus: true
)
}
+ // Attribute update failures to the task, not a
later response stage.
+ if ( updateStatus == 0 ) {
+ echo 'Pi completed the project update
successfully.'
+ } else {
+ error("Pi could not complete the project
update (exit code ${updateStatus}).")
+ }
}
} finally {
try {
- // Stop writes before archiving, including on
Jenkins cancellation.
- sh '''
- set +x
- docker rm --force "$LLMAO_CONTAINER"
>/dev/null 2>&1 || true
- '''
- dir(reportDirectory) {
- publishLlmaoUsage(llmaoConfig.llmaoModel,
updateStatus)
+ stage('Publish Token Usage') {
+ // Stop writes before archiving, including on
Jenkins cancellation.
+ sh '''
+ set +x
+ docker rm --force "$LLMAO_CONTAINER"
>/dev/null 2>&1 || true
+ '''
+ dir(reportDirectory) {
+ publishLlmaoUsage(llmaoConfig.llmaoModel,
updateStatus)
+ }
}
} finally {
- sh '''
- set +x
- rm -f image/Dockerfile inputs/models.json
inputs/settings.json \\
- inputs/system-prompt.txt
inputs/prompt_input.txt inputs/run-pi.sh \\
- inputs/tool-output-logger.mjs
inputs/usage-reporter.mjs
- rm -f "$LLMAO_REPORT_DIR/llmao-usage.json"
"$LLMAO_REPORT_DIR/llmao-usage.json.tmp"
- rmdir "$LLMAO_REPORT_DIR" >/dev/null 2>&1 ||
true
- '''
+ stage('Clean Up') {
+ sh '''
+ set +x
+ rm -f image/Dockerfile inputs/models.json
inputs/settings.json \\
+ inputs/system-prompt.txt
inputs/prompt_input.txt inputs/run-pi.sh \\
+ inputs/tool-output-logger.mjs
inputs/usage-reporter.mjs
+ rm -f "$LLMAO_REPORT_DIR/llmao-usage.json"
"$LLMAO_REPORT_DIR/llmao-usage.json.tmp"
+ rmdir "$LLMAO_REPORT_DIR" >/dev/null 2>&1
|| true
+ '''
+ }
}
}
}
}
-
- stage('Process LLMAO Response') {
- if ( updateStatus == 0 ) {
- echo 'Pi completed the project update successfully.'
- } else {
- error("Pi could not complete the project update (exit code
${updateStatus}).")
- }
- }
}
}
}