ci(python): gate the Windows x64 installed wheel
Add node24-win-x64 to the required pull-request and public-release matrices on a native windows-2025 runner, and publish the same win_amd64 artifact from the GitLab tag pipeline. GitHub uses Git Bash for the shared release script while selecting the Windows venv's Scripts/python.exe explicitly; the Linux and macOS legs retain their existing commands and native checks. Run the complete installed-wheel keyless suite and the trusted two-turn DeepSeek smoke on Windows exactly as on the existing targets. Make the minimal blackbox choose persistent PowerShell on Windows, keep advanced and restart snapshots platform-stable by disabling both one-shot shell variants, locate the generated dsh.exe console command, and validate text lines without assuming POSIX newlines. Workflow tests pin the four-target matrix, Windows runner and wheel tag, cross-platform venv selection, GitLab publication dependency, and full blackbox invocation. The existing POSIX minimal snapshot changes only its platform-neutral prompt wording; Windows owns a separate model-visible snapshot.
This commit is contained in:
1 parent
ca0b21661e
commit
026a37fc07
8 files changed
+586
-48
No files matched your search
@@ -2,7 +2,7 @@ name: Build single-exe
|
|||||||
|
|
||||||
# Native builds for the release targets; see
|
# Native builds for the release targets; see
|
||||||
# .agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md.
|
# .agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md.
|
||||||
# A full target run retains one SDK wheel and three runtime wheels; subset
|
# A full target run retains one SDK wheel and four runtime wheels; subset
|
||||||
# dispatch retains the SDK wheel and selected runtime wheels. Bare executables
|
# dispatch retains the SDK wheel and selected runtime wheels. Bare executables
|
||||||
# and source closures are test inputs. Run manually, label a PR `build-exe`
|
# and source closures are test inputs. Run manually, label a PR `build-exe`
|
||||||
# (remove and reapply to rerun), or call it from the Python release workflow.
|
# (remove and reapply to rerun), or call it from the Python release workflow.
|
||||||
@@ -11,7 +11,7 @@ on:
|
|||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
targets:
|
targets:
|
||||||
description: Comma-separated pkg targets to build; empty builds all three.
|
description: Comma-separated pkg targets to build; empty builds all four.
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
@@ -34,8 +34,8 @@ on:
|
|||||||
targets:
|
targets:
|
||||||
description: >-
|
description: >-
|
||||||
Comma-separated pkg targets to build. Any subset of:
|
Comma-separated pkg targets to build. Any subset of:
|
||||||
node24-linux-x64, node24-linux-arm64, node24-macos-arm64.
|
node24-linux-x64, node24-linux-arm64, node24-macos-arm64,
|
||||||
Empty builds all three.
|
node24-win-x64. Empty builds all four.
|
||||||
type: string
|
type: string
|
||||||
required: false
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
id: plan
|
id: plan
|
||||||
env:
|
env:
|
||||||
# Label runs and blank dispatch inputs build all targets.
|
# Label runs and blank dispatch inputs build all targets.
|
||||||
TARGETS: ${{ inputs.targets || 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64' }}
|
TARGETS: ${{ inputs.targets || 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64' }}
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
matrix='[]'
|
matrix='[]'
|
||||||
@@ -104,8 +104,9 @@ jobs:
|
|||||||
node24-linux-x64) runner=ubuntu-latest ;;
|
node24-linux-x64) runner=ubuntu-latest ;;
|
||||||
node24-linux-arm64) runner=ubuntu-24.04-arm ;;
|
node24-linux-arm64) runner=ubuntu-24.04-arm ;;
|
||||||
node24-macos-arm64) runner=macos-latest ;;
|
node24-macos-arm64) runner=macos-latest ;;
|
||||||
|
node24-win-x64) runner=windows-2025 ;;
|
||||||
*)
|
*)
|
||||||
echo "::error::Unknown target '$t'. Supported: node24-linux-x64, node24-linux-arm64, node24-macos-arm64."
|
echo "::error::Unknown target '$t'. Supported: node24-linux-x64, node24-linux-arm64, node24-macos-arm64, node24-win-x64."
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -155,10 +156,22 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include: ${{ fromJSON(needs.plan.outputs.matrix) }}
|
include: ${{ fromJSON(needs.plan.outputs.matrix) }}
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
dest: ${{ runner.temp }}/setup-pnpm-js
|
||||||
|
|
||||||
|
- name: Enable Windows Developer Mode (symlink support)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
shell: pwsh
|
||||||
|
run: >-
|
||||||
|
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
|
||||||
|
/t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1"
|
||||||
|
|
||||||
# setup-node's built-in pnpm store cache keys on platform AND arch, so
|
# setup-node's built-in pnpm store cache keys on platform AND arch, so
|
||||||
# the Linux architectures sharing runner.os stay on separate caches.
|
# the Linux architectures sharing runner.os stay on separate caches.
|
||||||
@@ -198,6 +211,7 @@ jobs:
|
|||||||
*) echo "::error::Unsupported Linux runner architecture $RUNNER_ARCH"; exit 1 ;;
|
*) echo "::error::Unsupported Linux runner architecture $RUNNER_ARCH"; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
addon_dir="$(realpath packages/subprocess/subprocess-local/node_modules/node-pty)"
|
addon_dir="$(realpath packages/subprocess/subprocess-local/node_modules/node-pty)"
|
||||||
|
pnpm_setup_root="$(realpath "$(dirname "$(dirname "$PNPM_HOME")")")"
|
||||||
(cd "$addon_dir" && npm_config_build_from_source=true pnpm run install)
|
(cd "$addon_dir" && npm_config_build_from_source=true pnpm run install)
|
||||||
addon="$addon_dir/build/Release/pty.node"
|
addon="$addon_dir/build/Release/pty.node"
|
||||||
[ -f "$addon_dir/build/Makefile" ] || {
|
[ -f "$addon_dir/build/Makefile" ] || {
|
||||||
@@ -208,7 +222,7 @@ jobs:
|
|||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
-v "$PWD:$PWD" \
|
-v "$PWD:$PWD" \
|
||||||
-v "$HOME/.cache/node-gyp:$HOME/.cache/node-gyp:ro" \
|
-v "$HOME/.cache/node-gyp:$HOME/.cache/node-gyp:ro" \
|
||||||
-v "$HOME/setup-pnpm:$HOME/setup-pnpm:ro" \
|
-v "$pnpm_setup_root:$pnpm_setup_root:ro" \
|
||||||
-w "$addon_dir" \
|
-w "$addon_dir" \
|
||||||
"$image" \
|
"$image" \
|
||||||
bash -euxo pipefail -c \
|
bash -euxo pipefail -c \
|
||||||
@@ -236,13 +250,21 @@ jobs:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
platform="${TARGET#node24-}"
|
platform="${TARGET#node24-}"
|
||||||
exe="$PWD/dist-exe/deepseek-harness-sdk-runtime-$platform"
|
exe="$PWD/dist-exe/deepseek-harness-sdk-runtime-$platform"
|
||||||
[ -x "$exe" ] || { echo "::error::$exe missing or not executable"; exit 1; }
|
|
||||||
case "$platform" in
|
case "$platform" in
|
||||||
linux-x64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl ;;
|
linux-x64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl ;;
|
||||||
linux-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl ;;
|
linux-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl ;;
|
||||||
macos-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl ;;
|
macos-arm64) wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl ;;
|
||||||
|
win-x64)
|
||||||
|
exe="$exe.exe"
|
||||||
|
wheel=deepseek_harness_runtime_bin-$VERSION-py3-none-win_amd64.whl
|
||||||
|
;;
|
||||||
*) echo "::error::Unsupported runtime platform $platform"; exit 1 ;;
|
*) echo "::error::Unsupported runtime platform $platform"; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
|
if [ "$RUNNER_OS" = Windows ]; then
|
||||||
|
[ -f "$exe" ] || { echo "::error::$exe missing"; exit 1; }
|
||||||
|
else
|
||||||
|
[ -x "$exe" ] || { echo "::error::$exe missing or not executable"; exit 1; }
|
||||||
|
fi
|
||||||
echo "platform=$platform" >> "$GITHUB_OUTPUT"
|
echo "platform=$platform" >> "$GITHUB_OUTPUT"
|
||||||
echo "exe=$exe" >> "$GITHUB_OUTPUT"
|
echo "exe=$exe" >> "$GITHUB_OUTPUT"
|
||||||
echo "wheel=$wheel" >> "$GITHUB_OUTPUT"
|
echo "wheel=$wheel" >> "$GITHUB_OUTPUT"
|
||||||
@@ -261,24 +283,32 @@ jobs:
|
|||||||
path: dist-python
|
path: dist-python
|
||||||
|
|
||||||
- name: Install local SDK and runtime wheels into a clean venv
|
- name: Install local SDK and runtime wheels into a clean venv
|
||||||
|
id: smoke-venv
|
||||||
env:
|
env:
|
||||||
RUNTIME_WHEEL: ${{ steps.runtime.outputs.wheel }}
|
RUNTIME_WHEEL: ${{ steps.runtime.outputs.wheel }}
|
||||||
SDK_WHEEL: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
SDK_WHEEL: deepseek_harness_sdk-${{ needs.plan.outputs.version }}-py3-none-any.whl
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
python -m venv "$RUNNER_TEMP/dsh-sdk-smoke"
|
venv="$(python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-smoke-"))')"
|
||||||
"$RUNNER_TEMP/dsh-sdk-smoke/bin/python" -m pip install \
|
python -m venv "$venv"
|
||||||
|
if [ "$RUNNER_OS" = Windows ]; then
|
||||||
|
smoke_python="$(cygpath -u "$venv")/Scripts/python.exe"
|
||||||
|
else
|
||||||
|
smoke_python="$venv/bin/python"
|
||||||
|
fi
|
||||||
|
"$smoke_python" -m pip install \
|
||||||
"dist-python/$SDK_WHEEL" \
|
"dist-python/$SDK_WHEEL" \
|
||||||
"dist-python/$RUNTIME_WHEEL"
|
"dist-python/$RUNTIME_WHEEL"
|
||||||
|
echo "python=$smoke_python" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Run installed-wheel keyless black-box tests
|
- name: Run installed-wheel keyless black-box tests
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
blackbox_root="$RUNNER_TEMP/dsh-sdk-blackbox"
|
blackbox_root="$(python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-blackbox-"))')"
|
||||||
mkdir -p "$blackbox_root"
|
if [ "$RUNNER_OS" = Windows ]; then blackbox_root="$(cygpath -u "$blackbox_root")"; fi
|
||||||
cd "$blackbox_root"
|
cd "$blackbox_root"
|
||||||
env -u PYTHONPATH -u DSH_RUNTIME_MODE \
|
env -u PYTHONPATH -u DSH_RUNTIME_MODE \
|
||||||
"$RUNNER_TEMP/dsh-sdk-smoke/bin/python" \
|
"${{ steps.smoke-venv.outputs.python }}" \
|
||||||
"$GITHUB_WORKSPACE/scripts/smoke-python-runtime.py" \
|
"$GITHUB_WORKSPACE/scripts/smoke-python-runtime.py" \
|
||||||
--scenario all \
|
--scenario all \
|
||||||
--installed-wheel
|
--installed-wheel
|
||||||
@@ -309,11 +339,11 @@ jobs:
|
|||||||
DEEPSEEK_BASE_URL: https://api.deepseek.com
|
DEEPSEEK_BASE_URL: https://api.deepseek.com
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
blackbox_root="$RUNNER_TEMP/dsh-sdk-blackbox-live"
|
blackbox_root="$(python -c 'import tempfile; print(tempfile.mkdtemp(prefix="dsh-sdk-blackbox-live-"))')"
|
||||||
mkdir -p "$blackbox_root"
|
if [ "$RUNNER_OS" = Windows ]; then blackbox_root="$(cygpath -u "$blackbox_root")"; fi
|
||||||
cd "$blackbox_root"
|
cd "$blackbox_root"
|
||||||
env -u PYTHONPATH -u DSH_RUNTIME_MODE \
|
env -u PYTHONPATH -u DSH_RUNTIME_MODE \
|
||||||
"$RUNNER_TEMP/dsh-sdk-smoke/bin/python" \
|
"${{ steps.smoke-venv.outputs.python }}" \
|
||||||
"$GITHUB_WORKSPACE/scripts/smoke-python-runtime.py" \
|
"$GITHUB_WORKSPACE/scripts/smoke-python-runtime.py" \
|
||||||
--scenario sdk-live \
|
--scenario sdk-live \
|
||||||
--installed-wheel
|
--installed-wheel
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ jobs:
|
|||||||
name: python runtime / release-shaped matrix
|
name: python runtime / release-shaped matrix
|
||||||
uses: ./.github/workflows/build-exe-for-python-sdk.yml
|
uses: ./.github/workflows/build-exe-for-python-sdk.yml
|
||||||
with:
|
with:
|
||||||
targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64
|
targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64
|
||||||
ci: true
|
ci: true
|
||||||
secrets:
|
secrets:
|
||||||
DEEPSEEK_API_KEY_EXTERNAL: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
DEEPSEEK_API_KEY_EXTERNAL: ${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build four wheels
|
name: Build five wheels
|
||||||
uses: ./.github/workflows/build-exe-for-python-sdk.yml
|
uses: ./.github/workflows/build-exe-for-python-sdk.yml
|
||||||
with:
|
with:
|
||||||
targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64
|
targets: node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64
|
||||||
release: true
|
release: true
|
||||||
|
|
||||||
python-compat:
|
python-compat:
|
||||||
@@ -151,6 +151,7 @@ jobs:
|
|||||||
"deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl" \
|
"deepseek_harness_runtime_bin-$VERSION-py3-none-macosx_14_0_arm64.whl" \
|
||||||
"deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl" \
|
"deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_aarch64.whl" \
|
||||||
"deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl" \
|
"deepseek_harness_runtime_bin-$VERSION-py3-none-manylinux_2_28_x86_64.whl" \
|
||||||
|
"deepseek_harness_runtime_bin-$VERSION-py3-none-win_amd64.whl" \
|
||||||
"deepseek_harness_sdk-$VERSION-py3-none-any.whl" > "$expected"
|
"deepseek_harness_sdk-$VERSION-py3-none-any.whl" > "$expected"
|
||||||
find dist -maxdepth 1 -type f -name '*.whl' -exec basename {} \; | sort > "$actual"
|
find dist -maxdepth 1 -type f -name '*.whl' -exec basename {} \; | sort > "$actual"
|
||||||
diff -u "$expected" "$actual"
|
diff -u "$expected" "$actual"
|
||||||
|
|||||||
+40
-1
@@ -97,6 +97,42 @@ runtime-macos-arm64:
|
|||||||
- job: sdk-wheel
|
- job: sdk-wheel
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
|
||||||
|
runtime-windows-x64:
|
||||||
|
stage: build
|
||||||
|
tags: [windows-x64]
|
||||||
|
variables:
|
||||||
|
PKG_TARGET: node24-win-x64
|
||||||
|
PLATFORM: win-x64
|
||||||
|
needs:
|
||||||
|
- job: sdk-wheel
|
||||||
|
artifacts: true
|
||||||
|
before_script:
|
||||||
|
- python -m venv .ci-python
|
||||||
|
- $env:DSH_VERSION = (& .ci-python\Scripts\python.exe -c 'import json; print(json.load(open("package.json"))["version"])')
|
||||||
|
- $env:DSH_WHEEL_VERSION = (& .ci-python\Scripts\python.exe -c 'import runpy; release = runpy.run_path("scripts/build-python-release.py"); print(release["pep440_version"](release["repository_version"]()))')
|
||||||
|
- if ($env:CI_COMMIT_TAG -ne "python-v$env:DSH_VERSION") { throw "Tag $env:CI_COMMIT_TAG does not match package.json version $env:DSH_VERSION" }
|
||||||
|
- .ci-python\Scripts\python.exe -m pip install uv==0.11.23
|
||||||
|
script:
|
||||||
|
- corepack enable
|
||||||
|
- pnpm install --frozen-lockfile
|
||||||
|
- pnpm run verify-runtime-closure
|
||||||
|
- pnpm exec tsx scripts/build-exe-for-python-sdk.ts --targets=$env:PKG_TARGET
|
||||||
|
- $exe = Join-Path $PWD "dist-exe\deepseek-harness-sdk-runtime-win-x64.exe"
|
||||||
|
- if (-not (Test-Path -LiteralPath $exe -PathType Leaf)) { throw "Runtime executable is missing at $exe" }
|
||||||
|
- uv run --python 3.10 --group test --project python/sdk python scripts/smoke-python-runtime.py --scenario all --exe $exe
|
||||||
|
- .ci-python\Scripts\python.exe scripts/build-python-release.py --package runtime --tag $env:CI_COMMIT_TAG --platform $env:PLATFORM --runtime-exe $exe --output-dir "release/$env:PLATFORM"
|
||||||
|
- python -m venv .wheel-smoke
|
||||||
|
- .wheel-smoke\Scripts\python.exe -m pip install "release/sdk/deepseek_harness_sdk-$env:DSH_WHEEL_VERSION-py3-none-any.whl" "release/win-x64/deepseek_harness_runtime_bin-$env:DSH_WHEEL_VERSION-py3-none-win_amd64.whl"
|
||||||
|
- Remove-Item Env:PYTHONPATH -ErrorAction SilentlyContinue
|
||||||
|
- Remove-Item Env:DSH_RUNTIME_MODE -ErrorAction SilentlyContinue
|
||||||
|
- $blackbox = Join-Path $env:TEMP "dsh-sdk-blackbox-$([guid]::NewGuid())"
|
||||||
|
- New-Item -ItemType Directory -Path $blackbox | Out-Null
|
||||||
|
- Push-Location $blackbox
|
||||||
|
- try { & "$env:CI_PROJECT_DIR\.wheel-smoke\Scripts\python.exe" "$env:CI_PROJECT_DIR\scripts\smoke-python-runtime.py" --scenario all --installed-wheel } finally { Pop-Location }
|
||||||
|
artifacts:
|
||||||
|
paths: [release/win-x64/*.whl]
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
publish-python:
|
publish-python:
|
||||||
stage: publish
|
stage: publish
|
||||||
tags: [linux-x64]
|
tags: [linux-x64]
|
||||||
@@ -110,6 +146,8 @@ publish-python:
|
|||||||
artifacts: true
|
artifacts: true
|
||||||
- job: runtime-macos-arm64
|
- job: runtime-macos-arm64
|
||||||
artifacts: true
|
artifacts: true
|
||||||
|
- job: runtime-windows-x64
|
||||||
|
artifacts: true
|
||||||
before_script:
|
before_script:
|
||||||
- python3 -m venv .ci-python
|
- python3 -m venv .ci-python
|
||||||
- . .ci-python/bin/activate
|
- . .ci-python/bin/activate
|
||||||
@@ -118,11 +156,12 @@ publish-python:
|
|||||||
- test "$CI_COMMIT_TAG" = "python-v$DSH_VERSION" || { echo "Tag $CI_COMMIT_TAG does not match package.json version $DSH_VERSION"; exit 1; }
|
- test "$CI_COMMIT_TAG" = "python-v$DSH_VERSION" || { echo "Tag $CI_COMMIT_TAG does not match package.json version $DSH_VERSION"; exit 1; }
|
||||||
- python -m pip install twine==6.2.0
|
- python -m pip install twine==6.2.0
|
||||||
script:
|
script:
|
||||||
- test "$(find release -name '*.whl' | wc -l | tr -d ' ')" = 4
|
- test "$(find release -name '*.whl' | wc -l | tr -d ' ')" = 5
|
||||||
- test -f "release/sdk/deepseek_harness_sdk-${DSH_WHEEL_VERSION}-py3-none-any.whl"
|
- test -f "release/sdk/deepseek_harness_sdk-${DSH_WHEEL_VERSION}-py3-none-any.whl"
|
||||||
- test -f "release/linux-x64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-manylinux_2_28_x86_64.whl"
|
- test -f "release/linux-x64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-manylinux_2_28_x86_64.whl"
|
||||||
- test -f "release/linux-arm64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-manylinux_2_28_aarch64.whl"
|
- test -f "release/linux-arm64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-manylinux_2_28_aarch64.whl"
|
||||||
- test -f "release/macos-arm64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-macosx_14_0_arm64.whl"
|
- test -f "release/macos-arm64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-macosx_14_0_arm64.whl"
|
||||||
|
- test -f "release/win-x64/deepseek_harness_runtime_bin-${DSH_WHEEL_VERSION}-py3-none-win_amd64.whl"
|
||||||
- python -m twine check release/*/*.whl
|
- python -m twine check release/*/*.whl
|
||||||
- export TWINE_USERNAME=gitlab-ci-token
|
- export TWINE_USERNAME=gitlab-ci-token
|
||||||
- export TWINE_PASSWORD="$CI_JOB_TOKEN"
|
- export TWINE_PASSWORD="$CI_JOB_TOKEN"
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ describe('CI workflow', () => {
|
|||||||
name: 'python runtime / release-shaped matrix',
|
name: 'python runtime / release-shaped matrix',
|
||||||
uses: './.github/workflows/build-exe-for-python-sdk.yml',
|
uses: './.github/workflows/build-exe-for-python-sdk.yml',
|
||||||
with: {
|
with: {
|
||||||
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64',
|
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64',
|
||||||
ci: true,
|
ci: true,
|
||||||
},
|
},
|
||||||
secrets: {
|
secrets: {
|
||||||
@@ -320,7 +320,7 @@ describe('Python release workflows', () => {
|
|||||||
expect(build).toMatchObject({
|
expect(build).toMatchObject({
|
||||||
uses: './.github/workflows/build-exe-for-python-sdk.yml',
|
uses: './.github/workflows/build-exe-for-python-sdk.yml',
|
||||||
with: {
|
with: {
|
||||||
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64',
|
targets: 'node24-linux-x64,node24-linux-arm64,node24-macos-arm64,node24-win-x64',
|
||||||
release: true,
|
release: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -390,10 +390,11 @@ describe('Python release workflows', () => {
|
|||||||
const manylinuxAddon = buildSteps.find(step => isRecord(step) && step.name === 'Rebuild Linux node-pty against manylinux 2.28')
|
const manylinuxAddon = buildSteps.find(step => isRecord(step) && step.name === 'Rebuild Linux node-pty against manylinux 2.28')
|
||||||
const macosCheck = buildSteps.find(step => isRecord(step) && step.name === 'Check macOS deployment target')
|
const macosCheck = buildSteps.find(step => isRecord(step) && step.name === 'Check macOS deployment target')
|
||||||
const manylinuxSmoke = buildSteps.find(step => isRecord(step) && step.name === 'Run wheel in a manylinux 2.28 container')
|
const manylinuxSmoke = buildSteps.find(step => isRecord(step) && step.name === 'Run wheel in a manylinux 2.28 container')
|
||||||
|
const cleanVenv = buildSteps.find(step => isRecord(step) && step.name === 'Install local SDK and runtime wheels into a clean venv')
|
||||||
const installedKeyless = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel keyless black-box tests')
|
const installedKeyless = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel keyless black-box tests')
|
||||||
const realApiPreflight = buildSteps.find(step => isRecord(step) && step.name === 'Preflight installed-wheel real API test')
|
const realApiPreflight = buildSteps.find(step => isRecord(step) && step.name === 'Preflight installed-wheel real API test')
|
||||||
const installedRealApi = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test')
|
const installedRealApi = buildSteps.find(step => isRecord(step) && step.name === 'Run installed-wheel real API black-box test')
|
||||||
if (!isRecord(installedKeyless) || !isRecord(realApiPreflight) || !isRecord(installedRealApi)) {
|
if (!isRecord(cleanVenv) || !isRecord(installedKeyless) || !isRecord(realApiPreflight) || !isRecord(installedRealApi)) {
|
||||||
throw new TypeError('Python wheel builder must define installed-wheel keyless and real API steps')
|
throw new TypeError('Python wheel builder must define installed-wheel keyless and real API steps')
|
||||||
}
|
}
|
||||||
expect(call.inputs).toHaveProperty('targets')
|
expect(call.inputs).toHaveProperty('targets')
|
||||||
@@ -407,11 +408,15 @@ describe('Python release workflows', () => {
|
|||||||
expect(workflow.concurrency).toMatchObject({
|
expect(workflow.concurrency).toMatchObject({
|
||||||
group: 'build-single-exe-${{ github.workflow }}-${{ github.ref }}',
|
group: 'build-single-exe-${{ github.workflow }}-${{ github.ref }}',
|
||||||
})
|
})
|
||||||
|
expect(build.defaults).toMatchObject({ run: { shell: 'bash' } })
|
||||||
expect(plan.if).toContain('inputs.ci')
|
expect(plan.if).toContain('inputs.ci')
|
||||||
expect(plan.if).toContain('inputs.release')
|
expect(plan.if).toContain('inputs.release')
|
||||||
expect(JSON.stringify(plan.steps)).toContain('pep440_version')
|
expect(JSON.stringify(plan.steps)).toContain('pep440_version')
|
||||||
const workflowJson = JSON.stringify(workflow)
|
const workflowJson = JSON.stringify(workflow)
|
||||||
expect(workflowJson).toContain('macosx_14_0_arm64')
|
expect(workflowJson).toContain('macosx_14_0_arm64')
|
||||||
|
expect(workflowJson).toContain('win_amd64')
|
||||||
|
expect(workflowJson).toContain('node24-win-x64')
|
||||||
|
expect(workflowJson).toContain('windows-2025')
|
||||||
expect(workflowJson).toContain('dist-python/$SDK_WHEEL')
|
expect(workflowJson).toContain('dist-python/$SDK_WHEEL')
|
||||||
expect(workflowJson).toContain('dist-python/$RUNTIME_WHEEL')
|
expect(workflowJson).toContain('dist-python/$RUNTIME_WHEEL')
|
||||||
expect(workflowJson).toContain('/work/dist-python/$SDK_WHEEL')
|
expect(workflowJson).toContain('/work/dist-python/$SDK_WHEEL')
|
||||||
@@ -422,7 +427,8 @@ describe('Python release workflows', () => {
|
|||||||
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_x86_64')
|
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_x86_64')
|
||||||
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_aarch64')
|
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_aarch64')
|
||||||
expect(JSON.stringify(manylinuxAddon)).toContain('npm_config_build_from_source=true pnpm run install')
|
expect(JSON.stringify(manylinuxAddon)).toContain('npm_config_build_from_source=true pnpm run install')
|
||||||
expect(JSON.stringify(manylinuxAddon)).toContain('$HOME/setup-pnpm:$HOME/setup-pnpm:ro')
|
expect(JSON.stringify(manylinuxAddon)).toContain('pnpm_setup_root')
|
||||||
|
expect(JSON.stringify(manylinuxAddon)).toContain('$pnpm_setup_root:$pnpm_setup_root:ro')
|
||||||
expect(JSON.stringify(manylinuxAddon)).toContain('node-pty-glibc-versions.txt')
|
expect(JSON.stringify(manylinuxAddon)).toContain('node-pty-glibc-versions.txt')
|
||||||
expect(JSON.stringify(manylinuxAddon)).toContain('le 2.28')
|
expect(JSON.stringify(manylinuxAddon)).toContain('le 2.28')
|
||||||
expect(macosCheck).toMatchObject({ if: "runner.os == 'macOS'" })
|
expect(macosCheck).toMatchObject({ if: "runner.os == 'macOS'" })
|
||||||
@@ -432,6 +438,7 @@ describe('Python release workflows', () => {
|
|||||||
expect(JSON.stringify(installedKeyless)).toContain('--installed-wheel')
|
expect(JSON.stringify(installedKeyless)).toContain('--installed-wheel')
|
||||||
expect(JSON.stringify(installedKeyless)).toContain('env -u PYTHONPATH')
|
expect(JSON.stringify(installedKeyless)).toContain('env -u PYTHONPATH')
|
||||||
expect(JSON.stringify(installedKeyless)).toContain('-u DSH_RUNTIME_MODE')
|
expect(JSON.stringify(installedKeyless)).toContain('-u DSH_RUNTIME_MODE')
|
||||||
|
expect(JSON.stringify(cleanVenv)).toContain('Scripts/python.exe')
|
||||||
expect(realApiPreflight).toMatchObject({
|
expect(realApiPreflight).toMatchObject({
|
||||||
env: { DEEPSEEK_API_KEY: '${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}' },
|
env: { DEEPSEEK_API_KEY: '${{ secrets.DEEPSEEK_API_KEY_EXTERNAL }}' },
|
||||||
})
|
})
|
||||||
@@ -469,6 +476,21 @@ describe('Python release workflows', () => {
|
|||||||
expect(macosCheck).toContain('scripts/check-macos-deployment-target.py')
|
expect(macosCheck).toContain('scripts/check-macos-deployment-target.py')
|
||||||
expect(macosCheck).toContain('"$EXE" "$EXE-spawn-helper"')
|
expect(macosCheck).toContain('"$EXE" "$EXE-spawn-helper"')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('builds and black-box tests the Windows x64 wheel in GitLab', () => {
|
||||||
|
const workflow = loadWorkflow('.gitlab-ci.yml')
|
||||||
|
const windows = workflow['runtime-windows-x64']
|
||||||
|
const publish = workflow['publish-python']
|
||||||
|
if (!isRecord(windows) || !Array.isArray(windows.script) || !isRecord(publish) || !Array.isArray(publish.needs)) {
|
||||||
|
throw new TypeError('GitLab CI must define the Windows runtime and aggregate publication jobs')
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(windows.tags).toEqual(['windows-x64'])
|
||||||
|
expect(windows.variables).toMatchObject({ PKG_TARGET: 'node24-win-x64', PLATFORM: 'win-x64' })
|
||||||
|
expect(JSON.stringify(windows.script)).toContain('win_amd64.whl')
|
||||||
|
expect(JSON.stringify(windows.script)).toContain('--scenario all --installed-wheel')
|
||||||
|
expect(publish.needs).toContainEqual({ job: 'runtime-windows-x64', artifacts: true })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Issue lifecycle workflow', () => {
|
describe('Issue lifecycle workflow', () => {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ CODE_PROMPT = "Use run_code to compute the packaged worker smoke value."
|
|||||||
CODE_WORKER_TEXT = "code worker smoke ok"
|
CODE_WORKER_TEXT = "code worker smoke ok"
|
||||||
WORKFLOW_PROMPT = "Use workflow to compute the packaged worker smoke value without agents."
|
WORKFLOW_PROMPT = "Use workflow to compute the packaged worker smoke value without agents."
|
||||||
WORKFLOW_WORKER_TEXT = "workflow worker smoke ok"
|
WORKFLOW_WORKER_TEXT = "workflow worker smoke ok"
|
||||||
MINIMAL_PROMPT = "Exercise the packaged minimal agent's persistent Bash and string-replacement editor."
|
MINIMAL_PROMPT = "Exercise the packaged minimal agent's persistent shell and string-replacement editor."
|
||||||
MINIMAL_TEXT = "minimal agent smoke ok"
|
MINIMAL_TEXT = "minimal agent smoke ok"
|
||||||
MINIMAL_EDITOR_PATH_PREFIX = "Editor path: "
|
MINIMAL_EDITOR_PATH_PREFIX = "Editor path: "
|
||||||
FS_SEARCH_PROMPT = "Exercise the packaged filesystem search tools."
|
FS_SEARCH_PROMPT = "Exercise the packaged filesystem search tools."
|
||||||
@@ -41,11 +41,20 @@ MCP_TEXT = "MCP client smoke ok"
|
|||||||
PROFILE_PLUGIN_PROMPT = "Verify the Python-installed dsh profile plugin."
|
PROFILE_PLUGIN_PROMPT = "Verify the Python-installed dsh profile plugin."
|
||||||
PROFILE_PLUGIN_TEXT = "profile plugin smoke ok"
|
PROFILE_PLUGIN_TEXT = "profile plugin smoke ok"
|
||||||
PROFILE_PLUGIN_MARKER = "PYTHON_INSTALLED_DSH_PROFILE_PLUGIN"
|
PROFILE_PLUGIN_MARKER = "PYTHON_INSTALLED_DSH_PROFILE_PLUGIN"
|
||||||
MINIMAL_BASH_COMMAND = (
|
IS_WINDOWS = sys.platform == "win32"
|
||||||
"counter=$(( ${counter:-0} + 1 )); export counter; "
|
MINIMAL_SHELL_TOOL = "pwsh" if IS_WINDOWS else "bash"
|
||||||
"printf 'COUNT=%s CWD=%s\\n' \"$counter\" \"$PWD\"; "
|
MINIMAL_SHELL_COMMAND = (
|
||||||
"if [ \"$counter\" -eq 1 ]; then cd /tmp; fi"
|
"$global:dshSdkCounter = [int]$global:dshSdkCounter + 1; "
|
||||||
|
'Write-Output "COUNT=$global:dshSdkCounter CWD=$((Get-Location).Path)"; '
|
||||||
|
"if ($global:dshSdkCounter -eq 1) { Set-Location $env:TEMP }"
|
||||||
|
if IS_WINDOWS
|
||||||
|
else (
|
||||||
|
"counter=$(( ${counter:-0} + 1 )); export counter; "
|
||||||
|
"printf 'COUNT=%s CWD=%s\\n' \"$counter\" \"$PWD\"; "
|
||||||
|
"if [ \"$counter\" -eq 1 ]; then cd /tmp; fi"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
MINIMAL_SHELL_SECOND_CWD = str(Path(tempfile.gettempdir()).resolve()) if IS_WINDOWS else "/tmp"
|
||||||
LEGACY_CUSTOM_DISABLED_ROWS = (
|
LEGACY_CUSTOM_DISABLED_ROWS = (
|
||||||
"agent-instructions",
|
"agent-instructions",
|
||||||
"goal",
|
"goal",
|
||||||
@@ -108,6 +117,8 @@ ADVANCED_SNAPSHOT_FILENAMES = ("result.json", "session.jsonl", "session.1.jsonl"
|
|||||||
MINIMAL_SNAPSHOT_DIRECTORY = (
|
MINIMAL_SNAPSHOT_DIRECTORY = (
|
||||||
Path(__file__).resolve().parent / "snapshots" / "python-sdk-single-exe" / "minimal"
|
Path(__file__).resolve().parent / "snapshots" / "python-sdk-single-exe" / "minimal"
|
||||||
)
|
)
|
||||||
|
if IS_WINDOWS:
|
||||||
|
MINIMAL_SNAPSHOT_DIRECTORY /= "win-x64"
|
||||||
MINIMAL_SNAPSHOT_FILENAMES = ("model-visible.json",)
|
MINIMAL_SNAPSHOT_FILENAMES = ("model-visible.json",)
|
||||||
RESTART_SNAPSHOT_DIRECTORY = (
|
RESTART_SNAPSHOT_DIRECTORY = (
|
||||||
Path(__file__).resolve().parent / "snapshots" / "python-sdk-single-exe" / "restart"
|
Path(__file__).resolve().parent / "snapshots" / "python-sdk-single-exe" / "restart"
|
||||||
@@ -301,8 +312,8 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
|
|||||||
if minimal_prompt is not None:
|
if minimal_prompt is not None:
|
||||||
return tool_call_chunks(
|
return tool_call_chunks(
|
||||||
"minimal-bash-1",
|
"minimal-bash-1",
|
||||||
"bash",
|
MINIMAL_SHELL_TOOL,
|
||||||
{"command": MINIMAL_BASH_COMMAND},
|
{"command": MINIMAL_SHELL_COMMAND},
|
||||||
)
|
)
|
||||||
scenario_prompts = {
|
scenario_prompts = {
|
||||||
SNAPSHOT_DIRECT_CHILD_PROMPT,
|
SNAPSHOT_DIRECT_CHILD_PROMPT,
|
||||||
@@ -438,17 +449,18 @@ def minimal_tool_followup(
|
|||||||
"""Verify the checked-in minimal composition's PTY and editor."""
|
"""Verify the checked-in minimal composition's PTY and editor."""
|
||||||
if not call_id.startswith("minimal-"):
|
if not call_id.startswith("minimal-"):
|
||||||
return None
|
return None
|
||||||
if call_id == "minimal-bash-1" and tool_name == "bash":
|
if call_id == "minimal-bash-1" and tool_name == MINIMAL_SHELL_TOOL:
|
||||||
if "COUNT=1" not in tool_text:
|
if "COUNT=1" not in tool_text:
|
||||||
raise AssertionError(f"first persistent bash call lost its output: {tool_text}")
|
raise AssertionError(f"first persistent shell call lost its output: {tool_text}")
|
||||||
return tool_call_chunks(
|
return tool_call_chunks(
|
||||||
"minimal-bash-2",
|
"minimal-bash-2",
|
||||||
"bash",
|
MINIMAL_SHELL_TOOL,
|
||||||
{"command": MINIMAL_BASH_COMMAND},
|
{"command": MINIMAL_SHELL_COMMAND},
|
||||||
)
|
)
|
||||||
if call_id == "minimal-bash-2" and tool_name == "bash":
|
if call_id == "minimal-bash-2" and tool_name == MINIMAL_SHELL_TOOL:
|
||||||
if "COUNT=2 CWD=/tmp" not in tool_text:
|
expected = f"COUNT=2 CWD={MINIMAL_SHELL_SECOND_CWD}"
|
||||||
raise AssertionError(f"persistent bash did not retain state: {tool_text}")
|
if expected.lower() not in tool_text.lower():
|
||||||
|
raise AssertionError(f"persistent shell did not retain state: {tool_text}")
|
||||||
messages = body.get("messages")
|
messages = body.get("messages")
|
||||||
if not isinstance(messages, list):
|
if not isinstance(messages, list):
|
||||||
raise AssertionError("persistent editor smoke request has no messages")
|
raise AssertionError("persistent editor smoke request has no messages")
|
||||||
@@ -800,8 +812,9 @@ def smoke_sdk_live() -> None:
|
|||||||
sessions = dsh_home / "sessions"
|
sessions = dsh_home / "sessions"
|
||||||
marker = root / "live-api-marker.txt"
|
marker = root / "live-api-marker.txt"
|
||||||
session_id = "installed-wheel-live-api"
|
session_id = "installed-wheel-live-api"
|
||||||
|
shell_tool = "pwsh" if IS_WINDOWS else "bash"
|
||||||
create_prompt = (
|
create_prompt = (
|
||||||
"Use the bash tool to create the file at the absolute path below with exactly one line "
|
f"Use the {shell_tool} tool to create the file at the absolute path below with exactly one line "
|
||||||
f"containing {LIVE_API_SENTINEL}. Then reply with exactly {LIVE_API_SENTINEL}.\n{marker}"
|
f"containing {LIVE_API_SENTINEL}. Then reply with exactly {LIVE_API_SENTINEL}.\n{marker}"
|
||||||
)
|
)
|
||||||
verify_prompt = (
|
verify_prompt = (
|
||||||
@@ -845,8 +858,8 @@ def smoke_sdk_live() -> None:
|
|||||||
raise AssertionError(f"{label} turn returned {result.final_response!r}")
|
raise AssertionError(f"{label} turn returned {result.final_response!r}")
|
||||||
if not marker.is_file():
|
if not marker.is_file():
|
||||||
raise AssertionError(f"real-model tool turn did not create {marker}")
|
raise AssertionError(f"real-model tool turn did not create {marker}")
|
||||||
if marker.read_bytes() != f"{LIVE_API_SENTINEL}\n".encode():
|
if marker.read_text(encoding="utf-8").splitlines() != [LIVE_API_SENTINEL]:
|
||||||
raise AssertionError(f"real-model tool turn wrote unexpected bytes to {marker}")
|
raise AssertionError(f"real-model tool turn wrote unexpected text to {marker}")
|
||||||
assert_zstd_session_log(sessions)
|
assert_zstd_session_log(sessions)
|
||||||
|
|
||||||
|
|
||||||
@@ -921,6 +934,7 @@ def smoke_sdk_custom(base_url: str, executable: Path) -> None:
|
|||||||
{"id": "session-log-deepseek", "config": {"enabled": True}},
|
{"id": "session-log-deepseek", "config": {"enabled": True}},
|
||||||
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
|
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
|
||||||
{"id": "tool-bash", "disabled": True},
|
{"id": "tool-bash", "disabled": True},
|
||||||
|
{"id": "tool-pwsh", "disabled": True},
|
||||||
{
|
{
|
||||||
"id": "tool-subagent",
|
"id": "tool-subagent",
|
||||||
"config": {
|
"config": {
|
||||||
@@ -989,7 +1003,7 @@ def smoke_sdk_minimal(base_url: str, executable: Path, update_snapshots: bool) -
|
|||||||
raise AssertionError(f"minimal agent run emitted no final response: {result.events}")
|
raise AssertionError(f"minimal agent run emitted no final response: {result.events}")
|
||||||
if editor_path.read_text() != "created by packaged editor\n":
|
if editor_path.read_text() != "created by packaged editor\n":
|
||||||
raise AssertionError(f"packaged editor wrote unexpected content: {editor_path.read_text()!r}")
|
raise AssertionError(f"packaged editor wrote unexpected content: {editor_path.read_text()!r}")
|
||||||
assert_session_log(sessions, root, MINIMAL_TEXT, "COUNT=1", "COUNT=2 CWD=/tmp")
|
assert_session_log(sessions, root, MINIMAL_TEXT, "COUNT=1", "COUNT=2")
|
||||||
|
|
||||||
files = build_minimal_snapshot_files(MockModelHandler.requests[first_request:], root)
|
files = build_minimal_snapshot_files(MockModelHandler.requests[first_request:], root)
|
||||||
compare_snapshot_files(
|
compare_snapshot_files(
|
||||||
@@ -1105,7 +1119,7 @@ def smoke_sdk_profile_plugin(base_url: str) -> None:
|
|||||||
"insert": [{"id": "python-sdk-blackbox-plugin", "name": "dsh-python-blackbox-plugin"}],
|
"insert": [{"id": "python-sdk-blackbox-plugin", "name": "dsh-python-blackbox-plugin"}],
|
||||||
}], indent=2))
|
}], indent=2))
|
||||||
|
|
||||||
dsh = Path(sysconfig.get_path("scripts")) / "dsh"
|
dsh = Path(sysconfig.get_path("scripts")) / ("dsh.exe" if IS_WINDOWS else "dsh")
|
||||||
environment = {**os.environ, "DSH_HOME": str(dsh_home)}
|
environment = {**os.environ, "DSH_HOME": str(dsh_home)}
|
||||||
installed = subprocess.run(
|
installed = subprocess.run(
|
||||||
[str(dsh), "plugin", "--profile", "sdk", "add", f"file:{plugin}"],
|
[str(dsh), "plugin", "--profile", "sdk", "add", f"file:{plugin}"],
|
||||||
@@ -1170,6 +1184,7 @@ def smoke_sdk_snapshot(base_url: str, executable: Path, update_snapshots: bool)
|
|||||||
{"id": "session-log-deepseek", "config": {"enabled": True}},
|
{"id": "session-log-deepseek", "config": {"enabled": True}},
|
||||||
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
|
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
|
||||||
{"id": "tool-bash", "disabled": True},
|
{"id": "tool-bash", "disabled": True},
|
||||||
|
{"id": "tool-pwsh", "disabled": True},
|
||||||
{
|
{
|
||||||
"id": "tool-subagent",
|
"id": "tool-subagent",
|
||||||
"config": {
|
"config": {
|
||||||
@@ -1243,6 +1258,7 @@ def smoke_sdk_restart_snapshot(base_url: str, executable: Path, update_snapshots
|
|||||||
{"id": "session-log-deepseek", "config": {"enabled": True}},
|
{"id": "session-log-deepseek", "config": {"enabled": True}},
|
||||||
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
|
*({"id": row_id, "disabled": True} for row_id in LEGACY_CUSTOM_DISABLED_ROWS),
|
||||||
{"id": "tool-bash", "disabled": True},
|
{"id": "tool-bash", "disabled": True},
|
||||||
|
{"id": "tool-pwsh", "disabled": True},
|
||||||
{
|
{
|
||||||
"id": "tool-subagent",
|
"id": "tool-subagent",
|
||||||
"config": {
|
"config": {
|
||||||
@@ -1758,7 +1774,7 @@ def compare_snapshot_files(
|
|||||||
if update:
|
if update:
|
||||||
directory.mkdir(parents=True, exist_ok=True)
|
directory.mkdir(parents=True, exist_ok=True)
|
||||||
for name, content in files.items():
|
for name, content in files.items():
|
||||||
(directory / name).write_text(content, encoding="utf-8")
|
(directory / name).write_text(content, encoding="utf-8", newline="\n")
|
||||||
print(f"smoke-python-runtime: updated snapshots in {directory}")
|
print(f"smoke-python-runtime: updated snapshots in {directory}")
|
||||||
|
|
||||||
existing = {
|
existing = {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
@@ -381,7 +381,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "user",
|
"role": "user",
|
||||||
"text": "Exercise the packaged minimal agent's persistent Bash and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}/created.txt"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"role": "assistant",
|
"role": "assistant",
|
||||||
|
|||||||
@@ -0,0 +1,430 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "pwsh",
|
||||||
|
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The PowerShell command to run. Relative path is preferred in the command."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "str_replace_editor",
|
||||||
|
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
|
||||||
|
"enum": [
|
||||||
|
"view",
|
||||||
|
"create",
|
||||||
|
"str_replace",
|
||||||
|
"insert"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
|
||||||
|
},
|
||||||
|
"file_text": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `create` command, with the content of the file to be created."
|
||||||
|
},
|
||||||
|
"insert_line": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
|
||||||
|
},
|
||||||
|
"new_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
|
||||||
|
},
|
||||||
|
"old_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
|
||||||
|
},
|
||||||
|
"view_range": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"text": "You are a helpful software engineer assistant."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "pwsh",
|
||||||
|
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The PowerShell command to run. Relative path is preferred in the command."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "str_replace_editor",
|
||||||
|
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
|
||||||
|
"enum": [
|
||||||
|
"view",
|
||||||
|
"create",
|
||||||
|
"str_replace",
|
||||||
|
"insert"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
|
||||||
|
},
|
||||||
|
"file_text": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `create` command, with the content of the file to be created."
|
||||||
|
},
|
||||||
|
"insert_line": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
|
||||||
|
},
|
||||||
|
"new_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
|
||||||
|
},
|
||||||
|
"old_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
|
||||||
|
},
|
||||||
|
"view_range": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"text": "You are a helpful software engineer assistant."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"toolCalls": [
|
||||||
|
{
|
||||||
|
"id": "minimal-bash-1",
|
||||||
|
"name": "pwsh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "tool",
|
||||||
|
"toolCallId": "minimal-bash-1",
|
||||||
|
"text": "{{tool-result}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "pwsh",
|
||||||
|
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The PowerShell command to run. Relative path is preferred in the command."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "str_replace_editor",
|
||||||
|
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
|
||||||
|
"enum": [
|
||||||
|
"view",
|
||||||
|
"create",
|
||||||
|
"str_replace",
|
||||||
|
"insert"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
|
||||||
|
},
|
||||||
|
"file_text": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `create` command, with the content of the file to be created."
|
||||||
|
},
|
||||||
|
"insert_line": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
|
||||||
|
},
|
||||||
|
"new_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
|
||||||
|
},
|
||||||
|
"old_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
|
||||||
|
},
|
||||||
|
"view_range": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"text": "You are a helpful software engineer assistant."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"toolCalls": [
|
||||||
|
{
|
||||||
|
"id": "minimal-bash-1",
|
||||||
|
"name": "pwsh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "tool",
|
||||||
|
"toolCallId": "minimal-bash-1",
|
||||||
|
"text": "{{tool-result}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"toolCalls": [
|
||||||
|
{
|
||||||
|
"id": "minimal-bash-2",
|
||||||
|
"name": "pwsh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "tool",
|
||||||
|
"toolCallId": "minimal-bash-2",
|
||||||
|
"text": "{{tool-result}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "pwsh",
|
||||||
|
"description": "Run commands in a PowerShell shell\n* When invoking this tool, the contents of the \"command\" parameter does NOT need to be XML-escaped.\n* You don't have access to the internet via this tool.\n* State is persistent across command calls and discussions with the user.\n* Use native Windows paths (C:\\...) and $env:NAME variables; this is PowerShell, not bash.\n* Please avoid commands that may produce a very large amount of output.\n* Please run long lived commands in the background, e.g. 'Start-Job' or start a server with Start-Process.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The PowerShell command to run. Relative path is preferred in the command."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function",
|
||||||
|
"function": {
|
||||||
|
"name": "str_replace_editor",
|
||||||
|
"description": "Custom editing tool for viewing, creating and editing files\n* State is persistent across command calls and discussions with the user\n* If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep\n* The `create` command cannot be used if the specified `path` already exists as a file\n* If a `command` generates a long output, it will be truncated and marked with `<response clipped>`\n\nNotes for using the `str_replace` command:\n* The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique\n* The `new_str` parameter should contain the edited lines that should replace the `old_str`",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"command": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
|
||||||
|
"enum": [
|
||||||
|
"view",
|
||||||
|
"create",
|
||||||
|
"str_replace",
|
||||||
|
"insert"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
|
||||||
|
},
|
||||||
|
"file_text": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `create` command, with the content of the file to be created."
|
||||||
|
},
|
||||||
|
"insert_line": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
|
||||||
|
},
|
||||||
|
"new_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
|
||||||
|
},
|
||||||
|
"old_str": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
|
||||||
|
},
|
||||||
|
"view_range": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"command",
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"text": "You are a helpful software engineer assistant."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"text": "Exercise the packaged minimal agent's persistent shell and string-replacement editor.\nEditor path: {{cwd}}\\created.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"toolCalls": [
|
||||||
|
{
|
||||||
|
"id": "minimal-bash-1",
|
||||||
|
"name": "pwsh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "tool",
|
||||||
|
"toolCallId": "minimal-bash-1",
|
||||||
|
"text": "{{tool-result}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"toolCalls": [
|
||||||
|
{
|
||||||
|
"id": "minimal-bash-2",
|
||||||
|
"name": "pwsh"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "tool",
|
||||||
|
"toolCallId": "minimal-bash-2",
|
||||||
|
"text": "{{tool-result}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "assistant",
|
||||||
|
"toolCalls": [
|
||||||
|
{
|
||||||
|
"id": "minimal-editor",
|
||||||
|
"name": "str_replace_editor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "tool",
|
||||||
|
"toolCallId": "minimal-editor",
|
||||||
|
"text": "{{tool-result}}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in new issue
Block a user