feat(agents-tab): הוראה למעלה + פעילות מקופלת + בורר-יעד עם "הרצה חדשה"
טאב הסוכנים בדף-התיק — מימוש מוקאפ X17 מאושר (18i3), פותר את התלונה החוזרת
שהיו"ר נחת בתחתית העמוד, שדה-ההוראה למטה, והטיוטה החדשה נבלעה בגלילה.
Frontend (web-ui/agent-activity-feed.tsx):
- **שדה-ההוראה עלה לראש הטאב** (Composer), מעל הפעילות — הכי זמין, בלי גלילה.
בוטל ה-auto-scroll-to-bottom (endRef/useEffect הוסרו).
- **כל הפעילות מקופלת כברירת-מחדל** — קבוצות-המשימה וגם "ממתין לתשובתך"
(defaultOpen=false); היו"ר פותח כדי להסתכל. סדר החדש-למעלה (תג "החדש למעלה").
- **בורר-יעד** (TargetSelector): מציג לאיזו משימה ההוראה תלך, בוחר משימה פעילה,
מסמן משימות סגורות כמנוטרלות ("שליחה אליהן לא תעיר סוכן"), אזהרת יעד-סגור
עם כפתור-שליחה מנוטרל, ואופציית **"פתח הרצה חדשה"**. מחשב את יעד-ברירת-המחדל
בצד-לקוח במראָה ל-pick_default_comment_target.
Backend:
- `open_ceo_run` (paperclip_client) — פותח הרצת-CEO טרייה דרך פרימיטיב ה-CEO-child
(#227): יוצר issue-ילד בבעלות CEO ומעיר עליו, ועוקף את issue_assignee_changed
על issue בבעלות-אדם (הבאג של #228). נחשף דרך ה-Port כ-`pc_open_ceo_run`.
- `/agents/comment` מקבל `new_run:bool`; `PaperclipIssue` מחזיר `parent_id`
(לבורר בצד-לקוח).
Invariants: G1 (נרמול-במקור), G2 (אין מסלול-ניתוב מקביל), G12 (מגע-Paperclip דרך ה-Port).
מקדם TaskMaster #228 (מנתב הרצה-חדשה דרך פרימיטיב ה-CEO-child).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1739,6 +1739,93 @@ async def wake_ceo_for_action(
|
||||
}
|
||||
|
||||
|
||||
async def open_ceo_run(
|
||||
case_number: str,
|
||||
instruction: str,
|
||||
company_id: str = "",
|
||||
) -> dict:
|
||||
"""Open a FRESH CEO-owned run carrying a free-form chair instruction.
|
||||
|
||||
Drives the "פתח הרצה חדשה" option of the agents-tab target selector: instead
|
||||
of appending the instruction to an existing (possibly human-owned or closed)
|
||||
issue, a **child issue assigned to the CEO** is created under the case's main
|
||||
issue and the CEO is woken on it. This is the same CEO-child primitive as
|
||||
:func:`wake_ceo_for_action` (#227) — it sidesteps the ``issue_assignee_changed``
|
||||
cancellation that fires when an agent is woken on a human-owned parent (the
|
||||
exact silent failure the chair hit on 1027-04-26; see TaskMaster #228).
|
||||
|
||||
Wakeup goes through the Paperclip API, never a direct DB insert. Returns
|
||||
``{"status":"ok", "issue_id"(=child), "identifier", ...}`` or
|
||||
``{"status":"skipped", "reason": ...}``.
|
||||
"""
|
||||
if not PAPERCLIP_BOARD_API_KEY:
|
||||
logger.warning("PAPERCLIP_BOARD_API_KEY not set — skipping CEO new-run")
|
||||
return {"status": "skipped", "reason": "no_api_key"}
|
||||
|
||||
issues = await get_case_issues(case_number)
|
||||
if not issues:
|
||||
logger.warning("No Paperclip issues for case %s — skipping CEO new-run", case_number)
|
||||
return {"status": "skipped", "reason": "no_issue"}
|
||||
|
||||
# Parent the new run under the live main issue (never a closed child).
|
||||
main_issue = pick_default_comment_target(issues)
|
||||
main_issue_id = main_issue["id"]
|
||||
if not company_id:
|
||||
company_id = main_issue.get("company_id", "")
|
||||
ceo_id = CEO_AGENTS.get(company_id, CEO_AGENT_ID)
|
||||
|
||||
title = f'[ערר {case_number}] הוראת יו"ר — הרצה חדשה'
|
||||
description = (
|
||||
'הוראת יו"ר שנשלחה כ"הרצה חדשה" מטאב הסוכנים. קרא את מצב התיק, טפל בהוראה '
|
||||
"בסגנון דפנה, ומסור disposition תקין בסיום.\n\n---\n\n" + instruction
|
||||
)
|
||||
child_resp = await pc_request(
|
||||
"POST",
|
||||
f"/api/issues/{main_issue_id}/children",
|
||||
json={
|
||||
"title": title,
|
||||
"description": description,
|
||||
"status": "in_progress",
|
||||
"priority": "medium",
|
||||
"assigneeAgentId": ceo_id,
|
||||
},
|
||||
raise_on_error=True,
|
||||
)
|
||||
sub_issue = child_resp.json()
|
||||
sub_issue_id = sub_issue["id"]
|
||||
|
||||
try:
|
||||
conn = await asyncpg.connect(PAPERCLIP_DB_URL)
|
||||
try:
|
||||
await _link_case_to_issue(conn, sub_issue_id, case_number)
|
||||
finally:
|
||||
await conn.close()
|
||||
except Exception as e:
|
||||
logger.warning("plugin_state link failed for new-run sub_issue=%s: %s", sub_issue_id, e)
|
||||
|
||||
await pc_request(
|
||||
"POST",
|
||||
f"/api/agents/{ceo_id}/wakeup",
|
||||
json={
|
||||
"source": "on_demand",
|
||||
"triggerDetail": "manual",
|
||||
"reason": f"chair_new_run_{case_number}",
|
||||
"payload": {"issueId": sub_issue_id, "case_number": case_number},
|
||||
},
|
||||
raise_on_error=True,
|
||||
)
|
||||
logger.info(
|
||||
"CEO new-run for case %s: child_issue=%s ceo=%s", case_number, sub_issue_id, ceo_id,
|
||||
)
|
||||
return {
|
||||
"status": "ok",
|
||||
"issue_id": sub_issue_id,
|
||||
"identifier": sub_issue.get("identifier", ""),
|
||||
"main_issue_id": main_issue_id,
|
||||
"ceo_id": ceo_id,
|
||||
}
|
||||
|
||||
|
||||
# Substring of the generation child-issue title per action (see _ceo_action_brief).
|
||||
GENERATION_TITLE_SUBSTR = {
|
||||
"party_claims_summary": "סיכום-מנהלים",
|
||||
|
||||
Reference in New Issue
Block a user