@mastra/factory 0.23.0 → 0.24.0-alpha.0
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 +3 -3
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +15 -65
- package/dist/factory.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/integrations/github/session-subscriptions.js +1 -1
- package/dist/integrations/slack/slack.js +1 -1
- package/dist/routes/attention-providers.d.ts +0 -17
- package/dist/routes/attention-providers.d.ts.map +1 -1
- package/dist/routes/attention-providers.js +2 -128
- package/dist/routes/attention-providers.js.map +1 -1
- package/dist/routes/attention.d.ts.map +1 -1
- package/dist/routes/attention.js +1 -2
- package/dist/routes/attention.js.map +1 -1
- package/dist/routes/config.d.ts +0 -28
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +4 -78
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/contracts.d.ts +19 -35
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/contracts.js +4 -24
- package/dist/routes/contracts.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +3 -2
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/surface.d.ts +0 -2
- package/dist/routes/surface.d.ts.map +1 -1
- package/dist/routes/surface.js +4 -5
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.d.ts.map +1 -1
- package/dist/routes/work-items.js +1 -7
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/processor.d.ts +3 -0
- package/dist/rules/processor.d.ts.map +1 -1
- package/dist/rules/processor.js +3 -3
- package/dist/rules/processor.js.map +1 -1
- package/dist/session/credential-policy.d.ts.map +1 -1
- package/dist/session/credential-policy.js +0 -15
- package/dist/session/credential-policy.js.map +1 -1
- package/dist/session/factory-session.js +2 -2
- package/dist/session/thinking-default.d.ts +18 -0
- package/dist/session/thinking-default.d.ts.map +1 -0
- package/dist/session/thinking-default.js +42 -0
- package/dist/session/thinking-default.js.map +1 -0
- package/dist/storage/domains/audit/domain.d.ts +1 -1
- package/dist/storage/domains/audit/domain.d.ts.map +1 -1
- package/dist/storage/domains/audit/domain.js.map +1 -1
- package/dist/storage/domains/projects/base.d.ts +5 -0
- package/dist/storage/domains/projects/base.d.ts.map +1 -1
- package/dist/storage/domains/projects/base.js +9 -1
- package/dist/storage/domains/projects/base.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts +1 -36
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +2 -144
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/telemetry-types.d.ts +1 -1
- package/dist/telemetry-types.d.ts.map +1 -1
- package/dist/telemetry-types.js +0 -1
- package/dist/telemetry-types.js.map +1 -1
- package/dist/workspace.d.ts +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +1 -11
- package/dist/workspace.js.map +1 -1
- package/factory-skills/configure-factory-rules/SKILL.md +2 -2
- package/package.json +11 -11
- package/dist/routes/supervisor.d.ts +0 -25
- package/dist/routes/supervisor.d.ts.map +0 -1
- package/dist/routes/supervisor.js +0 -35
- package/dist/routes/supervisor.js.map +0 -1
- package/dist/supervisor/health-worker.d.ts +0 -19
- package/dist/supervisor/health-worker.d.ts.map +0 -1
- package/dist/supervisor/health-worker.js +0 -74
- package/dist/supervisor/health-worker.js.map +0 -1
- package/dist/supervisor/health.d.ts +0 -79
- package/dist/supervisor/health.d.ts.map +0 -1
- package/dist/supervisor/health.js +0 -228
- package/dist/supervisor/health.js.map +0 -1
- package/dist/supervisor/instructions.d.ts +0 -6
- package/dist/supervisor/instructions.d.ts.map +0 -1
- package/dist/supervisor/instructions.js +0 -66
- package/dist/supervisor/instructions.js.map +0 -1
- package/dist/supervisor/read-tools.d.ts +0 -43
- package/dist/supervisor/read-tools.d.ts.map +0 -1
- package/dist/supervisor/read-tools.js +0 -343
- package/dist/supervisor/read-tools.js.map +0 -1
- package/dist/supervisor/session-messaging.d.ts +0 -26
- package/dist/supervisor/session-messaging.d.ts.map +0 -1
- package/dist/supervisor/session-messaging.js +0 -21
- package/dist/supervisor/session-messaging.js.map +0 -1
- package/dist/supervisor/session.d.ts +0 -38
- package/dist/supervisor/session.d.ts.map +0 -1
- package/dist/supervisor/session.js +0 -79
- package/dist/supervisor/session.js.map +0 -1
- package/dist/supervisor/write-tools.d.ts +0 -30
- package/dist/supervisor/write-tools.d.ts.map +0 -1
- package/dist/supervisor/write-tools.js +0 -231
- package/dist/supervisor/write-tools.js.map +0 -1
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
//#region src/supervisor/instructions.ts
|
|
2
|
-
/**
|
|
3
|
-
* The supervisor's playbook. Lives in code (not a workspace skill) because
|
|
4
|
-
* the supervisor session has no checkout to load skills from.
|
|
5
|
-
*/
|
|
6
|
-
const SUPERVISOR_INSTRUCTIONS = `# Factory supervisor
|
|
7
|
-
|
|
8
|
-
You supervise one Software Factory: a pipeline of cards (work items) that move
|
|
9
|
-
intake → triage → planning → execute → review → done|canceled. Four agent roles
|
|
10
|
-
(triage, plan, work, review) each hold a *seat* (run binding) on a card while
|
|
11
|
-
they act on it; every role on a card shares one session thread. Typed rules
|
|
12
|
-
emit *decisions* (invoke a skill, send a message, sync a linked card, …) that a
|
|
13
|
-
dispatcher executes with retries; a decision that exhausts its retries is
|
|
14
|
-
*failed* and shows the card red. Some decisions are *proposals* parked for a
|
|
15
|
-
person to approve. Non-bug cards are *held* in triage until a maintainer
|
|
16
|
-
accepts them.
|
|
17
|
-
|
|
18
|
-
You have no repository and no sandbox. Everything you know comes from the
|
|
19
|
-
\`factory_*\` tools, which read the Factory's own records.
|
|
20
|
-
|
|
21
|
-
## How to answer
|
|
22
|
-
|
|
23
|
-
- Ground every claim in a tool result. Quote ids (card number, decision id,
|
|
24
|
-
seat id, thread id) and timestamps so the person can click through. Never
|
|
25
|
-
guess at a cause the records do not show.
|
|
26
|
-
- Start with \`factory_health_check\` for "what's wrong", \`factory_list_attention\`
|
|
27
|
-
for "what needs me", and \`factory_inspect_work_item\` for questions about one
|
|
28
|
-
card. Use
|
|
29
|
-
\`factory_read_session\` only when the records don't explain a card and the
|
|
30
|
-
worker's own transcript might.
|
|
31
|
-
- Lead with the answer, then the evidence, then the standard repair. Keep it
|
|
32
|
-
short; the person will ask for more.
|
|
33
|
-
- Group like with like: several cards failing with the same code and error at
|
|
34
|
-
the same time are one incident, not several.
|
|
35
|
-
|
|
36
|
-
## Reading the records
|
|
37
|
-
|
|
38
|
-
- Failed decisions and proposals waiting on a person are not health findings;
|
|
39
|
-
the board and the attention inbox already carry them. Read them with
|
|
40
|
-
\`factory_list_attention\`. A failed decision whose cause was transient (a
|
|
41
|
-
restart, a fixed bug, a rate limit) will succeed on retry; one whose card
|
|
42
|
-
already moved past its role is moot and should be dismissed, not retried.
|
|
43
|
-
- \`decision-stuck\` — retry/pending past its backoff, or a lease that
|
|
44
|
-
expired: the dispatcher is not picking it up. Usually a stalled process.
|
|
45
|
-
- \`seat-missing\` — a card sits in a working lane with nobody bound to it
|
|
46
|
-
and nothing in flight; it will not progress until a run is started.
|
|
47
|
-
- \`seat-orphaned\` — a seat is active on a card that already finished or
|
|
48
|
-
left that role's lane; a lifecycle bug left it behind.
|
|
49
|
-
- \`start-stalled\` — a run was asked for but the kickoff never landed.
|
|
50
|
-
- \`held-waiting\` — a maintainer is the blocker. Say so plainly and name
|
|
51
|
-
what they need to decide.
|
|
52
|
-
- \`label-drift\` — the GitHub labels disagree with the card's accepted
|
|
53
|
-
state; reconcile its acceptance labels after confirming the repair.
|
|
54
|
-
|
|
55
|
-
## Repairs
|
|
56
|
-
|
|
57
|
-
Write tools require confirmation and are recorded against the person who
|
|
58
|
-
asked. Use the repair suggested by the health finding: retry or dismiss a
|
|
59
|
-
decision, accept a held card, approve or dismiss a proposal, revoke an
|
|
60
|
-
orphaned seat, signal a worker, or reconcile stale acceptance labels. Never
|
|
61
|
-
claim a repair happened unless a tool result says it did.
|
|
62
|
-
`;
|
|
63
|
-
//#endregion
|
|
64
|
-
export { SUPERVISOR_INSTRUCTIONS };
|
|
65
|
-
|
|
66
|
-
//# sourceMappingURL=instructions.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.js","names":[],"sources":["../../src/supervisor/instructions.ts"],"sourcesContent":["/**\n * The supervisor's playbook. Lives in code (not a workspace skill) because\n * the supervisor session has no checkout to load skills from.\n */\nexport const SUPERVISOR_INSTRUCTIONS = `# Factory supervisor\n\nYou supervise one Software Factory: a pipeline of cards (work items) that move\nintake → triage → planning → execute → review → done|canceled. Four agent roles\n(triage, plan, work, review) each hold a *seat* (run binding) on a card while\nthey act on it; every role on a card shares one session thread. Typed rules\nemit *decisions* (invoke a skill, send a message, sync a linked card, …) that a\ndispatcher executes with retries; a decision that exhausts its retries is\n*failed* and shows the card red. Some decisions are *proposals* parked for a\nperson to approve. Non-bug cards are *held* in triage until a maintainer\naccepts them.\n\nYou have no repository and no sandbox. Everything you know comes from the\n\\`factory_*\\` tools, which read the Factory's own records.\n\n## How to answer\n\n- Ground every claim in a tool result. Quote ids (card number, decision id,\n seat id, thread id) and timestamps so the person can click through. Never\n guess at a cause the records do not show.\n- Start with \\`factory_health_check\\` for \"what's wrong\", \\`factory_list_attention\\`\n for \"what needs me\", and \\`factory_inspect_work_item\\` for questions about one\n card. Use\n \\`factory_read_session\\` only when the records don't explain a card and the\n worker's own transcript might.\n- Lead with the answer, then the evidence, then the standard repair. Keep it\n short; the person will ask for more.\n- Group like with like: several cards failing with the same code and error at\n the same time are one incident, not several.\n\n## Reading the records\n\n- Failed decisions and proposals waiting on a person are not health findings;\n the board and the attention inbox already carry them. Read them with\n \\`factory_list_attention\\`. A failed decision whose cause was transient (a\n restart, a fixed bug, a rate limit) will succeed on retry; one whose card\n already moved past its role is moot and should be dismissed, not retried.\n- \\`decision-stuck\\` — retry/pending past its backoff, or a lease that\n expired: the dispatcher is not picking it up. Usually a stalled process.\n- \\`seat-missing\\` — a card sits in a working lane with nobody bound to it\n and nothing in flight; it will not progress until a run is started.\n- \\`seat-orphaned\\` — a seat is active on a card that already finished or\n left that role's lane; a lifecycle bug left it behind.\n- \\`start-stalled\\` — a run was asked for but the kickoff never landed.\n- \\`held-waiting\\` — a maintainer is the blocker. Say so plainly and name\n what they need to decide.\n- \\`label-drift\\` — the GitHub labels disagree with the card's accepted\n state; reconcile its acceptance labels after confirming the repair.\n\n## Repairs\n\nWrite tools require confirmation and are recorded against the person who\nasked. Use the repair suggested by the health finding: retry or dismiss a\ndecision, accept a held card, approve or dismiss a proposal, revoke an\norphaned seat, signal a worker, or reconcile stale acceptance labels. Never\nclaim a repair happened unless a tool result says it did.\n`;\n"],"mappings":";;;;;AAIA,MAAa,0BAA0B"}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Supervisor read surface. Every tool is bounded (hard row caps, truncated
|
|
3
|
-
* text) and answers with ids a person can click on the board, so the model
|
|
4
|
-
* can explain a card's state without ever touching the database itself.
|
|
5
|
-
*/
|
|
6
|
-
import type { MastraDBMessage } from '@mastra/core/agent/message-list';
|
|
7
|
-
import type { BoardRegistry } from '../boards/index.js';
|
|
8
|
-
import type { IntegrationTools } from '../integrations/base.js';
|
|
9
|
-
import type { AuditStorage } from '../storage/domains/audit/base.js';
|
|
10
|
-
import type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';
|
|
11
|
-
import type { WorkItemsStorage } from '../storage/domains/work-items/base.js';
|
|
12
|
-
import type { FactoryHealthThresholds } from './health.js';
|
|
13
|
-
export interface SupervisorScope {
|
|
14
|
-
orgId: string;
|
|
15
|
-
factoryProjectId: string;
|
|
16
|
-
}
|
|
17
|
-
export interface SupervisorMessageReader {
|
|
18
|
-
listMessages(input: {
|
|
19
|
-
threadId: string;
|
|
20
|
-
resourceId?: string;
|
|
21
|
-
page: number;
|
|
22
|
-
perPage: number;
|
|
23
|
-
orderBy: {
|
|
24
|
-
field: 'createdAt';
|
|
25
|
-
direction: 'ASC' | 'DESC';
|
|
26
|
-
};
|
|
27
|
-
}): Promise<{
|
|
28
|
-
messages: MastraDBMessage[];
|
|
29
|
-
hasMore: boolean;
|
|
30
|
-
}>;
|
|
31
|
-
}
|
|
32
|
-
export interface SupervisorReadDependencies {
|
|
33
|
-
scope: SupervisorScope;
|
|
34
|
-
workItems: WorkItemsStorage;
|
|
35
|
-
boards: BoardRegistry;
|
|
36
|
-
comments: WorkItemCommentsStorage;
|
|
37
|
-
audit: AuditStorage;
|
|
38
|
-
messageReader?: SupervisorMessageReader;
|
|
39
|
-
healthThresholds?: FactoryHealthThresholds;
|
|
40
|
-
now?: () => Date;
|
|
41
|
-
}
|
|
42
|
-
export declare function createFactorySupervisorReadTools(deps: SupervisorReadDependencies): IntegrationTools;
|
|
43
|
-
//# sourceMappingURL=read-tools.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"read-tools.d.ts","sourceRoot":"","sources":["../../src/supervisor/read-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAIvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAKhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,KAAK,EAGV,gBAAgB,EACjB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,KAAK,EAAuB,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGhF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC,YAAY,CAAC,KAAK,EAAE;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE;YAAE,KAAK,EAAE,WAAW,CAAC;YAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;SAAE,CAAC;KAC5D,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,EAAE,eAAe,CAAC;IACvB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,KAAK,EAAE,YAAY,CAAC;IACpB,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,gBAAgB,CAAC,EAAE,uBAAuB,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAmID,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,0BAA0B,GAAG,gBAAgB,CA8PnG"}
|
|
@@ -1,343 +0,0 @@
|
|
|
1
|
-
import { FACTORY_RULE_STAGES, factoryRuleStage } from "../rules/types.js";
|
|
2
|
-
import { factoryDispatchFailureMetadata } from "../rules/dispatch-errors.js";
|
|
3
|
-
import { decisionRetryable, overtakenDecisionIds } from "../rules/decision-applicability.js";
|
|
4
|
-
import { runFactoryHealthCheck } from "./health.js";
|
|
5
|
-
import { z } from "zod";
|
|
6
|
-
import { createTool } from "@mastra/core/tools";
|
|
7
|
-
//#region src/supervisor/read-tools.ts
|
|
8
|
-
const MAX_TEXT = 600;
|
|
9
|
-
const MAX_ERROR = 400;
|
|
10
|
-
const MAX_LIST = 50;
|
|
11
|
-
function truncate(text, max) {
|
|
12
|
-
return text.length > max ? `${text.slice(0, max - 1)}…` : text;
|
|
13
|
-
}
|
|
14
|
-
function iso(value) {
|
|
15
|
-
if (!value) return null;
|
|
16
|
-
const date = value instanceof Date ? value : new Date(value);
|
|
17
|
-
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
18
|
-
}
|
|
19
|
-
function itemNumber(item) {
|
|
20
|
-
const number = item.metadata?.number ?? item.metadata?.githubIssueNumber ?? item.metadata?.githubPullRequestNumber;
|
|
21
|
-
return typeof number === "number" ? number : null;
|
|
22
|
-
}
|
|
23
|
-
function itemLabels(item) {
|
|
24
|
-
const labels = item.metadata?.labels;
|
|
25
|
-
return Array.isArray(labels) ? labels.filter((label) => typeof label === "string") : [];
|
|
26
|
-
}
|
|
27
|
-
function summarizeItem(item) {
|
|
28
|
-
return {
|
|
29
|
-
id: item.id,
|
|
30
|
-
number: itemNumber(item),
|
|
31
|
-
title: item.title,
|
|
32
|
-
stage: factoryRuleStage(item.stages) ?? item.stages.join("+"),
|
|
33
|
-
source: item.externalSource ? `${item.externalSource.integrationId}:${item.externalSource.type}` : "manual",
|
|
34
|
-
url: typeof item.metadata?.url === "string" ? item.metadata.url : null,
|
|
35
|
-
triageType: item.triageType,
|
|
36
|
-
acceptedAt: iso(item.acceptedAt),
|
|
37
|
-
autonomyArmedAt: iso(item.autonomyArmedAt),
|
|
38
|
-
parentWorkItemId: item.parentWorkItemId,
|
|
39
|
-
revision: item.revision,
|
|
40
|
-
updatedAt: iso(item.updatedAt)
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
function summarizeDecision(decision, overtaken = false) {
|
|
44
|
-
const type = typeof decision.decision.type === "string" ? decision.decision.type : "decision";
|
|
45
|
-
const role = typeof decision.decision.role === "string" ? decision.decision.role : null;
|
|
46
|
-
const skill = typeof decision.decision.skillName === "string" ? decision.decision.skillName : null;
|
|
47
|
-
return {
|
|
48
|
-
id: decision.id,
|
|
49
|
-
workItemId: decision.workItemId,
|
|
50
|
-
type,
|
|
51
|
-
role,
|
|
52
|
-
skill,
|
|
53
|
-
status: decision.status,
|
|
54
|
-
attempts: decision.attempts,
|
|
55
|
-
availableAt: iso(decision.availableAt),
|
|
56
|
-
leaseOwner: decision.leaseOwner,
|
|
57
|
-
leaseExpiresAt: iso(decision.leaseExpiresAt),
|
|
58
|
-
failureCode: decision.failureCode,
|
|
59
|
-
failureLabel: decision.failureCode ? factoryDispatchFailureMetadata(decision.failureCode).label : null,
|
|
60
|
-
canRetry: decisionRetryable(decision, overtaken),
|
|
61
|
-
lastError: decision.lastError ? truncate(decision.lastError, MAX_ERROR) : null,
|
|
62
|
-
approvedBy: decision.approvedBy,
|
|
63
|
-
createdAt: iso(decision.createdAt),
|
|
64
|
-
updatedAt: iso(decision.updatedAt),
|
|
65
|
-
completedAt: iso(decision.completedAt)
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function messageParts(content) {
|
|
69
|
-
if (Array.isArray(content)) return content;
|
|
70
|
-
if (content && typeof content === "object") {
|
|
71
|
-
const parts = content.parts;
|
|
72
|
-
if (Array.isArray(parts)) return parts;
|
|
73
|
-
}
|
|
74
|
-
return [];
|
|
75
|
-
}
|
|
76
|
-
function messageText(message) {
|
|
77
|
-
const content = message.content;
|
|
78
|
-
const parts = messageParts(content);
|
|
79
|
-
const text = [];
|
|
80
|
-
for (const part of parts) if (part && typeof part === "object" && part.type === "text") {
|
|
81
|
-
const value = part.text;
|
|
82
|
-
if (typeof value === "string") text.push(value);
|
|
83
|
-
}
|
|
84
|
-
if (text.length === 0 && typeof content === "string") text.push(content);
|
|
85
|
-
return text.join("\n");
|
|
86
|
-
}
|
|
87
|
-
function messageToolCalls(message) {
|
|
88
|
-
const parts = messageParts(message.content);
|
|
89
|
-
const calls = [];
|
|
90
|
-
for (const rawPart of parts) {
|
|
91
|
-
if (!rawPart || typeof rawPart !== "object") continue;
|
|
92
|
-
const part = rawPart;
|
|
93
|
-
const invocation = part.type === "tool-invocation" && part.toolInvocation && typeof part.toolInvocation === "object" ? part.toolInvocation : typeof part.type === "string" && part.type.startsWith("tool-") ? part : void 0;
|
|
94
|
-
if (!invocation) continue;
|
|
95
|
-
const name = invocation.toolName ?? invocation.name ?? (typeof part.type === "string" ? part.type.slice(5) : null);
|
|
96
|
-
if (typeof name !== "string") continue;
|
|
97
|
-
calls.push({
|
|
98
|
-
tool: name,
|
|
99
|
-
state: typeof invocation.state === "string" ? invocation.state : null
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
return calls;
|
|
103
|
-
}
|
|
104
|
-
async function findItem(deps, ref) {
|
|
105
|
-
if (ref.id) return deps.workItems.getForProject(deps.scope.orgId, deps.scope.factoryProjectId, ref.id);
|
|
106
|
-
if (ref.number === void 0) return null;
|
|
107
|
-
const matches = (await deps.workItems.list(deps.scope)).filter((item) => itemNumber(item) === ref.number);
|
|
108
|
-
return matches.find((item) => item.externalSource?.type !== "pull-request") ?? matches[0] ?? null;
|
|
109
|
-
}
|
|
110
|
-
const itemRefSchema = z.object({
|
|
111
|
-
id: z.string().uuid().optional().describe("Work item id."),
|
|
112
|
-
number: z.number().int().positive().optional().describe("Card number as shown on the board, e.g. 22874.")
|
|
113
|
-
}).refine((ref) => ref.id !== void 0 || ref.number !== void 0, { message: "Provide an id or a number." });
|
|
114
|
-
function createFactorySupervisorReadTools(deps) {
|
|
115
|
-
const now = deps.now ?? (() => /* @__PURE__ */ new Date());
|
|
116
|
-
const scope = deps.scope;
|
|
117
|
-
return {
|
|
118
|
-
factory_overview: createTool({
|
|
119
|
-
id: "factory_overview",
|
|
120
|
-
description: "Counts per pipeline stage, decisions by status, active seats, open proposals and held cards for this Factory. Start here for \"what needs me\" questions.",
|
|
121
|
-
inputSchema: z.object({}).strict(),
|
|
122
|
-
execute: async () => {
|
|
123
|
-
const [items, decisions, bindings, pendingStarts] = await Promise.all([
|
|
124
|
-
deps.workItems.list(scope),
|
|
125
|
-
deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId),
|
|
126
|
-
deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId),
|
|
127
|
-
deps.workItems.listPendingStarts(scope.orgId, scope.factoryProjectId)
|
|
128
|
-
]);
|
|
129
|
-
const stages = Object.fromEntries(FACTORY_RULE_STAGES.map((stage) => [stage, 0]));
|
|
130
|
-
let held = 0;
|
|
131
|
-
for (const item of items) {
|
|
132
|
-
const stage = factoryRuleStage(item.stages);
|
|
133
|
-
if (stage) stages[stage] += 1;
|
|
134
|
-
if (stage === "triage" && item.triageType && item.triageType !== "bug" && !item.acceptedAt) held += 1;
|
|
135
|
-
}
|
|
136
|
-
const decisionsByStatus = {};
|
|
137
|
-
for (const decision of decisions) decisionsByStatus[decision.status] = (decisionsByStatus[decision.status] ?? 0) + 1;
|
|
138
|
-
const failed = decisions.filter((d) => d.status === "failed").slice(0, MAX_LIST);
|
|
139
|
-
const overtaken = await overtakenDecisionIds(deps.workItems, deps.boards, scope, failed);
|
|
140
|
-
const activeSeats = bindings.filter((binding) => binding.status === "active");
|
|
141
|
-
const seatsByRole = {};
|
|
142
|
-
for (const seat of activeSeats) seatsByRole[seat.role] = (seatsByRole[seat.role] ?? 0) + 1;
|
|
143
|
-
return {
|
|
144
|
-
checkedAt: now().toISOString(),
|
|
145
|
-
workItems: {
|
|
146
|
-
total: items.length,
|
|
147
|
-
byStage: stages,
|
|
148
|
-
heldForDecision: held
|
|
149
|
-
},
|
|
150
|
-
decisions: decisionsByStatus,
|
|
151
|
-
openProposals: decisions.filter((d) => d.status === "proposed").map((decision) => summarizeDecision(decision)).slice(0, MAX_LIST),
|
|
152
|
-
failedDecisions: failed.map((decision) => summarizeDecision(decision, overtaken.has(decision.id))),
|
|
153
|
-
activeSeats: {
|
|
154
|
-
total: activeSeats.length,
|
|
155
|
-
byRole: seatsByRole
|
|
156
|
-
},
|
|
157
|
-
pendingStarts: pendingStarts.filter((start) => start.status !== "sent").length
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
}),
|
|
161
|
-
factory_health_check: createTool({
|
|
162
|
-
id: "factory_health_check",
|
|
163
|
-
description: "Deterministic list of things wrong with this Factory right now (stuck decisions, stalled starts, orphaned or missing seats, held cards waiting on a person, label drift). Each finding carries evidence and the standard repair. Explain these; do not invent findings that are not listed.",
|
|
164
|
-
inputSchema: z.object({}).strict(),
|
|
165
|
-
execute: async () => runFactoryHealthCheck(deps.workItems, deps.boards, scope, {
|
|
166
|
-
now: now(),
|
|
167
|
-
thresholds: deps.healthThresholds
|
|
168
|
-
})
|
|
169
|
-
}),
|
|
170
|
-
factory_inspect_work_item: createTool({
|
|
171
|
-
id: "factory_inspect_work_item",
|
|
172
|
-
description: "Everything the Factory knows about one card: row, stage history, seats (run bindings), decisions with errors, recent audit events, recent feed comments, linked parent/children and last observed labels. Use for \"why is #N in this state\".",
|
|
173
|
-
inputSchema: itemRefSchema,
|
|
174
|
-
execute: async (ref) => {
|
|
175
|
-
const item = await findItem(deps, ref);
|
|
176
|
-
if (!item) throw new Error(`No work item matches ${ref.id ?? `#${ref.number}`} in this Factory.`);
|
|
177
|
-
const [decisions, bindings, audit, feed, all] = await Promise.all([
|
|
178
|
-
deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, { workItemId: item.id }),
|
|
179
|
-
deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId, item.id),
|
|
180
|
-
deps.audit.list({
|
|
181
|
-
orgId: scope.orgId,
|
|
182
|
-
factoryProjectId: scope.factoryProjectId,
|
|
183
|
-
limit: 200
|
|
184
|
-
}),
|
|
185
|
-
deps.comments.listRecent({
|
|
186
|
-
...scope,
|
|
187
|
-
workItemId: item.id,
|
|
188
|
-
limit: 10
|
|
189
|
-
}),
|
|
190
|
-
deps.workItems.list(scope)
|
|
191
|
-
]);
|
|
192
|
-
const parent = item.parentWorkItemId ? all.find((candidate) => candidate.id === item.parentWorkItemId) : void 0;
|
|
193
|
-
const children = all.filter((candidate) => candidate.parentWorkItemId === item.id);
|
|
194
|
-
const itemDecisions = decisions.filter((decision) => decision.workItemId === item.id).slice(-50);
|
|
195
|
-
const overtaken = await overtakenDecisionIds(deps.workItems, deps.boards, scope, itemDecisions.filter((decision) => decision.status === "failed"));
|
|
196
|
-
return {
|
|
197
|
-
item: summarizeItem(item),
|
|
198
|
-
labels: itemLabels(item),
|
|
199
|
-
stageHistory: item.stageHistory.map((entry) => ({
|
|
200
|
-
stage: entry.stage,
|
|
201
|
-
enteredAt: entry.enteredAt,
|
|
202
|
-
exitedAt: entry.exitedAt ?? null,
|
|
203
|
-
by: entry.by
|
|
204
|
-
})),
|
|
205
|
-
sessions: Object.entries(item.sessions).map(([role, ref]) => ({
|
|
206
|
-
role,
|
|
207
|
-
sessionId: ref.sessionId,
|
|
208
|
-
threadId: ref.threadId,
|
|
209
|
-
branch: ref.branch,
|
|
210
|
-
startedBy: ref.startedBy
|
|
211
|
-
})),
|
|
212
|
-
seats: bindings.map((binding) => ({
|
|
213
|
-
id: binding.id,
|
|
214
|
-
role: binding.role,
|
|
215
|
-
status: binding.status,
|
|
216
|
-
sessionId: binding.sessionId,
|
|
217
|
-
threadId: binding.threadId,
|
|
218
|
-
createdAt: iso(binding.createdAt),
|
|
219
|
-
revokedAt: iso(binding.revokedAt)
|
|
220
|
-
})),
|
|
221
|
-
decisions: itemDecisions.map((decision) => summarizeDecision(decision, overtaken.has(decision.id))),
|
|
222
|
-
audit: audit.events.filter((event) => event.targets.some((target) => target.type === "work_item" && target.id === item.id)).slice(0, 25).map((event) => ({
|
|
223
|
-
id: event.id,
|
|
224
|
-
action: event.action,
|
|
225
|
-
actorId: event.actorId,
|
|
226
|
-
actorType: event.actorType,
|
|
227
|
-
occurredAt: iso(event.occurredAt),
|
|
228
|
-
metadata: event.metadata
|
|
229
|
-
})),
|
|
230
|
-
feed: feed.map((comment) => ({
|
|
231
|
-
id: comment.id,
|
|
232
|
-
kind: comment.kind,
|
|
233
|
-
author: comment.author,
|
|
234
|
-
occurredAt: iso(comment.occurredAt),
|
|
235
|
-
body: truncate(comment.body, MAX_TEXT)
|
|
236
|
-
})),
|
|
237
|
-
parent: parent ? summarizeItem(parent) : null,
|
|
238
|
-
children: children.map(summarizeItem)
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
}),
|
|
242
|
-
factory_list_attention: createTool({
|
|
243
|
-
id: "factory_list_attention",
|
|
244
|
-
description: "Failed decisions grouped by failure code and error text, so a batch of cards that broke the same way reads as one incident. Also lists proposals waiting on a person and terminal cards that still hold seats.",
|
|
245
|
-
inputSchema: z.object({ limit: z.number().int().min(1).max(MAX_LIST).default(25) }).strict(),
|
|
246
|
-
execute: async ({ limit }) => {
|
|
247
|
-
const [decisions, items] = await Promise.all([deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, { statuses: ["failed", "proposed"] }), deps.workItems.list(scope)]);
|
|
248
|
-
const itemsById = new Map(items.map((item) => [item.id, item]));
|
|
249
|
-
const groups = /* @__PURE__ */ new Map();
|
|
250
|
-
for (const decision of decisions) {
|
|
251
|
-
if (decision.status !== "failed") continue;
|
|
252
|
-
const error = truncate(decision.lastError ?? "", 160);
|
|
253
|
-
const key = `${decision.failureCode ?? "unknown"}|${error}`;
|
|
254
|
-
const group = groups.get(key) ?? {
|
|
255
|
-
failureCode: decision.failureCode ?? "unknown",
|
|
256
|
-
error,
|
|
257
|
-
decisions: []
|
|
258
|
-
};
|
|
259
|
-
group.decisions.push(decision);
|
|
260
|
-
groups.set(key, group);
|
|
261
|
-
}
|
|
262
|
-
return {
|
|
263
|
-
incidents: [...groups.values()].sort((a, b) => b.decisions.length - a.decisions.length).slice(0, limit).map((group) => ({
|
|
264
|
-
failureCode: group.failureCode,
|
|
265
|
-
failureLabel: factoryDispatchFailureMetadata(group.decisions[0].failureCode).label,
|
|
266
|
-
error: group.error,
|
|
267
|
-
count: group.decisions.length,
|
|
268
|
-
firstFailedAt: iso(new Date(group.decisions.reduce((earliest, decision) => Math.min(earliest, decision.updatedAt.getTime()), Infinity))),
|
|
269
|
-
lastFailedAt: iso(new Date(group.decisions.reduce((latest, decision) => Math.max(latest, decision.updatedAt.getTime()), -Infinity))),
|
|
270
|
-
decisions: group.decisions.slice(0, limit).map((decision) => {
|
|
271
|
-
const item = decision.workItemId ? itemsById.get(decision.workItemId) : void 0;
|
|
272
|
-
return {
|
|
273
|
-
id: decision.id,
|
|
274
|
-
workItemId: decision.workItemId,
|
|
275
|
-
number: item ? itemNumber(item) : null,
|
|
276
|
-
title: item?.title ?? null,
|
|
277
|
-
attempts: decision.attempts
|
|
278
|
-
};
|
|
279
|
-
})
|
|
280
|
-
})),
|
|
281
|
-
proposals: decisions.filter((d) => d.status === "proposed").slice(0, limit).map((decision) => summarizeDecision(decision))
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
}),
|
|
285
|
-
factory_read_session: createTool({
|
|
286
|
-
id: "factory_read_session",
|
|
287
|
-
description: "The most recent turns of a card's shared agent thread: who spoke, when, the text (truncated) and which tools were called. Use to see what a worker actually did. Give a work item (id or number) or a threadId.",
|
|
288
|
-
inputSchema: z.object({
|
|
289
|
-
id: z.string().uuid().optional(),
|
|
290
|
-
number: z.number().int().positive().optional(),
|
|
291
|
-
threadId: z.string().min(1).optional(),
|
|
292
|
-
limit: z.number().int().min(1).max(40).default(20)
|
|
293
|
-
}).strict().refine((ref) => ref.id !== void 0 || ref.number !== void 0 || ref.threadId !== void 0, { message: "Provide a work item id, a number, or a threadId." }),
|
|
294
|
-
execute: async ({ limit, ...ref }) => {
|
|
295
|
-
if (!deps.messageReader) throw new Error("Session transcripts are not available on this deployment.");
|
|
296
|
-
let threadId = ref.threadId;
|
|
297
|
-
let resourceId;
|
|
298
|
-
if (!threadId) {
|
|
299
|
-
const item = await findItem(deps, ref);
|
|
300
|
-
if (!item) throw new Error(`No work item matches ${ref.id ?? `#${ref.number}`} in this Factory.`);
|
|
301
|
-
const session = Object.values(item.sessions)[0];
|
|
302
|
-
if (!session) return {
|
|
303
|
-
threadId: null,
|
|
304
|
-
item: summarizeItem(item),
|
|
305
|
-
turns: []
|
|
306
|
-
};
|
|
307
|
-
threadId = session.threadId;
|
|
308
|
-
resourceId = session.sessionId;
|
|
309
|
-
} else {
|
|
310
|
-
const binding = (await deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId)).find((candidate) => candidate.threadId === threadId);
|
|
311
|
-
if (!binding) throw new Error(`Thread ${threadId} is not bound to a card in this Factory.`);
|
|
312
|
-
resourceId = binding.resourceId;
|
|
313
|
-
}
|
|
314
|
-
const page = await deps.messageReader.listMessages({
|
|
315
|
-
threadId,
|
|
316
|
-
...resourceId ? { resourceId } : {},
|
|
317
|
-
page: 0,
|
|
318
|
-
perPage: limit,
|
|
319
|
-
orderBy: {
|
|
320
|
-
field: "createdAt",
|
|
321
|
-
direction: "DESC"
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
const turns = [...page.messages].reverse().map((message) => ({
|
|
325
|
-
id: message.id,
|
|
326
|
-
role: message.role,
|
|
327
|
-
createdAt: iso(message.createdAt),
|
|
328
|
-
text: truncate(messageText(message), MAX_TEXT),
|
|
329
|
-
tools: messageToolCalls(message)
|
|
330
|
-
}));
|
|
331
|
-
return {
|
|
332
|
-
threadId,
|
|
333
|
-
hasOlder: page.hasMore,
|
|
334
|
-
turns
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
})
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
//#endregion
|
|
341
|
-
export { createFactorySupervisorReadTools };
|
|
342
|
-
|
|
343
|
-
//# sourceMappingURL=read-tools.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"read-tools.js","names":[],"sources":["../../src/supervisor/read-tools.ts"],"sourcesContent":["/**\n * Supervisor read surface. Every tool is bounded (hard row caps, truncated\n * text) and answers with ids a person can click on the board, so the model\n * can explain a card's state without ever touching the database itself.\n */\n\nimport type { MastraDBMessage } from '@mastra/core/agent/message-list';\nimport { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\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 { FACTORY_RULE_STAGES, factoryRuleStage } from '../rules/types.js';\nimport type { FactoryRuleStage } from '../rules/types.js';\nimport type { AuditStorage } from '../storage/domains/audit/base.js';\nimport type { WorkItemCommentsStorage } from '../storage/domains/comments/base.js';\nimport type {\n FactoryDeferredDecisionRecord,\n WorkItemRow,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport type { FactoryHealthReport, FactoryHealthThresholds } from './health.js';\nimport { runFactoryHealthCheck } from './health.js';\n\nexport interface SupervisorScope {\n orgId: string;\n factoryProjectId: string;\n}\n\nexport interface SupervisorMessageReader {\n listMessages(input: {\n threadId: string;\n resourceId?: string;\n page: number;\n perPage: number;\n orderBy: { field: 'createdAt'; direction: 'ASC' | 'DESC' };\n }): Promise<{ messages: MastraDBMessage[]; hasMore: boolean }>;\n}\n\nexport interface SupervisorReadDependencies {\n scope: SupervisorScope;\n workItems: WorkItemsStorage;\n boards: BoardRegistry;\n comments: WorkItemCommentsStorage;\n audit: AuditStorage;\n messageReader?: SupervisorMessageReader;\n healthThresholds?: FactoryHealthThresholds;\n now?: () => Date;\n}\n\nconst MAX_TEXT = 600;\nconst MAX_ERROR = 400;\nconst MAX_LIST = 50;\n\nfunction 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\nfunction itemNumber(item: WorkItemRow): number | null {\n const number = item.metadata?.number ?? item.metadata?.githubIssueNumber ?? item.metadata?.githubPullRequestNumber;\n return typeof number === 'number' ? number : null;\n}\n\nfunction itemLabels(item: WorkItemRow): string[] {\n const labels = item.metadata?.labels;\n return Array.isArray(labels) ? labels.filter((label): label is string => typeof label === 'string') : [];\n}\n\nfunction summarizeItem(item: WorkItemRow) {\n return {\n id: item.id,\n number: itemNumber(item),\n title: item.title,\n stage: factoryRuleStage(item.stages) ?? item.stages.join('+'),\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 acceptedAt: iso(item.acceptedAt),\n autonomyArmedAt: iso(item.autonomyArmedAt),\n parentWorkItemId: item.parentWorkItemId,\n revision: item.revision,\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 const skill = typeof decision.decision.skillName === 'string' ? decision.decision.skillName : null;\n return {\n id: decision.id,\n workItemId: decision.workItemId,\n type,\n role,\n skill,\n status: decision.status,\n attempts: decision.attempts,\n availableAt: iso(decision.availableAt),\n leaseOwner: decision.leaseOwner,\n leaseExpiresAt: iso(decision.leaseExpiresAt),\n failureCode: decision.failureCode,\n failureLabel: decision.failureCode ? factoryDispatchFailureMetadata(decision.failureCode).label : null,\n canRetry: decisionRetryable(decision, overtaken),\n lastError: decision.lastError ? truncate(decision.lastError, MAX_ERROR) : null,\n approvedBy: decision.approvedBy,\n createdAt: iso(decision.createdAt),\n updatedAt: iso(decision.updatedAt),\n completedAt: iso(decision.completedAt),\n };\n}\n\nfunction messageParts(content: unknown): unknown[] {\n if (Array.isArray(content)) return content;\n if (content && typeof content === 'object') {\n const parts = (content as { parts?: unknown }).parts;\n if (Array.isArray(parts)) return parts;\n }\n return [];\n}\n\nfunction messageText(message: MastraDBMessage): string {\n const content: unknown = message.content;\n const parts = messageParts(content);\n const text: string[] = [];\n for (const part of parts) {\n if (part && typeof part === 'object' && (part as { type?: unknown }).type === 'text') {\n const value = (part as { text?: unknown }).text;\n if (typeof value === 'string') text.push(value);\n }\n }\n if (text.length === 0 && typeof content === 'string') text.push(content);\n return text.join('\\n');\n}\n\nfunction messageToolCalls(message: MastraDBMessage): Array<{ tool: string; state: string | null }> {\n const parts = messageParts(message.content);\n const calls: Array<{ tool: string; state: string | null }> = [];\n for (const rawPart of parts) {\n if (!rawPart || typeof rawPart !== 'object') continue;\n const part = rawPart as Record<string, unknown>;\n const invocation =\n part.type === 'tool-invocation' && part.toolInvocation && typeof part.toolInvocation === 'object'\n ? (part.toolInvocation as Record<string, unknown>)\n : typeof part.type === 'string' && part.type.startsWith('tool-')\n ? part\n : undefined;\n if (!invocation) continue;\n const name = invocation.toolName ?? invocation.name ?? (typeof part.type === 'string' ? part.type.slice(5) : null);\n if (typeof name !== 'string') continue;\n calls.push({ tool: name, state: typeof invocation.state === 'string' ? invocation.state : null });\n }\n return calls;\n}\n\nasync function findItem(\n deps: SupervisorReadDependencies,\n ref: { id?: string; number?: number },\n): Promise<WorkItemRow | null> {\n if (ref.id) return deps.workItems.getForProject(deps.scope.orgId, deps.scope.factoryProjectId, ref.id);\n if (ref.number === undefined) return null;\n const items = await deps.workItems.list(deps.scope);\n const matches = items.filter(item => itemNumber(item) === ref.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\nconst itemRefSchema = z\n .object({\n id: z.string().uuid().optional().describe('Work item id.'),\n number: z.number().int().positive().optional().describe('Card number as shown on the board, e.g. 22874.'),\n })\n .refine(ref => ref.id !== undefined || ref.number !== undefined, { message: 'Provide an id or a number.' });\n\nexport function createFactorySupervisorReadTools(deps: SupervisorReadDependencies): IntegrationTools {\n const now = deps.now ?? (() => new Date());\n const scope = deps.scope;\n\n return {\n factory_overview: createTool({\n id: 'factory_overview',\n description:\n 'Counts per pipeline stage, decisions by status, active seats, open proposals and held cards for this Factory. Start here for \"what needs me\" questions.',\n inputSchema: z.object({}).strict(),\n execute: async () => {\n const [items, decisions, bindings, pendingStarts] = await Promise.all([\n deps.workItems.list(scope),\n deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId),\n deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId),\n deps.workItems.listPendingStarts(scope.orgId, scope.factoryProjectId),\n ]);\n const stages = Object.fromEntries(FACTORY_RULE_STAGES.map(stage => [stage, 0])) as Record<\n FactoryRuleStage,\n number\n >;\n let held = 0;\n for (const item of items) {\n const stage = factoryRuleStage(item.stages);\n if (stage) stages[stage] += 1;\n if (stage === 'triage' && item.triageType && item.triageType !== 'bug' && !item.acceptedAt) held += 1;\n }\n const decisionsByStatus: Record<string, number> = {};\n for (const decision of decisions) {\n decisionsByStatus[decision.status] = (decisionsByStatus[decision.status] ?? 0) + 1;\n }\n const failed = decisions.filter(d => d.status === 'failed').slice(0, MAX_LIST);\n const overtaken = await overtakenDecisionIds(deps.workItems, deps.boards, scope, failed);\n const activeSeats = bindings.filter(binding => binding.status === 'active');\n const seatsByRole: Record<string, number> = {};\n for (const seat of activeSeats) seatsByRole[seat.role] = (seatsByRole[seat.role] ?? 0) + 1;\n return {\n checkedAt: now().toISOString(),\n workItems: { total: items.length, byStage: stages, heldForDecision: held },\n decisions: decisionsByStatus,\n openProposals: decisions\n .filter(d => d.status === 'proposed')\n .map(decision => summarizeDecision(decision))\n .slice(0, MAX_LIST),\n failedDecisions: failed.map(decision => summarizeDecision(decision, overtaken.has(decision.id))),\n activeSeats: { total: activeSeats.length, byRole: seatsByRole },\n pendingStarts: pendingStarts.filter(start => start.status !== 'sent').length,\n };\n },\n }),\n\n factory_health_check: createTool({\n id: 'factory_health_check',\n description:\n 'Deterministic list of things wrong with this Factory right now (stuck decisions, stalled starts, orphaned or missing seats, held cards waiting on a person, label drift). Each finding carries evidence and the standard repair. Explain these; do not invent findings that are not listed.',\n inputSchema: z.object({}).strict(),\n execute: async (): Promise<FactoryHealthReport> =>\n runFactoryHealthCheck(deps.workItems, deps.boards, scope, { now: now(), thresholds: deps.healthThresholds }),\n }),\n\n factory_inspect_work_item: createTool({\n id: 'factory_inspect_work_item',\n description:\n 'Everything the Factory knows about one card: row, stage history, seats (run bindings), decisions with errors, recent audit events, recent feed comments, linked parent/children and last observed labels. Use for \"why is #N in this state\".',\n inputSchema: itemRefSchema,\n execute: async ref => {\n const item = await findItem(deps, ref);\n if (!item) throw new Error(`No work item matches ${ref.id ?? `#${ref.number}`} in this Factory.`);\n const [decisions, bindings, audit, feed, all] = await Promise.all([\n deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, { workItemId: item.id }),\n deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId, item.id),\n deps.audit.list({ orgId: scope.orgId, factoryProjectId: scope.factoryProjectId, limit: 200 }),\n deps.comments.listRecent({ ...scope, workItemId: item.id, limit: 10 }),\n deps.workItems.list(scope),\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 const itemDecisions = decisions.filter(decision => decision.workItemId === item.id).slice(-MAX_LIST);\n const overtaken = await overtakenDecisionIds(\n deps.workItems,\n deps.boards,\n scope,\n itemDecisions.filter(decision => decision.status === 'failed'),\n );\n return {\n item: summarizeItem(item),\n labels: itemLabels(item),\n stageHistory: item.stageHistory.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 branch: ref.branch,\n startedBy: ref.startedBy,\n })),\n seats: bindings.map(binding => ({\n id: binding.id,\n role: binding.role,\n status: binding.status,\n sessionId: binding.sessionId,\n threadId: binding.threadId,\n createdAt: iso(binding.createdAt),\n revokedAt: iso(binding.revokedAt),\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 id: event.id,\n action: event.action,\n actorId: event.actorId,\n actorType: event.actorType,\n occurredAt: iso(event.occurredAt),\n metadata: event.metadata,\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) : null,\n children: children.map(summarizeItem),\n };\n },\n }),\n\n factory_list_attention: createTool({\n id: 'factory_list_attention',\n description:\n 'Failed decisions grouped by failure code and error text, so a batch of cards that broke the same way reads as one incident. Also lists proposals waiting on a person and terminal cards that still hold seats.',\n inputSchema: z.object({ limit: z.number().int().min(1).max(MAX_LIST).default(25) }).strict(),\n execute: async ({ limit }) => {\n const [decisions, items] = await Promise.all([\n deps.workItems.listDeferredDecisions(scope.orgId, scope.factoryProjectId, {\n statuses: ['failed', 'proposed'],\n }),\n deps.workItems.list(scope),\n ]);\n const itemsById = new Map(items.map(item => [item.id, item]));\n const groups = new Map<\n string,\n { failureCode: string; error: string; decisions: FactoryDeferredDecisionRecord[] }\n >();\n for (const decision of decisions) {\n if (decision.status !== 'failed') continue;\n const error = truncate(decision.lastError ?? '', 160);\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 incidents = [...groups.values()]\n .sort((a, b) => b.decisions.length - a.decisions.length)\n .slice(0, limit)\n .map(group => ({\n failureCode: group.failureCode,\n failureLabel: factoryDispatchFailureMetadata(group.decisions[0]!.failureCode).label,\n error: group.error,\n count: group.decisions.length,\n firstFailedAt: iso(\n new Date(\n group.decisions.reduce(\n (earliest, decision) => Math.min(earliest, decision.updatedAt.getTime()),\n Infinity,\n ),\n ),\n ),\n lastFailedAt: iso(\n new Date(\n group.decisions.reduce((latest, decision) => Math.max(latest, decision.updatedAt.getTime()), -Infinity),\n ),\n ),\n decisions: group.decisions.slice(0, limit).map(decision => {\n const item = decision.workItemId ? itemsById.get(decision.workItemId) : undefined;\n return {\n id: decision.id,\n workItemId: decision.workItemId,\n number: item ? itemNumber(item) : null,\n title: item?.title ?? null,\n attempts: decision.attempts,\n };\n }),\n }));\n return {\n incidents,\n proposals: decisions\n .filter(d => d.status === 'proposed')\n .slice(0, limit)\n .map(decision => summarizeDecision(decision)),\n };\n },\n }),\n\n factory_read_session: createTool({\n id: 'factory_read_session',\n description:\n \"The most recent turns of a card's shared agent thread: who spoke, when, the text (truncated) and which tools were called. Use to see what a worker actually did. Give a work item (id or number) or a threadId.\",\n inputSchema: z\n .object({\n id: z.string().uuid().optional(),\n number: z.number().int().positive().optional(),\n threadId: z.string().min(1).optional(),\n limit: z.number().int().min(1).max(40).default(20),\n })\n .strict()\n .refine(ref => ref.id !== undefined || ref.number !== undefined || ref.threadId !== undefined, {\n message: 'Provide a work item id, a number, or a threadId.',\n }),\n execute: async ({ limit, ...ref }) => {\n if (!deps.messageReader) throw new Error('Session transcripts are not available on this deployment.');\n let threadId = ref.threadId;\n let resourceId: string | undefined;\n if (!threadId) {\n const item = await findItem(deps, ref);\n if (!item) throw new Error(`No work item matches ${ref.id ?? `#${ref.number}`} in this Factory.`);\n const session = Object.values(item.sessions)[0];\n if (!session) return { threadId: null, item: summarizeItem(item), turns: [] };\n threadId = session.threadId;\n resourceId = session.sessionId;\n } else {\n // A thread the caller named must still belong to a card in this Factory.\n const bindings = await deps.workItems.listRunBindings(scope.orgId, scope.factoryProjectId);\n const binding = bindings.find(candidate => candidate.threadId === threadId);\n if (!binding) throw new Error(`Thread ${threadId} is not bound to a card in this Factory.`);\n resourceId = binding.resourceId;\n }\n const page = await deps.messageReader.listMessages({\n threadId,\n ...(resourceId ? { resourceId } : {}),\n page: 0,\n perPage: limit,\n orderBy: { field: 'createdAt', direction: 'DESC' },\n });\n const turns = [...page.messages].reverse().map(message => ({\n id: message.id,\n role: message.role,\n createdAt: iso(message.createdAt),\n text: truncate(messageText(message), MAX_TEXT),\n tools: messageToolCalls(message),\n }));\n return { threadId, hasOlder: page.hasMore, turns };\n },\n }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { RequestContext } from '@mastra/core/request-context';
|
|
2
|
-
export type WorkerMessageResult = void | {
|
|
3
|
-
status: 'interrupted';
|
|
4
|
-
};
|
|
5
|
-
type WorkerSession = {
|
|
6
|
-
sendMessage(input: {
|
|
7
|
-
content: string;
|
|
8
|
-
requestContext?: RequestContext;
|
|
9
|
-
}): Promise<unknown>;
|
|
10
|
-
queueMessage(input: {
|
|
11
|
-
content: string;
|
|
12
|
-
requestContext?: RequestContext;
|
|
13
|
-
}): Promise<unknown>;
|
|
14
|
-
};
|
|
15
|
-
type WorkerSessionController = {
|
|
16
|
-
getSessionByResource(sessionId: string): Promise<WorkerSession | undefined>;
|
|
17
|
-
};
|
|
18
|
-
export declare function messageWorkerSession({ controller, sessionId, message, delivery, requestContext, }: {
|
|
19
|
-
controller: WorkerSessionController;
|
|
20
|
-
sessionId: string;
|
|
21
|
-
message: string;
|
|
22
|
-
delivery: 'send' | 'queue';
|
|
23
|
-
requestContext?: RequestContext;
|
|
24
|
-
}): Promise<WorkerMessageResult>;
|
|
25
|
-
export {};
|
|
26
|
-
//# sourceMappingURL=session-messaging.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-messaging.d.ts","sourceRoot":"","sources":["../../src/supervisor/session-messaging.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC;AAEnE,KAAK,aAAa,GAAG;IACnB,WAAW,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3F,YAAY,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,cAAc,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7F,CAAC;AAEF,KAAK,uBAAuB,GAAG;IAC7B,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CAC7E,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,EACzC,UAAU,EACV,SAAS,EACT,OAAO,EACP,QAAQ,EACR,cAAc,GACf,EAAE;IACD,UAAU,EAAE,uBAAuB,CAAC;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAe/B"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { isSessionStartupCancelledError } from "@mastra/core/agent-controller";
|
|
2
|
-
//#region src/supervisor/session-messaging.ts
|
|
3
|
-
async function messageWorkerSession({ controller, sessionId, message, delivery, requestContext }) {
|
|
4
|
-
const session = await controller.getSessionByResource(sessionId);
|
|
5
|
-
if (!session) throw new Error("The worker session is not currently available.");
|
|
6
|
-
const input = {
|
|
7
|
-
content: message,
|
|
8
|
-
...requestContext ? { requestContext } : {}
|
|
9
|
-
};
|
|
10
|
-
try {
|
|
11
|
-
if (delivery === "queue") await session.queueMessage(input);
|
|
12
|
-
else await session.sendMessage(input);
|
|
13
|
-
} catch (error) {
|
|
14
|
-
if (isSessionStartupCancelledError(error)) return { status: "interrupted" };
|
|
15
|
-
throw error;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
//#endregion
|
|
19
|
-
export { messageWorkerSession };
|
|
20
|
-
|
|
21
|
-
//# sourceMappingURL=session-messaging.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-messaging.js","names":[],"sources":["../../src/supervisor/session-messaging.ts"],"sourcesContent":["import { isSessionStartupCancelledError } from '@mastra/core/agent-controller';\nimport type { RequestContext } from '@mastra/core/request-context';\n\nexport type WorkerMessageResult = void | { status: 'interrupted' };\n\ntype WorkerSession = {\n sendMessage(input: { content: string; requestContext?: RequestContext }): Promise<unknown>;\n queueMessage(input: { content: string; requestContext?: RequestContext }): Promise<unknown>;\n};\n\ntype WorkerSessionController = {\n getSessionByResource(sessionId: string): Promise<WorkerSession | undefined>;\n};\n\nexport async function messageWorkerSession({\n controller,\n sessionId,\n message,\n delivery,\n requestContext,\n}: {\n controller: WorkerSessionController;\n sessionId: string;\n message: string;\n delivery: 'send' | 'queue';\n requestContext?: RequestContext;\n}): Promise<WorkerMessageResult> {\n const session = await controller.getSessionByResource(sessionId);\n if (!session) throw new Error('The worker session is not currently available.');\n\n const input = { content: message, ...(requestContext ? { requestContext } : {}) };\n try {\n if (delivery === 'queue') {\n await session.queueMessage(input);\n } else {\n await session.sendMessage(input);\n }\n } catch (error) {\n if (isSessionStartupCancelledError(error)) return { status: 'interrupted' };\n throw error;\n }\n}\n"],"mappings":";;AAcA,eAAsB,qBAAqB,EACzC,YACA,WACA,SACA,UACA,kBAO+B;CAC/B,MAAM,UAAU,MAAM,WAAW,qBAAqB,SAAS;CAC/D,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,gDAAgD;CAE9E,MAAM,QAAQ;EAAE,SAAS;EAAS,GAAI,iBAAiB,EAAE,eAAe,IAAI,CAAC;CAAG;CAChF,IAAI;EACF,IAAI,aAAa,SACf,MAAM,QAAQ,aAAa,KAAK;OAEhC,MAAM,QAAQ,YAAY,KAAK;CAEnC,SAAS,OAAO;EACd,IAAI,+BAA+B,KAAK,GAAG,OAAO,EAAE,QAAQ,cAAc;EAC1E,MAAM;CACR;AACF"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The supervisor session: one per factory, addressed by a self-describing
|
|
3
|
-
* resourceId so a restarted server can recover its scope without a lookup
|
|
4
|
-
* table. The session has no repository, no sandbox and no work-item seat —
|
|
5
|
-
* its tools talk to storage directly.
|
|
6
|
-
*/
|
|
7
|
-
import type { MastraCodeState } from '@mastra/code-sdk/schema';
|
|
8
|
-
import type { AgentController } from '@mastra/core/agent-controller';
|
|
9
|
-
import type { RequestContext } from '@mastra/core/request-context';
|
|
10
|
-
import type { ModelDefaultsStorage } from '../storage/domains/model-defaults/base.js';
|
|
11
|
-
import type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';
|
|
12
|
-
import type { SupervisorScope } from './read-tools.js';
|
|
13
|
-
type FactorySession = Awaited<ReturnType<AgentController<MastraCodeState>['createSession']>>;
|
|
14
|
-
export declare function supervisorResourceId(factoryProjectId: string): string;
|
|
15
|
-
/** The supervisor thread shares the session's id: one thread per factory. */
|
|
16
|
-
export declare function supervisorThreadId(factoryProjectId: string): string;
|
|
17
|
-
export declare function parseSupervisorResourceId(resourceId: string | undefined | null): string | null;
|
|
18
|
-
/**
|
|
19
|
-
* Scope a request to a supervisor session the caller is allowed to drive:
|
|
20
|
-
* the resourceId must name a project, and the caller's org must own it.
|
|
21
|
-
* Anything else yields null and the supervisor tools stay unregistered.
|
|
22
|
-
*/
|
|
23
|
-
export declare function resolveSupervisorScope(options: {
|
|
24
|
-
requestContext: RequestContext | undefined;
|
|
25
|
-
projects: Pick<FactoryProjectsStorage, 'get'>;
|
|
26
|
-
}): Promise<SupervisorScope | null>;
|
|
27
|
-
/**
|
|
28
|
-
* Session-start hook: stamp the owning project onto a supervisor session and
|
|
29
|
-
* apply the factory's default model. Runs on every (re)creation so a restarted
|
|
30
|
-
* server heals the in-memory state. Sessions
|
|
31
|
-
* that are not supervisors are left untouched.
|
|
32
|
-
*/
|
|
33
|
-
export declare function hydrateSupervisorSession(session: FactorySession, deps: {
|
|
34
|
-
projects: FactoryProjectsStorage;
|
|
35
|
-
modelDefaults: ModelDefaultsStorage;
|
|
36
|
-
}): Promise<void>;
|
|
37
|
-
export {};
|
|
38
|
-
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/supervisor/session.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAiC,MAAM,+BAA+B,CAAC;AACpG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAKnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIvD,KAAK,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;AAE7F,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAI9F;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,cAAc,EAAE,cAAc,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;CAC/C,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAWlC;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,cAAc,EACvB,IAAI,EAAE;IACJ,QAAQ,EAAE,sBAAsB,CAAC;IACjC,aAAa,EAAE,oBAAoB,CAAC;CACrC,GACA,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
|