get_case_issues: also match issues by [ערר X] title prefix
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s
The original implementation only returned issues with a plugin_state
linkage (legal-case-number key), which was set just on the initial
setup issue. Sub-agents that created follow-up issues during the case
workflow tagged them in the title ("[ערר 1130-25] כתיבת החלטה" etc.)
but didn't write a plugin_state row, so 23 of 24 historical issues
for case 1130-25 were invisible to the agent activity feed.
Widened the lookup to UNION two paths:
(a) plugin_state.scope_id matches via the legal-case-number key
(b) issues.title LIKE '%[ערר {case_number}]%' OR '%ערר {case_number}%'
Used DISTINCT ON (i.id) + post-sort by created_at to dedupe and keep
chronological order. The widget on https://legal-ai.../cases/1130-25
will now show the full history (was 1 issue → now 16).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -386,22 +386,35 @@ async def create_workflow_issue(case_number: str, title: str) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
async def get_case_issues(case_number: str) -> list[dict]:
|
async def get_case_issues(case_number: str) -> list[dict]:
|
||||||
"""Get all Paperclip issues linked to a legal-ai case number."""
|
"""Get all Paperclip issues linked to a legal-ai case number.
|
||||||
|
|
||||||
|
Matches via two paths to avoid missing historical issues:
|
||||||
|
(a) the original setup linkage in plugin_state (state_key = legal-case-number)
|
||||||
|
(b) issues whose title contains "[ערר {case_number}]" or "ערר {case_number}"
|
||||||
|
— that's how sub-agents conventionally tag follow-up issues.
|
||||||
|
Returns the union of both, deduplicated by issue id, ordered by creation time.
|
||||||
|
"""
|
||||||
|
title_patterns = [f"%[ערר {case_number}]%", f"%ערר {case_number}%"]
|
||||||
conn = await asyncpg.connect(PAPERCLIP_DB_URL)
|
conn = await asyncpg.connect(PAPERCLIP_DB_URL)
|
||||||
try:
|
try:
|
||||||
rows = await conn.fetch(
|
rows = await conn.fetch(
|
||||||
"""SELECT i.id, i.title, i.status, i.identifier, i.priority,
|
"""SELECT DISTINCT ON (i.id)
|
||||||
|
i.id, i.title, i.status, i.identifier, i.priority,
|
||||||
i.assignee_agent_id, a.name AS assignee_name,
|
i.assignee_agent_id, a.name AS assignee_name,
|
||||||
i.started_at, i.completed_at, i.created_at, i.company_id
|
i.started_at, i.completed_at, i.created_at, i.company_id
|
||||||
FROM issues i
|
FROM issues i
|
||||||
JOIN plugin_state ps ON ps.scope_id = i.id::text
|
|
||||||
LEFT JOIN agents a ON i.assignee_agent_id = a.id
|
LEFT JOIN agents a ON i.assignee_agent_id = a.id
|
||||||
WHERE ps.plugin_id = $1::uuid
|
LEFT JOIN plugin_state ps ON ps.scope_id = i.id::text
|
||||||
AND ps.state_key = 'legal-case-number'
|
AND ps.plugin_id = $1::uuid
|
||||||
AND ps.value_json = $2::jsonb
|
AND ps.state_key = 'legal-case-number'
|
||||||
ORDER BY i.created_at""",
|
AND ps.value_json = $2::jsonb
|
||||||
PLUGIN_ID, json.dumps(case_number),
|
WHERE ps.scope_id IS NOT NULL
|
||||||
|
OR i.title LIKE ANY($3::text[])
|
||||||
|
ORDER BY i.id, i.created_at""",
|
||||||
|
PLUGIN_ID, json.dumps(case_number), title_patterns,
|
||||||
)
|
)
|
||||||
|
# Sort by created_at after dedup
|
||||||
|
sorted_rows = sorted(rows, key=lambda r: r["created_at"])
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"id": str(r["id"]),
|
"id": str(r["id"]),
|
||||||
@@ -415,7 +428,7 @@ async def get_case_issues(case_number: str) -> list[dict]:
|
|||||||
"created_at": r["created_at"].isoformat() if r["created_at"] else None,
|
"created_at": r["created_at"].isoformat() if r["created_at"] else None,
|
||||||
"company_id": str(r["company_id"]),
|
"company_id": str(r["company_id"]),
|
||||||
}
|
}
|
||||||
for r in rows
|
for r in sorted_rows
|
||||||
]
|
]
|
||||||
finally:
|
finally:
|
||||||
await conn.close()
|
await conn.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user