Files
workinf_Blender_Wasm/my-tools/wbv2_payload_budget.py
mes123456 f3e21c6b98
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
chore: checkpoint web Blender migration source, tools and docs
Accumulated uncommitted work: GHOST Web backend, WebGL/GPU web layer,
web workflow engine and protocol, tooling, docs and task records.
Large generated evidence, user-testing archives, build snapshots and
imported test assets remain untracked.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-10 11:18:01 +08:00

69 lines
7.7 KiB
Python

"""Bound runner-owned model input; keep omitted context locally, never erase scope."""
import json
MIN_BYTES, DEFAULT_BYTES, MAX_BYTES = 12 * 1024, 16 * 1024, 24 * 1024
def encoded(value):
return json.dumps(value, ensure_ascii=False, separators=(',', ':')).encode('utf-8')
def budget_state(state):
provider = state.get('provider', {})
recovering = provider.get('consecutiveFailures', 0) > 0 and provider.get('errorKind') in {'transport', 'payload_limit'}
budget = state.setdefault('modelPayload', {'limitBytes': MIN_BYTES if recovering else DEFAULT_BYTES, 'stableTurns': 0})
budget['limitBytes'] = max(MIN_BYTES, min(MAX_BYTES, int(budget.get('limitBytes', DEFAULT_BYTES))))
return budget
def update_budget(state, outcome):
budget = budget_state(state)
budget['stableTurns'] = budget.get('stableTurns', 0) + 1 if outcome == 'stable' else 0
if outcome == 'pressure':
budget['limitBytes'] = max(MIN_BYTES, budget['limitBytes'] // 2)
elif budget['stableTurns'] >= 3:
budget.update(limitBytes=min(MAX_BYTES, budget['limitBytes'] + 2048), stableTurns=0)
budget['lastOutcome'] = outcome
GUIDANCE = '''Continue one authorized Blender 5.2 -> Web Blender user-operation gap. Preserve task/parent/nextTask, all residuals and existing dirty source; no reset/clean/commit/push, second scheduler, control-file edits or deployment. NOT_RUN/NOT_CLAIMED: no tests, browser, syntax/type/context checks or evidence audits. Build only needed artifacts in the existing tree, -j8, no repeated unchanged builds.
Runner already supplied EXECUTION_QUEUE, task context and current parent; do not reread them. Use the latest handoff, exact nextSourcePaths and focused search-wbv2-batch-source; pass only Blender files with --source and Web/runtime files with --runtime. No inventories, full files or historical logs. Each source window <=30 lines: start with4-8 lines and narrow after truncation. Search results default to1KiB with384-byte match windows; refine the exact pattern/path instead of repeating oversized reads. Each edit <=2 files and <=10 changed lines including continuationNotes. Record breakpoint, completed facts, residual and next direct action after each batch.
CURRENT CONTEXT is already loaded. Read context.json only for an explicitly deferredField needed now; never reload supplied fields or prior worker logs. Respect unreleased foreground ownership. Preserve omitted scope by reference. Search syntax is node tools/web/search-wbv2-batch-source.mjs --task WBV2-P1424-001 --source <Blender-file> OR --runtime <Web-file> --pattern <exact-symbol> --max-hits 6; do not inspect the search tool itself.
Before reopening an older missing/unlocated claim, reconcile it with rootRepair.resultPath, the latest foreground handoff; read only its relevant short section. Delivered implemented-unverified facts supersede older claims, not residuals. Record that manifest and the concrete remaining edge in continuationNotes; if already reconciled and unchanged, resume the edge without rereading. Never repeat completed traces/builds merely for missing verification. INTEGRATE_PENDING retains priority.
Use original Blender/WASM callers and existing modules; OCCT is the sole geometry kernel, Three.js displays results only. Trace one immediate call chain in <=30-line windows within CURRENT CONTEXT.investigationBudget (readCommands / activeNonBuildSeconds); use eight reads / 120 seconds only if absent. Edit only a confirmed missing edge and return the final handoff. If unresolved, hand off the exact symbol/line and next bounded read. Preserve residuals; no JS simulation, stubs, duplicate implementations or edits merely to satisfy a timer. Never bypass external limits.
Honor priority: LOCATE_SOURCE only traces the exact boundary; IMPLEMENT_FAMILY finishes one operation; INTEGRATE_PENDING reuses a matching linked pair or incrementally builds web_engine, packages once with tools/web/build-main-desktop-candidate.py, reports candidate.json, then ends. Never package incomplete native inputs. An active integrationRetry means retain pending/ownership/old candidate and work independently. Generated artifacts, service uptime and reads are not functional completion.
If integrationRetry.active=false, its deadline has expired; retain the old failure as history and reconcile the named dependency before proceeding. Historical foreground-ownership prose alone does not establish a current owner. Honor any concrete live ownership restriction and name the actual blocking resource; never renew a wait solely because an expired retry object exists.
Write a brief current-cycle report and continuationNotes with module, workflow, native/WASM route, changed paths, exact breakpoint and residuals. Emit schema JSON only as the final response, never as repeated progress messages. Build fields must reflect actual commands; not_run has empty log/artifacts/blockers. Set batchReadyForIntegration only for fully wired source awaiting delivery. Completion flags stay false while any owned gap remains; efficiencyReview.inspected=false unless performed. Reference broader scope locally and end after final handoff.
Set delivery.stageId to CURRENT CONTEXT.stageId and nextSourcePaths to at most eight exact files; write the report to tests/golden/<task>/unattended-reports/cycle-<six-digit-cycle>.md. Keep UI labels, enablement, shortcuts, cancel/retry and native ownership aligned with Blender; classify actual missing edges separately from implemented-unverified routes. Full original guidance is preserved in prompt.source.txt; read only a needed paragraph, never reload the whole file.
'''
def prepare_submission(prompt, schema_bytes, directory, state):
budget = budget_state(state)
context = json.loads(prompt.partition('CURRENT CONTEXT: ')[2].split('\n', 1)[0])
context_path = directory / 'context.json'
context_path.write_bytes(encoded(context))
(directory / 'prompt.source.txt').write_text(prompt, encoding='utf-8')
view = dict(context, contextReference=str(context_path))
limit = budget['limitBytes']
instructions = GUIDANCE + f'Payload limit={limit} bytes including output schema; tool output soft budget={2 * limit} bytes. Request max_output_tokens<={limit // 32} per tool, redirect long output to local logs; after the soft budget hand off before more reads. Final JSON target<=4096 bytes; preserve required paths and ownership, reference broader residuals locally.\n'
def render():
return instructions + 'CURRENT CONTEXT: ' + encoded(view).decode('utf-8') + '\n'
required = {'task', 'parent', 'cycle', 'stageId', 'focus', 'phase', 'priority', 'investigationBudget', 'assignment', 'continuationNotes', 'nextSourcePaths', 'interrupted', 'handoff', 'integrationRetry', 'recoveryDirection'}
for key in sorted(context, key=lambda name: (name in required, -len(encoded(context[name])))):
if len(render().encode('utf-8')) + schema_bytes <= limit:
break
if key == 'rootRepair':
continue # Keep the small latest-delivery reference ahead of stale handoffs.
if len(encoded(context[key])) > len(encoded({'deferredField': key})):
view[key] = {'deferredField': key}
fitted = render()
prompt_bytes = len(fitted.encode('utf-8'))
budget.update(promptBytes=prompt_bytes, schemaBytes=schema_bytes, submittedBytes=prompt_bytes + schema_bytes,
toolOutputTokenLimit=limit // 48,
toolOutputSoftBytes=limit, toolOutputHardBytes=2 * limit,
deferredFields=[key for key in context if view[key] != context[key]],
measuredScope='runner prompt+schema UTF-8 only; CLI instructions/tool definitions/history excluded')
(directory / 'payload.json').write_bytes(encoded(dict(budget, admitted=budget['submittedBytes'] <= limit)))
return fitted if budget['submittedBytes'] <= limit else None