feat: add stale-case-reminder and weekly-feedback-analysis jobs
Declare two new cron jobs in plugin.json and manifest.ts, and implement their handlers in worker.ts. stale-case-reminder runs daily at 08:00 and posts a warning comment on any Paperclip issue linked to a legal-ai case that has not been updated in 3+ days. weekly-feedback-analysis runs every Sunday at 19:00, fetches the weekly chair-feedback summary from legal-ai, and invokes the CEO agent to update decision-lessons.md with new lessons.
This commit is contained in:
12
plugin.json
12
plugin.json
@@ -63,6 +63,18 @@
|
||||
"displayName": "סנכרון סטטוס תיקים",
|
||||
"description": "סנכרון סטטוס בין legal-ai ל-Paperclip כל 15 דקות",
|
||||
"schedule": "*/15 * * * *"
|
||||
},
|
||||
{
|
||||
"jobKey": "stale-case-reminder",
|
||||
"displayName": "תזכורת תיקים תקועים",
|
||||
"description": "מזהה תיקים שלא עודכנו 3+ ימים ומוסיף תגובה ל-issue",
|
||||
"schedule": "0 8 * * *"
|
||||
},
|
||||
{
|
||||
"jobKey": "weekly-feedback-analysis",
|
||||
"displayName": "ניתוח פידבק שבועי",
|
||||
"description": "מסכם פידבק יו\"ר מהשבוע האחרון ומעדכן את decision-lessons.md",
|
||||
"schedule": "0 19 * * 0"
|
||||
}
|
||||
],
|
||||
"webhooks": [
|
||||
|
||||
@@ -158,6 +158,18 @@ export default {
|
||||
"Polls legal-ai for case status changes and updates Paperclip issues",
|
||||
schedule: "*/15 * * * *",
|
||||
},
|
||||
{
|
||||
jobKey: "stale-case-reminder",
|
||||
displayName: "תזכורת תיקים תקועים",
|
||||
description: "מזהה תיקים שלא עודכנו 3+ ימים ומוסיף תגובה ל-issue",
|
||||
schedule: "0 8 * * *",
|
||||
},
|
||||
{
|
||||
jobKey: "weekly-feedback-analysis",
|
||||
displayName: "ניתוח פידבק שבועי",
|
||||
description: 'מסכם פידבק יו"ר מהשבוע האחרון ומעדכן את decision-lessons.md',
|
||||
schedule: "0 19 * * 0",
|
||||
},
|
||||
],
|
||||
webhooks: [
|
||||
{
|
||||
|
||||
@@ -706,6 +706,91 @@ const plugin = definePlugin({
|
||||
}
|
||||
});
|
||||
|
||||
ctx.jobs.register("stale-case-reminder", async (_job) => {
|
||||
ctx.logger.info("stale-case-reminder: starting");
|
||||
const config = await ctx.config.get();
|
||||
const apiBase = (config.legalApiBaseUrl as string) ?? "http://localhost:8085";
|
||||
|
||||
const resp = await ctx.http.fetch(`${apiBase}/api/cases/stale?days=3`);
|
||||
if (!resp.ok) {
|
||||
ctx.logger.error(`stale-case-reminder: API error ${resp.status}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = (await resp.json()) as {
|
||||
cases: Array<{ case_number: string; title: string; status: string; days_stale: number }>;
|
||||
total: number;
|
||||
};
|
||||
|
||||
let reminded = 0;
|
||||
for (const staleCase of data.cases) {
|
||||
const companies = await ctx.companies.list();
|
||||
for (const company of companies) {
|
||||
const issues = await ctx.issues.list({ companyId: company.id });
|
||||
let linkedIssueId: string | null = null;
|
||||
for (const issue of issues) {
|
||||
const linkedCase = await ctx.state.get({
|
||||
scopeKind: "issue",
|
||||
scopeId: issue.id,
|
||||
stateKey: "legal-case-number",
|
||||
});
|
||||
if (linkedCase === staleCase.case_number) {
|
||||
linkedIssueId = issue.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!linkedIssueId) continue;
|
||||
|
||||
await ctx.issues.createComment(
|
||||
linkedIssueId,
|
||||
`⚠️ **תיק תקוע ${staleCase.case_number}** — ${staleCase.days_stale} ימים ללא עדכון (סטטוס: ${staleCase.status}). האם נדרשת פעולה?`,
|
||||
company.id,
|
||||
);
|
||||
reminded++;
|
||||
ctx.logger.info(`stale-case-reminder: reminded case ${staleCase.case_number} (${staleCase.days_stale}d)`);
|
||||
break; // Found the company, move to next case
|
||||
}
|
||||
}
|
||||
|
||||
ctx.logger.info(`stale-case-reminder: done. ${reminded}/${data.total} cases reminded`);
|
||||
});
|
||||
|
||||
ctx.jobs.register("weekly-feedback-analysis", async (_job) => {
|
||||
ctx.logger.info("weekly-feedback-analysis: starting");
|
||||
const config = await ctx.config.get();
|
||||
const apiBase = (config.legalApiBaseUrl as string) ?? "http://localhost:8085";
|
||||
|
||||
const resp = await ctx.http.fetch(`${apiBase}/api/chair-feedback/weekly-summary`);
|
||||
if (!resp.ok) {
|
||||
ctx.logger.error(`weekly-feedback-analysis: API error ${resp.status}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = (await resp.json()) as { summary: string; entry_count: number };
|
||||
|
||||
if (data.entry_count === 0) {
|
||||
ctx.logger.info("weekly-feedback-analysis: no feedback this week, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const companies = await ctx.companies.list();
|
||||
const company = companies[0];
|
||||
if (!company) return;
|
||||
|
||||
const ceoId = CEO_AGENT_IDS[company.id];
|
||||
if (!ceoId) {
|
||||
ctx.logger.warn(`weekly-feedback-analysis: no CEO agent for company ${company.id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.agents.invoke(ceoId, company.id, {
|
||||
prompt: `ניתוח פידבק שבועי יו"ר (${data.entry_count} פריטים):\n\n${data.summary}\n\nהמשימה: עדכן את /home/chaim/legal-ai/docs/legal-decision-lessons.md עם הלקחים החדשים שעולים מהפידבק. הוסף רק לקחים חדשים שלא קיימים כבר. קבץ לפי נושא.`,
|
||||
reason: "weekly-feedback-analysis scheduled job",
|
||||
});
|
||||
|
||||
ctx.logger.info(`weekly-feedback-analysis: invoked CEO ${ceoId} with ${data.entry_count} feedback entries`);
|
||||
});
|
||||
|
||||
ctx.logger.info("Legal AI plugin ready");
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user