pantheon-opencode 1.5.0-beta.1 → 1.5.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/scripts/cost.mjs +30 -14
- package/scripts/mcp_persistence_server.py +44 -7
- package/scripts/probe-context-rehydrate.mjs +240 -0
- package/scripts/probe-pantheon-cost.mjs +304 -0
- package/scripts/test-opencode-v1-v2-sandbox.sh +394 -41
- package/src/mcp/mcp_persistence_server.py +44 -7
- package/src/pantheon/cost-command.ts +49 -32
- package/src/pantheon/delegate-manager.ts +285 -0
- package/src/pantheon/token-opt.ts +237 -11
- package/src/plugin-v2.ts +2 -14
- package/src/plugin.ts +3 -8
- package/src/plugins/tui/package.json +1 -1
- package/.pantheon/code-mode/.gitkeep +0 -0
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-1.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-10.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-11.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-2.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-3.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-4.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-5.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-6.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-7.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-8.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/checkpoint-9.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/heartbeat.json +0 -8
- package/.pantheon/code-mode/.pantheon/deepwork/initial-token-40k/session.json +0 -11
- package/src/pantheon/delegate-task-adapter.ts +0 -444
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
# (config is regenerated for that version first).
|
|
14
14
|
# --prompts Prompt battery via `opencode run --format json` for every
|
|
15
15
|
# requested version (with --run vX) or both versions alone.
|
|
16
|
+
# --cost Offline/ambiental pantheon_cost probe for the requested
|
|
17
|
+
# version (with --run vX) or both versions alone.
|
|
18
|
+
# The probe's synthetic checks run in explicit --fixture mode.
|
|
19
|
+
# --rehydrate Offline/ambiental context_rehydrate + context_session_summary
|
|
20
|
+
# probe for the requested version (with --run vX) or both.
|
|
16
21
|
# --reset Wipe the sandbox root.
|
|
17
22
|
# --help Usage.
|
|
18
23
|
#
|
|
@@ -49,11 +54,15 @@ V1_BIN="${OPENCODE_V1_BIN:-opencode}"
|
|
|
49
54
|
V2_BIN="${OPENCODE_V2_BIN:-opencode2}"
|
|
50
55
|
|
|
51
56
|
REPORT_FILE="$SANDBOX_ROOT/prompts-report.md"
|
|
57
|
+
COST_REPORT_FILE="$SANDBOX_ROOT/pantheon-cost-report.md"
|
|
58
|
+
REHYDRATE_REPORT_FILE="$SANDBOX_ROOT/context-rehydrate-report.md"
|
|
52
59
|
EXTRACT_PY="$SANDBOX_ROOT/.prompt-extract-json.py"
|
|
53
60
|
|
|
54
61
|
MODE_PREPARE=0
|
|
55
62
|
MODE_RESET=0
|
|
56
63
|
MODE_PROMPTS=0
|
|
64
|
+
MODE_COST=0
|
|
65
|
+
MODE_REHYDRATE=0
|
|
57
66
|
RUN_VERSION=""
|
|
58
67
|
|
|
59
68
|
usage() {
|
|
@@ -105,8 +114,8 @@ write_run_test_sh() {
|
|
|
105
114
|
cat > "$SANDBOX_ROOT/run-test.sh" <<'RUNTEST'
|
|
106
115
|
#!/usr/bin/env bash
|
|
107
116
|
# Generated by pantheon-opencode scripts/test-opencode-v1-v2-sandbox.sh --prepare
|
|
108
|
-
# Validates the global install: binaries, 5
|
|
109
|
-
# AND the CONTENT of
|
|
117
|
+
# Validates the global install: binaries, exactly 5 connected MCPs per version,
|
|
118
|
+
# doctor 0 errors, AND the CONTENT of pantheon://agents (zeus/hermes present).
|
|
110
119
|
set -euo pipefail
|
|
111
120
|
|
|
112
121
|
SANDBOX_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
@@ -124,9 +133,81 @@ export HOME="$SANDBOX_HOME"
|
|
|
124
133
|
export PATH="$NPM_PREFIX/bin:$SANDBOX_VENV/bin:$PATH"
|
|
125
134
|
export npm_config_prefix="$NPM_PREFIX"
|
|
126
135
|
|
|
136
|
+
STATUS_FAIL=0
|
|
137
|
+
STATUS_AMBIENTAL=0
|
|
138
|
+
STATUS_NOT_TESTED=0
|
|
139
|
+
STATUS_PASS=0
|
|
140
|
+
MCP_AMBIENTAL_RE='needs authentication|unauthorized|authentication failure|api key|credentials|401|docker|econnrefused|enotfound|etimedout|econnreset|connection refused|rate.?limit|429|quota|overloaded|edgesout|npm err'
|
|
141
|
+
|
|
142
|
+
record_status() { # label status detail
|
|
143
|
+
local label="$1" status="$2" detail="$3"
|
|
144
|
+
case "$status" in
|
|
145
|
+
PASS) STATUS_PASS=$((STATUS_PASS + 1)) ;;
|
|
146
|
+
FAIL) STATUS_FAIL=$((STATUS_FAIL + 1)) ;;
|
|
147
|
+
AMBIENTAL) STATUS_AMBIENTAL=$((STATUS_AMBIENTAL + 1)) ;;
|
|
148
|
+
NOT_TESTED) STATUS_NOT_TESTED=$((STATUS_NOT_TESTED + 1)) ;;
|
|
149
|
+
esac
|
|
150
|
+
printf '%s: %s — %s\n' "$status" "$label" "$detail"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
check_binary() { # label binary
|
|
154
|
+
local label="$1" bin="$2" out rc=0
|
|
155
|
+
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
156
|
+
record_status "$label" "NOT_TESTED" "binary '$bin' is not installed in the sandbox prefix"
|
|
157
|
+
return 0
|
|
158
|
+
fi
|
|
159
|
+
set +e
|
|
160
|
+
out="$("$bin" --version 2>&1)"
|
|
161
|
+
rc=$?
|
|
162
|
+
set -e
|
|
163
|
+
if [ "$rc" -eq 0 ]; then
|
|
164
|
+
record_status "$label" "PASS" "${out:-version command exited 0}"
|
|
165
|
+
elif printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
166
|
+
record_status "$label" "AMBIENTAL" "version check unavailable (exit $rc)"
|
|
167
|
+
else
|
|
168
|
+
record_status "$label" "FAIL" "version check exited $rc"
|
|
169
|
+
fi
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
check_mcp() { # label binary project
|
|
173
|
+
local label="$1" bin="$2" project="$3" out connected_count rc=0
|
|
174
|
+
if ! command -v "$bin" >/dev/null 2>&1; then
|
|
175
|
+
record_status "$label MCP" "NOT_TESTED" "binary '$bin' is not installed in the sandbox prefix"
|
|
176
|
+
return 0
|
|
177
|
+
fi
|
|
178
|
+
if [ ! -d "$project" ]; then
|
|
179
|
+
record_status "$label MCP" "NOT_TESTED" "project directory is missing: $project"
|
|
180
|
+
return 0
|
|
181
|
+
fi
|
|
182
|
+
set +e
|
|
183
|
+
out="$(cd "$project" && "$bin" mcp list 2>&1)"
|
|
184
|
+
rc=$?
|
|
185
|
+
set -e
|
|
186
|
+
out="$(printf '%s' "$out" | sed -E $'s/\x1B\\[[0-?]*[ -/]*[@-~]//g')"
|
|
187
|
+
printf '%s\n' "$out"
|
|
188
|
+
if [ "$rc" -ne 0 ]; then
|
|
189
|
+
if printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
190
|
+
record_status "$label MCP" "AMBIENTAL" "mcp list environmental failure (exit $rc)"
|
|
191
|
+
else
|
|
192
|
+
record_status "$label MCP" "FAIL" "mcp list exited $rc"
|
|
193
|
+
fi
|
|
194
|
+
return 0
|
|
195
|
+
fi
|
|
196
|
+
connected_count="$(printf '%s' "$out" | grep -Eic '(^|[^[:alnum:]_])connected([^[:alnum:]_]|$)')" || connected_count=0
|
|
197
|
+
if [ "$connected_count" -eq 5 ] \
|
|
198
|
+
&& ! printf '%s' "$out" | grep -Eiq 'failed|✘' \
|
|
199
|
+
&& ! printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
200
|
+
record_status "$label MCP" "PASS" "exactly 5 connected MCPs"
|
|
201
|
+
elif printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
202
|
+
record_status "$label MCP" "AMBIENTAL" "environmental MCP status; found $connected_count connected"
|
|
203
|
+
else
|
|
204
|
+
record_status "$label MCP" "FAIL" "expected exactly 5 connected MCPs; found $connected_count or failures reported"
|
|
205
|
+
fi
|
|
206
|
+
}
|
|
207
|
+
|
|
127
208
|
echo "--- Binaries ---"
|
|
128
|
-
opencode
|
|
129
|
-
opencode2
|
|
209
|
+
check_binary "V1 binary" opencode
|
|
210
|
+
check_binary "V2 binary" opencode2
|
|
130
211
|
|
|
131
212
|
echo "--- Building tarball ---"
|
|
132
213
|
cd "$REPO_DIR"
|
|
@@ -134,42 +215,80 @@ npm pack 2>/dev/null || { echo "ERROR: npm pack failed"; exit 1; }
|
|
|
134
215
|
TGZ=$(ls -t pantheon-opencode-*.tgz | head -1)
|
|
135
216
|
npm rm -g pantheon-opencode 2>/dev/null || true
|
|
136
217
|
npm install -g "$TGZ"
|
|
218
|
+
if ! git -C "$REPO_DIR" ls-files --error-unmatch -- "$TGZ" >/dev/null 2>&1; then rm -f -- "$TGZ"; fi
|
|
137
219
|
|
|
138
220
|
echo "--- Init (headless) ---"
|
|
139
221
|
pantheon-opencode init --headless -y
|
|
140
222
|
|
|
141
|
-
echo "--- MCP
|
|
142
|
-
opencode
|
|
143
|
-
|
|
144
|
-
echo "--- MCP List (V2) ---"
|
|
145
|
-
opencode2 mcp list
|
|
223
|
+
echo "--- MCP Validation ---"
|
|
224
|
+
check_mcp "V1" opencode "$SANDBOX_DIR/project-v1"
|
|
225
|
+
check_mcp "V2" opencode2 "$SANDBOX_DIR/project-v2"
|
|
146
226
|
|
|
147
227
|
echo "--- Doctor ---"
|
|
148
|
-
pantheon-opencode
|
|
228
|
+
if command -v pantheon-opencode >/dev/null 2>&1; then
|
|
229
|
+
set +e
|
|
230
|
+
DOCTOR_OUTPUT="$(pantheon-opencode doctor --target "$SANDBOX_DIR" 2>&1)"
|
|
231
|
+
DOCTOR_RC=$?
|
|
232
|
+
set -e
|
|
233
|
+
if [ "$DOCTOR_RC" -eq 0 ]; then
|
|
234
|
+
record_status "doctor" "PASS" "exit 0"
|
|
235
|
+
elif printf '%s' "$DOCTOR_OUTPUT" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
236
|
+
record_status "doctor" "AMBIENTAL" "environmental doctor failure (exit $DOCTOR_RC)"
|
|
237
|
+
else
|
|
238
|
+
record_status "doctor" "FAIL" "doctor exited $DOCTOR_RC"
|
|
239
|
+
fi
|
|
240
|
+
else
|
|
241
|
+
record_status "doctor" "NOT_TESTED" "pantheon-opencode is not installed in the sandbox prefix"
|
|
242
|
+
fi
|
|
149
243
|
|
|
150
244
|
echo "--- Gate (b): pantheon://agents CONTENT check ---"
|
|
151
245
|
RESOURCES_SRV="$PANTHEON_GLOBAL/scripts/mcp_resources_server.py"
|
|
152
246
|
if [ ! -f "$RESOURCES_SRV" ]; then
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
247
|
+
record_status "pantheon://agents resource" "NOT_TESTED" "resources server not found at $RESOURCES_SRV"
|
|
248
|
+
else
|
|
249
|
+
set +e
|
|
250
|
+
AGENTS_CONTENT="$("$SANDBOX_VENV/bin/python" - "$RESOURCES_SRV" <<'PYEOF'
|
|
156
251
|
import asyncio, importlib.util, sys
|
|
252
|
+
from pathlib import Path
|
|
253
|
+
resource_path = Path(sys.argv[1]).resolve()
|
|
254
|
+
sys.path.insert(0, str(resource_path.parent))
|
|
157
255
|
spec = importlib.util.spec_from_file_location("mrs", sys.argv[1])
|
|
158
256
|
mod = importlib.util.module_from_spec(spec)
|
|
159
257
|
spec.loader.exec_module(mod)
|
|
160
258
|
print(asyncio.run(mod.list_agents()))
|
|
161
259
|
PYEOF
|
|
162
260
|
)"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
261
|
+
AGENTS_RC=$?
|
|
262
|
+
set -e
|
|
263
|
+
printf '%s\n' "$AGENTS_CONTENT" | head -8
|
|
264
|
+
if [ "$AGENTS_RC" -ne 0 ]; then
|
|
265
|
+
if printf '%s' "$AGENTS_CONTENT" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
266
|
+
record_status "pantheon://agents resource" "AMBIENTAL" "resource probe environmental failure (exit $AGENTS_RC)"
|
|
267
|
+
else
|
|
268
|
+
record_status "pantheon://agents resource" "FAIL" "resource probe exited $AGENTS_RC"
|
|
269
|
+
fi
|
|
270
|
+
elif printf '%s\n' "$AGENTS_CONTENT" | grep -qi 'zeus' \
|
|
271
|
+
&& printf '%s\n' "$AGENTS_CONTENT" | grep -qi 'hermes'; then
|
|
272
|
+
record_status "pantheon://agents resource" "PASS" "pantheon://agents content includes zeus and hermes"
|
|
273
|
+
else
|
|
274
|
+
record_status "pantheon://agents resource" "FAIL" "content missing zeus/hermes (connectivity alone is not enough)"
|
|
275
|
+
fi
|
|
169
276
|
fi
|
|
170
|
-
|
|
171
277
|
echo ""
|
|
172
278
|
echo "=== VALIDATION COMPLETE ==="
|
|
279
|
+
if [ "$STATUS_FAIL" -gt 0 ]; then
|
|
280
|
+
FINAL_VERDICT="FAIL"
|
|
281
|
+
elif [ "$STATUS_NOT_TESTED" -gt 0 ]; then
|
|
282
|
+
FINAL_VERDICT="NOT_TESTED"
|
|
283
|
+
elif [ "$STATUS_AMBIENTAL" -gt 0 ]; then
|
|
284
|
+
FINAL_VERDICT="AMBIENTAL"
|
|
285
|
+
else
|
|
286
|
+
FINAL_VERDICT="PASS"
|
|
287
|
+
fi
|
|
288
|
+
printf 'Final verdict: %s\n' "$FINAL_VERDICT"
|
|
289
|
+
if [ "$FINAL_VERDICT" = "FAIL" ]; then
|
|
290
|
+
exit 1
|
|
291
|
+
fi
|
|
173
292
|
echo "Next: open the isolated TUI with: $SANDBOX_DIR/start-pantheon.sh"
|
|
174
293
|
RUNTEST
|
|
175
294
|
chmod +x "$SANDBOX_ROOT/run-test.sh"
|
|
@@ -195,6 +314,7 @@ install_binaries() {
|
|
|
195
314
|
tgz=$(ls -t pantheon-opencode-*.tgz | head -1)
|
|
196
315
|
npm rm -g pantheon-opencode 2>/dev/null || true
|
|
197
316
|
npm install -g "$REPO_DIR/$tgz" || die "install of $tgz failed"
|
|
317
|
+
if ! git -C "$REPO_DIR" ls-files --error-unmatch -- "$tgz" >/dev/null 2>&1; then rm -f -- "$tgz"; fi
|
|
198
318
|
log "--- Installing OpenCode V1 ($OPENCODE_V1_SPEC) ---"
|
|
199
319
|
npm install -g "$OPENCODE_V1_SPEC" \
|
|
200
320
|
|| warn "V1 binary install failed ($OPENCODE_V1_SPEC) — v1 prompts will be AMBIENTAL"
|
|
@@ -273,6 +393,7 @@ PYEOF
|
|
|
273
393
|
|
|
274
394
|
# Known environmental failure signatures (never fail the run).
|
|
275
395
|
AMBIENTAL_RE='bifrost|unauthorized|authentication failure|api key|credentials|401|docker|econnrefused|enotfound|etimedout|econnreset|connection refused|rate.?limit|429|quota|overloaded|edgesout|npm err'
|
|
396
|
+
MCP_AMBIENTAL_RE='needs authentication|unauthorized|authentication failure|api key|credentials|401|docker|econnrefused|enotfound|etimedout|econnreset|connection refused|rate.?limit|429|quota|overloaded|edgesout|npm err'
|
|
276
397
|
|
|
277
398
|
PROMPT_IDS=()
|
|
278
399
|
PROMPT_TEXTS=()
|
|
@@ -354,12 +475,20 @@ run_prompt_attempt() { # v idx current_bin — sets ATTEMPT_RESULT / ATTEMPT_DET
|
|
|
354
475
|
if [ "$rc" -eq 124 ]; then
|
|
355
476
|
ATTEMPT_RESULT="AMBIENTAL"
|
|
356
477
|
ATTEMPT_DETAIL="timeout after ${PANTHEON_PROMPT_TIMEOUT}s (provider latency)"
|
|
478
|
+
elif [ "$rc" -ne 0 ]; then
|
|
479
|
+
if [ -n "$amb_marker" ] && printf '%s' "$extracted" | grep -q "$amb_marker"; then
|
|
480
|
+
ATTEMPT_RESULT="AMBIENTAL"
|
|
481
|
+
ATTEMPT_DETAIL="explicit $amb_marker (exit $rc)"
|
|
482
|
+
elif printf '%s' "$raw" | grep -Eiq "$AMBIENTAL_RE"; then
|
|
483
|
+
ATTEMPT_RESULT="AMBIENTAL"
|
|
484
|
+
ATTEMPT_DETAIL="environmental signature with exit $rc"
|
|
485
|
+
else
|
|
486
|
+
ATTEMPT_RESULT="FAIL"
|
|
487
|
+
ATTEMPT_DETAIL="marker $marker absent; exit $rc; snippet: $(printf '%s' "$raw" | cut -c1-160)"
|
|
488
|
+
fi
|
|
357
489
|
elif printf '%s' "$extracted" | grep -q "$marker"; then
|
|
358
490
|
ATTEMPT_RESULT="PASS"
|
|
359
491
|
ATTEMPT_DETAIL="marker $marker found"
|
|
360
|
-
elif [ -n "$amb_marker" ] && printf '%s' "$extracted" | grep -q "$amb_marker"; then
|
|
361
|
-
ATTEMPT_RESULT="AMBIENTAL"
|
|
362
|
-
ATTEMPT_DETAIL="explicit $amb_marker"
|
|
363
492
|
elif [ -n "$verify" ] \
|
|
364
493
|
&& [ "$(cat "${verify%%::*}" 2>/dev/null)" = "${verify##*::}" ]; then
|
|
365
494
|
ATTEMPT_RESULT="PASS"
|
|
@@ -398,7 +527,7 @@ run_prompt() { # v idx current_bin — ONE retry after cooldown for real FAIL on
|
|
|
398
527
|
}
|
|
399
528
|
|
|
400
529
|
check_mcp_list() { # v
|
|
401
|
-
local v="$1" bin out rc=0
|
|
530
|
+
local v="$1" bin out connected_count rc=0
|
|
402
531
|
if ! bin="$(sandbox_bin_v "$v")"; then
|
|
403
532
|
record "$v" "mcp-list" "AMBIENTAL" "binary not installed in sandbox prefix"
|
|
404
533
|
return 0
|
|
@@ -407,13 +536,24 @@ check_mcp_list() { # v
|
|
|
407
536
|
out="$(cd "$(project_for "$v")" && "$bin" mcp list 2>&1)"
|
|
408
537
|
rc=$?
|
|
409
538
|
set -e
|
|
539
|
+
out="$(printf '%s' "$out" | sed -E $'s/\x1B\\[[0-?]*[ -/]*[@-~]//g')"
|
|
410
540
|
if [ "$rc" -ne 0 ]; then
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
541
|
+
if printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
542
|
+
record "$v" "mcp-list" "AMBIENTAL" "mcp list environmental failure (exit $rc)"
|
|
543
|
+
else
|
|
544
|
+
record "$v" "mcp-list" "FAIL" "opencode mcp list exited $rc"
|
|
545
|
+
fi
|
|
546
|
+
return 0
|
|
547
|
+
fi
|
|
548
|
+
connected_count="$(printf '%s' "$out" | grep -Eic '(^|[^[:alnum:]_])connected([^[:alnum:]_]|$)')" || connected_count=0
|
|
549
|
+
if [ "$connected_count" -eq 5 ] \
|
|
550
|
+
&& ! printf '%s' "$out" | grep -Eiq "failed|✘" \
|
|
551
|
+
&& ! printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
552
|
+
record "$v" "mcp-list" "PASS" "$connected_count connected (expected exactly 5)"
|
|
553
|
+
elif printf '%s' "$out" | grep -Eiq "$MCP_AMBIENTAL_RE"; then
|
|
554
|
+
record "$v" "mcp-list" "AMBIENTAL" "environmental MCP status; found $connected_count connected"
|
|
415
555
|
else
|
|
416
|
-
record "$v" "mcp-list" "FAIL" "
|
|
556
|
+
record "$v" "mcp-list" "FAIL" "expected exactly 5 connected MCPs; found $connected_count or failures reported"
|
|
417
557
|
fi
|
|
418
558
|
}
|
|
419
559
|
|
|
@@ -434,6 +574,90 @@ check_doctor() { # v
|
|
|
434
574
|
fi
|
|
435
575
|
}
|
|
436
576
|
|
|
577
|
+
installed_package_root() {
|
|
578
|
+
local pan resolved
|
|
579
|
+
if ! pan="$(sandbox_bin_for "pantheon-opencode")"; then
|
|
580
|
+
return 1
|
|
581
|
+
fi
|
|
582
|
+
resolved="$(readlink -f "$pan" 2>/dev/null || true)"
|
|
583
|
+
[ -n "$resolved" ] || return 1
|
|
584
|
+
dirname "$(dirname "$resolved")"
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
run_cost_probe() { # v
|
|
588
|
+
local v="$1" package_root probe raw status detail
|
|
589
|
+
if ! package_root="$(installed_package_root)"; then
|
|
590
|
+
record "$v" "pantheon-cost" "NOT_TESTED" "sandbox package is not installed"
|
|
591
|
+
return 0
|
|
592
|
+
fi
|
|
593
|
+
probe="$package_root/scripts/probe-pantheon-cost.mjs"
|
|
594
|
+
if [ ! -f "$probe" ]; then
|
|
595
|
+
record "$v" "pantheon-cost" "NOT_TESTED" "installed package has no offline cost probe"
|
|
596
|
+
return 0
|
|
597
|
+
fi
|
|
598
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
599
|
+
record "$v" "pantheon-cost" "AMBIENTAL" "node runtime is not available"
|
|
600
|
+
return 0
|
|
601
|
+
fi
|
|
602
|
+
set +e
|
|
603
|
+
raw="$(node "$probe" --version "$v" --fixture --json 2>&1)"
|
|
604
|
+
local rc=$?
|
|
605
|
+
set -e
|
|
606
|
+
case "$raw" in
|
|
607
|
+
*'"status":"PASS"'*) status="PASS" ;;
|
|
608
|
+
*'"status":"NOT_TESTED"'*) status="NOT_TESTED" ;;
|
|
609
|
+
*'"status":"AMBIENTAL"'*) status="AMBIENTAL" ;;
|
|
610
|
+
*) status="FAIL" ;;
|
|
611
|
+
esac
|
|
612
|
+
detail="$(printf '%s' "$raw" | tr '\n' ' ' | cut -c1-400)"
|
|
613
|
+
if [ "$rc" -ne 0 ] && [ "$status" = "PASS" ]; then
|
|
614
|
+
status="FAIL"
|
|
615
|
+
detail="$detail (probe exit $rc)"
|
|
616
|
+
elif [ "$rc" -ne 0 ] && [ "$status" != "FAIL" ]; then
|
|
617
|
+
detail="$detail (probe exit $rc)"
|
|
618
|
+
fi
|
|
619
|
+
record "$v" "pantheon-cost" "$status" "$detail"
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
run_rehydrate_probe() { # v
|
|
623
|
+
local v="$1" package_root probe raw status detail
|
|
624
|
+
if ! package_root="$(installed_package_root)"; then
|
|
625
|
+
record "$v" "context-rehydrate" "NOT_TESTED" "sandbox package is not installed"
|
|
626
|
+
return 0
|
|
627
|
+
fi
|
|
628
|
+
probe="$package_root/scripts/probe-context-rehydrate.mjs"
|
|
629
|
+
if [ ! -f "$probe" ]; then
|
|
630
|
+
record "$v" "context-rehydrate" "NOT_TESTED" "installed package has no offline context probe"
|
|
631
|
+
return 0
|
|
632
|
+
fi
|
|
633
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
634
|
+
record "$v" "context-rehydrate" "AMBIENTAL" "node runtime is not available"
|
|
635
|
+
return 0
|
|
636
|
+
fi
|
|
637
|
+
set +e
|
|
638
|
+
raw="$(timeout 30 node "$probe" --version "$v" --json 2>&1)"
|
|
639
|
+
local rc=$?
|
|
640
|
+
set -e
|
|
641
|
+
case "$raw" in
|
|
642
|
+
*'"status":"PASS"'*) status="PASS" ;;
|
|
643
|
+
*'"status":"NOT_TESTED"'*) status="NOT_TESTED" ;;
|
|
644
|
+
*'"status":"AMBIENTAL"'*) status="AMBIENTAL" ;;
|
|
645
|
+
*) status="FAIL" ;;
|
|
646
|
+
esac
|
|
647
|
+
detail="$(printf '%s' "$raw" | tr '\n' ' ' | cut -c1-400)"
|
|
648
|
+
if [ "$rc" -eq 124 ]; then
|
|
649
|
+
status="AMBIENTAL"
|
|
650
|
+
detail="context probe timed out after 30s"
|
|
651
|
+
elif [ "$rc" -ne 0 ] && [ "$status" = "PASS" ]; then
|
|
652
|
+
# A non-zero probe exit must never be reported as PASS.
|
|
653
|
+
status="FAIL"
|
|
654
|
+
detail="$detail (probe exit $rc)"
|
|
655
|
+
elif [ "$rc" -ne 0 ] && [ "$status" != "FAIL" ]; then
|
|
656
|
+
detail="$detail (probe exit $rc)"
|
|
657
|
+
fi
|
|
658
|
+
record "$v" "context-rehydrate" "$status" "$detail"
|
|
659
|
+
}
|
|
660
|
+
|
|
437
661
|
run_version_prompts() { # v
|
|
438
662
|
local v="$1" bin
|
|
439
663
|
if ! bin="$(sandbox_bin_v "$v")"; then
|
|
@@ -459,8 +683,22 @@ run_version_prompts() { # v
|
|
|
459
683
|
check_doctor "$v"
|
|
460
684
|
}
|
|
461
685
|
|
|
686
|
+
probe_verdict() { # fail pass ambiental not_tested → one final status
|
|
687
|
+
# Verdict: PASS; Verdict: FAIL; Verdict: AMBIENTAL; Verdict: NOT_TESTED remain distinct.
|
|
688
|
+
local fail="$1" pass="$2" ambiental="$3" not_tested="$4"
|
|
689
|
+
if [ "$fail" -gt 0 ]; then
|
|
690
|
+
printf 'FAIL'
|
|
691
|
+
elif [ "$not_tested" -gt 0 ]; then
|
|
692
|
+
printf 'NOT_TESTED'
|
|
693
|
+
elif [ "$ambiental" -gt 0 ]; then
|
|
694
|
+
printf 'AMBIENTAL'
|
|
695
|
+
else
|
|
696
|
+
printf 'PASS'
|
|
697
|
+
fi
|
|
698
|
+
}
|
|
699
|
+
|
|
462
700
|
write_report() { # versions...
|
|
463
|
-
local versions=("$@") total_fail=0 total_pass=0 total_amb=0
|
|
701
|
+
local versions=("$@") total_fail=0 total_pass=0 total_amb=0 total_not_tested=0
|
|
464
702
|
{
|
|
465
703
|
printf '# Pantheon Sandbox Prompts Report\n\n'
|
|
466
704
|
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
@@ -475,26 +713,114 @@ write_report() { # versions...
|
|
|
475
713
|
for id in "${PROMPT_IDS[@]}" mcp-list doctor; do
|
|
476
714
|
res="${RESULTS["$v:$id"]:-SKIP}"
|
|
477
715
|
case "$res" in
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
716
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
717
|
+
AMBIENTAL) total_amb=$((total_amb + 1)) ;;
|
|
718
|
+
FAIL) total_fail=$((total_fail + 1)) ;;
|
|
719
|
+
NOT_TESTED) total_not_tested=$((total_not_tested + 1)) ;;
|
|
481
720
|
esac
|
|
482
721
|
printf '| %s | %s | %s |\n' "$id" "$res" "${DETAILS["$v:$id"]:-—}"
|
|
483
722
|
done
|
|
484
723
|
printf '\n'
|
|
485
724
|
done
|
|
486
725
|
printf '## Summary\n\n'
|
|
487
|
-
printf -- '- PASS: %d\n- FAIL (real): %d\n- AMBIENTAL: %d\n- Retries used: %d\n\n' \
|
|
488
|
-
"$total_pass" "$total_fail" "$total_amb" "$RETRIES_USED"
|
|
489
|
-
|
|
490
|
-
printf '**Verdict: PASS** — no real failures (AMBIENTAL issues do not block).\n'
|
|
491
|
-
else
|
|
492
|
-
printf '**Verdict: FAIL** — real failures detected (see table above).\n'
|
|
493
|
-
fi
|
|
726
|
+
printf -- '- PASS: %d\n- FAIL (real): %d\n- AMBIENTAL: %d\n- NOT_TESTED: %d\n- Retries used: %d\n\n' \
|
|
727
|
+
"$total_pass" "$total_fail" "$total_amb" "$total_not_tested" "$RETRIES_USED"
|
|
728
|
+
printf '**Verdict: %s**\n' "$(probe_verdict "$total_fail" "$total_pass" "$total_amb" "$total_not_tested")"
|
|
494
729
|
} > "$REPORT_FILE"
|
|
495
730
|
log "Report written to $REPORT_FILE"
|
|
496
731
|
}
|
|
497
732
|
|
|
733
|
+
write_cost_report() { # versions...
|
|
734
|
+
local versions=("$@") total_fail=0 total_pass=0 total_ambient=0 total_not_tested=0
|
|
735
|
+
{
|
|
736
|
+
printf '# Pantheon Cost Probe Report\n\n'
|
|
737
|
+
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
738
|
+
printf -- '- **Sandbox:** %s\n\n' "$SANDBOX_ROOT"
|
|
739
|
+
printf '| Version | Result | Detail |\n|---|---|---|\n'
|
|
740
|
+
local v result
|
|
741
|
+
for v in "${versions[@]}"; do
|
|
742
|
+
result="${RESULTS["$v:pantheon-cost"]:-NOT_TESTED}"
|
|
743
|
+
case "$result" in
|
|
744
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
745
|
+
FAIL) total_fail=$((total_fail + 1)) ;;
|
|
746
|
+
AMBIENTAL) total_ambient=$((total_ambient + 1)) ;;
|
|
747
|
+
NOT_TESTED) total_not_tested=$((total_not_tested + 1)) ;;
|
|
748
|
+
esac
|
|
749
|
+
printf '| %s | %s | %s |\n' "$v" "$result" "${DETAILS["$v:pantheon-cost"]:-—}"
|
|
750
|
+
done
|
|
751
|
+
printf '\n## Summary\n\n'
|
|
752
|
+
printf -- '- PASS: %d\n- FAIL (real): %d\n- AMBIENTAL: %d\n- NOT_TESTED: %d\n\n' \
|
|
753
|
+
"$total_pass" "$total_fail" "$total_ambient" "$total_not_tested"
|
|
754
|
+
printf '**Verdict: %s**\n' "$(probe_verdict "$total_fail" "$total_pass" "$total_ambient" "$total_not_tested")"
|
|
755
|
+
} > "$COST_REPORT_FILE"
|
|
756
|
+
log "Cost probe report written to $COST_REPORT_FILE"
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
write_rehydrate_report() { # versions...
|
|
760
|
+
local versions=("$@") total_fail=0 total_pass=0 total_ambient=0 total_not_tested=0
|
|
761
|
+
{
|
|
762
|
+
printf '# Pantheon Context Rehydration Probe Report\n\n'
|
|
763
|
+
printf -- '- **Date:** %s\n' "$(date -u '+%Y-%m-%d %H:%M UTC')"
|
|
764
|
+
printf -- '- **Sandbox:** %s\n\n' "$SANDBOX_ROOT"
|
|
765
|
+
printf '| Version | Probe | Result | Detail |\n|---|---|---|---|\n'
|
|
766
|
+
local v result
|
|
767
|
+
for v in "${versions[@]}"; do
|
|
768
|
+
result="${RESULTS["$v:context-rehydrate"]:-NOT_TESTED}"
|
|
769
|
+
case "$result" in
|
|
770
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
771
|
+
FAIL) total_fail=$((total_fail + 1)) ;;
|
|
772
|
+
AMBIENTAL) total_ambient=$((total_ambient + 1)) ;;
|
|
773
|
+
NOT_TESTED) total_not_tested=$((total_not_tested + 1)) ;;
|
|
774
|
+
esac
|
|
775
|
+
printf '| %s | context_rehydrate + context_session_summary | %s | %s |\n' \
|
|
776
|
+
"$v" "$result" "${DETAILS["$v:context-rehydrate"]:-—}"
|
|
777
|
+
done
|
|
778
|
+
printf '\n## Summary\n\n'
|
|
779
|
+
printf -- '- PASS: %d\n- FAIL (real): %d\n- AMBIENTAL: %d\n- NOT_TESTED: %d\n\n' \
|
|
780
|
+
"$total_pass" "$total_fail" "$total_ambient" "$total_not_tested"
|
|
781
|
+
printf '**Verdict: %s**\n' "$(probe_verdict "$total_fail" "$total_pass" "$total_ambient" "$total_not_tested")"
|
|
782
|
+
} > "$REHYDRATE_REPORT_FILE"
|
|
783
|
+
log "Context probe report written to $REHYDRATE_REPORT_FILE"
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
run_cost() { # versions...
|
|
787
|
+
local versions=("$@") v fail=0
|
|
788
|
+
mkdir -p "$SANDBOX_ROOT"
|
|
789
|
+
for v in "${versions[@]}"; do
|
|
790
|
+
log "[$v] pantheon_cost offline probe ..."
|
|
791
|
+
run_cost_probe "$v"
|
|
792
|
+
log "[$v] pantheon-cost → ${RESULTS["$v:pantheon-cost"]}"
|
|
793
|
+
done
|
|
794
|
+
write_cost_report "${versions[@]}"
|
|
795
|
+
for v in "${versions[@]}"; do
|
|
796
|
+
[ "${RESULTS["$v:pantheon-cost"]:-}" = "FAIL" ] && fail=$((fail + 1)) || true
|
|
797
|
+
done
|
|
798
|
+
if [ "$fail" -gt 0 ]; then
|
|
799
|
+
log "Cost probe: $fail real FAIL(s)."
|
|
800
|
+
exit 1
|
|
801
|
+
fi
|
|
802
|
+
log "Cost probe: no real failures (NOT_TESTED/AMBIENTAL is non-blocking)."
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
run_rehydrate() { # versions...
|
|
806
|
+
local versions=("$@") v fail=0
|
|
807
|
+
mkdir -p "$SANDBOX_ROOT"
|
|
808
|
+
for v in "${versions[@]}"; do
|
|
809
|
+
log "[$v] context_rehydrate/session_summary offline probe ..."
|
|
810
|
+
run_rehydrate_probe "$v"
|
|
811
|
+
log "[$v] context probe → ${RESULTS["$v:context-rehydrate"]}"
|
|
812
|
+
done
|
|
813
|
+
write_rehydrate_report "${versions[@]}"
|
|
814
|
+
for v in "${versions[@]}"; do
|
|
815
|
+
[ "${RESULTS["$v:context-rehydrate"]:-}" = "FAIL" ] && fail=$((fail + 1)) || true
|
|
816
|
+
done
|
|
817
|
+
if [ "$fail" -gt 0 ]; then
|
|
818
|
+
log "Context probe: $fail real FAIL(s)."
|
|
819
|
+
exit 1
|
|
820
|
+
fi
|
|
821
|
+
log "Context probe: no real failures (NOT_TESTED/AMBIENTAL is non-blocking)."
|
|
822
|
+
}
|
|
823
|
+
|
|
498
824
|
run_battery() { # versions...
|
|
499
825
|
local versions=("$@")
|
|
500
826
|
mkdir -p "$SANDBOX_ROOT"
|
|
@@ -551,6 +877,8 @@ while [ $# -gt 0 ]; do
|
|
|
551
877
|
--prepare) MODE_PREPARE=1 ;;
|
|
552
878
|
--reset) MODE_RESET=1 ;;
|
|
553
879
|
--prompts) MODE_PROMPTS=1 ;;
|
|
880
|
+
--cost) MODE_COST=1 ;;
|
|
881
|
+
--rehydrate) MODE_REHYDRATE=1 ;;
|
|
554
882
|
--run)
|
|
555
883
|
shift
|
|
556
884
|
case "${1:-}" in
|
|
@@ -569,7 +897,9 @@ if [ "$MODE_RESET" -eq 1 ]; then
|
|
|
569
897
|
exit 0
|
|
570
898
|
fi
|
|
571
899
|
|
|
572
|
-
if [ "$MODE_PREPARE" -eq 0 ] && [ -z "$RUN_VERSION" ]
|
|
900
|
+
if [ "$MODE_PREPARE" -eq 0 ] && [ -z "$RUN_VERSION" ] \
|
|
901
|
+
&& [ "$MODE_PROMPTS" -eq 0 ] && [ "$MODE_COST" -eq 0 ] \
|
|
902
|
+
&& [ "$MODE_REHYDRATE" -eq 0 ]; then
|
|
573
903
|
usage
|
|
574
904
|
fi
|
|
575
905
|
|
|
@@ -585,7 +915,30 @@ if [ -n "$RUN_VERSION" ]; then
|
|
|
585
915
|
sandbox_env
|
|
586
916
|
run_base "$RUN_VERSION"
|
|
587
917
|
fi
|
|
918
|
+
if [ "$MODE_COST" -eq 1 ]; then
|
|
919
|
+
sandbox_env
|
|
920
|
+
run_cost "$RUN_VERSION"
|
|
921
|
+
fi
|
|
922
|
+
if [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
923
|
+
sandbox_env
|
|
924
|
+
run_rehydrate "$RUN_VERSION"
|
|
925
|
+
fi
|
|
588
926
|
elif [ "$MODE_PROMPTS" -eq 1 ]; then
|
|
589
927
|
sandbox_env
|
|
590
928
|
run_battery v1 v2
|
|
929
|
+
if [ "$MODE_COST" -eq 1 ]; then
|
|
930
|
+
run_cost v1 v2
|
|
931
|
+
fi
|
|
932
|
+
if [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
933
|
+
run_rehydrate v1 v2
|
|
934
|
+
fi
|
|
935
|
+
elif [ "$MODE_COST" -eq 1 ]; then
|
|
936
|
+
sandbox_env
|
|
937
|
+
run_cost v1 v2
|
|
938
|
+
if [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
939
|
+
run_rehydrate v1 v2
|
|
940
|
+
fi
|
|
941
|
+
elif [ "$MODE_REHYDRATE" -eq 1 ]; then
|
|
942
|
+
sandbox_env
|
|
943
|
+
run_rehydrate v1 v2
|
|
591
944
|
fi
|
|
@@ -566,7 +566,7 @@ async def kv_delete_namespace(
|
|
|
566
566
|
# ── Context Checkpoint Tools ────────────────────────────────────────────────────
|
|
567
567
|
# Session-scoped context storage for deepwork checkpoints, phase state,
|
|
568
568
|
# tool call history, and reasoning chains. All entries use namespace
|
|
569
|
-
# "checkpoint:{slug}" with auto-TTL of 4 hours (session duration).
|
|
569
|
+
# "checkpoint:{slug}:{session}" with auto-TTL of 4 hours (session duration).
|
|
570
570
|
|
|
571
571
|
DEFAULT_CONTEXT_TTL: int = 14400 # 4 hours
|
|
572
572
|
|
|
@@ -1023,6 +1023,31 @@ def _load_checkpoint_for_rehydrate(
|
|
|
1023
1023
|
return None
|
|
1024
1024
|
|
|
1025
1025
|
|
|
1026
|
+
def _checkpoint_namespaces(
|
|
1027
|
+
conn: sqlite3.Connection, slug: str, session_id: str | None
|
|
1028
|
+
) -> list[str]:
|
|
1029
|
+
"""Resolve checkpoint namespaces while preserving session isolation.
|
|
1030
|
+
|
|
1031
|
+
``context_save`` always creates a session-qualified namespace, including
|
|
1032
|
+
when the caller omits ``session_id`` (it generates one and returns it).
|
|
1033
|
+
Runtime callers may not retain that return value after compaction, so an
|
|
1034
|
+
unqualified rehydrate/summary must discover the newest matching session.
|
|
1035
|
+
The prefix comparison is parameterized and avoids LIKE wildcard leakage.
|
|
1036
|
+
"""
|
|
1037
|
+
if session_id:
|
|
1038
|
+
return [f"checkpoint:{slug}:{session_id}"]
|
|
1039
|
+
prefix = f"checkpoint:{slug}:"
|
|
1040
|
+
rows = conn.execute(
|
|
1041
|
+
"SELECT namespace FROM kv_store "
|
|
1042
|
+
"WHERE substr(namespace, 1, ?) = ? "
|
|
1043
|
+
"AND (expires_at IS NULL OR datetime(expires_at) > datetime('now')) "
|
|
1044
|
+
"AND deleted_at IS NULL "
|
|
1045
|
+
"GROUP BY namespace ORDER BY MAX(updated_at) DESC LIMIT 20",
|
|
1046
|
+
(len(prefix), prefix),
|
|
1047
|
+
).fetchall()
|
|
1048
|
+
return [str(row[0]) for row in rows if row and row[0]]
|
|
1049
|
+
|
|
1050
|
+
|
|
1026
1051
|
def _refresh_heartbeat_ttl(conn: sqlite3.Connection, namespace: str) -> None:
|
|
1027
1052
|
"""Extend an unexpired heartbeat TTL; never shorten, never resurrect."""
|
|
1028
1053
|
row = conn.execute(
|
|
@@ -1055,7 +1080,8 @@ def _refresh_heartbeat_ttl(conn: sqlite3.Connection, namespace: str) -> None:
|
|
|
1055
1080
|
@mcp.tool(
|
|
1056
1081
|
name="context_rehydrate",
|
|
1057
1082
|
description="Rehydrate critical context after native compaction. "
|
|
1058
|
-
"Reads 'latest' + serialized 'tail' from
|
|
1083
|
+
"Reads 'latest' + serialized 'tail' from a session-qualified checkpoint "
|
|
1084
|
+
"namespace and rebuilds "
|
|
1059
1085
|
"goal/phase/delegation blocks deterministically (no LLM). Refreshes the "
|
|
1060
1086
|
"heartbeat TTL. Idempotent. Honors PANTHEON_COMPACTION=off.",
|
|
1061
1087
|
)
|
|
@@ -1068,14 +1094,21 @@ async def context_rehydrate(
|
|
|
1068
1094
|
if _compaction_disabled():
|
|
1069
1095
|
return None
|
|
1070
1096
|
conn = _db(scope)
|
|
1071
|
-
|
|
1072
|
-
checkpoint =
|
|
1097
|
+
namespaces = _checkpoint_namespaces(conn, slug, session_id)
|
|
1098
|
+
checkpoint = None
|
|
1099
|
+
selected_namespace = None
|
|
1100
|
+
for namespace in namespaces:
|
|
1101
|
+
checkpoint = _load_checkpoint_for_rehydrate(conn, namespace)
|
|
1102
|
+
if checkpoint is not None:
|
|
1103
|
+
selected_namespace = namespace
|
|
1104
|
+
break
|
|
1073
1105
|
if checkpoint is None:
|
|
1074
1106
|
return None
|
|
1075
1107
|
blocks = build_rehydration_blocks(checkpoint)
|
|
1076
1108
|
if blocks is None:
|
|
1077
1109
|
return None
|
|
1078
|
-
|
|
1110
|
+
if selected_namespace is not None:
|
|
1111
|
+
_refresh_heartbeat_ttl(conn, selected_namespace)
|
|
1079
1112
|
return blocks
|
|
1080
1113
|
|
|
1081
1114
|
|
|
@@ -1095,8 +1128,12 @@ async def context_session_summary(
|
|
|
1095
1128
|
if os.environ.get(SESSION_END_SUMMARY_ENV, "").lower() == "off":
|
|
1096
1129
|
return None
|
|
1097
1130
|
conn = _db(scope)
|
|
1098
|
-
|
|
1099
|
-
checkpoint =
|
|
1131
|
+
namespaces = _checkpoint_namespaces(conn, slug, session_id)
|
|
1132
|
+
checkpoint = None
|
|
1133
|
+
for namespace in namespaces:
|
|
1134
|
+
checkpoint = _load_checkpoint_for_rehydrate(conn, namespace)
|
|
1135
|
+
if checkpoint is not None:
|
|
1136
|
+
break
|
|
1100
1137
|
if checkpoint is None:
|
|
1101
1138
|
return None
|
|
1102
1139
|
return build_session_end_summary(checkpoint)
|