Compare commits
3 Commits
project-2_
...
1.0.1_rest
| Author | SHA1 | Date | |
|---|---|---|---|
| f29b77bcab | |||
| ebd3474db3 | |||
| e814569a07 |
@@ -154,7 +154,7 @@ volume, and none of those name a person or a checkout.
|
||||
```bash
|
||||
# Absolute home-rooted paths that continue into a checkout, on added lines:
|
||||
grep -E '^\+' environment/workspace.patch | grep -vE '^\+\+\+' \
|
||||
| grep -nE '(/home/[a-zA-Z][^/[:space:]"'"'"']*|/Users/[a-zA-Z][^/[:space:]"'"'"']*|/mnt/[a-z]/[a-zA-Z][^/[:space:]"'"'"']*)(/[^/[:space:]"'"'"']+)*/(worker-toolkit-[a-z0-9-]+|Toolkits|repo)/'
|
||||
| grep -nE '(/home/[a-zA-Z][^/[:space:]"'"'"']*|/Users/[a-zA-Z][^/[:space:]"'"'"']*|/mnt/[a-z]/[a-zA-Z][^/[:space:]"'"'"']*)(/[^/[:space:]"'"'"']+)*/(worker-toolkit-[a-z0-9.-]+|Toolkits|repo)/'
|
||||
```
|
||||
|
||||
A hit is an `internal-leak`. Across the corpus this fires on 2 of 350 patches,
|
||||
@@ -172,8 +172,8 @@ To grade under the atomic rubric inside the worker toolkit, stage the grading
|
||||
copies with `npx tsx scripts/stage-atomic-rubric.ts <task-slug>`. Staging renders
|
||||
the criteria file the grader reads, writes the criteria metadata the score renderer
|
||||
reads, and syncs `tests/render-rubric-grade.py` from `task-shared/`. Re-run it
|
||||
after every rubric edit. Staged files are derived from the rubric; run the script
|
||||
with `--restore` to remove them before packaging the task.
|
||||
after every rubric edit. Staged files are derived from the rubric; `submit-task`
|
||||
leaves them out of the package.
|
||||
|
||||
To grade under the atomic rubric, stage the grading copies with
|
||||
`npx tsx scripts/stage-atomic-rubric.ts <task-slug>` inside the devcontainer: staging
|
||||
@@ -3,7 +3,7 @@
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"TOOLKIT_BUILD_ID": "1790712369311-8xr6mu"
|
||||
"TOOLKIT_BUILD_ID": "1791247286386-y2uh1u"
|
||||
}
|
||||
},
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
|
||||
@@ -123,8 +123,8 @@ bash scripts/welcome.sh authoring 2>/dev/null
|
||||
|
||||
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
||||
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
||||
_WID="w-mun3wr6n-v83f"
|
||||
_VER="1.0.0"
|
||||
_WID="w-muvydvub-qn4j"
|
||||
_VER="1.0.1"
|
||||
_CT="authoring"
|
||||
_RP=$(node -e "try{process.stdout.write(require('$PWD/toolkit.json').repo)}catch{}" 2>/dev/null)
|
||||
_SID="$(date +%s)-$$"
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"version": 1,
|
||||
"generatedAt": "2026-09-29T20:06:24.470Z",
|
||||
"generatedAt": "2026-10-06T00:41:40.489Z",
|
||||
"files": {
|
||||
"scripts/atif_session.py": "9984fd180d08c2eaecf752cc5accfbf874396396cdcf599f69259b5127f90859",
|
||||
"scripts/browser_note.py": "7ee1485c459e76b47ff03a672357ae2d0910890cdc9fdb816a53c56977ff2985",
|
||||
"scripts/build-workspace.sh": "e40cebbcad520aaeea2a3c0352bae880dd779011e92926de66d9132514041c2a",
|
||||
"scripts/build-workspace.sh": "0792690e1c28acd8d2902134504158a18a0f4bf4671d6e8733a09bfb8a1440a5",
|
||||
"scripts/check-task-infra.ts": "678dfb26b11d1fcd2c48345708262fb2c2d5ba0057fb96eabc072eed10fdb4cf",
|
||||
"scripts/check-workspace-sync.sh": "14a6e877ff51f8b86e5e1e32f0ed3143f9e718793b20640b51060eacbbf2f9d4",
|
||||
"scripts/codex_agent.py": "87e1df907bea2b1c56b032c0848f0108c948cdf63a5a0682255b7d702aacc6be",
|
||||
"scripts/codex_agent.py": "7953d0b511843591c7ed82d8a2316c52ed79c4cf948dd42fba7d094bb5f4857a",
|
||||
"scripts/codex-rollout-template.jsonl": "9026ef83466a5c657dc88faaf2ebf0bad93ff865afe4531e9b78465eb99504d1",
|
||||
"scripts/copy-reference-run.ts": "260a970f9165d3e35013232a4e364c07827e0c04db995bc3dc14aa4b545244b8",
|
||||
"scripts/dnsjail.py": "d814f1103860ac34f4ed191edd5a6e19580c9d1519cb1c51aaaf53cf709cbc0e",
|
||||
"scripts/guidance-target.sh": "edcb5b497206911ffdfef432629ea7afc229aac641700166209ad68d22f04a2d",
|
||||
"scripts/harbor-regrade": "c3c67fc339fc9264bf85234d3fc15116467be79f841a3bdaed76716c4a358305",
|
||||
"scripts/harbor-run": "0ee5f6b1e9a7ca4b872faba0431c3868840a9a5d466bf7aab21bd39455cf6bdd",
|
||||
"scripts/harbor-regrade": "a9ff2ae923324dd422cb51c9576536850f900bf8af577637ec6adfbcbca9f6f5",
|
||||
"scripts/harbor-run": "ec98b793179554e874c86655841744f7c61486a8a5e40bb293130258b8f2cb58",
|
||||
"scripts/harness-registry.toml": "ebe2c2002c35499a6c03dc0bed46c64e90e9d27aee8e33cb35aca74c925388e7",
|
||||
"scripts/harness-session.d.mts": "73223ab9fd003e2e299e0e46a02ee0be00d7541a2fcf803b871195688d4b8109",
|
||||
"scripts/harness-session.mjs": "ca4d6dc835453b207511275775a71383bb1358a64ba7257877592f8616b2118f",
|
||||
@@ -29,8 +29,10 @@
|
||||
"scripts/lib/notice-banner.ts": "6a35e92600a9f3ac46c49197eef44d49705f7a5205d1f14f3a20b65bc9cf19b7",
|
||||
"scripts/lib/patch-size.ts": "9f5da242c6eafc510e9b95ae5764074eca3b287858b83f087aeb4a47972b4089",
|
||||
"scripts/lib/resolve-pin.sh": "00883384bc26aafdf2c2cc9884d1768560301689d493ac1ba276e8618dc72901",
|
||||
"scripts/lib/task-infra-integrity.ts": "9749de98356a3eb435dd6386266b6560785378bcb930c306d11ff22ef93feb70",
|
||||
"scripts/lib/toolkit-script-integrity.ts": "6b88e40832d268c15af6568acc97c877210169d73ee31e50903e8e1e936dbb16",
|
||||
"scripts/lib/secret-scrub.test.ts": "f4e96cf8b2de74af845fa8c2dc3dff16d3fe11a0be41caa47d3cc124149a22dd",
|
||||
"scripts/lib/secret-scrub.ts": "0a174a42cb32c0909fd91b0ff7ca3d8009dfc8fa302549f2edd5468f46f28f0a",
|
||||
"scripts/lib/task-infra-integrity.ts": "5936c14ffab215076921df753c6c0da12ba19125d389edc7362970463bacde90",
|
||||
"scripts/lib/toolkit-script-integrity.ts": "5fd5b9ce493e292e402732726d1418b36dd7640209d05255953fbfa835244ea5",
|
||||
"scripts/lib/tree-permissions.test.ts": "31692facc68a3c7930655626374c48de8be1ed11d97242eb74538df2a80f2a35",
|
||||
"scripts/lib/tree-permissions.ts": "06e9934fe0937e430071b1a33653f8682193e90078908740512f7e06475e94ec",
|
||||
"scripts/record-detector-inputs.ts": "b22245dafa74cc7ad6376cffb4eafc349e39efb94dc71e025550abab033b68e9",
|
||||
@@ -38,11 +40,11 @@
|
||||
"scripts/refresh-harness-auth": "b056eb1ec092a7fb3dde549ac3d353abc141cb32367f6b484fc9f879e99733fd",
|
||||
"scripts/replay_agent.py": "feeea82daa555e3203cb131bbb002c4e6f0d7d492570bfd657cfc22b9fc40cde",
|
||||
"scripts/resolve_harness.py": "06e1529431db040dab776aad34e1b8c6af4f29172bca5dd93c040f7d9b6f6547",
|
||||
"scripts/sanitize-session-jsonl.ts": "6bbe28d70c4366f96758cdda366549ec37e1d069020066ba608f72f7e239a218",
|
||||
"scripts/sanitize-session-jsonl.ts": "3aa9d0c696cf999c56adac7a359e4a842afa7c8898e95176772caaff13f47d5a",
|
||||
"scripts/session-id.ts": "bb21a90a235785fd69296b05c47fa4bb081abce6d254e5a9ad65d19016dbc421",
|
||||
"scripts/setup-harnesses.sh": "39f6ca5cfa795d2d621dfa48287545486f060cfeae34c9e2b9ae6921d7275ea4",
|
||||
"scripts/snapshot_agent.py": "7f6a25e20deab4ec32f411dc5f179428a140dca7844f7c7d36aae348f0f88459",
|
||||
"scripts/snapshot-to-task.ts": "ec6f270f7e479bdac4da70811ed4bf6edac86e53455590bff5bbdf14f73966d4",
|
||||
"scripts/snapshot_agent.py": "a15a939e62af7dfe150ef79c44db71e18b713c1bac72cbd508f1298c42d584b8",
|
||||
"scripts/snapshot-to-task.ts": "e60d0e18615123f8d36d614bd72237350d84f1e997aa543081ccc0c456556b67",
|
||||
"scripts/stage-atomic-rubric.ts": "008132bb078face75011b727d17354711e2550d33ea55ae12d00cb29be9a4dee",
|
||||
"scripts/stamp-trial-inputs.ts": "7b9780d8062e99999dd7e2c63f4eca1c4f043b46641881db725b1f1980b47633",
|
||||
"scripts/str_replace_editor": "943bcf04b010bba7c6a71ed32b5384a00c5ba0ca10a4ef249f0359af6bbbfb0f",
|
||||
@@ -50,7 +52,7 @@
|
||||
"scripts/str_replace_editor_vendor/base.py": "469db977748364092c977c436f29df4f45f46ae7b511ea6f1e0289e5e7e3e9d2",
|
||||
"scripts/str_replace_editor_vendor/edit.py": "778784efd243cae802f0c472a3daadd054a972bcdf07fa66bf0b07f46920a093",
|
||||
"scripts/str_replace_editor_vendor/run.py": "0bae4a787dfe7ad00ad2732c4cbb857701545324b21295771113d1d2e0d42295",
|
||||
"scripts/submit-task.ts": "995d46d36e91917635987b5efbba7ee3ff41bbe3271b375e2ff8feb5b4f1ff25",
|
||||
"scripts/submit-task.ts": "493152f871bbe2b833210700cf24456e82041da710791c1d42579a362813e3ba",
|
||||
"scripts/toolset_note_browser.md": "4f58008444ef854454420c299b268135a82c9d324a840744fd0460d51e9edd98",
|
||||
"scripts/toolset_note_read.md": "bb969d696898e2ecadb81b875beaef3ae3b11df1961d35fd43114c748c83c3ce",
|
||||
"scripts/toolset_note.md": "7dff7325f48f1fa0e01ca5794c866ab5e61098d3a7aeae69b21331110bb1ac04",
|
||||
@@ -139,8 +139,8 @@ The same goes for the toolkit's own `scripts/`. Nothing in there belongs to a ta
|
||||
edit looks harmless — but `build-workspace.sh` stages each task's `tests/test-commands.sh`,
|
||||
fills in parts of its `environment/Dockerfile`, and records the checksums a reviewer reads.
|
||||
A task built by an altered copy looks normal and isn't. `harbor-run` and `submit-task.ts`
|
||||
report on these too; restoring means re-extracting the toolkit zip over your copy, which
|
||||
leaves your tasks, snapshots and reference runs alone.
|
||||
report on these too; restoring means re-extracting the zip this toolkit came from over
|
||||
your copy, which leaves your tasks, snapshots and reference runs alone.
|
||||
|
||||
## Reference-data corpus (only some toolkits)
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- **Fixed: on the uberduck-polyglot toolkit, `run-app uberduck` now installs the frontend dependencies before starting the app.** Before, setup skipped that step and the frontend failed to start.
|
||||
- **`submit-task.ts` now leaves the staged atomic-rubric copies out of the package, so you no longer need to run `stage-atomic-rubric.ts --restore` first.**
|
||||
- **Fixed: on the swingbell-polyglot toolkit, `ai-usecase` task images now install its app's dependencies.** The app lives in `vite-project/`, and the image used to install only the empty top-level `package.json`; a task you created on an earlier release keeps its own `environment/Dockerfile`.
|
||||
|
||||
- **Fixed: on the swingbell-polyglot toolkit, `run-app` now starts `book-my-minutes-onboarding`, `book-my-minutes-onboarding-expert-app`, `on-boarding-ui-ssr` and `ai-usecase`, and prints the address that works for apps served under a sub-path, such as `/care` or `/expert`.** In Explore, the company's live hostnames now resolve nowhere, so a running app can no longer load data from the production site.
|
||||
- **Fixed: on polyglot toolkits, `run-app` now installs and starts a member whose app lives in a subfolder of its repo from that subfolder.** Before, those members installed nothing or said they had no dev-server script.
|
||||
- **Fixed: on the speedwell-polyglot toolkit, `mix test` in `strongsuit_phx` no longer fails four `cronofy_account_controller_test` tests with 401 in the Explore container.** The container no longer sets `API_AUTH_TOKEN` or `PHX_AUTH_TOKEN`, so the app, the Phoenix server and its tests all use the same built-in default. Reported by a worker.
|
||||
- **Fixed: on the swingbell-polyglot toolkit, the Java services now build in Explore.** The Explore container installs the shared libraries they depend on (`common-repository`, `common-aws-service`, `jasper-report`, `jwt-encryption-decryption`, and the `book-my-minutes-*` versions of the first two) when it is created, so `mvn package` no longer fails on missing `com.swingbell` dependencies.
|
||||
- **Fixed: on the swingbell-polyglot toolkit, `meetings`, `nhcx-provider` and `book-my-minutes-jobs` tasks now build against the shared-library versions their code is written for.** Before, their task images failed to compile; re-run `build-workspace.sh` on an existing task for one of them to pick this up.
|
||||
- **Fixed: a snapshot no longer loses the output of the first of two tool calls the agent made at once.** Those commands used to show no output when the task resumed; snapshots taken before this release keep the gaps. Reported by a worker.
|
||||
- **Fixed: on the potion-polyglot toolkit, the `potion-wp-site` task image now builds on x86_64 and includes the Claude CLI, so its tasks can be run and regraded.** A task you created on an earlier release keeps its own `environment/Dockerfile`. Reported by a worker.
|
||||
- **`harbor-regrade` accepts `HARBOR_GRADER_MODE=atomic` and `=holistic`** (also `atomic-scalar` and `holistic-one-shot`), the names the two scores go by. The old names still work.
|
||||
- **Fixed: a test command that hangs no longer leaves a trial ungraded.** Each check in `test-commands.sh` now stops after 30 minutes (`SIGNAL_TIMEOUT_SEC`), and the grader sees it as timed out with the output so far.
|
||||
- **When the Codex grader fails, its error now shows the reason Codex gave**, not just an exit status.
|
||||
- **Fixed: the Codex grader no longer fails with `401 Incorrect API key` on task images that set a placeholder `OPENAI_API_KEY` for the app.** It now uses the key that matches the proxy route it grades through.
|
||||
- **Fixed: on the zeta-polyglot toolkit, `read_sql` in `zeta-predictors` no longer raises `ValueError: orient 'record' not understood`.** Every `zeta_ds` reader that goes through it, such as `get_table_size` and `count`, failed on the image's pandas 2.x before running its query; a task you created on an earlier release keeps its own copy of the code. Reported by a worker.
|
||||
- **A task image now fails to build when its Codex CLI is missing or older than 0.158.0, the oldest the grader accepts.** Before, the build carried on and every grade then failed; an image cached with an older Codex rebuilds.
|
||||
- **Fixed: local trials now give Opus the same 1M-token context window as Explore.** Before, trials ran with 200k and compacted a long Explore session before the first reply.
|
||||
- **`submit-task.ts` refuses a task that holds one of your API keys in a file you wrote, such as `workspace.patch`, and names the file.** A key that ends up in a session file or reference run is removed for you.
|
||||
- **Fixed: in local trials, the agent can no longer find what `workspace.patch` or a hand edit changed by sorting files by time or permissions.** `harbor-run` now gives every workspace file the same modified time and removes group write. Reported by a worker.
|
||||
- **The toolkit now unzips into a folder named with its version, so a new release sits next to the old one instead of on top of it.** Stop the old toolkit's Explore container before you start the new one, since both use the same port.
|
||||
- **Fixed: on the palolo-031 toolkit, an agent that starts the app with `pnpm run dev` now gets the client on port 3000, which the API accepts.** A task you created on an earlier release keeps its own `environment/Dockerfile`. Reported by a worker.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- New tasks are graded with **GPT-6 Sol / high / one sample**.
|
||||
@@ -137,8 +137,8 @@ The same goes for the toolkit's own `scripts/`. Nothing in there belongs to a ta
|
||||
edit looks harmless — but `build-workspace.sh` stages each task's `tests/test-commands.sh`,
|
||||
fills in parts of its `environment/Dockerfile`, and records the checksums a reviewer reads.
|
||||
A task built by an altered copy looks normal and isn't. `harbor-run` and `submit-task.ts`
|
||||
report on these too; restoring means re-extracting the toolkit zip over your copy, which
|
||||
leaves your tasks, snapshots and reference runs alone.
|
||||
report on these too; restoring means re-extracting the zip this toolkit came from over
|
||||
your copy, which leaves your tasks, snapshots and reference runs alone.
|
||||
|
||||
## Reference-data corpus (only some toolkits)
|
||||
|
||||
@@ -335,8 +335,9 @@ The toolkit's own `scripts/` are checked the same way, and for the same reason.
|
||||
aren't part of any task, which is what makes an edit there easy to miss — but
|
||||
`build-workspace.sh` stages each task's `tests/test-commands.sh`, fills in parts of its
|
||||
`environment/Dockerfile`, and records the checksums a reviewer reads. Restoring means
|
||||
re-extracting the toolkit zip over your copy; your tasks, snapshots and reference runs
|
||||
are untouched by that. Scripts you add yourself are yours and are never reported.
|
||||
re-extracting the zip this toolkit came from over your copy; your tasks, snapshots and
|
||||
reference runs are untouched by that. Scripts you add yourself are yours and are never
|
||||
reported.
|
||||
|
||||
## Key principles
|
||||
|
||||
@@ -363,7 +364,7 @@ See `.claude/skills/` for detailed guidance (available in the Authoring containe
|
||||
|
||||
**The database isn't running after a reboot or container stop** — Re-run `npx @devcontainers/cli up`; whichever database your toolkit uses is restarted automatically on every container start. (You no longer need to start it by hand.)
|
||||
|
||||
**Ports stopped working after a toolkit upgrade** — Docker fixes a container's port mappings when it's first created, so an old container won't pick up new ports just from `up`. Recreate it: `npx @devcontainers/cli up --remove-existing-container`. This wipes the container's Claude history, so run `/create-snapshot:snapshot` first if there's a conversation you want to keep.
|
||||
**"port is already allocated" after a toolkit upgrade** — The old toolkit's Explore container still holds the port. Stop it with `docker stop $(docker ps -q --filter publish=<port>)`, using the port from the error.
|
||||
|
||||
**Snapshot command not found** — Make sure you're in the Explore container, not the Authoring container.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile",
|
||||
"args": {
|
||||
"TOOLKIT_BUILD_ID": "1790712369311-8xr6mu"
|
||||
"TOOLKIT_BUILD_ID": "1791247286386-y2uh1u"
|
||||
}
|
||||
},
|
||||
"appPort": [
|
||||
@@ -438,6 +438,39 @@ print('admin user ready')
|
||||
;;
|
||||
esac
|
||||
|
||||
# The swingbell Java services resolve sibling members' com.swingbell* SNAPSHOT libs only from a
|
||||
# local Maven repo. The book-my-minutes-* twins reuse those coordinates, so they get their own.
|
||||
_sbl_install() { # <local repo> <member>[@<revision>]...
|
||||
local repo_local="$1" m rev src; shift
|
||||
for m in "$@"; do
|
||||
rev=HEAD; case "$m" in *@*) rev=${m#*@}; m=${m%@*} ;; esac
|
||||
[ -e "/workspace/repos/$m/.git" ] || continue
|
||||
src=$(mktemp -d)
|
||||
( git -C "/workspace/repos/$m" archive "$rev" | tar -x -C "$src" \
|
||||
&& cd "$src" && mvn -q -B -Dstyle.color=never -DskipTests -Dmaven.repo.local="$repo_local" install ) \
|
||||
|| echo "WARNING: could not install $m into $repo_local; services that depend on it won't build until it is" >&2
|
||||
rm -rf "$src"
|
||||
done
|
||||
}
|
||||
_sbl_use() { # <member> <local repo>
|
||||
local d="/workspace/repos/$1"
|
||||
[ -f "$d/pom.xml" ] || return 0
|
||||
mkdir -p "$d/.mvn" "$d/.git/info"
|
||||
printf -- '-Dmaven.repo.local=%s\n' "$2" > "$d/.mvn/maven.config"
|
||||
grep -qxF '.mvn/maven.config' "$d/.git/info/exclude" 2>/dev/null \
|
||||
|| printf '\n# raccoon-explore: selects this service'"'"'s local Maven repo\n.mvn/maven.config\n' >> "$d/.git/info/exclude"
|
||||
}
|
||||
if [ -n "$IS_POLYGLOT" ] && grep -qs 'com\.swingbell' /workspace/repos/common-repository/pom.xml; then
|
||||
_sbl_install "$HOME/.m2/repository" common-repository common-aws-service jwt-encryption-decryption reports
|
||||
_sbl_install "$HOME/.m2/bmm-repository" book-my-minutes-common-repository book-my-minutes-common-aws-service reports
|
||||
for d in /workspace/repos/book-my-minutes-* /workspace/repos/meetings; do _sbl_use "$(basename "$d")" "$HOME/.m2/bmm-repository"; done
|
||||
# These two were written against a different revision of their library than the one pinned.
|
||||
_sbl_install "$HOME/.m2/nhcx-provider-repository" common-repository@208aea7be jwt-encryption-decryption
|
||||
_sbl_use nhcx-provider "$HOME/.m2/nhcx-provider-repository"
|
||||
_sbl_install "$HOME/.m2/bmm-jobs-repository" book-my-minutes-common-repository@f15e7c128
|
||||
_sbl_use book-my-minutes-jobs "$HOME/.m2/bmm-jobs-repository"
|
||||
fi
|
||||
|
||||
# Mirror Harbor's reduced toolset in the interactive Explore session. Use
|
||||
# Harbor's /opt path when available, but fall back to a user-writable path for
|
||||
# generic devcontainer fixtures that run lifecycle hooks as a non-root user.
|
||||
@@ -528,8 +561,8 @@ bash /workspace/welcome.sh explore 2>/dev/null
|
||||
|
||||
_AK="fde503c3bdb6e5cc9c48b1f8e4c2abeb"
|
||||
_DK="e966e45af5ad1a18005f9fdb831186ea"
|
||||
_WID="w-mun3wr6n-v83f"
|
||||
_VER="1.0.0"
|
||||
_WID="w-muvydvub-qn4j"
|
||||
_VER="1.0.1"
|
||||
_CT="explore"
|
||||
_RP=$(node -e "try{process.stdout.write(require('/workspace/toolkit.json').repo)}catch{}" 2>/dev/null)
|
||||
_SID="$(date +%s)-$$"
|
||||
@@ -415,6 +415,24 @@ while (current) {
|
||||
current = byUuid[current]?.parentUuid || null;
|
||||
}
|
||||
|
||||
// Parallel tool calls can be written call, call, result, result: the first result then hangs
|
||||
// off the first call on a side branch the walk above never visits, so add those back.
|
||||
const blocksOf = (e) => (Array.isArray(e?.message?.content) ? e.message.content : []);
|
||||
const activeToolUseIds = new Set();
|
||||
for (const uuid of activeBranchUuids) {
|
||||
for (const b of blocksOf(byUuid[uuid])) if (b?.type === 'tool_use') activeToolUseIds.add(b.id);
|
||||
}
|
||||
for (const e of Object.values(byUuid)) {
|
||||
if (activeBranchUuids.has(e.uuid) || !activeBranchUuids.has(e.parentUuid)) continue;
|
||||
const blocks = blocksOf(e);
|
||||
if (
|
||||
blocks.length &&
|
||||
blocks.every((b) => b?.type === 'tool_result' && activeToolUseIds.has(b.tool_use_id))
|
||||
) {
|
||||
activeBranchUuids.add(e.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: filter — keep entries on the active branch.
|
||||
//
|
||||
// Claude Code writes several bookkeeping entry types alongside the message
|
||||
@@ -743,7 +761,7 @@ fi
|
||||
# Install conversation so the authoring harness can resume it
|
||||
${
|
||||
IS_CLAUDE
|
||||
? `ENCODED_CWD=$(echo "$PWD" | sed 's|/|-|g; s|^-||')
|
||||
? `ENCODED_CWD=$(echo "$PWD" | sed 's|[^a-zA-Z0-9]|-|g; s|^-||')
|
||||
DEST_DIR="$HOME/.claude/projects/-$ENCODED_CWD"
|
||||
mkdir -p "$DEST_DIR"
|
||||
cp "$SCRIPT_DIR/session.jsonl" "$DEST_DIR/$SESSION_UUID.jsonl"
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* Plugin-side re-export, so snapshot-to-task.ts resolves `./lib/secret-scrub`
|
||||
* both here and in the toolkit's flat scripts/ dir.
|
||||
*/
|
||||
export * from '../../../../static/scripts/lib/secret-scrub';
|
||||
@@ -162,10 +162,13 @@ function replacePrefixAtBoundary(haystack: string, needle: string, replacement:
|
||||
}
|
||||
}
|
||||
|
||||
/** Must match Claude Code's `.claude/projects/` folder names. */
|
||||
const encodeProjectDir = (p: string) => p.replace(/[^a-zA-Z0-9]/g, '-');
|
||||
|
||||
/** Replace a prefix and its dash-encoded form (`.claude/projects/<encoded>/`). */
|
||||
function stripBothForms(haystack: string, needle: string, replacement: string): string {
|
||||
const out = literalReplaceAll(haystack, needle, replacement);
|
||||
return literalReplaceAll(out, needle.replace(/\//g, '-'), replacement.replace(/\//g, '-'));
|
||||
return literalReplaceAll(out, encodeProjectDir(needle), replacement.replace(/\//g, '-'));
|
||||
}
|
||||
|
||||
export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): SanitizeResult {
|
||||
@@ -193,7 +196,7 @@ export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): S
|
||||
// EVERY root before ANY home dir: a home pass run between roots would rewrite a
|
||||
// sibling root's own prefix, leaving it unmatched when its turn came.
|
||||
for (const prefix of prefixes) {
|
||||
const encodedPrefix = prefix.replace(/\//g, '-');
|
||||
const encodedPrefix = encodeProjectDir(prefix);
|
||||
working = replacePrefixAtBoundary(working, prefix, placeholder);
|
||||
working = literalReplaceAll(working, encodedPrefix, placeholder.replace(/\//g, '-'));
|
||||
prefixStripped ??= prefix;
|
||||
@@ -206,7 +209,7 @@ export function sanitizeSessionJsonl(raw: string, opts: SanitizeOptions = {}): S
|
||||
.filter((h): h is string => h !== null && !prefixes.includes(h))
|
||||
);
|
||||
for (const homeDir of homeDirs) {
|
||||
const encodedHomeDir = homeDir.replace(/\//g, '-');
|
||||
const encodedHomeDir = encodeProjectDir(homeDir);
|
||||
working = replacePrefixAtBoundary(working, homeDir, HOME_DIR_PLACEHOLDER);
|
||||
working = literalReplaceAll(working, encodedHomeDir, HOME_DIR_PLACEHOLDER.replace(/\//g, '-'));
|
||||
homeDirStripped ??= homeDir;
|
||||
@@ -26,6 +26,7 @@ import { stripAuthoringScaffolding, truncationIndex, turnsFromLines } from './ha
|
||||
// This script must not call cpSync — it fails EACCES on a macOS docker bind mount.
|
||||
import { holisticRubricScaffoldFor } from './holistic-rubric-scaffold';
|
||||
import { copyTree } from './lib/copy-tree';
|
||||
import { readEnvSecrets, scrubTaskSecrets } from './lib/secret-scrub';
|
||||
import { collectCwds, sanitizeSessionJsonl } from './sanitize-session-jsonl';
|
||||
|
||||
// --- CLI ---
|
||||
@@ -576,6 +577,13 @@ if (existsSync(sessionDir) && statSync(sessionDir).isDirectory()) {
|
||||
mkdirSync(join(taskDir, 'environment', 'session'), { recursive: true });
|
||||
}
|
||||
|
||||
// The Explore agent can print the .env it runs with (`env`, `cat .env`), so its keys can be in
|
||||
// the capture. The scrub is silent: the worker didn't put them there and has nothing to do.
|
||||
const secretScan = scrubTaskSecrets(taskDir, readEnvSecrets(repoRoot));
|
||||
for (const file of secretScan.flagged) {
|
||||
log.warn({ file }, 'This file holds an API key from your .env. Remove it before you submit.');
|
||||
}
|
||||
|
||||
// The harness that captured the snapshot; the trial runs this one.
|
||||
const harness =
|
||||
typeof metadata.harness === 'string' && metadata.harness ? metadata.harness : 'claude-code';
|
||||
1
worker-toolkit-potion-polyglot-v1.0.1/explore/repos
Symbolic link
1
worker-toolkit-potion-polyglot-v1.0.1/explore/repos
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/eric/workspaces/dataannotation/project-2/worker-toolkit-potion-polyglot-v1.0.1/repos
|
||||
@@ -319,6 +319,18 @@ _node_bin() {
|
||||
d=$(ls -d "$nvm_dir"/versions/node/v"$major".* 2>/dev/null | sort -V | tail -1)
|
||||
[ -n "$d" ] && printf '%s/bin' "$d"
|
||||
}
|
||||
# First dev-server script <dir>/package.json defines. `next start` serves a production build that
|
||||
# a fresh checkout doesn't have, so a Next app boots `dev` instead.
|
||||
_dev_script() {
|
||||
node -e "const s=(require('$1/package.json').scripts)||{};const o=['start','dev','develop','serve'].filter(k=>s[k]&&!(k==='start'&&/^next start/.test(s[k])&&s.dev));if(o[0])process.stdout.write(o[0])" 2>/dev/null
|
||||
}
|
||||
# Path the app serves under in dev: a path "homepage" (CRA) or a Next.js basePath, e.g. /app.
|
||||
_homepage_path() {
|
||||
local p
|
||||
p=$(node -e "const h=(require('$1/package.json').homepage)||'';let p=h;try{p=new URL(h).pathname}catch{};if(/^\/[^/]/.test(p))process.stdout.write(p.replace(/\/$/,''))" 2>/dev/null)
|
||||
[ -n "$p" ] || p=$(cat "$1"/next.config.* 2>/dev/null | sed -nE "s/^[[:space:]]*basePath:[[:space:]]*['\"](\/[^'\"]+)['\"].*/\1/p" | head -1)
|
||||
printf '%s' "$p"
|
||||
}
|
||||
# Symlink ./node_modules (cwd = the dir being installed) to a container-local tree keyed by
|
||||
# <key> — see the ENFILE rationale at the call site. The target must itself be named
|
||||
# `node_modules` (Node resolves the symlink, then walks ancestors for that literal name),
|
||||
@@ -637,36 +649,37 @@ setup_repo() {
|
||||
else
|
||||
_mark_ctr_nodeps "$repo"
|
||||
printf " ${YELLOW}\xe2\x9a\xa0 %s: dependencies did not install${RESET} \xe2\x80\x94 explore-only in this container.\n ${GRAY}Reading the code, git and the editor still work; running the app or its tests will not.\n Usually a pin with no build for this machine's architecture. To retry: rm %s/%s.done${RESET}\n" "$repo" "$CTR_MARKER_DIR" "$repo"
|
||||
_mark_ctr_setup "$repo"; return 0
|
||||
fi
|
||||
_mark_ctr_setup "$repo"; return 0
|
||||
fi
|
||||
_py_have "$ver" || { printf " ${GRAY}(Python %s not in this image; skipping deps \xe2\x80\x94 explore-only)${RESET}\n" "$ver"; _mark_ctr_setup "$repo"; return 0; }
|
||||
# Some poetry repos depend on sibling repos via `git = "ssh://git@github.com/AskZeta/<name>.git"`,
|
||||
# which can't resolve in the container (no SSH key, no network). The deps are TRANSITIVE
|
||||
# (cx-chatbot → compiler-agent → agent-tools → leaves), so rewrite the target AND every
|
||||
# sibling pyproject to local path deps — else poetry shells out to `ssh` for a transitive
|
||||
# git dep and fails ("No such file or directory: 'ssh'").
|
||||
for pp in /workspace/repos/*/pyproject.toml; do
|
||||
[ -f "$pp" ] && _rewrite_askzeta_git_deps "$pp"
|
||||
done
|
||||
( cd "$dir" && export PATH="$PYENV_PATH:$PATH" PYENV_VERSION="$ver" \
|
||||
&& { [ -f .env.example ] && cp -n .env.example .env; true; } \
|
||||
&& { for kv in $bootenv; do grep -qxF "$kv" .env 2>/dev/null || echo "$kv" >> .env; done; true; } \
|
||||
&& { if [ -f pyproject.toml ]; then \
|
||||
# Every member Dockerfile sets this; without it poetry builds a .venv here
|
||||
# that the trial image has no equivalent of.
|
||||
poetry config virtualenvs.create false 2>/dev/null || true; \
|
||||
# The git→path rewrite invalidates poetry.lock ("changed significantly"), so
|
||||
# re-lock preserving pins: --no-update on poetry 1.x, the default on 2.x.
|
||||
poetry lock --no-update 2>/dev/null || poetry lock 2>/dev/null || true; \
|
||||
# --no-root: install deps only, not the project package itself. Some members'
|
||||
# pyproject package name doesn't map to a folder poetry can find ("No file/folder
|
||||
# found for package <x>"), which fails the whole install. The worker explores +
|
||||
# runs the code from the repo dir (cwd on path), so the project never needs to be
|
||||
# pip-installed as a package. Mirrors the harbor build.
|
||||
poetry install --no-interaction --no-root; \
|
||||
elif [ -f requirements.txt ]; then pip install -r requirements.txt; \
|
||||
elif [ -f setup.py ]; then pip install -e .; else true; fi; } ) || return 1 ;;
|
||||
else
|
||||
_py_have "$ver" || { printf " ${GRAY}(Python %s not in this image; skipping deps \xe2\x80\x94 explore-only)${RESET}\n" "$ver"; _mark_ctr_setup "$repo"; return 0; }
|
||||
# Some poetry repos depend on sibling repos via `git = "ssh://git@github.com/AskZeta/<name>.git"`,
|
||||
# which can't resolve in the container (no SSH key, no network). The deps are TRANSITIVE
|
||||
# (cx-chatbot → compiler-agent → agent-tools → leaves), so rewrite the target AND every
|
||||
# sibling pyproject to local path deps — else poetry shells out to `ssh` for a transitive
|
||||
# git dep and fails ("No such file or directory: 'ssh'").
|
||||
for pp in /workspace/repos/*/pyproject.toml; do
|
||||
[ -f "$pp" ] && _rewrite_askzeta_git_deps "$pp"
|
||||
done
|
||||
( cd "$dir" && export PATH="$PYENV_PATH:$PATH" PYENV_VERSION="$ver" \
|
||||
&& { [ -f .env.example ] && cp -n .env.example .env; true; } \
|
||||
&& { for kv in $bootenv; do grep -qxF "$kv" .env 2>/dev/null || echo "$kv" >> .env; done; true; } \
|
||||
&& { if [ -f pyproject.toml ]; then \
|
||||
# Every member Dockerfile sets this; without it poetry builds a .venv here
|
||||
# that the trial image has no equivalent of.
|
||||
poetry config virtualenvs.create false 2>/dev/null || true; \
|
||||
# The git→path rewrite invalidates poetry.lock ("changed significantly"), so
|
||||
# re-lock preserving pins: --no-update on poetry 1.x, the default on 2.x.
|
||||
poetry lock --no-update 2>/dev/null || poetry lock 2>/dev/null || true; \
|
||||
# --no-root: install deps only, not the project package itself. Some members'
|
||||
# pyproject package name doesn't map to a folder poetry can find ("No file/folder
|
||||
# found for package <x>"), which fails the whole install. The worker explores +
|
||||
# runs the code from the repo dir (cwd on path), so the project never needs to be
|
||||
# pip-installed as a package. Mirrors the harbor build.
|
||||
poetry install --no-interaction --no-root; \
|
||||
elif [ -f requirements.txt ]; then pip install -r requirements.txt; \
|
||||
elif [ -f setup.py ]; then pip install -e .; else true; fi; } ) || return 1
|
||||
fi ;;
|
||||
rust)
|
||||
command -v cargo >/dev/null 2>&1 || { printf " ${GRAY}(Rust not in this image; skipping build \xe2\x80\x94 explore-only)${RESET}\n"; _mark_ctr_setup "$repo"; return 0; }
|
||||
# Build to a container-local target dir (same ENFILE/bind-mount rationale as
|
||||
@@ -696,7 +709,15 @@ setup_repo() {
|
||||
printf " ${GRAY}preparing %s (one-time; details in ${RESET}${GRAY}run-app --logs${RESET}${GRAY})\xe2\x80\xa6${RESET}\n" "$repo"
|
||||
if ( cd "$dir" \
|
||||
&& export PATH="${spath:+$spath:}$PATH" \
|
||||
&& case "$kind" in ruby) export RBENV_VERSION="$ver" ;; python) export PYENV_VERSION="$ver" ;; esac \
|
||||
&& case "$kind" in
|
||||
ruby) export RBENV_VERSION="$ver" ;;
|
||||
python)
|
||||
if _py_uv_ok "$ver"; then
|
||||
. "$(_uv_venv_dir "$repo")/bin/activate"
|
||||
else
|
||||
export PYENV_VERSION="$ver"
|
||||
fi ;;
|
||||
esac \
|
||||
&& { for kv in $bootenv; do export "$kv"; done; } \
|
||||
&& eval "$setupcmd" ) > "$slog" 2>&1; then
|
||||
printf " ${GRAY}\xe2\x9c\x93 %s prepared${RESET}\n" "$repo"
|
||||
@@ -793,10 +814,8 @@ start_poly() {
|
||||
if [ -n "$startcmd" ]; then
|
||||
cmd="env $bootenv PORT=3000 BROWSER=none HOST=0.0.0.0 $startcmd"
|
||||
else
|
||||
local s2=""
|
||||
for s2 in start dev develop serve; do
|
||||
if node -e "process.exit((((require('$dir/package.json')||{}).scripts)||{})['$s2']?0:1)" 2>/dev/null; then break; else s2=""; fi
|
||||
done
|
||||
local s2
|
||||
s2=$(_dev_script "$dir")
|
||||
if [ -z "$s2" ]; then
|
||||
printf " ${GRAY}%s: deps installed, no dev-server script \xe2\x80\x94 run its tests directly (${RESET}${GRAY}yarn test${RESET}${GRAY}).${RESET}\n" "$repo"
|
||||
return 0
|
||||
@@ -811,10 +830,7 @@ start_poly() {
|
||||
return 0
|
||||
else
|
||||
# CRA / generic: first dev-server script the repo defines, bound to :3000.
|
||||
local s
|
||||
for s in start dev develop serve; do
|
||||
if node -e "process.exit((((require('$dir/package.json')||{}).scripts)||{})['$s']?0:1)" 2>/dev/null; then sc="$s"; break; fi
|
||||
done
|
||||
sc=$(_dev_script "$dir")
|
||||
if [ -z "$sc" ]; then
|
||||
printf " ${GRAY}%s: deps installed, no dev-server script \xe2\x80\x94 run its tests directly (${RESET}${GRAY}yarn test${RESET}${GRAY}).${RESET}\n" "$repo"
|
||||
return 0
|
||||
@@ -840,7 +856,11 @@ start_poly() {
|
||||
craenv="CI=true DANGEROUSLY_DISABLE_HOST_CHECK=true"
|
||||
case "${ver%%.*}" in 1[7-9]|[2-9][0-9]) craenv="NODE_OPTIONS=--openssl-legacy-provider $craenv" ;; esac
|
||||
fi
|
||||
cmd="env $bootenv $craenv PATH=$nbin:\$PATH PORT=3000 BROWSER=none HOST=0.0.0.0 yarn $sc"
|
||||
# Vite ignores PORT/HOST and listens on localhost:5173, which the published port can't reach.
|
||||
local viteargs=""
|
||||
node -e "process.exit(/^vite( |$)(?!build|preview)/.test((require('$dir/package.json').scripts||{})['$sc']||'')?0:1)" 2>/dev/null \
|
||||
&& viteargs=" --host 0.0.0.0 --port 3000"
|
||||
cmd="env $bootenv $craenv PATH=$nbin:\$PATH PORT=3000 BROWSER=none HOST=0.0.0.0 yarn $sc$viteargs"
|
||||
fi ;;
|
||||
python)
|
||||
if _ctr_nodeps "$repo"; then
|
||||
@@ -890,9 +910,9 @@ start_poly() {
|
||||
|| printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx database prep failed \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||
if [ -d "$phx_dir/deps" ] && [ -d "$phx_dir/_build" ]; then
|
||||
printf " ${CYAN}\xe2\x96\xb6${RESET} starting strongsuit_phx (elixir)\xe2\x80\xa6\n"
|
||||
# Derived, not a second env var: the app sends PHX_AUTH_TOKEN and the phx plug
|
||||
# compares against API_AUTH_TOKEN, and a drift shows up only as silent 401s.
|
||||
_spawn phx "$phx_dir" "env MIX_ENV=dev PHX_PORT=$COMPANION_PORT API_AUTH_TOKEN=${PHX_AUTH_TOKEN:-dummy} mix phx.server"
|
||||
# The app sends PHX_AUTH_TOKEN and the phx plug compares API_AUTH_TOKEN; both default
|
||||
# to the same value, so pass one only when the other was set.
|
||||
_spawn phx "$phx_dir" "env MIX_ENV=dev PHX_PORT=$COMPANION_PORT ${PHX_AUTH_TOKEN:+API_AUTH_TOKEN=$PHX_AUTH_TOKEN} mix phx.server"
|
||||
_wait_tcp "$COMPANION_PORT" 45 || printf " ${YELLOW}\xe2\x9a\xa0 strongsuit_phx didn't come up \xe2\x80\x94 ${RESET}${GRAY}run-app --logs${RESET}\n"
|
||||
else
|
||||
printf " ${GRAY}strongsuit_phx isn't built \xe2\x80\x94 the backend on :%s will be absent.\n" "$COMPANION_PORT"
|
||||
@@ -908,6 +928,8 @@ start_poly() {
|
||||
local landing=""
|
||||
case "$repo" in
|
||||
strongsuit-app) landing="/dev-login" ;;
|
||||
ABDM-FE) landing="/app/login" ;;
|
||||
*) [ "$kind" = node ] && landing=$(_homepage_path "$dir") ;;
|
||||
esac
|
||||
printf " ${CYAN}\xe2\x9c\x85 %s is up${RESET} open ${CYAN}http://localhost:%s%s${RESET}\n" "$repo" "$CLIENT_HOST_PORT" "$landing"
|
||||
# Per-member "how do I actually get in" notes. Only members whose landing page needs
|
||||
@@ -922,11 +944,15 @@ start_poly() {
|
||||
printf " Auth0 and cannot work offline.${RESET}\n"
|
||||
;;
|
||||
ABDM-FE)
|
||||
printf " ${GRAY}This app is served under a ${RESET}${GRAY}/app${RESET}${GRAY} basename, so the bare URL above renders\n"
|
||||
printf " nothing. Open ${RESET}${CYAN}http://localhost:%s/app/login${RESET}${GRAY} instead.\n" "$CLIENT_HOST_PORT"
|
||||
printf " Sign-in itself calls hosted services that aren't reachable offline, so the\n"
|
||||
printf " ${GRAY}Sign-in calls hosted services that aren't reachable offline, so the\n"
|
||||
printf " login page is as far as you can get — read and edit the code from there.${RESET}\n"
|
||||
;;
|
||||
book-my-minutes-app)
|
||||
printf " ${GRAY}This is the signed-in dashboard: every page needs a session, and signing in happens\n"
|
||||
printf " on a separate hosted app that isn't reachable offline, so the page above stays\n"
|
||||
printf " blank. Read and edit the code instead, or run ${RESET}${GRAY}book-my-minutes-onboarding${RESET}${GRAY} to see the\n"
|
||||
printf " public side of the product.${RESET}\n"
|
||||
;;
|
||||
search-api-v2)
|
||||
printf " ${GRAY}Browse and try the API at ${RESET}${CYAN}http://localhost:%s/docs${RESET}${GRAY}.\n" "$CLIENT_HOST_PORT"
|
||||
printf " Sign-in goes through a hosted identity provider that isn't reachable offline,\n"
|
||||
Binary file not shown.
@@ -271,9 +271,9 @@
|
||||
}
|
||||
],
|
||||
"defaultRepo": "potion-app",
|
||||
"version": "1.0.0",
|
||||
"buildSha": "f62b06f",
|
||||
"packedFrom": "565c9589c46926ee3025f82d28f31be0aae007e8",
|
||||
"version": "1.0.1",
|
||||
"buildSha": "5e48703",
|
||||
"packedFrom": "9b0c19e8f35875c162ad4e6129dfbdcbfc5f177c",
|
||||
"blockedHosts": [
|
||||
"sendpotion.com",
|
||||
"www.sendpotion.com",
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"version": 1,
|
||||
"stampedAt": "2026-09-29T20:06:24.427Z",
|
||||
"stampedAt": "2026-10-06T00:41:40.440Z",
|
||||
"files": {
|
||||
"tests/test.sh": "67d84a6d694718a777dfb9d79cb629206f769b92c67d66e19d9bb98bda168d04",
|
||||
"tests/test.sh": "32eb923e2772d1a7a0393f333adeff5eb33f68132cb5cadf4480ce1eb0ad5329",
|
||||
"tests/grader-system-prompt-consolidated.md": "032ce032728a8c0b2717478b929dbd7535e07c96ffe2e991097dd2c233543275"
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ commit = "f89abccf"
|
||||
# The toolkit release this task was created with. Written by the toolkit —
|
||||
# leave it in place: task tooling reads it to know which toolkit's assets
|
||||
# this task grades with.
|
||||
toolkit_version = "1.0.0"
|
||||
toolkit_version = "1.0.1"
|
||||
# Set true for a task about a UI: the trial gets Playwright + Chromium (`pw <script.js>`),
|
||||
# and on claude the `Read` tool so the agent can view a screenshot it takes. Leave false
|
||||
# when the point of the task is that something cannot be verified.
|
||||
@@ -17,7 +17,9 @@ def command(args, env, output):
|
||||
if not anthropic.endswith('/anthropic'):
|
||||
raise ValueError('Codex grading needs OPENAI_BASE_URL or the existing ANTHROPIC_BASE_URL proxy route')
|
||||
base = anthropic[:-len('/anthropic')] + '/openai/v1'
|
||||
key = (env.get('OPENAI_API_KEY') or env.get('ANTHROPIC_API_KEY') or '').strip()
|
||||
# Take the key from the route the URL came from: task images may set a dummy OPENAI_API_KEY for the app.
|
||||
paired = ('OPENAI_API_KEY', 'ANTHROPIC_API_KEY') if env.get('OPENAI_BASE_URL', '').strip() else ('ANTHROPIC_API_KEY', 'OPENAI_API_KEY')
|
||||
key = next((env[name].strip() for name in paired if env.get(name, '').strip()), '')
|
||||
if not key:
|
||||
raise ValueError('Codex grading needs the runtime proxy API key')
|
||||
metadata = '{"origin":"harbor-grading"}'
|
||||
@@ -77,7 +79,8 @@ def run(args, prompt, env):
|
||||
# Codex may have followed the original file-writing instruction before failing.
|
||||
grade.unlink(missing_ok=True)
|
||||
if process.returncode:
|
||||
raise ValueError(f'Codex exited with status {process.returncode}')
|
||||
failures = [line for line in process.stdout.splitlines() if '"error"' in line or '"turn.failed"' in line]
|
||||
raise ValueError(f'Codex exited with status {process.returncode}' + ''.join(f'\n {line[:2000]}' for line in failures[-5:]))
|
||||
events = [json.loads(line) for line in process.stdout.splitlines() if line.strip()]
|
||||
session = next((e.get('thread_id') for e in events if e.get('type') == 'thread.started'), None)
|
||||
completed = [e for e in events if e.get('type') == 'turn.completed']
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user