@mastra/factory 0.24.0-alpha.1 → 0.24.0-alpha.3
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/README.md +103 -4
- package/dist/auth.d.ts +14 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +45 -9
- package/dist/auth.js.map +1 -1
- package/dist/boards/work-transition-policy.d.ts.map +1 -1
- package/dist/boards/work-transition-policy.js +10 -0
- package/dist/boards/work-transition-policy.js.map +1 -1
- package/dist/boards/work.d.ts +14 -0
- package/dist/boards/work.d.ts.map +1 -1
- package/dist/boards/work.js +70 -7
- package/dist/boards/work.js.map +1 -1
- package/dist/capabilities/version-control.d.ts +26 -0
- package/dist/capabilities/version-control.d.ts.map +1 -1
- package/dist/factory.d.ts +8 -0
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +191 -16
- package/dist/factory.js.map +1 -1
- package/dist/integrations/github/integration.d.ts.map +1 -1
- package/dist/integrations/github/integration.js +37 -1
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/gitlab/api.d.ts +15 -0
- package/dist/integrations/gitlab/api.d.ts.map +1 -1
- package/dist/integrations/gitlab/api.js +9 -0
- package/dist/integrations/gitlab/api.js.map +1 -1
- package/dist/integrations/gitlab/version-control.d.ts.map +1 -1
- package/dist/integrations/gitlab/version-control.js +37 -3
- package/dist/integrations/gitlab/version-control.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +27 -1
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/subscription-session.d.ts +15 -0
- package/dist/integrations/subscription-session.d.ts.map +1 -1
- package/dist/integrations/subscription-session.js +30 -13
- package/dist/integrations/subscription-session.js.map +1 -1
- package/dist/mcp/disconnect.d.ts +10 -0
- package/dist/mcp/disconnect.d.ts.map +1 -0
- package/dist/mcp/disconnect.js +44 -0
- package/dist/mcp/disconnect.js.map +1 -0
- package/dist/mcp/routes.d.ts +46 -0
- package/dist/mcp/routes.d.ts.map +1 -0
- package/dist/mcp/routes.js +243 -0
- package/dist/mcp/routes.js.map +1 -0
- package/dist/provider-display-name.d.ts +2 -0
- package/dist/provider-display-name.d.ts.map +1 -0
- package/dist/provider-display-name.js +16 -0
- package/dist/provider-display-name.js.map +1 -0
- package/dist/routes/config.js +2 -2
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/contracts.d.ts +4 -0
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/contracts.js +3 -1
- package/dist/routes/contracts.js.map +1 -1
- package/dist/routes/oauth.js +1 -1
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/provider-credentials.d.ts +6 -2
- package/dist/routes/provider-credentials.d.ts.map +1 -1
- package/dist/routes/provider-credentials.js +20 -7
- package/dist/routes/provider-credentials.js.map +1 -1
- package/dist/routes/source-control-sessions.d.ts +1 -0
- package/dist/routes/source-control-sessions.d.ts.map +1 -1
- package/dist/routes/source-control-sessions.js +1 -1
- package/dist/routes/source-control-sessions.js.map +1 -1
- package/dist/routes/surface.d.ts +1 -0
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +4 -3
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +61 -121
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/dispatcher.d.ts +7 -0
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +62 -5
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +2 -1
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/tools.d.ts.map +1 -1
- package/dist/rules/tools.js +82 -3
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.d.ts +17 -0
- package/dist/rules/transition-service.d.ts.map +1 -1
- package/dist/rules/transition-service.js +25 -0
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.d.ts +2 -4
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/types.js +1 -4
- package/dist/rules/types.js.map +1 -1
- package/dist/sandbox/local-factory-sandbox.d.ts.map +1 -1
- package/dist/sandbox/local-factory-sandbox.js +1 -0
- package/dist/sandbox/local-factory-sandbox.js.map +1 -1
- package/dist/session/factory-session.d.ts +15 -1
- package/dist/session/factory-session.d.ts.map +1 -1
- package/dist/session/factory-session.js +4 -2
- package/dist/session/factory-session.js.map +1 -1
- package/dist/session/reply-credential-processor.d.ts +15 -0
- package/dist/session/reply-credential-processor.d.ts.map +1 -0
- package/dist/session/reply-credential-processor.js +40 -0
- package/dist/session/reply-credential-processor.js.map +1 -0
- package/dist/session/source-control-tools.d.ts +19 -1
- package/dist/session/source-control-tools.d.ts.map +1 -1
- package/dist/session/source-control-tools.js +70 -3
- package/dist/session/source-control-tools.js.map +1 -1
- package/dist/storage/domains/audit/domain.js +1 -1
- package/dist/storage/domains/projects/base.d.ts +6 -0
- package/dist/storage/domains/projects/base.d.ts.map +1 -1
- package/dist/storage/domains/projects/base.js +12 -0
- package/dist/storage/domains/projects/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +17 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +23 -0
- package/dist/storage/domains/source-control/base.js.map +1 -1
- package/dist/storage/domains/source-control/inmemory.d.ts +4 -0
- package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/source-control/inmemory.js +5 -1
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +56 -0
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +139 -25
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/tools/annotations.d.ts +7 -0
- package/dist/tools/annotations.d.ts.map +1 -0
- package/dist/tools/annotations.js +102 -0
- package/dist/tools/annotations.js.map +1 -0
- package/dist/tools/approval-tools.d.ts +15 -0
- package/dist/tools/approval-tools.d.ts.map +1 -0
- package/dist/tools/approval-tools.js +77 -0
- package/dist/tools/approval-tools.js.map +1 -0
- package/dist/tools/deliver.d.ts +54 -0
- package/dist/tools/deliver.d.ts.map +1 -0
- package/dist/tools/deliver.js +105 -0
- package/dist/tools/deliver.js.map +1 -0
- package/dist/tools/index.d.ts +29 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +39 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/messaging-tools.d.ts +28 -0
- package/dist/tools/messaging-tools.d.ts.map +1 -0
- package/dist/tools/messaging-tools.js +312 -0
- package/dist/tools/messaging-tools.js.map +1 -0
- package/dist/tools/permissions.d.ts +31 -0
- package/dist/tools/permissions.d.ts.map +1 -0
- package/dist/tools/permissions.js +44 -0
- package/dist/tools/permissions.js.map +1 -0
- package/dist/tools/read-tools.d.ts +27 -0
- package/dist/tools/read-tools.d.ts.map +1 -0
- package/dist/tools/read-tools.js +285 -0
- package/dist/tools/read-tools.js.map +1 -0
- package/dist/tools/reports.d.ts +163 -0
- package/dist/tools/reports.d.ts.map +1 -0
- package/dist/tools/reports.js +352 -0
- package/dist/tools/reports.js.map +1 -0
- package/dist/tools/run-watch.d.ts +46 -0
- package/dist/tools/run-watch.d.ts.map +1 -0
- package/dist/tools/run-watch.js +102 -0
- package/dist/tools/run-watch.js.map +1 -0
- package/dist/tools/scope.d.ts +45 -0
- package/dist/tools/scope.d.ts.map +1 -0
- package/dist/tools/scope.js +73 -0
- package/dist/tools/scope.js.map +1 -0
- package/dist/tools/session-tools.d.ts +31 -0
- package/dist/tools/session-tools.d.ts.map +1 -0
- package/dist/tools/session-tools.js +312 -0
- package/dist/tools/session-tools.js.map +1 -0
- package/dist/tools/sessions-state-processor.d.ts +37 -0
- package/dist/tools/sessions-state-processor.d.ts.map +1 -0
- package/dist/tools/sessions-state-processor.js +206 -0
- package/dist/tools/sessions-state-processor.js.map +1 -0
- package/dist/tools/work-item-tools.d.ts +28 -0
- package/dist/tools/work-item-tools.d.ts.map +1 -0
- package/dist/tools/work-item-tools.js +322 -0
- package/dist/tools/work-item-tools.js.map +1 -0
- package/dist/work-items/create-work-item.d.ts +55 -0
- package/dist/work-items/create-work-item.d.ts.map +1 -0
- package/dist/work-items/create-work-item.js +101 -0
- package/dist/work-items/create-work-item.js.map +1 -0
- package/dist/work-items/decision-actions.d.ts +42 -0
- package/dist/work-items/decision-actions.d.ts.map +1 -0
- package/dist/work-items/decision-actions.js +70 -0
- package/dist/work-items/decision-actions.js.map +1 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +3 -1
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-gitlab-rereview/SKILL.md +1 -1
- package/factory-skills/factory-gitlab-review/SKILL.md +1 -1
- package/factory-skills/factory-plan/SKILL.md +4 -4
- package/factory-skills/factory-rereview/SKILL.md +3 -1
- package/factory-skills/factory-review/SKILL.md +3 -1
- package/factory-skills/factory-self-review/SKILL.md +46 -0
- package/package.json +13 -11
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { boardForWorkItem } from "../boards/semantics.js";
|
|
2
|
+
import "../boards/index.js";
|
|
3
|
+
import { factoryDispatchFailureMetadata } from "../rules/dispatch-errors.js";
|
|
4
|
+
import { decisionRetryable, overtakenDecisionIds } from "../rules/decision-applicability.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { createTool } from "@mastra/core/tools";
|
|
7
|
+
//#region src/tools/read-tools.ts
|
|
8
|
+
const MAX_TEXT = 600;
|
|
9
|
+
const MAX_ERROR = 400;
|
|
10
|
+
const MAX_LIST = 50;
|
|
11
|
+
const DEFAULT_LIST = 25;
|
|
12
|
+
function truncate(text, max) {
|
|
13
|
+
return text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
14
|
+
}
|
|
15
|
+
function iso(value) {
|
|
16
|
+
if (!value) return null;
|
|
17
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
18
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
19
|
+
}
|
|
20
|
+
/** The number a person sees on the card: the issue or PR number the item was filed from. */
|
|
21
|
+
function workItemNumber(item) {
|
|
22
|
+
const number = item.metadata?.number ?? item.metadata?.githubIssueNumber ?? item.metadata?.githubPullRequestNumber;
|
|
23
|
+
return typeof number === "number" ? number : null;
|
|
24
|
+
}
|
|
25
|
+
function workItemStage(item) {
|
|
26
|
+
return item.stages.join("+");
|
|
27
|
+
}
|
|
28
|
+
/** A work item id or its card number; anything else can't name an item. */
|
|
29
|
+
const workItemRefSchema = z.string().trim().max(64).refine((ref) => z.string().uuid().safeParse(ref).success || /^#?\d+$/.test(ref), { message: "Use a work item id (UUID) or its number like \"#123\"." }).describe("Work item id, or its number like \"#123\".");
|
|
30
|
+
/** Resolve `<uuid>` or `#123` to an item in this Factory only. Pass a ref validated by `workItemRefSchema`. */
|
|
31
|
+
async function findWorkItem(workItems, scope, ref) {
|
|
32
|
+
const trimmed = ref.trim();
|
|
33
|
+
const number = /^#?(\d+)$/.exec(trimmed)?.[1];
|
|
34
|
+
if (number === void 0) return workItems.getForProject(scope.orgId, scope.factoryProjectId, trimmed);
|
|
35
|
+
const matches = (await workItems.list(scope)).filter((item) => workItemNumber(item) === Number(number));
|
|
36
|
+
return matches.find((item) => item.externalSource?.type !== "pull-request") ?? matches[0] ?? null;
|
|
37
|
+
}
|
|
38
|
+
function workItemNotFound(ref) {
|
|
39
|
+
return /* @__PURE__ */ new Error(`No work item ${ref} was found in this Factory.`);
|
|
40
|
+
}
|
|
41
|
+
function activeWorker(bindings, itemId) {
|
|
42
|
+
const binding = bindings.find((candidate) => candidate.workItemId === itemId && candidate.status === "active");
|
|
43
|
+
return binding ? {
|
|
44
|
+
role: binding.role,
|
|
45
|
+
sessionId: binding.sessionId
|
|
46
|
+
} : null;
|
|
47
|
+
}
|
|
48
|
+
function summarizeItem(item, bindings) {
|
|
49
|
+
return {
|
|
50
|
+
id: item.id,
|
|
51
|
+
number: workItemNumber(item),
|
|
52
|
+
title: truncate(item.title, 600),
|
|
53
|
+
board: boardForWorkItem(item),
|
|
54
|
+
stage: workItemStage(item),
|
|
55
|
+
activeWorker: activeWorker(bindings, item.id),
|
|
56
|
+
requestedBy: item.createdBy,
|
|
57
|
+
updatedAt: iso(item.updatedAt)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function summarizeDecision(decision, overtaken = false) {
|
|
61
|
+
const type = typeof decision.decision.type === "string" ? decision.decision.type : "decision";
|
|
62
|
+
const role = typeof decision.decision.role === "string" ? decision.decision.role : null;
|
|
63
|
+
return {
|
|
64
|
+
id: decision.id,
|
|
65
|
+
workItemId: decision.workItemId,
|
|
66
|
+
type,
|
|
67
|
+
role,
|
|
68
|
+
status: decision.status,
|
|
69
|
+
attempts: decision.attempts,
|
|
70
|
+
failureCode: decision.failureCode,
|
|
71
|
+
failureLabel: decision.failureCode ? factoryDispatchFailureMetadata(decision.failureCode).label : null,
|
|
72
|
+
canRetry: decisionRetryable(decision, overtaken),
|
|
73
|
+
error: decision.lastError ? truncate(decision.lastError, 400) : null,
|
|
74
|
+
approvedBy: decision.approvedBy,
|
|
75
|
+
updatedAt: iso(decision.updatedAt)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Held: a non-bug item triage parked until a person accepts it. */
|
|
79
|
+
function isHeld(item) {
|
|
80
|
+
return item.stages.includes("triage") && !!item.triageType && item.triageType !== "bug" && !item.acceptedAt;
|
|
81
|
+
}
|
|
82
|
+
const listInputSchema = z.object({
|
|
83
|
+
query: z.string().trim().min(1).max(200).optional().describe("Case-insensitive text in the title, or an exact card number like \"#123\"."),
|
|
84
|
+
stage: z.string().min(1).max(64).optional().describe("Only items in this stage, e.g. \"triage\" or \"review\"."),
|
|
85
|
+
board: z.string().min(1).max(64).optional().describe("Only items on this board, e.g. \"work\" or \"review\"."),
|
|
86
|
+
role: z.string().min(1).max(64).optional().describe("Only items that have a session for this role."),
|
|
87
|
+
active: z.boolean().optional().describe("true: only items with an agent working now; false: only idle items."),
|
|
88
|
+
requestedBy: z.literal("me").optional().describe("\"me\": only items you filed."),
|
|
89
|
+
subscribed: z.boolean().optional().describe("true: only items this session follows; false: only items it does not."),
|
|
90
|
+
limit: z.number().int().min(1).max(50).optional().describe(`Default ${DEFAULT_LIST}, max 50.`)
|
|
91
|
+
}).strict();
|
|
92
|
+
function createFactoryReadTools(scope, deps) {
|
|
93
|
+
const project = {
|
|
94
|
+
orgId: scope.orgId,
|
|
95
|
+
factoryProjectId: scope.factoryProjectId
|
|
96
|
+
};
|
|
97
|
+
return {
|
|
98
|
+
factory_list_work_items: createTool({
|
|
99
|
+
id: "factory_list_work_items",
|
|
100
|
+
description: "List this Factory's work items, newest activity first, with counts per stage for the whole Factory. Filter by text or #number, stage, board, role, whether an agent is working on it, items you filed, or items this session follows. Check here for an existing item before filing a new one.",
|
|
101
|
+
inputSchema: listInputSchema,
|
|
102
|
+
execute: async (input) => {
|
|
103
|
+
const [items, bindings, followed] = await Promise.all([
|
|
104
|
+
deps.workItems.list(project),
|
|
105
|
+
deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId),
|
|
106
|
+
input.subscribed === void 0 ? void 0 : deps.workItems.listSessionSubscriptions({
|
|
107
|
+
...project,
|
|
108
|
+
sessionId: scope.sessionId
|
|
109
|
+
})
|
|
110
|
+
]);
|
|
111
|
+
const followedIds = new Set(followed?.map((subscription) => subscription.workItemId));
|
|
112
|
+
const byStage = {};
|
|
113
|
+
for (const item of items) {
|
|
114
|
+
const stage = workItemStage(item);
|
|
115
|
+
byStage[stage] = (byStage[stage] ?? 0) + 1;
|
|
116
|
+
}
|
|
117
|
+
const numberQuery = input.query ? /^#(\d+)$/.exec(input.query)?.[1] : void 0;
|
|
118
|
+
const text = input.query?.toLowerCase();
|
|
119
|
+
const matches = items.filter((item) => {
|
|
120
|
+
if (numberQuery !== void 0) {
|
|
121
|
+
if (workItemNumber(item) !== Number(numberQuery)) return false;
|
|
122
|
+
} else if (text && !item.title.toLowerCase().includes(text)) return false;
|
|
123
|
+
if (input.stage && !item.stages.includes(input.stage)) return false;
|
|
124
|
+
if (input.board && boardForWorkItem(item) !== input.board) return false;
|
|
125
|
+
if (input.role && !item.sessions[input.role]) return false;
|
|
126
|
+
if (input.active !== void 0 && activeWorker(bindings, item.id) !== null !== input.active) return false;
|
|
127
|
+
if (input.requestedBy === "me" && item.createdBy !== scope.userId) return false;
|
|
128
|
+
if (input.subscribed !== void 0 && followedIds.has(item.id) !== input.subscribed) return false;
|
|
129
|
+
return true;
|
|
130
|
+
}).sort((left, right) => right.updatedAt.getTime() - left.updatedAt.getTime());
|
|
131
|
+
const limit = input.limit ?? DEFAULT_LIST;
|
|
132
|
+
return {
|
|
133
|
+
counts: {
|
|
134
|
+
total: items.length,
|
|
135
|
+
byStage
|
|
136
|
+
},
|
|
137
|
+
items: matches.slice(0, limit).map((item) => summarizeItem(item, bindings)),
|
|
138
|
+
truncated: matches.length > limit
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}),
|
|
142
|
+
factory_inspect_work_item: createTool({
|
|
143
|
+
id: "factory_inspect_work_item",
|
|
144
|
+
description: "Everything the Factory knows about one work item: stage history, sessions by role, decisions with errors, recent audit events, recent feed comments, labels, linked items and the sessions following it. Use it to explain why an item is where it is.",
|
|
145
|
+
inputSchema: z.object({ workItem: workItemRefSchema }).strict(),
|
|
146
|
+
execute: async ({ workItem }) => {
|
|
147
|
+
const item = await findWorkItem(deps.workItems, scope, workItem);
|
|
148
|
+
if (!item) throw workItemNotFound(workItem);
|
|
149
|
+
const [bindings, decisions, audit, feed, all, subscribers] = await Promise.all([
|
|
150
|
+
deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId, item.id),
|
|
151
|
+
deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, { workItemId: item.id }),
|
|
152
|
+
deps.audit.list({
|
|
153
|
+
...project,
|
|
154
|
+
limit: 200
|
|
155
|
+
}),
|
|
156
|
+
deps.comments.listRecent({
|
|
157
|
+
...project,
|
|
158
|
+
workItemId: item.id,
|
|
159
|
+
limit: 10
|
|
160
|
+
}),
|
|
161
|
+
deps.workItems.list(project),
|
|
162
|
+
deps.workItems.listWorkItemSubscribers({
|
|
163
|
+
orgId: scope.orgId,
|
|
164
|
+
workItemId: item.id
|
|
165
|
+
})
|
|
166
|
+
]);
|
|
167
|
+
const itemDecisions = decisions.slice(-50);
|
|
168
|
+
const overtaken = await overtakenDecisionIds(deps.workItems, deps.boards, project, itemDecisions.filter((decision) => decision.status === "failed"));
|
|
169
|
+
const labels = Array.isArray(item.metadata?.labels) ? item.metadata.labels.filter((label) => typeof label === "string").slice(0, 50) : [];
|
|
170
|
+
const parent = item.parentWorkItemId ? all.find((candidate) => candidate.id === item.parentWorkItemId) : void 0;
|
|
171
|
+
const children = all.filter((candidate) => candidate.parentWorkItemId === item.id);
|
|
172
|
+
return {
|
|
173
|
+
item: {
|
|
174
|
+
...summarizeItem(item, bindings),
|
|
175
|
+
source: item.externalSource ? `${item.externalSource.integrationId}:${item.externalSource.type}` : "manual",
|
|
176
|
+
url: typeof item.metadata?.url === "string" ? item.metadata.url : null,
|
|
177
|
+
triageType: item.triageType,
|
|
178
|
+
revision: item.revision
|
|
179
|
+
},
|
|
180
|
+
labels,
|
|
181
|
+
stageHistory: item.stageHistory.slice(-50).map((entry) => ({
|
|
182
|
+
stage: entry.stage,
|
|
183
|
+
enteredAt: entry.enteredAt,
|
|
184
|
+
exitedAt: entry.exitedAt ?? null,
|
|
185
|
+
by: entry.by
|
|
186
|
+
})),
|
|
187
|
+
sessions: Object.entries(item.sessions).map(([role, ref]) => ({
|
|
188
|
+
role,
|
|
189
|
+
sessionId: ref.sessionId,
|
|
190
|
+
threadId: ref.threadId,
|
|
191
|
+
startedBy: ref.startedBy,
|
|
192
|
+
active: bindings.some((binding) => binding.role === role && binding.sessionId === ref.sessionId && binding.status === "active")
|
|
193
|
+
})),
|
|
194
|
+
decisions: itemDecisions.map((decision) => summarizeDecision(decision, overtaken.has(decision.id))),
|
|
195
|
+
audit: audit.events.filter((event) => event.targets.some((target) => target.type === "work_item" && target.id === item.id)).slice(0, 25).map((event) => ({
|
|
196
|
+
action: event.action,
|
|
197
|
+
actorId: event.actorId,
|
|
198
|
+
actorType: event.actorType,
|
|
199
|
+
occurredAt: iso(event.occurredAt)
|
|
200
|
+
})),
|
|
201
|
+
feed: feed.map((comment) => ({
|
|
202
|
+
id: comment.id,
|
|
203
|
+
kind: comment.kind,
|
|
204
|
+
author: comment.author,
|
|
205
|
+
occurredAt: iso(comment.occurredAt),
|
|
206
|
+
body: truncate(comment.body, 600)
|
|
207
|
+
})),
|
|
208
|
+
parent: parent ? summarizeItem(parent, bindings) : null,
|
|
209
|
+
children: children.slice(0, 50).map((child) => summarizeItem(child, bindings)),
|
|
210
|
+
subscribers: subscribers.slice(0, 50).map((subscription) => ({
|
|
211
|
+
sessionId: subscription.sessionId,
|
|
212
|
+
reason: subscription.reason,
|
|
213
|
+
isCaller: subscription.sessionId === scope.sessionId
|
|
214
|
+
}))
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}),
|
|
218
|
+
factory_list_attention: createTool({
|
|
219
|
+
id: "factory_list_attention",
|
|
220
|
+
description: "What in this Factory needs a person: failed decisions grouped by failure code and error (one incident per group), proposals waiting for approval, and items triage is holding until someone accepts them.",
|
|
221
|
+
inputSchema: z.object({ limit: z.number().int().min(1).max(50).optional() }).strict(),
|
|
222
|
+
execute: async ({ limit = DEFAULT_LIST }) => {
|
|
223
|
+
const [decisions, items] = await Promise.all([deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, { statuses: ["failed", "proposed"] }), deps.workItems.list(project)]);
|
|
224
|
+
const itemsById = new Map(items.map((item) => [item.id, item]));
|
|
225
|
+
const failed = decisions.filter((decision) => decision.status === "failed");
|
|
226
|
+
const groups = /* @__PURE__ */ new Map();
|
|
227
|
+
for (const decision of failed) {
|
|
228
|
+
const error = truncate(decision.lastError ?? "", 400);
|
|
229
|
+
const key = `${decision.failureCode ?? "unknown"}|${error}`;
|
|
230
|
+
const group = groups.get(key) ?? {
|
|
231
|
+
failureCode: decision.failureCode ?? "unknown",
|
|
232
|
+
error,
|
|
233
|
+
decisions: []
|
|
234
|
+
};
|
|
235
|
+
group.decisions.push(decision);
|
|
236
|
+
groups.set(key, group);
|
|
237
|
+
}
|
|
238
|
+
const ref = (workItemId) => {
|
|
239
|
+
const item = workItemId ? itemsById.get(workItemId) : void 0;
|
|
240
|
+
return {
|
|
241
|
+
workItemId,
|
|
242
|
+
number: item ? workItemNumber(item) : null,
|
|
243
|
+
title: item ? truncate(item.title, 600) : null
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
const allIncidents = [...groups.values()].sort((a, b) => b.decisions.length - a.decisions.length);
|
|
247
|
+
const incidents = allIncidents.slice(0, limit).map((group) => ({
|
|
248
|
+
...group,
|
|
249
|
+
shown: group.decisions.slice(0, limit)
|
|
250
|
+
}));
|
|
251
|
+
const overtaken = await overtakenDecisionIds(deps.workItems, deps.boards, project, incidents.flatMap((group) => group.shown));
|
|
252
|
+
const proposals = decisions.filter((decision) => decision.status === "proposed");
|
|
253
|
+
const held = items.filter(isHeld);
|
|
254
|
+
return {
|
|
255
|
+
incidents: incidents.map((group) => ({
|
|
256
|
+
failureCode: group.failureCode,
|
|
257
|
+
failureLabel: factoryDispatchFailureMetadata(group.decisions[0].failureCode).label,
|
|
258
|
+
error: group.error,
|
|
259
|
+
count: group.decisions.length,
|
|
260
|
+
decisions: group.shown.map((decision) => ({
|
|
261
|
+
id: decision.id,
|
|
262
|
+
...ref(decision.workItemId),
|
|
263
|
+
attempts: decision.attempts,
|
|
264
|
+
canRetry: decisionRetryable(decision, overtaken.has(decision.id))
|
|
265
|
+
}))
|
|
266
|
+
})),
|
|
267
|
+
proposals: proposals.slice(0, limit).map((decision) => ({
|
|
268
|
+
...summarizeDecision(decision),
|
|
269
|
+
...ref(decision.workItemId)
|
|
270
|
+
})),
|
|
271
|
+
held: held.slice(0, limit).map((item) => ({
|
|
272
|
+
...ref(item.id),
|
|
273
|
+
triageType: item.triageType,
|
|
274
|
+
stage: workItemStage(item)
|
|
275
|
+
})),
|
|
276
|
+
truncated: allIncidents.length > limit || incidents.some((group) => group.shown.length < group.decisions.length) || proposals.length > limit || held.length > limit
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
//#endregion
|
|
283
|
+
export { MAX_ERROR, MAX_LIST, MAX_TEXT, createFactoryReadTools, findWorkItem, truncate, workItemNotFound, workItemNumber, workItemRefSchema, workItemStage };
|
|
284
|
+
|
|
285
|
+
//# sourceMappingURL=read-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-tools.js","names":[],"sources":["../../src/tools/read-tools.ts"],"sourcesContent":["import { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { boardForWorkItem } from '../boards/index.js';\nimport type { BoardRegistry } from '../boards/index.js';\nimport type { IntegrationTools } from '../integrations/base.js';\nimport { decisionRetryable, overtakenDecisionIds } from '../rules/decision-applicability.js';\nimport { factoryDispatchFailureMetadata } from '../rules/dispatch-errors.js';\nimport type { AuditStorage } from '../storage/domains/audit/base.js';\nimport type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';\nimport type {\n FactoryDeferredDecisionRecord,\n FactoryRunBindingRecord,\n WorkItemRow,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport type { FactoryToolScope } from './scope.js';\n\nexport const MAX_TEXT = 600;\nexport const MAX_ERROR = 400;\nexport const MAX_LIST = 50;\nconst DEFAULT_LIST = 25;\n\nexport interface FactoryReadToolDependencies {\n workItems: Pick<\n WorkItemsStorage,\n | 'list'\n | 'getForProject'\n | 'listRunBindings'\n | 'listDeferredDecisions'\n | 'listByIds'\n | 'listDecisionsForEvaluations'\n | 'listWorkItemSubscribers'\n | 'listSessionSubscriptions'\n >;\n comments: Pick<WorkItemCommentsStorage, 'listRecent'>;\n audit: Pick<AuditStorage, 'list'>;\n boards: BoardRegistry;\n}\n\nexport function truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction iso(value: Date | string | null | undefined): string | null {\n if (!value) return null;\n const date = value instanceof Date ? value : new Date(value);\n return Number.isFinite(date.getTime()) ? date.toISOString() : null;\n}\n\n/** The number a person sees on the card: the issue or PR number the item was filed from. */\nexport function workItemNumber(item: Pick<WorkItemRow, 'metadata'>): number | null {\n const number = item.metadata?.number ?? item.metadata?.githubIssueNumber ?? item.metadata?.githubPullRequestNumber;\n return typeof number === 'number' ? number : null;\n}\n\nexport function workItemStage(item: Pick<WorkItemRow, 'stages'>): string {\n return item.stages.join('+');\n}\n\n/** A work item id or its card number; anything else can't name an item. */\nexport const workItemRefSchema = z\n .string()\n .trim()\n .max(64)\n .refine(ref => z.string().uuid().safeParse(ref).success || /^#?\\d+$/.test(ref), {\n message: 'Use a work item id (UUID) or its number like \"#123\".',\n })\n .describe('Work item id, or its number like \"#123\".');\n\n/** Resolve `<uuid>` or `#123` to an item in this Factory only. Pass a ref validated by `workItemRefSchema`. */\nexport async function findWorkItem(\n workItems: Pick<WorkItemsStorage, 'list' | 'getForProject'>,\n scope: Pick<FactoryToolScope, 'orgId' | 'factoryProjectId'>,\n ref: string,\n): Promise<WorkItemRow | null> {\n const trimmed = ref.trim();\n const number = /^#?(\\d+)$/.exec(trimmed)?.[1];\n if (number === undefined) return workItems.getForProject(scope.orgId, scope.factoryProjectId, trimmed);\n const items = await workItems.list(scope);\n const matches = items.filter(item => workItemNumber(item) === Number(number));\n // Issue and PR numbers share a space on GitHub; prefer the Work-board card.\n return matches.find(item => item.externalSource?.type !== 'pull-request') ?? matches[0] ?? null;\n}\n\nexport function workItemNotFound(ref: string): Error {\n return new Error(`No work item ${ref} was found in this Factory.`);\n}\n\nfunction activeWorker(bindings: FactoryRunBindingRecord[], itemId: string) {\n const binding = bindings.find(candidate => candidate.workItemId === itemId && candidate.status === 'active');\n return binding ? { role: binding.role, sessionId: binding.sessionId } : null;\n}\n\nfunction summarizeItem(item: WorkItemRow, bindings: FactoryRunBindingRecord[]) {\n return {\n id: item.id,\n number: workItemNumber(item),\n title: truncate(item.title, MAX_TEXT),\n board: boardForWorkItem(item),\n stage: workItemStage(item),\n activeWorker: activeWorker(bindings, item.id),\n requestedBy: item.createdBy,\n updatedAt: iso(item.updatedAt),\n };\n}\n\nfunction summarizeDecision(decision: FactoryDeferredDecisionRecord, overtaken = false) {\n const type = typeof decision.decision.type === 'string' ? decision.decision.type : 'decision';\n const role = typeof decision.decision.role === 'string' ? decision.decision.role : null;\n return {\n id: decision.id,\n workItemId: decision.workItemId,\n type,\n role,\n status: decision.status,\n attempts: decision.attempts,\n failureCode: decision.failureCode,\n failureLabel: decision.failureCode ? factoryDispatchFailureMetadata(decision.failureCode).label : null,\n canRetry: decisionRetryable(decision, overtaken),\n error: decision.lastError ? truncate(decision.lastError, MAX_ERROR) : null,\n approvedBy: decision.approvedBy,\n updatedAt: iso(decision.updatedAt),\n };\n}\n\n/** Held: a non-bug item triage parked until a person accepts it. */\nfunction isHeld(item: WorkItemRow): boolean {\n return item.stages.includes('triage') && !!item.triageType && item.triageType !== 'bug' && !item.acceptedAt;\n}\n\nconst listInputSchema = z\n .object({\n query: z\n .string()\n .trim()\n .min(1)\n .max(200)\n .optional()\n .describe('Case-insensitive text in the title, or an exact card number like \"#123\".'),\n stage: z.string().min(1).max(64).optional().describe('Only items in this stage, e.g. \"triage\" or \"review\".'),\n board: z.string().min(1).max(64).optional().describe('Only items on this board, e.g. \"work\" or \"review\".'),\n role: z.string().min(1).max(64).optional().describe('Only items that have a session for this role.'),\n active: z.boolean().optional().describe('true: only items with an agent working now; false: only idle items.'),\n requestedBy: z.literal('me').optional().describe('\"me\": only items you filed.'),\n subscribed: z\n .boolean()\n .optional()\n .describe('true: only items this session follows; false: only items it does not.'),\n limit: z.number().int().min(1).max(MAX_LIST).optional().describe(`Default ${DEFAULT_LIST}, max ${MAX_LIST}.`),\n })\n .strict();\n\nexport function createFactoryReadTools(scope: FactoryToolScope, deps: FactoryReadToolDependencies): IntegrationTools {\n const project = { orgId: scope.orgId, factoryProjectId: scope.factoryProjectId };\n\n return {\n factory_list_work_items: createTool({\n id: 'factory_list_work_items',\n description:\n \"List this Factory's work items, newest activity first, with counts per stage for the whole Factory. Filter by text or #number, stage, board, role, whether an agent is working on it, items you filed, or items this session follows. Check here for an existing item before filing a new one.\",\n inputSchema: listInputSchema,\n execute: async input => {\n const [items, bindings, followed] = await Promise.all([\n deps.workItems.list(project),\n deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId),\n input.subscribed === undefined\n ? undefined\n : deps.workItems.listSessionSubscriptions({ ...project, sessionId: scope.sessionId }),\n ]);\n const followedIds = new Set(followed?.map(subscription => subscription.workItemId));\n const byStage: Record<string, number> = {};\n for (const item of items) {\n const stage = workItemStage(item);\n byStage[stage] = (byStage[stage] ?? 0) + 1;\n }\n const numberQuery = input.query ? /^#(\\d+)$/.exec(input.query)?.[1] : undefined;\n const text = input.query?.toLowerCase();\n const matches = items\n .filter(item => {\n if (numberQuery !== undefined) {\n if (workItemNumber(item) !== Number(numberQuery)) return false;\n } else if (text && !item.title.toLowerCase().includes(text)) return false;\n if (input.stage && !item.stages.includes(input.stage)) return false;\n if (input.board && boardForWorkItem(item) !== input.board) return false;\n if (input.role && !item.sessions[input.role]) return false;\n if (input.active !== undefined && (activeWorker(bindings, item.id) !== null) !== input.active) return false;\n if (input.requestedBy === 'me' && item.createdBy !== scope.userId) return false;\n if (input.subscribed !== undefined && followedIds.has(item.id) !== input.subscribed) return false;\n return true;\n })\n .sort((left, right) => right.updatedAt.getTime() - left.updatedAt.getTime());\n const limit = input.limit ?? DEFAULT_LIST;\n return {\n counts: { total: items.length, byStage },\n items: matches.slice(0, limit).map(item => summarizeItem(item, bindings)),\n truncated: matches.length > limit,\n };\n },\n }),\n\n factory_inspect_work_item: createTool({\n id: 'factory_inspect_work_item',\n description:\n 'Everything the Factory knows about one work item: stage history, sessions by role, decisions with errors, recent audit events, recent feed comments, labels, linked items and the sessions following it. Use it to explain why an item is where it is.',\n inputSchema: z.object({ workItem: workItemRefSchema }).strict(),\n execute: async ({ workItem }) => {\n const item = await findWorkItem(deps.workItems, scope, workItem);\n if (!item) throw workItemNotFound(workItem);\n const [bindings, decisions, audit, feed, all, subscribers] = await Promise.all([\n deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId, item.id),\n deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, { workItemId: item.id }),\n deps.audit.list({ ...project, limit: 200 }),\n deps.comments.listRecent({ ...project, workItemId: item.id, limit: 10 }),\n deps.workItems.list(project),\n deps.workItems.listWorkItemSubscribers({ orgId: scope.orgId, workItemId: item.id }),\n ]);\n const itemDecisions = decisions.slice(-MAX_LIST);\n const overtaken = await overtakenDecisionIds(\n deps.workItems,\n deps.boards,\n project,\n itemDecisions.filter(decision => decision.status === 'failed'),\n );\n const labels = Array.isArray(item.metadata?.labels)\n ? item.metadata.labels.filter((label): label is string => typeof label === 'string').slice(0, MAX_LIST)\n : [];\n const parent = item.parentWorkItemId\n ? all.find(candidate => candidate.id === item.parentWorkItemId)\n : undefined;\n const children = all.filter(candidate => candidate.parentWorkItemId === item.id);\n return {\n item: {\n ...summarizeItem(item, bindings),\n source: item.externalSource ? `${item.externalSource.integrationId}:${item.externalSource.type}` : 'manual',\n url: typeof item.metadata?.url === 'string' ? item.metadata.url : null,\n triageType: item.triageType,\n revision: item.revision,\n },\n labels,\n stageHistory: item.stageHistory.slice(-MAX_LIST).map(entry => ({\n stage: entry.stage,\n enteredAt: entry.enteredAt,\n exitedAt: entry.exitedAt ?? null,\n by: entry.by,\n })),\n sessions: Object.entries(item.sessions).map(([role, ref]) => ({\n role,\n sessionId: ref.sessionId,\n threadId: ref.threadId,\n startedBy: ref.startedBy,\n active: bindings.some(\n binding => binding.role === role && binding.sessionId === ref.sessionId && binding.status === 'active',\n ),\n })),\n decisions: itemDecisions.map(decision => summarizeDecision(decision, overtaken.has(decision.id))),\n audit: audit.events\n .filter(event => event.targets.some(target => target.type === 'work_item' && target.id === item.id))\n .slice(0, 25)\n .map(event => ({\n action: event.action,\n actorId: event.actorId,\n actorType: event.actorType,\n occurredAt: iso(event.occurredAt),\n })),\n feed: feed.map(comment => ({\n id: comment.id,\n kind: comment.kind,\n author: comment.author,\n occurredAt: iso(comment.occurredAt),\n body: truncate(comment.body, MAX_TEXT),\n })),\n parent: parent ? summarizeItem(parent, bindings) : null,\n children: children.slice(0, MAX_LIST).map(child => summarizeItem(child, bindings)),\n subscribers: subscribers.slice(0, MAX_LIST).map(subscription => ({\n sessionId: subscription.sessionId,\n reason: subscription.reason,\n isCaller: subscription.sessionId === scope.sessionId,\n })),\n };\n },\n }),\n\n factory_list_attention: createTool({\n id: 'factory_list_attention',\n description:\n 'What in this Factory needs a person: failed decisions grouped by failure code and error (one incident per group), proposals waiting for approval, and items triage is holding until someone accepts them.',\n inputSchema: z.object({ limit: z.number().int().min(1).max(MAX_LIST).optional() }).strict(),\n execute: async ({ limit = DEFAULT_LIST }) => {\n const [decisions, items] = await Promise.all([\n deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, {\n statuses: ['failed', 'proposed'],\n }),\n deps.workItems.list(project),\n ]);\n const itemsById = new Map(items.map(item => [item.id, item]));\n const failed = decisions.filter(decision => decision.status === 'failed');\n const groups = new Map<\n string,\n { failureCode: string; error: string; decisions: FactoryDeferredDecisionRecord[] }\n >();\n for (const decision of failed) {\n const error = truncate(decision.lastError ?? '', MAX_ERROR);\n const key = `${decision.failureCode ?? 'unknown'}|${error}`;\n const group = groups.get(key) ?? { failureCode: decision.failureCode ?? 'unknown', error, decisions: [] };\n group.decisions.push(decision);\n groups.set(key, group);\n }\n const ref = (workItemId: string | null) => {\n const item = workItemId ? itemsById.get(workItemId) : undefined;\n return {\n workItemId,\n number: item ? workItemNumber(item) : null,\n title: item ? truncate(item.title, MAX_TEXT) : null,\n };\n };\n const allIncidents = [...groups.values()].sort((a, b) => b.decisions.length - a.decisions.length);\n const incidents = allIncidents\n .slice(0, limit)\n .map(group => ({ ...group, shown: group.decisions.slice(0, limit) }));\n // Check exactly the decisions this call returns, so every canRetry is real.\n const overtaken = await overtakenDecisionIds(\n deps.workItems,\n deps.boards,\n project,\n incidents.flatMap(group => group.shown),\n );\n const proposals = decisions.filter(decision => decision.status === 'proposed');\n const held = items.filter(isHeld);\n return {\n incidents: incidents.map(group => ({\n failureCode: group.failureCode,\n failureLabel: factoryDispatchFailureMetadata(group.decisions[0]!.failureCode).label,\n error: group.error,\n count: group.decisions.length,\n decisions: group.shown.map(decision => ({\n id: decision.id,\n ...ref(decision.workItemId),\n attempts: decision.attempts,\n canRetry: decisionRetryable(decision, overtaken.has(decision.id)),\n })),\n })),\n proposals: proposals\n .slice(0, limit)\n .map(decision => ({ ...summarizeDecision(decision), ...ref(decision.workItemId) })),\n held: held.slice(0, limit).map(item => ({\n ...ref(item.id),\n triageType: item.triageType,\n stage: workItemStage(item),\n })),\n truncated:\n allIncidents.length > limit ||\n incidents.some(group => group.shown.length < group.decisions.length) ||\n proposals.length > limit ||\n held.length > limit,\n };\n },\n }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reports from sessions doing the work back to whoever follows it: a side
|
|
3
|
+
* session's origin, or every subscriber of a work item. The agent reports with
|
|
4
|
+
* `factory_message_origin`; when a run ends without one, the run-end backstop
|
|
5
|
+
* sends it, so each run produces exactly one final report per recipient.
|
|
6
|
+
*/
|
|
7
|
+
import type { NotificationPriority, NotificationsStorage, SendNotificationSignalInput } from '@mastra/core/notifications';
|
|
8
|
+
import type { SourceControlSessionLookup } from '../session/factory-session.js';
|
|
9
|
+
import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
|
|
10
|
+
import type { FactoryDeliveryResult, FactoryDeliveryTarget } from './deliver.js';
|
|
11
|
+
export type FactoryReportStatus = 'progress' | 'blocked' | 'done' | 'failed';
|
|
12
|
+
/** How each report status travels. Final reports never coalesce, so a later report can't overwrite them. */
|
|
13
|
+
export declare const FACTORY_REPORT_FORMS: Record<FactoryReportStatus | 'report', {
|
|
14
|
+
kind: string;
|
|
15
|
+
priority: NotificationPriority;
|
|
16
|
+
coalesce: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
export interface FactoryReportSender {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
threadId: string;
|
|
21
|
+
userId: string;
|
|
22
|
+
}
|
|
23
|
+
export type FactoryReportDeliver = (target: FactoryDeliveryTarget, notification: Omit<SendNotificationSignalInput, 'source'>, options?: {
|
|
24
|
+
onlyIfLive?: boolean;
|
|
25
|
+
}) => Promise<FactoryDeliveryResult>;
|
|
26
|
+
export interface FactoryReporting {
|
|
27
|
+
deliver: FactoryReportDeliver;
|
|
28
|
+
notifications: Pick<NotificationsStorage, 'listNotifications'>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Whether `senderSessionId` already put a report of one of `kinds` on the
|
|
32
|
+
* recipient thread since `since`. Reads the durable notifications store, so it
|
|
33
|
+
* holds across restarts. `listNotifications` has no time filter: records come
|
|
34
|
+
* newest-updated first, and the scan stops at the first one last updated
|
|
35
|
+
* before `since` (nothing after it can have been created later).
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasFinalReport(notifications: FactoryReporting['notifications'], { senderSessionId, recipientThreadId, since, kinds, agentOnly, }: {
|
|
38
|
+
senderSessionId: string;
|
|
39
|
+
recipientThreadId: string;
|
|
40
|
+
since: Date;
|
|
41
|
+
kinds: readonly string[];
|
|
42
|
+
/** Ignore reports Factory sent on the session's behalf (the backstop). */
|
|
43
|
+
agentOnly?: boolean;
|
|
44
|
+
}): Promise<boolean>;
|
|
45
|
+
export declare function reportNotification({ sender, status, message, attributes, }: {
|
|
46
|
+
sender: FactoryReportSender;
|
|
47
|
+
status?: FactoryReportStatus;
|
|
48
|
+
message: string;
|
|
49
|
+
attributes?: Record<string, string>;
|
|
50
|
+
}): Omit<SendNotificationSignalInput, 'source'>;
|
|
51
|
+
/** Everyone following a work item, except the session doing the reporting. */
|
|
52
|
+
export declare function workItemReportRecipients(workItems: Pick<WorkItemsStorage, 'listWorkItemSubscribers'>, { orgId, workItemId, senderSessionId }: {
|
|
53
|
+
orgId: string;
|
|
54
|
+
workItemId: string;
|
|
55
|
+
senderSessionId: string;
|
|
56
|
+
}): Promise<FactoryDeliveryTarget[]>;
|
|
57
|
+
/** Attributes that say which item and role a worker's report is about. */
|
|
58
|
+
export declare function workItemReportAttributes(workItems: Pick<WorkItemsStorage, 'getForProject'>, { orgId, factoryProjectId, workItemId, role, }: {
|
|
59
|
+
orgId: string;
|
|
60
|
+
factoryProjectId: string;
|
|
61
|
+
workItemId: string;
|
|
62
|
+
role: string;
|
|
63
|
+
}): Promise<{
|
|
64
|
+
label: string;
|
|
65
|
+
attributes: Record<string, string>;
|
|
66
|
+
}>;
|
|
67
|
+
export type FactoryRunOutcome = {
|
|
68
|
+
status: 'done';
|
|
69
|
+
} | {
|
|
70
|
+
status: 'failed';
|
|
71
|
+
reason: string;
|
|
72
|
+
failureCode?: string;
|
|
73
|
+
} | {
|
|
74
|
+
status: 'blocked';
|
|
75
|
+
toolName?: string;
|
|
76
|
+
approval?: boolean;
|
|
77
|
+
};
|
|
78
|
+
/** `waiting`: the session is waiting for an answer, so a later run owes the final report. */
|
|
79
|
+
export interface FactoryRunEndResult {
|
|
80
|
+
waiting: boolean;
|
|
81
|
+
deliveries?: FactoryDeliveryResult[];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The run-end backstop: send `outcome` to each recipient that hasn't had a
|
|
85
|
+
* final report from this sender since the run started. An agent's own `done`
|
|
86
|
+
* or `failed` report wins. A run that completes after the agent's own
|
|
87
|
+
* `blocked` sends nothing: the agent ended its turn to wait for an answer, and
|
|
88
|
+
* its `done` comes from a later run. A `failed` backstop still goes out after an
|
|
89
|
+
* earlier `blocked`.
|
|
90
|
+
*/
|
|
91
|
+
export declare function sendRunEndReport(reporting: FactoryReporting, { sender, recipients, since, outcome, subject, attributes, }: {
|
|
92
|
+
sender: FactoryReportSender;
|
|
93
|
+
recipients: FactoryDeliveryTarget[];
|
|
94
|
+
since: Date;
|
|
95
|
+
outcome: FactoryRunOutcome;
|
|
96
|
+
/** Who finished, e.g. "The work session for #12". */
|
|
97
|
+
subject: string;
|
|
98
|
+
attributes?: Record<string, string>;
|
|
99
|
+
}): Promise<FactoryRunEndResult>;
|
|
100
|
+
export interface FactoryRunEndInput {
|
|
101
|
+
orgId: string;
|
|
102
|
+
factoryProjectId: string;
|
|
103
|
+
workItemId: string;
|
|
104
|
+
role: string;
|
|
105
|
+
sender: FactoryReportSender;
|
|
106
|
+
since: Date;
|
|
107
|
+
outcome: FactoryRunOutcome;
|
|
108
|
+
}
|
|
109
|
+
export type FactoryRunEndReporter = (input: FactoryRunEndInput) => Promise<FactoryRunEndResult>;
|
|
110
|
+
/** The backstop for a work-item run: reports to the item's subscribers. Failures are logged, never thrown. */
|
|
111
|
+
export declare function createWorkItemRunEndReporter({ workItems, reporting, }: {
|
|
112
|
+
workItems: Pick<WorkItemsStorage, 'listWorkItemSubscribers' | 'getForProject'>;
|
|
113
|
+
/** Resolved per report: the controller exists only once the mount is up. */
|
|
114
|
+
reporting: () => Promise<FactoryReporting | null>;
|
|
115
|
+
}): FactoryRunEndReporter;
|
|
116
|
+
export interface FactoryStageChange {
|
|
117
|
+
orgId: string;
|
|
118
|
+
factoryProjectId: string;
|
|
119
|
+
workItemId: string;
|
|
120
|
+
fromStage: string | undefined;
|
|
121
|
+
toStage: string;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Tells a work item's subscribers it moved, at `low` priority. Only sessions
|
|
125
|
+
* already live hear it: a stage change never brings a session online; an
|
|
126
|
+
* offline subscriber sees the stage in its state signal on its next turn.
|
|
127
|
+
*/
|
|
128
|
+
export declare function createStageChangeNotifier({ workItems, reporting, }: {
|
|
129
|
+
workItems: Pick<WorkItemsStorage, 'listWorkItemSubscribers' | 'getForProject'>;
|
|
130
|
+
reporting: () => Promise<FactoryReporting | null>;
|
|
131
|
+
}): (change: FactoryStageChange) => Promise<void>;
|
|
132
|
+
/** Reports one run end of a session; the thread is the one the run used. */
|
|
133
|
+
export type FactorySessionRunEndReporter = (input: {
|
|
134
|
+
sessionId: string;
|
|
135
|
+
threadId: string | null;
|
|
136
|
+
outcome: FactoryRunOutcome;
|
|
137
|
+
since: Date;
|
|
138
|
+
}) => Promise<void>;
|
|
139
|
+
/** A tool call a session's run is holding until someone approves or declines it. */
|
|
140
|
+
export interface FactoryApprovalRequest {
|
|
141
|
+
sessionId: string;
|
|
142
|
+
threadId: string | null;
|
|
143
|
+
toolName: string;
|
|
144
|
+
toolCallId: string;
|
|
145
|
+
args: unknown;
|
|
146
|
+
}
|
|
147
|
+
export type FactoryApprovalNotifier = (request: FactoryApprovalRequest) => Promise<void>;
|
|
148
|
+
interface SessionReportDependencies {
|
|
149
|
+
sessions: Pick<SourceControlSessionLookup, 'getBySessionId'>;
|
|
150
|
+
workItems: Pick<WorkItemsStorage, 'findActiveRunBindingForSession' | 'findRunBindingBySession' | 'listWorkItemSubscribers' | 'getForProject'>;
|
|
151
|
+
reporting: () => Promise<FactoryReporting | null>;
|
|
152
|
+
}
|
|
153
|
+
/** Reports each run end of a work or side session to whoever follows it. */
|
|
154
|
+
export declare function createSessionRunEndReporter(deps: SessionReportDependencies): FactorySessionRunEndReporter;
|
|
155
|
+
/**
|
|
156
|
+
* Tells whoever follows a session, urgently, the moment its run holds a tool
|
|
157
|
+
* call for approval. The run stays open on the gate, so no run end would say
|
|
158
|
+
* so; the notice names the session and call so a follower can answer it with
|
|
159
|
+
* `factory_answer_approval`.
|
|
160
|
+
*/
|
|
161
|
+
export declare function createSessionApprovalNotifier(deps: SessionReportDependencies): FactoryApprovalNotifier;
|
|
162
|
+
export {};
|
|
163
|
+
//# sourceMappingURL=reports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reports.d.ts","sourceRoot":"","sources":["../../src/tools/reports.ts"],"names":[],"mappings":"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"}
|