Commit Graph

17 Commits

Author SHA1 Message Date
Mao Weiming 1268b67223 fix(company): stop Report #N storm and spill large Cursor prompts to files
Cursor-agent puts prompts on argv, so oversized company/report handoffs hit
OS ARG_MAX, crash the card as FAILED, and reconcile kept minting new Report
attempts forever. Spill large Cursor prompts to a workspace file and hold the
report chain after consecutive failures.
2026-07-31 19:47:41 +08:00
LZH-YS1998 6c5acbf10e fix(company): make delivery-review self-evolution survive the hardened runtime
Approving (or sending feedback on) the delivery review card runs employee
self-evolution as company work items, but the finalizer required the
turn's FINAL chat text to be bare JSON. The hardened native runtime
appends a verification status line to every final text and the manager
dispatch guard displaces the final message with a justification, so every
reflection died with invalid_self_evolution_json even when the model
produced valid patches on all three attempts, and the FAILED items
polluted the delivered run's terminal verdict.

- Add a submit_self_evolution_patches tool as the authoritative result
  channel (exposed only on self-evolution work items, approval-exempt).
  The text parser becomes a fallback that scans fenced blocks and
  balanced JSON objects, and retry feedback now carries the concrete
  parse failure plus the tool instruction.
- Settle abandoned reflections as CANCELLED (self_evolution_abandoned)
  and exclude kind=self_evolution from run-lifecycle settlement so an
  opt-in reflection can never dirty a delivered run.
- Claim the review card with a consuming CAS before spawning (duplicate
  approve/feedback replies answer idempotently instead of re-entering),
  bound the reflection run with a 40-minute deadline that cancels
  leftover self-evolution items, and hand the claim back to pending when
  the consumed run crashes mid-flight.

Verified live on real runs: the unfixed code failed the approve path in
90s with zero patches recorded; with the fix both the approve and the
feedback paths recorded patches end-to-end (CEO->COO and CEO->CMO
cascades, zero retries, human feedback reflected in patch content).
tests/: 1924 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 00:36:53 +08:00
LZH-YS1998 d14f3920e0 fix(company): stop/resume identity truth, failure-path closure, quota park
OBS-11 — stop/resume killed pure-native runs over a phantom external pin.
Role templates' preferred_external_agent leaked into execution identity even
when the user requested native and execution actually ran native; on resume
the availability gate trusted the pin and failed every non-terminal item.
Root fixes across the whole chain:
- Staffing card per-role defaults are now the RESOLVED backend (explicit
  session agent choice > runnable template preference > native), never a
  hardcoded external default; seat enrichment and the dispatch selector's
  locked branch downgrade provably unavailable externals to native and
  record the wish in execution_agent_unavailable.
- The resume availability gate fails closed only when a resumable external
  session actually exists; a bare pin heals to native (snapshot AND task
  durable identity) and the run resumes — mirroring dispatch fallback.
- Suspend-checkpoint replies: force_resume (chat/headless spelling) is
  recognized alongside ui_force_resume, and bare continuation tokens
  (English and Chinese spellings) take the plain-resume path instead of
  being routed to the final decider as content, which reopened the
  already-approved intake card.

OBS-5 — failed runs never closed and dropped new input. The dispatcher's
convergence exit now settles terminally-failed runs (status=failed,
lifecycle=closed_failed, run_failure metadata) and emits a
company_run_failure_review card whose replies never swallow messages:
dismiss acknowledges, content falls through so normal routing starts a
fresh run. _maybe_resume_existing_company_runtime no longer re-executes a
terminally-failed tree: control replies get an honest closed status,
content-bearing input starts a new run.

OBS-6 — provider quota exhaustion terminally failed work items. Rate-limit
rejections are classified (LLMProvider.is_rate_limit_error, covering
status codes, exception types, and English/Chinese provider error text),
the agent runtime raises typed ProviderQuotaExhaustedError instead of
burning conversation-feedback retries, and the company dispatcher parks:
the item returns to READY (attempt interrupted, no terminal failure), the
member session idles, and claiming backs off exponentially (60s doubling
to a 900s cap; a quiet 30min resets the streak) before resuming
automatically.

Verified end-to-end on the real minimax-m3 campaign: same goal, same 300s
stop point, same run shape that previously killed the whole tree within
90s now resumes cleanly and completes with all items approved; staffing
defaults native for all 11 roles.

Tests: test_stop_resume_native_pin (10), test_run_failure_settlement (6),
test_provider_quota_park (9); attempt-ledger, recruiter, and
suspend-resume suites updated to the new contracts (their old assertions
pinned the defective behaviors).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 17:03:40 +08:00
LZH-YS1998 14ee8806de fix(engine): single live dispatcher per run + unified approval decision channel
OBS-4: checkpoint answers for a run whose dispatcher is still live no longer
re-enter _execute_company_mode (re-entry reset live claim registries and the
attempt ledger stamped in-flight cards interrupted until the streak limit
killed them). The executor keeps a _live_run_dispatchers refcount; task and
peer checkpoint resumes deliver the input in place and wake the dispatcher.
Runs without a live dispatcher keep the original re-entry resume semantics.

OBS-7: approval decisions expressed through the chat/checkpoint route now
reach the approval engine instead of being parsed as plain task input
(which _ask_user treated as deny, re-escalating until the card died).
normalize_escalation_reply maps decision tokens/synonyms (never silently
denies free text), escalation_context_for_blocked_tool rebuilds the
allowlist context from pause_request.permission_context, and
_resume_task_checkpoint applies the grant via
apply_deferred_escalation_decision — the same engine path as the UI card.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 10:55:55 +08:00
LZH-YS1998 2df564d9e9 Merge PR #9: harden company resume, external sessions, and Office UI i18n
Merges xiaodong-l's hardening work: company suspend-checkpoint resume
reconciliation, external session token lifecycle fixes, Windows launch
shims, codex shell_environment_policy forwarding, Office UI i18n
(en/zh-CN), and two org presets. frontend_dist is rebuilt from the
merged sources in this commit so the #11 runtime-status fixes and the
i18n bundle coexist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

# Conflicts:
#	opc/plugins/office_ui/frontend_dist/assets/index-BgyI65M_.js
#	opc/plugins/office_ui/frontend_dist/index.html
2026-07-21 15:34:28 +08:00
LZH-YS1998 9aed328d02 fix(company): add dispatch attempt ledger to brake infinite re-dispatch loops (#10)
Work items whose execution kept dying without a durable verdict (crash
mid-dispatch, kill -9, cancel-before-harvest) were re-dispatched forever:
every exit path was responsible for remembering to write a terminal
phase, and any path that forgot left the card RUNNING and eligible again.

Replace that with structural accounting:

- claim CAS opens an attempt in the same UPDATE (attempt_seq+1,
  attempt_settled=false) so no dispatch can start unaccounted (store.py)
- transition_work_item becomes the settlement authority: every
  non-RUNNING transition settles the open attempt in the same write;
  crashed/interrupted outcomes accumulate streaks, clean outcomes reset
  them; claim release folds into the same write; settlement still lands
  when the phase write loses a race (work_item_transition.py)
- dispatcher refuses cards over the streak limits (crash>=3,
  interrupted>=5) in both is_dispatchable and _work_item_is_runnable,
  and a per-tick reconcile pass back-fills dead attempts as interrupted
  and terminalizes over-limit cards to FAILED with a visible
  blocked_reason (dispatch_hold quarantine if even that write fails)
  (phase.py, company_mode.py)
- crash exits now settle: cancellation unwind harvests coroutines that
  died on a real exception before discarding them, the crashed-item
  handler releases the claim and settles as crashed with a quarantine
  fallback, and the timeout path settles as crashed (company_mode.py)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 11:18:12 +08:00
小东 cb6b8ed6e1 feat: harden company resume, external sessions, and Office UI i18n
Improve suspend/resume identity continuity and external broker session handling, add Office UI internationalization with rebuilt assets, and expand company org configs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-16 09:20:40 +08:00
LZH-YS1998 297295a4aa fix: preserve company resume control and agent identity 2026-07-14 16:59:24 +08:00
LZH-YS1998 b8202bbe9e fix: unify company runtime recovery lifecycle 2026-07-14 14:35:43 +08:00
LZH-YS1998 5e02364eb4 fix(company): make delegation review lifecycle durable 2026-07-14 10:52:22 +08:00
LZH-YS1998 4e7aa75ba5 fix(company): stop failed children from wedging the tree and soften the dispatch guard
Root-cause fix for the project-4444 class of deadlocks: any FAILED/
CANCELLED work item with downstream dependents used to block its whole
tree forever, because the advancement gate required all dependencies to
be APPROVED and nothing ever propagated or triaged failures.

Settlement mechanism (work_item_transition.py):
- compute doomed set (FAILED/CANCELLED seeds contagious through hard
  deps); settlement-released cards are treated as alive
- three-way advancement gate: all-approved (unchanged) / settled-with-
  failures releases the nearest decision-capable card (manager parent ->
  failure-triage synthesis turn, rollup delivery/aggregate -> READY)
  with an atomic dependency_settlement stamp; released cards never
  oscillate back
- claim/park/resume/dispatcher-tick all honor the stamp: runnable gates
  admit settled failed+stuck deps, parking excludes settled deps and
  re-arms triage when a failure raced the park, engine resume no longer
  re-locks released cards, the dispatcher tick releases rollup cards
  created after the failure
- settlement cascade: once the settled card is APPROVED, stuck children
  the manager did not rebuild are cancelled (transitive closure over
  stamped stuck seeds, retried until every cancel lands)
- info-class deps never block settlement; adaptive runnable gate now
  shares DEPENDENCY_CLASS_DEFAULT with the release gates

Dispatch guard (company_mode.py):
- NO_DELEGATION_JUSTIFICATION parsing tolerates markdown decoration
  (bold/lists/quotes/full-width colon) and rejects placeholder echoes
  across all artifact/metadata/content channels
- retries exhausted no longer FAILs the work item: dispatch is a soft
  constraint, so the turn output is accepted as normal completion and
  annotated via manager_dispatch_guard_unresolved; the reminder loop is
  unchanged, and the mutation flag is now reset per turn so one past
  delegation can never mute future reminders
- manager board context now surfaces failed/cancelled children with
  their preserved output and pending-cancellation stuck list so the
  triage turn can rebuild, accept partial results, or escalate

Self-produced delegation output goes through review (persisted fact,
single predicate):
- the DONE transition classifies what a dispatch/intake/plan turn
  actually delivered from store ground truth (live children => delegated,
  none => self_produced) and persists turn_output_kind/-source on the
  WorkItem
- is_manager_reviewable_turn honors the persisted marker, so the DONE
  routing, report spawn, report completion and recovery scans all read
  the same fact — this closes a pre-existing hole where
  NO_DELEGATION_JUSTIFICATION output auto-approved with no review at all
- escalation requires a real agent manager above; top seats reporting to
  the human owner keep auto-approve (covered by final delivery's human
  acceptance) instead of minting unclaimable review cards
- dispatcher tick reconciles reviewable cards stuck in
  AWAITING_MANAGER_REVIEW with no live report/review card by rebuilding
  the report card idempotently (legacy DBs, crash windows)

Verified: 4444 tasks.db replay unwedges end to end; real-store
report->review chain exercised without lifecycle mocks (mutation check
confirms the tests bite); full suite failure set identical to a
same-session HEAD baseline run (all remaining failures pre-existing or
environment flakes reproduced at HEAD).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 20:19:09 +08:00
LZH-YS1998 e3bed49811 perf(office-ui): stop per-token full-tree renders, sleep hidden Phaser loop, cut broadcast churn
Company-mode UIs became unusably slow once work items and transcripts
grew. Three presentation-layer fixes, none touching work progression:

- App.tsx: buffer assistant_delta/thinking_delta store writes per task
  and flush every 80ms instead of once per token; any non-delta event
  for the same task flushes first so draft/clearDraft ordering is
  byte-identical. The unconditional per-event setUiTick (whole-app
  re-render per websocket event) is now a 300ms trailing throttle.
- PhaserGame: display:none does not stop requestAnimationFrame, so the
  office scene kept burning CPU on every other page. The loop now
  sleeps when the office page is hidden and wakes (with a parent-bounds
  refresh) on return; bridge writes stay synchronous so no state is lost.
- Kanban collab_sync debounce 0.2s -> 1.5s: the broadcaster is a
  trailing coalescer, so the final board state still always ships; each
  fire is a full-project snapshot build, which at 5/s dominated backend
  CPU on large projects. CommsPanel poll 8s -> 30s (comms_state_dirty
  push already drives freshness) and its interval no longer pins a
  stale onRefresh closure.

Verified: tsc + vite build, App.test.tsx / workItemSessions structural
tests, backend suites (company_review_flow incl. debounce push test,
kanban_push_runtime, actor_runtime_company_mode, task_mode_contract,
work_item_transition — 119 green), and canvas_smoke e2e against a real
server with zero console errors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 16:36:39 +08:00
LZH-YS1998 5aa57e69ee fix: release comms-blocking parks when replies arrive and give every role file authoring tools
Project 3333 forensics: env_engineer sent a blocking question to the CTO,
got a full reply 96s later, and still deadlocked the whole run — the
park half (`_park_for_blocking_comms`) had no wired consumer, so
WAITING_FOR_PEER work items could never be released.

Unpark path (root fix):
- The dispatcher loop now calls `_try_unpark_blocking_comms` each tick
  for parked, non-in-flight tasks; blocking replies land as durable
  inbox files, so the check is read-only until all replies are present.
- `_try_unpark_blocking_comms` accepts orphaned waits (peer_wait
  stripped by the legacy resolver while the work item stayed parked)
  and falls back to the park predicate itself: an empty unresolved
  blocking outbox releases the task, anything pending keeps it parked.
- `resolve_task_peer_wait` no longer touches comms_blocking waits (it
  flipped task.status without the work-item phase and stripped the
  peer_wait evidence); `_resume_peer_checkpoint` re-enters the company
  runtime for comms/orphaned waits and lets the dispatcher converge.

File tools (defaults changed at their declaration sites, honoring the
"empty tools = everything, explicit list = exactly that" contract):
- corporate builtin groups gain file_write/file_edit for coordination,
  QA, and data-acquisition roles.
- all shipped org YAML role tool lists gain the missing
  file_write/file_edit entries.
- coordination turn modes no longer strip file_write/file_edit at
  runtime — in-context content (briefs, matrices) must be persistable
  instead of getting trapped in blocking DM hand-offs.

Also includes the pending office_ui ws_handler change from the working
tree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 21:06:39 +08:00
LZH-YS1998 447516d93c fix: converge approval park/resume through the work-item state machine
Four coordinated fixes for company runs permanently stalling around
tool-approval parks (project 1111 forensics + live reproduction):

- company executor dispatch loop now exits convergently when nothing is
  in flight and every remaining task waits on a human: immediate parked
  exit when all waiters have pending checkpoints, bounded stall ticks
  otherwise. Previously it polled sleep(5) forever, hanging the turn
  (observed 7.5h), never answering the user, and holding claims that
  blocked any later rescue turn.
- _resume_task_checkpoint routes work-item runtime tasks through the
  delegation state machine: release the human wait via the legal
  AWAITING_HUMAN -> READY recovery exit, clear stale claims, and hand
  the item back to the dispatcher (runtime-snapshot fallback when the
  checkpoint payload lacks a plan) instead of a detached single-agent
  re-run that never advances the work item phase.
- startup recovery reverse self-heal: an awaiting_human task whose park
  checkpoint was already resolved (human answered, resume cut off before
  the phase write) is reopened for dispatch instead of being preserved
  as a wait nobody can end. Runs before the metadata-plan gate since
  modern runs no longer carry the plan in task metadata.
- pause checkpoints record execution_mode from the durable
  work_item_runtime marker instead of volatile task metadata, which
  degraded to task_mode after a first resume and misrouted the next one.

Validated end-to-end on a live native-agent minimal-org run
(park -> approve -> re-park -> approve -> complete -> deliver, plus
synthesized crash-between-resolve-and-phase-write healed on restart).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 10:52:02 +08:00
LZH-YS1998 b4d28aefeb fix: stop misreading per-work-item spec as run-level company plan
Every completed company session's follow-up was answered with the canned
"Legacy company runtime run ... read-only" text (project 000, 2026-07-07).
Root cause: snapshot loaders read task.metadata work_item_runtime_plan as a
serialized run-level CompanyWorkItemRuntimePlan, but work-item tasks persist a
per-item assignment spec (projection_id/turn_type/summary/deliverables/...)
under that key. from_dict on the wrong shape silently yields an empty plan
(no projections, empty metadata), _runtime_uses_multi_team_org returns False,
and the resume path falls through to the legacy read-only branch.

Add is_serialized_company_work_item_runtime_plan (a run-level plan always
serializes with projections + runtime_model; a spec always carries
projection_id) and route all full-plan metadata reads through
serialized_company_plan_from_metadata, which skips wrong-shaped candidates so
the loaders fall back to the sample-metadata-constructed plan instead of an
empty one. Fixes existing DBs read-side; no data migration.

Verified: old path on the 000 shape classifies multi_team_org=False, new path
True; regression tests cover shape discrimination, snapshot classification,
and the follow-up never reporting legacy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 22:33:39 +08:00
LZH-YS1998 08e48c2f9c fix(logging): replace stdlib-style exc_info kwargs with loguru opt(exception=)
Loguru has no exc_info kwarg: extra kwargs are str.format() arguments, so
logger.error(f"...{e}", exc_info=True) forces .format() on the rendered
message — any error text containing braces (e.g. a JSON error body) raises
KeyError FROM the log call itself, escaping the surrounding except block and
killing the caller (observed: whole agent turns dying in benchmark runs).
The intended traceback was also never logged, since exc_info is not a loguru
feature.

Batch fix of all 143 sites across 11 files:
  logger.X(msg, exc_info=True) -> logger.opt(exception=True).X(msg)
  (one exc_info=exc site -> opt(exception=exc))
Messages are byte-identical; with the kwarg gone loguru never calls
.format(), so brace-containing f-string messages are inert.

Verified: AST post-conditions per file, py_compile, import smoke of all
modules, behavioral equivalence of the 3 patterns, full unit suite (1549
passed) with a failure set identical to the pristine tree (22 pre-existing,
zero regressions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Also add pixel-agents to the README acknowledgements.
2026-07-03 20:07:37 +08:00
LZH-YS1998 d78931979d Initial commit 2026-07-01 17:56:31 +08:00