crewly 1.20.349 → 1.20.351
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/skills/agent/core/complete-task/SKILL.md +6 -5
- package/config/skills/agent/core/complete-task/execute.sh +13 -4
- package/config/skills/agent/core/complete-task/execute.test.sh +7 -0
- package/config/skills/agent/core/report-status/SKILL.md +3 -3
- package/config/skills/agent/core/report-status/execute.sh +9 -5
- package/config/skills/agent/core/trace-read/SKILL.md +14 -0
- package/config/skills/agent/core/trace-read/execute.sh +25 -2
- package/config/skills/orchestrator/complete-task/SKILL.md +1 -1
- package/config/skills/orchestrator/complete-task/execute.sh +3 -2
- package/config/skills/orchestrator/render-verdict/SKILL.md +2 -1
- package/config/skills/orchestrator/render-verdict/execute.sh +8 -4
- package/config/skills/team-leader/verify-output/SKILL.md +8 -3
- package/config/skills/team-leader/verify-output/execute.sh +4 -3
- package/config/skills/team-leader/verify-output/execute.test.sh +2 -0
- package/dist/backend/backend/src/constants.d.ts +30 -5
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +32 -5
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/request/request.controller.d.ts +12 -0
- package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/request/request.controller.js +48 -0
- package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/request/request.routes.d.ts +1 -0
- package/dist/backend/backend/src/controllers/request/request.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/request/request.routes.js +4 -1
- package/dist/backend/backend/src/controllers/request/request.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +8 -5
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +91 -16
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +3 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.d.ts +6 -0
- package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.js +9 -0
- package/dist/backend/backend/src/services/messaging/agent-ask-ledger.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/completion-evidence.service.d.ts +74 -5
- package/dist/backend/backend/src/services/task-pool/completion-evidence.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/completion-evidence.service.js +187 -21
- package/dist/backend/backend/src/services/task-pool/completion-evidence.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-whereabouts.service.d.ts +88 -0
- package/dist/backend/backend/src/services/v3/request-whereabouts.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/v3/request-whereabouts.service.js +193 -0
- package/dist/backend/backend/src/services/v3/request-whereabouts.service.js.map +1 -0
- package/dist/backend/backend/src/types/v2/completion-evidence.types.d.ts +16 -0
- package/dist/backend/backend/src/types/v2/completion-evidence.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/completion-evidence.types.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +6 -0
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js +6 -0
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +30 -5
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +32 -5
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.d.ts +6 -0
- package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.js +9 -0
- package/dist/cli/backend/src/services/messaging/agent-ask-ledger.service.js.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +6 -0
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js +6 -0
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/frontend/dist/assets/{index-36b1788c.js → index-b1fc60ea.js} +65 -65
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/packages/crewly-agent/src/runtime/tool-registry.test.ts +26 -0
- package/packages/crewly-agent/src/runtime/tool-registry.ts +31 -4
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - POST /api/requests — create a Request
|
|
8
8
|
* - POST /api/requests/plan — plan tasks from a user message
|
|
9
9
|
* - PUT /api/requests/:id — update a Request
|
|
10
|
+
* - GET /api/requests/:id/whereabouts — who holds it now, doing what, since when
|
|
10
11
|
*
|
|
11
12
|
* @module controllers/request/request.controller
|
|
12
13
|
*/
|
|
@@ -25,6 +26,17 @@ export declare function listRequests(req: ExpressRequest, res: Response): Promis
|
|
|
25
26
|
* @param res - Express response with Request or 404
|
|
26
27
|
*/
|
|
27
28
|
export declare function getRequest(req: ExpressRequest, res: Response): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Who holds a Request now, doing what, since when: its open WorkItems (the
|
|
31
|
+
* worker, or the reviewer once the worker is done) and agent-to-agent
|
|
32
|
+
* hand-offs from the ask ledger. See services/v3/request-whereabouts.service.ts.
|
|
33
|
+
*
|
|
34
|
+
* Responses: 200 `{success, data: RequestWhereabouts}`, 404 unknown request.
|
|
35
|
+
*
|
|
36
|
+
* @param req - Express request with id param (request id or `TKT-n`)
|
|
37
|
+
* @param res - Express response
|
|
38
|
+
*/
|
|
39
|
+
export declare function getRequestWhereabouts(req: ExpressRequest, res: Response): Promise<void>;
|
|
28
40
|
/**
|
|
29
41
|
* Creates a new Request.
|
|
30
42
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.controller.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"request.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,IAAI,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAuBnE;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpF;AAMD;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBlF;AAqBD;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAa7F;AAMD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B5F;AAMD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBnF;AAMD;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BrF"}
|
|
@@ -7,12 +7,16 @@
|
|
|
7
7
|
* - POST /api/requests — create a Request
|
|
8
8
|
* - POST /api/requests/plan — plan tasks from a user message
|
|
9
9
|
* - PUT /api/requests/:id — update a Request
|
|
10
|
+
* - GET /api/requests/:id/whereabouts — who holds it now, doing what, since when
|
|
10
11
|
*
|
|
11
12
|
* @module controllers/request/request.controller
|
|
12
13
|
*/
|
|
13
14
|
import { RequestService } from '../../services/v3/request.service.js';
|
|
14
15
|
import { readAgentSessionHeader } from '../../utils/agent-caller.utils.js';
|
|
15
16
|
import { ensureTraceForSession } from '../../services/trace/trace-recorder.js';
|
|
17
|
+
import { TaskPoolService } from '../../services/task-pool/task-pool.service.js';
|
|
18
|
+
import { getAgentAskLedger } from '../../services/messaging/agent-ask-ledger.service.js';
|
|
19
|
+
import { computeWhereabouts } from '../../services/v3/request-whereabouts.service.js';
|
|
16
20
|
/**
|
|
17
21
|
* Gets the RequestService singleton.
|
|
18
22
|
*
|
|
@@ -66,6 +70,50 @@ export async function getRequest(req, res) {
|
|
|
66
70
|
res.status(500).json({ success: false, error: error.message });
|
|
67
71
|
}
|
|
68
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Find a Request by id, or by its ticket number (`TKT-12` or `12`).
|
|
75
|
+
*
|
|
76
|
+
* @param ref - Request id or ticket number
|
|
77
|
+
* @returns The Request, or null
|
|
78
|
+
*/
|
|
79
|
+
async function findRequest(ref) {
|
|
80
|
+
const byId = await getService().getById(ref);
|
|
81
|
+
if (byId)
|
|
82
|
+
return byId;
|
|
83
|
+
const m = /^(?:TKT-)?(\d+)$/i.exec(ref.trim());
|
|
84
|
+
if (!m)
|
|
85
|
+
return null;
|
|
86
|
+
const n = Number(m[1]);
|
|
87
|
+
return (await getService().listAll()).find((r) => r.ticketNumber === n) ?? null;
|
|
88
|
+
}
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// GET /api/requests/:id/whereabouts — where the Request is now
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
/**
|
|
93
|
+
* Who holds a Request now, doing what, since when: its open WorkItems (the
|
|
94
|
+
* worker, or the reviewer once the worker is done) and agent-to-agent
|
|
95
|
+
* hand-offs from the ask ledger. See services/v3/request-whereabouts.service.ts.
|
|
96
|
+
*
|
|
97
|
+
* Responses: 200 `{success, data: RequestWhereabouts}`, 404 unknown request.
|
|
98
|
+
*
|
|
99
|
+
* @param req - Express request with id param (request id or `TKT-n`)
|
|
100
|
+
* @param res - Express response
|
|
101
|
+
*/
|
|
102
|
+
export async function getRequestWhereabouts(req, res) {
|
|
103
|
+
try {
|
|
104
|
+
const request = await findRequest(req.params.id ?? '');
|
|
105
|
+
if (!request) {
|
|
106
|
+
res.status(404).json({ success: false, error: `Request not found: ${req.params.id}` });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const items = await TaskPoolService.getInstance().getAllItems();
|
|
110
|
+
const asks = getAgentAskLedger()?.openAsks() ?? [];
|
|
111
|
+
res.json({ success: true, data: computeWhereabouts(request, items, asks, Date.now()) });
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
res.status(500).json({ success: false, error: error.message });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
69
117
|
// ---------------------------------------------------------------------------
|
|
70
118
|
// POST /api/requests — Create a Request
|
|
71
119
|
// ---------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.controller.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.controller.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"request.controller.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtE,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sDAAsD,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,kDAAkD,CAAC;AAGtF;;;;GAIG;AACH,SAAS,UAAU;IACjB,OAAO,cAAc,CAAC,WAAW,EAAE,CAAC;AACtC,CAAC;AAED,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAmB,EAAE,GAAa;IACnE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,UAAU,EAAE,CAAC,OAAO,EAAE,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,+CAA+C;AAC/C,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAmB,EAAE,GAAa;IACjE,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5E,OAAO;QACT,CAAC;QAED,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,WAAW,CAAC,GAAW;IACpC,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7C,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,OAAO,CAAC,MAAM,UAAU,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC;AAClF,CAAC;AAED,8EAA8E;AAC9E,+DAA+D;AAC/D,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAmB,EAAE,GAAa;IAC5E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACvF,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,CAAC,WAAW,EAAE,CAAC;QAChE,MAAM,IAAI,GAAG,iBAAiB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACnD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAmB,EAAE,GAAa;IAC3E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,CAAC,IAA0B,CAAC;QAE5C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC1F,OAAO;QACT,CAAC;QAED,kEAAkE;QAClE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC;QAClG,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAElG,qEAAqE;QACrE,iEAAiE;QACjE,mEAAmE;QACnE,uDAAuD;QAEvD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAI,KAAe,CAAC,OAAO,CAAC;QACzC,IAAI,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,CAAC;YACnD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,2DAA2D;AAC3D,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAmB,EAAE,GAAa;IAClE,IAAI,CAAC;QACH,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC,IAGhC,CAAC;QAEF,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,gDAAgD,EAAE,CAAC,CAAC;YAClG,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACvD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,2CAA2C;AAC3C,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAmB,EAAE,GAAa;IACpE,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,GAAG,CAAC,IAA0B,CAAC;QAC/C,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAC,CAAC;YAC1F,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACvD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAI,KAAe,CAAC,OAAO,CAAC;QACzC,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAClC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,CAAC;YACzD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -18,6 +18,7 @@ import { Router } from 'express';
|
|
|
18
18
|
* - POST /open-items/backfill — scan the last 7 days (dry-run unless apply)
|
|
19
19
|
* - POST /:id/open-items/:itemId/skip — the owner skips an open item
|
|
20
20
|
* - GET /:id — get a single request
|
|
21
|
+
* - GET /:id/whereabouts — who holds it now, doing what, since when
|
|
21
22
|
* - PUT /:id — update a request
|
|
22
23
|
*
|
|
23
24
|
* @returns Express router for /api/requests routes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"request.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAWjC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CA6B5C"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module controllers/request/request.routes
|
|
8
8
|
*/
|
|
9
9
|
import { Router } from 'express';
|
|
10
|
-
import { listRequests, getRequest, createRequestHandler, planRequest, updateRequest, } from './request.controller.js';
|
|
10
|
+
import { listRequests, getRequest, createRequestHandler, planRequest, updateRequest, getRequestWhereabouts, } from './request.controller.js';
|
|
11
11
|
import { listOpenItems, backfillOpenItemsHandler, skipOpenItemHandler } from './open-items.controller.js';
|
|
12
12
|
/**
|
|
13
13
|
* Creates the request router with all endpoints.
|
|
@@ -20,6 +20,7 @@ import { listOpenItems, backfillOpenItemsHandler, skipOpenItemHandler } from './
|
|
|
20
20
|
* - POST /open-items/backfill — scan the last 7 days (dry-run unless apply)
|
|
21
21
|
* - POST /:id/open-items/:itemId/skip — the owner skips an open item
|
|
22
22
|
* - GET /:id — get a single request
|
|
23
|
+
* - GET /:id/whereabouts — who holds it now, doing what, since when
|
|
23
24
|
* - PUT /:id — update a request
|
|
24
25
|
*
|
|
25
26
|
* @returns Express router for /api/requests routes
|
|
@@ -37,6 +38,8 @@ export function createRequestRouter() {
|
|
|
37
38
|
router.post('/open-items/backfill', backfillOpenItemsHandler);
|
|
38
39
|
// Get a single request by ID
|
|
39
40
|
router.get('/:id', getRequest);
|
|
41
|
+
// Where it is now (holder, state, since)
|
|
42
|
+
router.get('/:id/whereabouts', getRequestWhereabouts);
|
|
40
43
|
// Update a request
|
|
41
44
|
router.put('/:id', updateRequest);
|
|
42
45
|
// The owner skips an open item ("I don't care about this anymore")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,UAAU,EACV,oBAAoB,EACpB,WAAW,EACX,aAAa,
|
|
1
|
+
{"version":3,"file":"request.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/request/request.routes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,UAAU,EACV,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,qBAAqB,GACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAE1G;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,oBAAoB;IACpB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAE9B,uBAAuB;IACvB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IAEvC,yEAAyE;IACzE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAElC,uEAAuE;IACvE,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IACzC,MAAM,CAAC,IAAI,CAAC,sBAAsB,EAAE,wBAAwB,CAAC,CAAC;IAE9D,6BAA6B;IAC7B,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAE/B,yCAAyC;IACzC,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAC;IAEtD,mBAAmB;IACnB,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAElC,mEAAmE;IACnE,MAAM,CAAC,IAAI,CAAC,8BAA8B,EAAE,mBAAmB,CAAC,CAAC;IAEjE,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -136,9 +136,10 @@ export declare function releaseItem(req: Request, res: Response): Promise<void>;
|
|
|
136
136
|
* - a `command` with non-zero `exitCode` → 400 `evidence_command_failed`;
|
|
137
137
|
* - an `artifact` local path that does not exist (relative paths resolve
|
|
138
138
|
* against the WorkItem's worktree, then `metadata.projectPath`) → 400;
|
|
139
|
-
* - missing/empty → `
|
|
140
|
-
* `
|
|
141
|
-
* `
|
|
139
|
+
* - missing/empty → `enforce` mode (default since #1312): 400
|
|
140
|
+
* `evidence_required`; `warn` mode (`CREWLY_EVIDENCE_MODE=warn`): accepted
|
|
141
|
+
* with a `warning` field. Exempt: a review item's verdict completion, and
|
|
142
|
+
* bookkeeping types outside `REQUIRED_FOR_TYPES` (triage, replans, retros).
|
|
142
143
|
*
|
|
143
144
|
* Any field beyond `summary` inside `result` (e.g. `prNumber`, `links`,
|
|
144
145
|
* `evidence`) is preserved into `WorkItem.output` via spread merge, so
|
|
@@ -200,7 +201,9 @@ export declare function failItemHandler(req: Request, res: Response): Promise<vo
|
|
|
200
201
|
/**
|
|
201
202
|
* POST /api/task-pool/items/:workItemId/verdict — record a review verdict.
|
|
202
203
|
*
|
|
203
|
-
* Body: `{ "verdict": "verified" | "rejected", "comment"?: string }`.
|
|
204
|
+
* Body: `{ "verdict": "verified" | "rejected", "comment"?: string, "checks"?: ReviewCheck[] }`.
|
|
205
|
+
* An agent's or the orchestrator's `verified` needs `checks` (#1314, see
|
|
206
|
+
* `decideReviewAccept`); the owner's does not.
|
|
204
207
|
*
|
|
205
208
|
* The caller is resolved from the request (`X-Agent-Session`, or the owner's
|
|
206
209
|
* dashboard marker) — never from the body (#813). An agent session acts as a
|
|
@@ -210,7 +213,7 @@ export declare function failItemHandler(req: Request, res: Response): Promise<vo
|
|
|
210
213
|
*
|
|
211
214
|
* Responses:
|
|
212
215
|
* - 200 `{ success: true, data: WorkItem }`
|
|
213
|
-
* - 400 invalid verdict
|
|
216
|
+
* - 400 invalid verdict, or `review_unchecked` / `review_checks_malformed` / `review_check_failed`
|
|
214
217
|
* - 403 `{ code: 'transition_not_reviewer' | 'transition_self_review' | … }`
|
|
215
218
|
* - 404 WorkItem not found
|
|
216
219
|
* - 409 item is not `done_by_worker`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-pool.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/task-pool/task-pool.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AASjD,OAAO,EAAE,qBAAqB,EAAoB,MAAM,8DAA8D,CAAC;
|
|
1
|
+
{"version":3,"file":"task-pool.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/task-pool/task-pool.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,12 +15,12 @@ import { ServiceContractGate } from '../../services/v3/service-contract-gate.ser
|
|
|
15
15
|
import { StorageService } from '../../services/core/storage.service.js';
|
|
16
16
|
import { GiveUpRecoveryService } from '../../services/task-pool/give-up/give-up-recovery.service.js';
|
|
17
17
|
import { computeGiveUpStats } from '../../services/task-pool/give-up/give-up-stats.js';
|
|
18
|
-
import { WORK_ITEM_TYPES, isValidWorkItemType, createWorkItem, validateCreateWorkItemInput, ForbiddenTransitionError, } from '../../types/v2/work-item.types.js';
|
|
18
|
+
import { WORK_ITEM_TYPES, isValidWorkItemType, createWorkItem, validateCreateWorkItemInput, ForbiddenTransitionError, WORK_ITEM_REVIEW_CHECKS_KEY, } from '../../types/v2/work-item.types.js';
|
|
19
19
|
import { formatError } from '../../utils/format-error.js';
|
|
20
20
|
import { TeamBudgetExceededError } from '../../services/budget/team-budget-gate.service.js';
|
|
21
21
|
import { LoggerService } from '../../services/core/logger.service.js';
|
|
22
22
|
import { ORCHESTRATOR_SESSION_NAME, PROJECT_TICKET_CONSTANTS, OPEN_ITEMS_CONSTANTS, PEOPLE_CONSTANTS, COMPLETION_EVIDENCE_CONSTANTS, TEAM_PAUSE_CONSTANTS } from '../../constants.js';
|
|
23
|
-
import { decideCompletion, resolveEvidenceEnforcementMode } from '../../services/task-pool/completion-evidence.service.js';
|
|
23
|
+
import { decideCompletion, decideReviewAccept, evidenceRequiredFor, resolveEvidenceEnforcementMode } from '../../services/task-pool/completion-evidence.service.js';
|
|
24
24
|
import { readAgentSessionHeader, resolveTransitionActor } from '../../utils/agent-caller.utils.js';
|
|
25
25
|
import { getTicketIntakeService } from '../../services/v3/ticket-intake.service.js';
|
|
26
26
|
import { ownerThreadHandover } from '../../services/orc/work-item-destination.js';
|
|
@@ -736,9 +736,51 @@ export async function releaseItem(req, res) {
|
|
|
736
736
|
handleServiceError(res, error);
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
739
|
+
/**
|
|
740
|
+
* The check-record decision for completing a review item as an accept
|
|
741
|
+
* (#1314), or null when the completion is not one: not a review item, no
|
|
742
|
+
* `metadata.verifyOf`, a `verdict: "rejected"`, or a source no longer
|
|
743
|
+
* awaiting review.
|
|
744
|
+
*
|
|
745
|
+
* @param reviewItem - The review WorkItem being completed
|
|
746
|
+
* @param result - The completion's `body.result`
|
|
747
|
+
* @param mode - Evidence rollout mode
|
|
748
|
+
* @returns The decision with its source id, or null
|
|
749
|
+
*/
|
|
750
|
+
async function decideReviewCheck(reviewItem, result, mode) {
|
|
751
|
+
const verifyOf = reviewItem?.type === 'review' ? reviewItem.metadata?.['verifyOf'] : undefined;
|
|
752
|
+
if (typeof verifyOf !== 'string' || result?.['verdict'] === 'rejected')
|
|
753
|
+
return null;
|
|
754
|
+
const source = await getService().findWorkItem(verifyOf).catch(() => null);
|
|
755
|
+
if (!source || source.status !== 'done_by_worker')
|
|
756
|
+
return null;
|
|
757
|
+
return { sourceId: verifyOf, decision: decideReviewAccept(result?.['checks'], source.output?.['evidence'], mode) };
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Stamp what the reviewer checked onto the worker's item (#1314), so the
|
|
761
|
+
* record is visible where the work is. Non-fatal.
|
|
762
|
+
*
|
|
763
|
+
* @param outcome - The accepted check decision
|
|
764
|
+
* @param reviewItemId - The review WorkItem (absent for a direct verdict)
|
|
765
|
+
* @param reviewer - Who reviewed
|
|
766
|
+
*/
|
|
767
|
+
async function recordReviewCheck(outcome, reviewItemId, reviewer) {
|
|
768
|
+
const d = outcome.decision;
|
|
769
|
+
if (d.action === 'reject')
|
|
770
|
+
return;
|
|
771
|
+
const record = {
|
|
772
|
+
...(reviewItemId ? { reviewItemId } : {}),
|
|
773
|
+
reviewer,
|
|
774
|
+
at: new Date().toISOString(),
|
|
775
|
+
...(d.action === 'accept' ? { checks: d.checks } : { unchecked: true }),
|
|
776
|
+
};
|
|
777
|
+
try {
|
|
778
|
+
await getService().mergeItemMetadata(outcome.sourceId, { [WORK_ITEM_REVIEW_CHECKS_KEY]: record });
|
|
779
|
+
}
|
|
780
|
+
catch (err) {
|
|
781
|
+
logger.warn('Failed to record review checks on the source (non-fatal)', { sourceId: outcome.sourceId, error: formatError(err) });
|
|
782
|
+
}
|
|
783
|
+
}
|
|
742
784
|
/**
|
|
743
785
|
* Marks a running WorkItem as completed ('done').
|
|
744
786
|
*
|
|
@@ -770,9 +812,10 @@ export async function releaseItem(req, res) {
|
|
|
770
812
|
* - a `command` with non-zero `exitCode` → 400 `evidence_command_failed`;
|
|
771
813
|
* - an `artifact` local path that does not exist (relative paths resolve
|
|
772
814
|
* against the WorkItem's worktree, then `metadata.projectPath`) → 400;
|
|
773
|
-
* - missing/empty → `
|
|
774
|
-
* `
|
|
775
|
-
* `
|
|
815
|
+
* - missing/empty → `enforce` mode (default since #1312): 400
|
|
816
|
+
* `evidence_required`; `warn` mode (`CREWLY_EVIDENCE_MODE=warn`): accepted
|
|
817
|
+
* with a `warning` field. Exempt: a review item's verdict completion, and
|
|
818
|
+
* bookkeeping types outside `REQUIRED_FOR_TYPES` (triage, replans, retros).
|
|
776
819
|
*
|
|
777
820
|
* Any field beyond `summary` inside `result` (e.g. `prNumber`, `links`,
|
|
778
821
|
* `evidence`) is preserved into `WorkItem.output` via spread merge, so
|
|
@@ -853,17 +896,27 @@ export async function completeItem(req, res) {
|
|
|
853
896
|
const evidenceMode = resolveEvidenceEnforcementMode();
|
|
854
897
|
const decision = await decideCompletion(result?.['evidence'], existing, {
|
|
855
898
|
mode: evidenceMode,
|
|
856
|
-
// A review item's verdict is its deliverable
|
|
857
|
-
|
|
899
|
+
// A review item's verdict is its deliverable; bookkeeping types
|
|
900
|
+
// (triage, replans, retros) have no artifact to show (#1312).
|
|
901
|
+
exemptFromMissing: typeof result?.['verdict'] === 'string' || !evidenceRequiredFor(existing?.type),
|
|
858
902
|
});
|
|
859
903
|
if (decision.action === 'reject') {
|
|
860
904
|
logger.info('complete: rejected by the evidence contract', { workItemId, agentId, code: decision.code });
|
|
861
905
|
res.status(decision.status).json({ success: false, error: decision.error, code: decision.code });
|
|
862
906
|
return;
|
|
863
907
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
908
|
+
// #1314: accepting a review needs a record of what the reviewer checked,
|
|
909
|
+
// per worker evidence entry. Sending it back does not.
|
|
910
|
+
const reviewCheck = await decideReviewCheck(existing, result, evidenceMode);
|
|
911
|
+
if (reviewCheck?.decision.action === 'reject') {
|
|
912
|
+
logger.info('complete: review accept refused, no usable check record', { workItemId, agentId, code: reviewCheck.decision.code });
|
|
913
|
+
res.status(reviewCheck.decision.status).json({ success: false, error: reviewCheck.decision.error, code: reviewCheck.decision.code });
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const reviewWarning = reviewCheck?.decision.action === 'accept_unchecked' ? reviewCheck.decision.warning : undefined;
|
|
917
|
+
const evidenceWarning = decision.action === 'complete' ? decision.warning : undefined;
|
|
918
|
+
const warningText = [evidenceWarning, reviewWarning].filter(Boolean).join(' ');
|
|
919
|
+
const warningFields = warningText ? { warning: warningText, evidenceMode } : {};
|
|
867
920
|
if (decision.action === 'complete' && decision.warning) {
|
|
868
921
|
logger.warn('complete: WorkItem completed without evidence (warn mode)', { workItemId, agentId });
|
|
869
922
|
}
|
|
@@ -881,6 +934,7 @@ export async function completeItem(req, res) {
|
|
|
881
934
|
...(result ?? {}),
|
|
882
935
|
// The validated evidence (only known fields), replacing the raw value.
|
|
883
936
|
...(decision.evidence ? { evidence: decision.evidence } : {}),
|
|
937
|
+
...(reviewCheck?.decision.action === 'accept' ? { checks: reviewCheck.decision.checks } : {}),
|
|
884
938
|
};
|
|
885
939
|
await getService().setOutput(workItemId, mergedOutput);
|
|
886
940
|
}
|
|
@@ -930,6 +984,8 @@ export async function completeItem(req, res) {
|
|
|
930
984
|
}
|
|
931
985
|
}
|
|
932
986
|
const outcome = await getGiveUp().complete(workItemId, result, actor);
|
|
987
|
+
if (reviewCheck)
|
|
988
|
+
await recordReviewCheck(reviewCheck, workItemId, actor.session ?? agentId);
|
|
933
989
|
if (outcome.action === 'retry_queued' || outcome.action === 'escalated_to_lead') {
|
|
934
990
|
res.json({
|
|
935
991
|
success: true,
|
|
@@ -1087,7 +1143,9 @@ export async function failItemHandler(req, res) {
|
|
|
1087
1143
|
/**
|
|
1088
1144
|
* POST /api/task-pool/items/:workItemId/verdict — record a review verdict.
|
|
1089
1145
|
*
|
|
1090
|
-
* Body: `{ "verdict": "verified" | "rejected", "comment"?: string }`.
|
|
1146
|
+
* Body: `{ "verdict": "verified" | "rejected", "comment"?: string, "checks"?: ReviewCheck[] }`.
|
|
1147
|
+
* An agent's or the orchestrator's `verified` needs `checks` (#1314, see
|
|
1148
|
+
* `decideReviewAccept`); the owner's does not.
|
|
1091
1149
|
*
|
|
1092
1150
|
* The caller is resolved from the request (`X-Agent-Session`, or the owner's
|
|
1093
1151
|
* dashboard marker) — never from the body (#813). An agent session acts as a
|
|
@@ -1097,7 +1155,7 @@ export async function failItemHandler(req, res) {
|
|
|
1097
1155
|
*
|
|
1098
1156
|
* Responses:
|
|
1099
1157
|
* - 200 `{ success: true, data: WorkItem }`
|
|
1100
|
-
* - 400 invalid verdict
|
|
1158
|
+
* - 400 invalid verdict, or `review_unchecked` / `review_checks_malformed` / `review_check_failed`
|
|
1101
1159
|
* - 403 `{ code: 'transition_not_reviewer' | 'transition_self_review' | … }`
|
|
1102
1160
|
* - 404 WorkItem not found
|
|
1103
1161
|
* - 409 item is not `done_by_worker`
|
|
@@ -1116,8 +1174,25 @@ export async function renderVerdict(req, res) {
|
|
|
1116
1174
|
const caller = resolveTransitionActor(req, 'POST /task-pool/items/:id/verdict');
|
|
1117
1175
|
// An agent session here is acting as a reviewer, not as the worker.
|
|
1118
1176
|
const actor = caller.role === 'agent' ? { ...caller, role: 'team_lead' } : caller;
|
|
1177
|
+
// #1314: an agent's or the orchestrator's accept records what it checked,
|
|
1178
|
+
// as on a review item's completion. The owner's dashboard click does not.
|
|
1179
|
+
let reviewCheck = null;
|
|
1180
|
+
if (verdict === 'verified' && caller.role !== 'owner') {
|
|
1181
|
+
const item = await getService().findWorkItem(workItemId).catch(() => null);
|
|
1182
|
+
if (item?.status === 'done_by_worker') {
|
|
1183
|
+
const mode = resolveEvidenceEnforcementMode();
|
|
1184
|
+
reviewCheck = { sourceId: workItemId, decision: decideReviewAccept(req.body['checks'], item.output?.['evidence'], mode) };
|
|
1185
|
+
if (reviewCheck.decision.action === 'reject') {
|
|
1186
|
+
res.status(reviewCheck.decision.status).json({ success: false, error: reviewCheck.decision.error, code: reviewCheck.decision.code });
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1119
1191
|
const updated = await getService().verifyItem(workItemId, actor, verdict, typeof comment === 'string' && comment.trim() ? comment.trim() : undefined);
|
|
1120
|
-
|
|
1192
|
+
if (reviewCheck)
|
|
1193
|
+
await recordReviewCheck(reviewCheck, undefined, caller.session ?? caller.role);
|
|
1194
|
+
const warning = reviewCheck?.decision.action === 'accept_unchecked' ? { warning: reviewCheck.decision.warning } : {};
|
|
1195
|
+
res.json({ success: true, data: updated, ...warning });
|
|
1121
1196
|
}
|
|
1122
1197
|
catch (error) {
|
|
1123
1198
|
handleServiceError(res, error);
|