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>
This commit is contained in:
@@ -70,6 +70,8 @@ roles:
|
|||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
- shell_exec
|
- shell_exec
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- Focus on technical feasibility, architecture quality, and engineering best practices.
|
- Focus on technical feasibility, architecture quality, and engineering best practices.
|
||||||
@@ -113,6 +115,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- Optimize for audience fit, brand consistency, and content quality.
|
- Optimize for audience fit, brand consistency, and content quality.
|
||||||
@@ -157,6 +161,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- Ensure operational efficiency, process compliance, and delivery quality.
|
- Ensure operational efficiency, process compliance, and delivery quality.
|
||||||
@@ -205,6 +211,7 @@ roles:
|
|||||||
- browser_select_option
|
- browser_select_option
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
- browser_close
|
- browser_close
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: claude_code
|
preferred_external_agent: claude_code
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- 'Run data acquisition in four phases: Discover, Verify, Prepare, Report.'
|
- 'Run data acquisition in four phases: Discover, Verify, Prepare, Report.'
|
||||||
@@ -440,6 +447,7 @@ roles:
|
|||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_select_option
|
- browser_select_option
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- Test rigorously. Reject unclear or unsafe outputs.
|
- Test rigorously. Reject unclear or unsafe outputs.
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: codex
|
preferred_external_agent: codex
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Studio Director. You are the owner-facing final decision role for
|
- You are the Studio Director. You are the owner-facing final decision role for
|
||||||
@@ -79,6 +81,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: claude_code
|
preferred_external_agent: claude_code
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Game Designer. Turn the user's request into a buildable gameplay brief
|
- You are the Game Designer. Turn the user's request into a buildable gameplay brief
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: claude_code
|
preferred_external_agent: claude_code
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Chief Analyst — the owner-facing final decision role for a lean research
|
- You are the Chief Analyst — the owner-facing final decision role for a lean research
|
||||||
@@ -81,6 +83,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: claude_code
|
preferred_external_agent: claude_code
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Researcher. Your job is to conduct thorough, evidence-based research
|
- You are the Researcher. Your job is to conduct thorough, evidence-based research
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- 'You are the Managing Partner. Defines the investment mandate, target stage, sector
|
- 'You are the Managing Partner. Defines the investment mandate, target stage, sector
|
||||||
@@ -83,6 +85,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- 'You are the Investment Director. Translates the user request into an investment
|
- 'You are the Investment Director. Translates the user request into an investment
|
||||||
@@ -137,6 +141,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Sector Analyst. Evaluates whether the target sector can compound over
|
- You are the Sector Analyst. Evaluates whether the target sector can compound over
|
||||||
@@ -181,6 +187,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Market Researcher. Quantifies TAM/SAM/SOM, buyer budgets, growth rates,
|
- You are the Market Researcher. Quantifies TAM/SAM/SOM, buyer budgets, growth rates,
|
||||||
@@ -226,6 +234,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Startup Scout. Builds a broad candidate pool with founding date, headquarters,
|
- You are the Startup Scout. Builds a broad candidate pool with founding date, headquarters,
|
||||||
@@ -274,6 +284,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Competitive Analyst. Maps incumbents, startup competitors, substitute
|
- You are the Competitive Analyst. Maps incumbents, startup competitors, substitute
|
||||||
@@ -318,6 +330,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the News & Signal Analyst. Tracks recent market signals, customer wins,
|
- You are the News & Signal Analyst. Tracks recent market signals, customer wins,
|
||||||
@@ -360,6 +374,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- 'You are the Due Diligence Lead. Turns the shortlist into a diligence plan, coordinates
|
- 'You are the Due Diligence Lead. Turns the shortlist into a diligence plan, coordinates
|
||||||
@@ -460,6 +476,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: claude_code
|
preferred_external_agent: claude_code
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Business DD Analyst. Evaluates target customers, sales motion, pricing
|
- You are the Business DD Analyst. Evaluates target customers, sales motion, pricing
|
||||||
@@ -552,6 +570,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Risk & Legal Analyst. Finds privacy, open-source license, supply-chain,
|
- You are the Risk & Legal Analyst. Finds privacy, open-source license, supply-chain,
|
||||||
@@ -595,6 +615,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- 'You are the Investment Committee Chair. Runs structured bull-case and bear-case
|
- 'You are the Investment Committee Chair. Runs structured bull-case and bear-case
|
||||||
@@ -644,6 +666,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Bull Case Reviewer. Builds the strongest evidence-backed case for
|
- You are the Bull Case Reviewer. Builds the strongest evidence-backed case for
|
||||||
@@ -688,6 +712,8 @@ roles:
|
|||||||
- browser_wait_for
|
- browser_wait_for
|
||||||
- browser_scroll
|
- browser_scroll
|
||||||
- browser_take_screenshot
|
- browser_take_screenshot
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Bear Case Reviewer. Builds the strongest evidence-backed case against
|
- You are the Bear Case Reviewer. Builds the strongest evidence-backed case against
|
||||||
@@ -726,6 +752,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- You are the Final Decision Reviewer. Reconciles bull and bear cases, ranks companies,
|
- You are the Final Decision Reviewer. Reconciles bull and bear cases, ranks companies,
|
||||||
@@ -768,6 +796,8 @@ roles:
|
|||||||
- todo_read
|
- todo_read
|
||||||
- web_search
|
- web_search
|
||||||
- web_fetch
|
- web_fetch
|
||||||
|
- file_write
|
||||||
|
- file_edit
|
||||||
preferred_external_agent: null
|
preferred_external_agent: null
|
||||||
prompt_refs:
|
prompt_refs:
|
||||||
- 'You are the Report & Delivery Lead. Owns final deliverables: investment memo,
|
- 'You are the Report & Delivery Lead. Owns final deliverables: investment memo,
|
||||||
|
|||||||
+9
-1
@@ -9953,8 +9953,16 @@ class OPCEngine:
|
|||||||
else:
|
else:
|
||||||
resolved = False
|
resolved = False
|
||||||
wait = dict(task.metadata.get("peer_wait", {}))
|
wait = dict(task.metadata.get("peer_wait", {}))
|
||||||
if wait.get("kind") == "meeting":
|
wait_kind = str(wait.get("kind") or "")
|
||||||
|
if wait_kind == "meeting":
|
||||||
resolved = await self.communication.resolve_task_meeting_wait(task)
|
resolved = await self.communication.resolve_task_meeting_wait(task)
|
||||||
|
elif wait_kind == "comms_blocking" or not wait:
|
||||||
|
# Comms-blocking (and orphaned) waits resolve from durable
|
||||||
|
# inbox files owned by the company dispatcher's per-tick
|
||||||
|
# unpark. Re-enter the runtime and let it converge: it
|
||||||
|
# either releases the park or re-parks and re-checkpoints
|
||||||
|
# consistently.
|
||||||
|
resolved = True
|
||||||
else:
|
else:
|
||||||
resolved = await self.communication.resolve_task_peer_wait(task)
|
resolved = await self.communication.resolve_task_peer_wait(task)
|
||||||
if not resolved:
|
if not resolved:
|
||||||
|
|||||||
@@ -1989,6 +1989,11 @@ class CommunicationManager:
|
|||||||
wait = dict(task.metadata.get("peer_wait", {}))
|
wait = dict(task.metadata.get("peer_wait", {}))
|
||||||
if not wait:
|
if not wait:
|
||||||
return False
|
return False
|
||||||
|
if str(wait.get("kind") or "") == "comms_blocking":
|
||||||
|
# File-comms blocking waits are owned by the company
|
||||||
|
# dispatcher's per-tick unpark; resolving them here would flip
|
||||||
|
# task.status without the work-item phase and strand the run.
|
||||||
|
return False
|
||||||
if wait.get("kind") != "meeting":
|
if wait.get("kind") != "meeting":
|
||||||
msg_id = wait.get("message_id")
|
msg_id = wait.get("message_id")
|
||||||
reply = await self.store.get_latest_reply(msg_id) if msg_id else None
|
reply = await self.store.get_latest_reply(msg_id) if msg_id else None
|
||||||
|
|||||||
@@ -4236,6 +4236,21 @@ class CompanyWorkItemExecutor:
|
|||||||
)
|
)
|
||||||
] or list(self._active_tasks)
|
] or list(self._active_tasks)
|
||||||
self._active_tasks = tasks
|
self._active_tasks = tasks
|
||||||
|
# Consumer half of `_park_for_blocking_comms`: blocking
|
||||||
|
# replies arrive as durable inbox files, so each tick checks
|
||||||
|
# parked tasks and releases the ones whose replies are all
|
||||||
|
# present. In-flight tasks are skipped — their coroutine
|
||||||
|
# still owns the Task object and a late save_task would
|
||||||
|
# clobber the transition.
|
||||||
|
in_flight_task_ids = {
|
||||||
|
claimed.id for _member, claimed in active_work_item_tasks.values()
|
||||||
|
}
|
||||||
|
for parked in tasks:
|
||||||
|
if (
|
||||||
|
parked.status == TaskStatus.AWAITING_PEER
|
||||||
|
and parked.id not in in_flight_task_ids
|
||||||
|
):
|
||||||
|
await self._try_unpark_blocking_comms(parked)
|
||||||
await self.runtime.refresh_inbox_state(tasks)
|
await self.runtime.refresh_inbox_state(tasks)
|
||||||
work_items = await self._load_delegation_work_items(tasks)
|
work_items = await self._load_delegation_work_items(tasks)
|
||||||
work_items = await self._refresh_ready_work_items(work_items, tasks=tasks)
|
work_items = await self._refresh_ready_work_items(work_items, tasks=tasks)
|
||||||
@@ -9225,7 +9240,13 @@ class CompanyWorkItemExecutor:
|
|||||||
if task.status != TaskStatus.AWAITING_PEER:
|
if task.status != TaskStatus.AWAITING_PEER:
|
||||||
return False
|
return False
|
||||||
peer_wait = dict(task.metadata.get("peer_wait", {}) or {})
|
peer_wait = dict(task.metadata.get("peer_wait", {}) or {})
|
||||||
if str(peer_wait.get("kind") or "") != "comms_blocking":
|
wait_kind = str(peer_wait.get("kind") or "")
|
||||||
|
# An empty kind is an orphaned wait (e.g. a legacy resolver popped
|
||||||
|
# `peer_wait` while the work item stayed WAITING_FOR_PEER); those
|
||||||
|
# are recoverable from the durable comms state below. Waits with a
|
||||||
|
# different explicit kind (meeting, message-id) have their own
|
||||||
|
# resolvers.
|
||||||
|
if wait_kind and wait_kind != "comms_blocking":
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
from opc.layer2_organization import comms as _comms
|
from opc.layer2_organization import comms as _comms
|
||||||
@@ -9240,7 +9261,11 @@ class CompanyWorkItemExecutor:
|
|||||||
return False
|
return False
|
||||||
blocking_ids = list(peer_wait.get("blocking_message_ids", []) or [])
|
blocking_ids = list(peer_wait.get("blocking_message_ids", []) or [])
|
||||||
if not blocking_ids:
|
if not blocking_ids:
|
||||||
# Nothing to wait for — defensively unpark.
|
# No recorded ids (orphaned or empty wait): fall back to the
|
||||||
|
# park predicate itself — any unanswered blocking outbox
|
||||||
|
# message keeps the task parked, none means release.
|
||||||
|
if _comms.find_unresolved_blocking_outbox(layout, role_id):
|
||||||
|
return False
|
||||||
task.metadata = dict(task.metadata)
|
task.metadata = dict(task.metadata)
|
||||||
task.metadata.pop("peer_wait", None)
|
task.metadata.pop("peer_wait", None)
|
||||||
await transition_work_item_from_task(
|
await transition_work_item_from_task(
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ _BROWSER_EXECUTION_TOOLS = [
|
|||||||
|
|
||||||
_CORPORATE_COORDINATION_TOOLS = [
|
_CORPORATE_COORDINATION_TOOLS = [
|
||||||
"file_read",
|
"file_read",
|
||||||
|
"file_write",
|
||||||
|
"file_edit",
|
||||||
"file_search",
|
"file_search",
|
||||||
"list_dir",
|
"list_dir",
|
||||||
"todo_write",
|
"todo_write",
|
||||||
@@ -49,8 +51,6 @@ _CORPORATE_COORDINATION_TOOLS = [
|
|||||||
_CORPORATE_BOOTSTRAP_TOOLS = [
|
_CORPORATE_BOOTSTRAP_TOOLS = [
|
||||||
*_CORPORATE_COORDINATION_TOOLS,
|
*_CORPORATE_COORDINATION_TOOLS,
|
||||||
"shell_exec",
|
"shell_exec",
|
||||||
"file_write",
|
|
||||||
"file_edit",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
_CORPORATE_WEB_COORDINATION_TOOLS = [
|
_CORPORATE_WEB_COORDINATION_TOOLS = [
|
||||||
@@ -76,6 +76,7 @@ _CORPORATE_EXECUTION_TOOLS = [
|
|||||||
_CORPORATE_QA_TOOLS = [
|
_CORPORATE_QA_TOOLS = [
|
||||||
"file_read",
|
"file_read",
|
||||||
"file_write",
|
"file_write",
|
||||||
|
"file_edit",
|
||||||
"file_search",
|
"file_search",
|
||||||
"list_dir",
|
"list_dir",
|
||||||
"shell_exec",
|
"shell_exec",
|
||||||
@@ -105,6 +106,7 @@ _CORPORATE_DATA_ACQUISITION_TOOLS = [
|
|||||||
"shell_exec",
|
"shell_exec",
|
||||||
"file_read",
|
"file_read",
|
||||||
"file_write",
|
"file_write",
|
||||||
|
"file_edit",
|
||||||
"file_search",
|
"file_search",
|
||||||
"list_dir",
|
"list_dir",
|
||||||
"web_search",
|
"web_search",
|
||||||
|
|||||||
@@ -121,10 +121,11 @@ _TASK_MODE_ORCHESTRATION = """
|
|||||||
work or context isolation when that improves the result.
|
work or context isolation when that improves the result.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# file_write / file_edit are deliberately NOT blocked: coordination turns
|
||||||
|
# produce in-context content (briefs, matrices, review notes) that must be
|
||||||
|
# persistable to the workspace, or it gets trapped in blocking DM hand-offs.
|
||||||
_MULTI_TEAM_COORDINATION_NATIVE_TOOL_BLOCKLIST = {
|
_MULTI_TEAM_COORDINATION_NATIVE_TOOL_BLOCKLIST = {
|
||||||
"shell_exec",
|
"shell_exec",
|
||||||
"file_write",
|
|
||||||
"file_edit",
|
|
||||||
"apply_patch",
|
"apply_patch",
|
||||||
"python_exec",
|
"python_exec",
|
||||||
"web_search",
|
"web_search",
|
||||||
|
|||||||
@@ -8476,6 +8476,16 @@ class WSHandler:
|
|||||||
for item in list(pause_request.get("required_fields", []) or [])
|
for item in list(pause_request.get("required_fields", []) or [])
|
||||||
if str(item).strip()
|
if str(item).strip()
|
||||||
]
|
]
|
||||||
|
resume_hint = str(pause_request.get("resume_hint", "") or "").strip()
|
||||||
|
if not resume_hint and "blocked by autonomy policy" in f"{prompt} {summary}".lower():
|
||||||
|
# This park came from a tool-approval timeout. The approval card
|
||||||
|
# posted earlier stays pending and clickable indefinitely, so point
|
||||||
|
# the user at it instead of leaving typed input as the only path.
|
||||||
|
resume_hint = (
|
||||||
|
"Tip: the tool-approval card above is still active — choose an option "
|
||||||
|
"there (e.g. Approve) to grant the permission and resume this task "
|
||||||
|
"automatically. Reply here only to give different instructions."
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"checkpoint_type": "task_user_input",
|
"checkpoint_type": "task_user_input",
|
||||||
@@ -8489,7 +8499,7 @@ class WSHandler:
|
|||||||
"input_questions": input_questions,
|
"input_questions": input_questions,
|
||||||
"required_fields": required_fields,
|
"required_fields": required_fields,
|
||||||
"context_note": str(pause_request.get("context_note", "") or "").strip(),
|
"context_note": str(pause_request.get("context_note", "") or "").strip(),
|
||||||
"resume_hint": str(pause_request.get("resume_hint", "") or "").strip(),
|
"resume_hint": resume_hint,
|
||||||
"requesting_role_id": str(
|
"requesting_role_id": str(
|
||||||
payload.get("requesting_role_id") or pause_request.get("requesting_role_id") or ""
|
payload.get("requesting_role_id") or pause_request.get("requesting_role_id") or ""
|
||||||
).strip(),
|
).strip(),
|
||||||
|
|||||||
@@ -640,7 +640,8 @@ class CompanyCollaborationTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
self.assertIn("acquisition_specialist", role_by_id)
|
self.assertIn("acquisition_specialist", role_by_id)
|
||||||
self.assertEqual(role_by_id["acquisition_specialist"].reports_to, "coo")
|
self.assertEqual(role_by_id["acquisition_specialist"].reports_to, "coo")
|
||||||
self.assertIn("acquisition_specialist", role_by_id["coo"].can_spawn)
|
self.assertIn("acquisition_specialist", role_by_id["coo"].can_spawn)
|
||||||
self.assertNotIn("file_edit", role_by_id["acquisition_specialist"].tools)
|
# Every company role can author files (file_write/file_edit baseline).
|
||||||
|
self.assertIn("file_edit", role_by_id["acquisition_specialist"].tools)
|
||||||
|
|
||||||
def test_data_acquisition_turn_type_stays_execute_even_with_audit_language(self) -> None:
|
def test_data_acquisition_turn_type_stays_execute_even_with_audit_language(self) -> None:
|
||||||
builder = CompanyRuntimeSpecBuilder(DummyOrgEngine())
|
builder = CompanyRuntimeSpecBuilder(DummyOrgEngine())
|
||||||
|
|||||||
@@ -463,8 +463,10 @@ class TaskModeNativeAgentTests(unittest.IsolatedAsyncioTestCase):
|
|||||||
self.assertIn("file_read", allowed)
|
self.assertIn("file_read", allowed)
|
||||||
self.assertIn("delegate_work", allowed)
|
self.assertIn("delegate_work", allowed)
|
||||||
self.assertIn("manager_board_read", allowed)
|
self.assertIn("manager_board_read", allowed)
|
||||||
|
# file_write stays available: coordination turns must be able to
|
||||||
|
# persist in-context content instead of trapping it in DM hand-offs.
|
||||||
|
self.assertIn("file_write", allowed)
|
||||||
self.assertNotIn("shell_exec", allowed)
|
self.assertNotIn("shell_exec", allowed)
|
||||||
self.assertNotIn("file_write", allowed)
|
|
||||||
self.assertNotIn("web_search", allowed)
|
self.assertNotIn("web_search", allowed)
|
||||||
self.assertNotIn("agent_spawn", allowed)
|
self.assertNotIn("agent_spawn", allowed)
|
||||||
self.assertNotIn("agent_wait", allowed)
|
self.assertNotIn("agent_wait", allowed)
|
||||||
|
|||||||
Reference in New Issue
Block a user