Skip to content

feat(session,tool/context): Pensieve context self-pruning with example #13008

feat(session,tool/context): Pensieve context self-pruning with example

feat(session,tool/context): Pensieve context self-pruning with example #13008

Workflow file for this run

name: Pull Request Check
on:
pull_request:
merge_group:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: read # Use with `only-new-issues` option.
env:
ROOT_GO_VERSION: "1.21"
EXAMPLES_GO_VERSION: "1.24.6"
jobs:
build:
name: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
- name: Build
run: go build -v ./...
discover-go-modules:
name: discover go modules
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v3
- id: set-matrix
shell: bash
run: |
set -euo pipefail
mapfile -t modules < <(find . -name go.mod \
-not -path "./.resource/*" \
-not -path "./docs/*" \
-not -path "./examples/*" \
-not -path "./test/*" | sort | while IFS= read -r mod; do
if head -n 5 "${mod}" | grep -q "DO NOT USE!"; then
continue
fi
echo "${mod}"
done)
if [ "${#modules[@]}" -eq 0 ]; then
echo "matrix={\"module\":[]}" >> "$GITHUB_OUTPUT"
exit 0
fi
matrix=$(printf '%s\n' "${modules[@]}" | sed 's|^\./||' | jq -R -s -c 'split("\n") | map(select(length>0))')
echo "matrix={\"module\":${matrix}}" >> "$GITHUB_OUTPUT"
test-go-modules:
name: go test (${{ matrix.module }})
runs-on: ubuntu-latest
needs: discover-go-modules
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.discover-go-modules.outputs.matrix) }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
- name: Prepare module metadata
id: module-info
shell: bash
run: |
set -euo pipefail
module='${{ matrix.module }}'
if [ -z "${module}" ]; then
echo "empty module path" >&2
exit 1
fi
rel="${module#./}"
if [ "${rel}" = "go.mod" ]; then
readable="root"
else
readable="${rel%/go.mod}"
fi
safe="${readable//\//_}"
safe="${safe//./_}"
if [ -z "${safe}" ]; then
safe="root"
fi
echo "safe_name=${safe}" >> "$GITHUB_OUTPUT"
- name: Test module
shell: bash
run: bash .github/scripts/run-go-tests.sh --module "${{ matrix.module }}"
- name: Prepare coverage artifact
shell: bash
run: mv coverage.out "coverage-${{ steps.module-info.outputs.safe_name }}.out"
- name: Upload coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage-${{ steps.module-info.outputs.safe_name }}
path: coverage-${{ steps.module-info.outputs.safe_name }}.out
if-no-files-found: error
e2e:
name: e2e test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
- name: Run e2e tests
shell: bash
run: |
set -euo pipefail
cd test
go test ./...
coverage:
name: coverage
runs-on: ubuntu-latest
needs: test-go-modules
steps:
- uses: actions/checkout@v3
- name: Download coverage artifacts
uses: actions/download-artifact@v4
with:
pattern: coverage-*
merge-multiple: true
path: coverage-artifacts
- name: Combine coverage reports
shell: bash
run: |
set -euo pipefail
mapfile -t files < <(find coverage-artifacts -maxdepth 1 -type f -name 'coverage-*.out' | sort)
if [ "${#files[@]}" -eq 0 ]; then
echo "no coverage files found" >&2
exit 1
fi
cp "${files[0]}" coverage.out
for file in "${files[@]:1}"; do
tail -n +2 "${file}" >> coverage.out
done
- name: Upload merged coverage artifact
uses: actions/upload-artifact@v4
with:
name: coverage-merged
path: coverage.out
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
files: coverage.out
flags: unittests
token: ${{ secrets.CODECOV_TOKEN }}
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
args: --timeout=10m
- name: gofmt
run: |
echo "::group::Checking for interface{} usage and gofmt formatting"
files=$(gofmt -r 'interface{} -> any' -l .)
if [ -n "$files" ]; then
echo "::error::Found files that need formatting or contain interface{} type usage."
echo "This check detects both:"
echo " - Files using 'interface{}' (should use 'any' in Go 1.18+)"
echo " - Files not properly formatted with gofmt"
echo ""
echo "Files that need attention:"
echo "$files"
echo ""
echo "You can fix this automatically by running:"
echo " gofmt -w -r 'interface{} -> any' ."
echo " # This will format files and replace interface{} with any"
exit 1
else
echo "✓ All files are properly formatted and use modern 'any' type"
fi
echo "::endgroup::"
- name: goimports
run: |
echo "::group::Checking import formatting with goimports"
go install golang.org/x/tools/cmd/goimports@latest
files=$(goimports -l .)
if [ -n "$files" ]; then
echo "::error::Found files with incorrect import formatting."
echo "goimports checks:"
echo " - Import statement formatting"
echo " - Import grouping (stdlib, external, internal)"
echo " - Import sorting within groups"
echo ""
echo "Files that need attention:"
echo "$files"
echo ""
echo "You can fix this automatically by running:"
echo " go install golang.org/x/tools/cmd/goimports@latest"
echo " goimports -w ."
exit 1
else
echo "✓ All files have properly formatted imports"
fi
echo "::endgroup::"
- name: license
run: |
echo "::group::Checking license headers in Go files"
missing_files=""
while IFS= read -r file; do
if [ -z "$file" ]; then continue; fi
# Check for Tencent license header (like artifacts.go format)
if head -n 10 "$file" | grep -q "Tencent is pleased to support the open source community" && \
head -n 10 "$file" | grep -q "trpc-agent-go is licensed under the Apache License" && \
head -n 10 "$file" | grep -q "Apache License Version 2.0."; then
continue
fi
missing_files="${missing_files}${file}\n"
done < <(git ls-files '*.go' | grep -Ev '(^vendor/|^third_party/|^out/|^build/|stub/)')
if [ -n "$missing_files" ]; then
echo "::error::Found Go files missing proper license headers:"
echo -e "$missing_files"
echo ""
echo "Please ensure all Go files have the standard Tencent license header."
exit 1
else
echo "✓ All Go files have proper license headers"
fi
echo "::endgroup::"
check-go-mod-tidy:
name: check go mod tidy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache: false
- name: Check go.mod and go.sum are tidy
shell: bash
run: bash .github/scripts/check-go-mod-tidy.sh
check-external-consumer:
name: check external consumer (${{ matrix.module }})
runs-on: ubuntu-latest
needs: discover-go-modules
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.discover-go-modules.outputs.matrix) }}
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
- name: Check module as an external consumer
shell: bash
run: bash .github/scripts/check-external-consumer.sh --module "${{ matrix.module }}"
check-examples:
name: check examples (${{ matrix.shard_label }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 4
matrix:
include:
- shard_index: 0
shard_total: 4
shard_label: 1/4
- shard_index: 1
shard_total: 4
shard_label: 2/4
- shard_index: 2
shard_total: 4
shard_label: 3/4
- shard_index: 3
shard_total: 4
shard_label: 4/4
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.EXAMPLES_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
examples/**/go.mod
examples/**/go.sum
- name: Check examples go.mod, go.sum and build
env:
EXAMPLES_SHARD_INDEX: ${{ matrix.shard_index }}
EXAMPLES_SHARD_TOTAL: ${{ matrix.shard_total }}
run: bash .github/scripts/check-examples.sh
check-examples-build-script:
name: check examples build script (${{ matrix.shard_label }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 4
matrix:
include:
- shard_index: 0
shard_total: 4
shard_label: 1/4
- shard_index: 1
shard_total: 4
shard_label: 2/4
- shard_index: 2
shard_total: 4
shard_label: 3/4
- shard_index: 3
shard_total: 4
shard_label: 4/4
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "${{ env.EXAMPLES_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
examples/**/go.mod
examples/**/go.sum
- name: Build examples with CGO disabled
shell: bash
env:
EXAMPLES_SHARD_INDEX: ${{ matrix.shard_index }}
EXAMPLES_SHARD_TOTAL: ${{ matrix.shard_total }}
run: bash .github/scripts/check-examples-build.sh
check-lfs-excluded:
name: check git lfs excluded
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate Git LFS files are excluded from published modules
run: bash .github/scripts/check-lfs-excluded.sh
check-file-size:
name: check file size
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Validate changed file sizes
env:
CHECK_FILE_SIZE_BASE_REF: ${{ github.base_ref }}
CHECK_FILE_SIZE_BEFORE_SHA: ${{ github.event.before }}
CHECK_FILE_SIZE_LIMIT_BYTES: 1572864
run: bash .github/scripts/check-file-size.sh
check-go-sumdb:
name: check sum.golang.org checksums
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
fetch-tags: true
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache: false
- name: Validate module checksums via sumdb
run: bash .github/scripts/check-go-sumdb.sh
typos:
name: typos
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: typos
uses: crate-ci/typos@master
go-apidiff:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
# Use merge-base to only detect breaking changes introduced by this PR,
# not changes from main that were merged after the PR branch was created.
- name: Get merge base
id: merge-base
run: |
MERGE_BASE=$(git merge-base HEAD origin/${{ github.base_ref }})
echo "sha=$MERGE_BASE" >> "$GITHUB_OUTPUT"
- uses: joelanford/go-apidiff@main
with:
base-ref: ${{ steps.merge-base.outputs.sha }}
docs-build:
name: docs-build
runs-on: ubuntu-latest
defaults:
run:
working-directory: docs
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install MkDocs dependencies
run: pip install -r mkdocs/assets/requirements.txt
- name: Build documentation
run: mkdocs build --strict
check-go-mod-version:
name: check go.mod version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
fetch-tags: true
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache: false
- name: Validate go.mod version strings
shell: bash
run: bash .github/scripts/check-go-mod-version.sh
benchmark-smoke:
name: benchmark smoke
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "${{ env.EXAMPLES_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
**/go.mod
**/go.sum
- name: Run all benchmarks once
shell: bash
run: |
.github/scripts/run-go-benchmarks.sh \
--suite all \
--mode smoke \
--output benchmark-smoke.txt
- name: Upload benchmark smoke output
if: always()
uses: actions/upload-artifact@v4
with:
name: benchmark-smoke
path: benchmark-smoke.txt
if-no-files-found: warn
benchmark-allocation-guard:
name: benchmark allocation guard
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
go.mod
go.sum
- name: Test allocation guard
run: go test ./.github/scripts/benchguard
- name: Measure stable Agent Loop allocations
shell: bash
run: |
.github/scripts/run-go-benchmarks.sh \
--suite agent-loop-core \
--mode measure \
--count 3 \
--benchtime 200ms \
--output benchmark-core.txt
- name: Enforce allocation budgets
run: |
go run ./.github/scripts/benchguard \
-input benchmark-core.txt \
-budgets .github/benchmarks/agentloop/budgets.json
- name: Upload core benchmark output
if: always()
uses: actions/upload-artifact@v4
with:
name: benchmark-core
path: benchmark-core.txt
if-no-files-found: warn
benchmark-report:
name: benchmark report
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Check out base revision
uses: actions/checkout@v4
with:
repository: "${{ github.event.pull_request.base.repo.full_name }}"
ref: "${{ github.event.pull_request.base.sha }}"
path: base
- name: Check out head revision
uses: actions/checkout@v4
with:
repository: "${{ github.event.pull_request.head.repo.full_name }}"
ref: "${{ github.event.pull_request.head.sha }}"
path: head
- uses: actions/setup-go@v5
with:
go-version: "${{ env.ROOT_GO_VERSION }}"
cache-dependency-path: |
base/go.mod
base/go.sum
head/go.mod
head/go.sum
- name: Measure base revision
continue-on-error: true
shell: bash
run: |
head/.github/scripts/run-go-benchmarks.sh \
--repo base \
--suite agent-loop \
--mode measure \
--count 6 \
--benchtime 200ms \
--output benchmark-base.txt \
--keep-going
- name: Measure head revision
shell: bash
run: |
head/.github/scripts/run-go-benchmarks.sh \
--repo head \
--suite agent-loop \
--mode measure \
--count 6 \
--benchtime 200ms \
--output benchmark-head.txt
- name: Compare revisions
shell: bash
run: |
go run golang.org/x/perf/cmd/benchstat@v0.0.0-20240510023725-bedb9135df6d \
benchmark-base.txt benchmark-head.txt | tee benchstat.txt
{
echo "## Agent Loop benchmark"
echo '```text'
cat benchstat.txt
echo '```'
} >>"${GITHUB_STEP_SUMMARY}"
- name: Upload benchmark comparison
if: always()
uses: actions/upload-artifact@v4
with:
name: benchmark-report
path: |
benchmark-base.txt
benchmark-head.txt
benchstat.txt
if-no-files-found: warn