@mastra/factory 0.2.2-alpha.0 → 0.2.2-alpha.2
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/CHANGELOG.md +36 -0
- package/dist/auth.d.ts +2 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +401 -314
- package/dist/auth.js.map +1 -1
- package/dist/capabilities/connection.js +1 -1
- package/dist/capabilities/intake.js +1 -1
- package/dist/capabilities/version-control.js +1 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +441 -39455
- package/dist/factory.js.map +1 -1
- package/dist/index.js +2 -39466
- package/dist/integrations/base.js +1 -1
- package/dist/integrations/github/config.js +36 -22
- package/dist/integrations/github/config.js.map +1 -1
- package/dist/integrations/github/factory-session.js +33 -37
- package/dist/integrations/github/factory-session.js.map +1 -1
- package/dist/integrations/github/integration.js +1037 -3624
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/issue-triage.js +71 -71
- package/dist/integrations/github/issue-triage.js.map +1 -1
- package/dist/integrations/github/pat.js +47 -36
- package/dist/integrations/github/pat.js.map +1 -1
- package/dist/integrations/github/provenance.js +72 -101
- package/dist/integrations/github/provenance.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +1272 -1833
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/rules.js +203 -471
- package/dist/integrations/github/rules.js.map +1 -1
- package/dist/integrations/github/sandbox.d.ts +2 -0
- package/dist/integrations/github/sandbox.d.ts.map +1 -1
- package/dist/integrations/github/sandbox.js +401 -326
- package/dist/integrations/github/sandbox.js.map +1 -1
- package/dist/integrations/github/session-subscriptions.js +165 -223
- package/dist/integrations/github/session-subscriptions.js.map +1 -1
- package/dist/integrations/github/subscriptions.js +43 -51
- package/dist/integrations/github/subscriptions.js.map +1 -1
- package/dist/integrations/github/token-refresh.js +15 -18
- package/dist/integrations/github/token-refresh.js.map +1 -1
- package/dist/integrations/github/webhook.js +359 -343
- package/dist/integrations/github/webhook.js.map +1 -1
- package/dist/integrations/linear/agent-tools.js +77 -100
- package/dist/integrations/linear/agent-tools.js.map +1 -1
- package/dist/integrations/linear/integration.js +611 -1309
- package/dist/integrations/linear/integration.js.map +1 -1
- package/dist/integrations/linear/routes.js +227 -230
- package/dist/integrations/linear/routes.js.map +1 -1
- package/dist/integrations/linear/rules.js +126 -346
- package/dist/integrations/linear/rules.js.map +1 -1
- package/dist/integrations/linear/storage.js +1 -1
- package/dist/integrations/platform/api-client.js +131 -135
- package/dist/integrations/platform/api-client.js.map +1 -1
- package/dist/integrations/platform/github/event-worker.js +275 -573
- package/dist/integrations/platform/github/event-worker.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +845 -3942
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/integrations/platform/linear/integration.js +457 -1309
- package/dist/integrations/platform/linear/integration.js.map +1 -1
- package/dist/integrations/workos/integration.js +80 -85
- package/dist/integrations/workos/integration.js.map +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +933 -915
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/custom-provider-source.js +110 -93
- package/dist/routes/custom-provider-source.js.map +1 -1
- package/dist/routes/fs.js +401 -349
- package/dist/routes/fs.js.map +1 -1
- package/dist/routes/intake.js +165 -165
- package/dist/routes/intake.js.map +1 -1
- package/dist/routes/oauth.js +447 -25166
- package/dist/routes/oauth.js.map +1 -1
- package/dist/routes/projects.js +437 -376
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/provider-credentials.js +76 -58
- package/dist/routes/provider-credentials.js.map +1 -1
- package/dist/routes/route.js +12 -8
- package/dist/routes/route.js.map +1 -1
- package/dist/routes/skills.js +160 -173
- package/dist/routes/skills.js.map +1 -1
- package/dist/routes/surface.js +250 -28618
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/tenant-credentials.js +141 -166
- package/dist/routes/tenant-credentials.js.map +1 -1
- package/dist/routes/work-items.js +654 -862
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/binding-context.js +23 -35
- package/dist/rules/binding-context.js.map +1 -1
- package/dist/rules/defaults.js +200 -309
- package/dist/rules/defaults.js.map +1 -1
- package/dist/rules/dispatcher.d.ts.map +1 -1
- package/dist/rules/dispatcher.js +438 -677
- package/dist/rules/dispatcher.js.map +1 -1
- package/dist/rules/index.js +5 -599
- package/dist/rules/processor.js +344 -596
- package/dist/rules/processor.js.map +1 -1
- package/dist/rules/resolve.js +21 -18
- package/dist/rules/resolve.js.map +1 -1
- package/dist/rules/start-coordinator.js +168 -157
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/rules/tools.js +50 -85
- package/dist/rules/tools.js.map +1 -1
- package/dist/rules/transition-service.js +183 -454
- package/dist/rules/transition-service.js.map +1 -1
- package/dist/rules/types.js +33 -29
- package/dist/rules/types.js.map +1 -1
- package/dist/rules/validation.js +266 -281
- package/dist/rules/validation.js.map +1 -1
- package/dist/sandbox/fleet.js +272 -250
- package/dist/sandbox/fleet.js.map +1 -1
- package/dist/sandbox/reattach.js +13 -6
- package/dist/sandbox/reattach.js.map +1 -1
- package/dist/server-error.js +12 -16
- package/dist/server-error.js.map +1 -1
- package/dist/skills/service.js +30 -35
- package/dist/skills/service.js.map +1 -1
- package/dist/spa-static.d.ts.map +1 -1
- package/dist/spa-static.js +91 -64
- package/dist/spa-static.js.map +1 -1
- package/dist/state-signing.js +73 -44
- package/dist/state-signing.js.map +1 -1
- package/dist/storage/domains/audit/agent-audit.js +60 -59
- package/dist/storage/domains/audit/agent-audit.js.map +1 -1
- package/dist/storage/domains/audit/base.js +169 -112
- package/dist/storage/domains/audit/base.js.map +1 -1
- package/dist/storage/domains/audit/domain.js +155 -153
- package/dist/storage/domains/audit/domain.js.map +1 -1
- package/dist/storage/domains/credentials/base.js +259 -243
- package/dist/storage/domains/credentials/base.js.map +1 -1
- package/dist/storage/domains/custom-providers/base.js +138 -143
- package/dist/storage/domains/custom-providers/base.js.map +1 -1
- package/dist/storage/domains/intake/base.js +75 -57
- package/dist/storage/domains/intake/base.js.map +1 -1
- package/dist/storage/domains/integrations/base.js +310 -245
- package/dist/storage/domains/integrations/base.js.map +1 -1
- package/dist/storage/domains/memory-settings/base.js +117 -102
- package/dist/storage/domains/memory-settings/base.js.map +1 -1
- package/dist/storage/domains/model-packs/base.js +89 -88
- package/dist/storage/domains/model-packs/base.js.map +1 -1
- package/dist/storage/domains/projects/base.js +97 -92
- package/dist/storage/domains/projects/base.js.map +1 -1
- package/dist/storage/domains/queue-health/base.js +111 -76
- package/dist/storage/domains/queue-health/base.js.map +1 -1
- package/dist/storage/domains/source-control/base.d.ts +9 -0
- package/dist/storage/domains/source-control/base.d.ts.map +1 -1
- package/dist/storage/domains/source-control/base.js +777 -702
- 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 +322 -344
- package/dist/storage/domains/source-control/inmemory.js.map +1 -1
- package/dist/storage/domains/work-items/base.d.ts.map +1 -1
- package/dist/storage/domains/work-items/base.js +1266 -1132
- package/dist/storage/domains/work-items/base.js.map +1 -1
- package/dist/storage/domains/work-items/metrics.js +202 -184
- package/dist/storage/domains/work-items/metrics.js.map +1 -1
- package/dist/timing.d.ts +15 -0
- package/dist/timing.d.ts.map +1 -0
- package/dist/timing.js +34 -0
- package/dist/timing.js.map +1 -0
- package/dist/workspace.d.ts +2 -3
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +236 -438
- package/dist/workspace.js.map +1 -1
- package/factory-skills/factory-review/SKILL.md +9 -2
- package/package.json +9 -9
- package/dist/capabilities/connection.js.map +0 -1
- package/dist/capabilities/intake.js.map +0 -1
- package/dist/capabilities/version-control.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/base.js.map +0 -1
- package/dist/integrations/linear/storage.js.map +0 -1
- package/dist/rules/index.js.map +0 -1
|
@@ -1,174 +1,185 @@
|
|
|
1
|
-
// src/rules/start-coordinator.ts
|
|
2
1
|
import { RequestContext } from "@mastra/core/request-context";
|
|
3
2
|
import { formatSkillActivation } from "@mastra/core/workspace";
|
|
3
|
+
//#region src/rules/start-coordinator.ts
|
|
4
4
|
var FactoryStartTransitionError = class extends Error {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
result;
|
|
6
|
+
constructor(result) {
|
|
7
|
+
super(result.reason);
|
|
8
|
+
this.name = "FactoryStartTransitionError";
|
|
9
|
+
this.result = result;
|
|
10
|
+
}
|
|
11
11
|
};
|
|
12
12
|
function escapeSkillBoundary(value) {
|
|
13
|
-
|
|
13
|
+
return value.replaceAll("</skill>", "</skill>");
|
|
14
14
|
}
|
|
15
15
|
async function resolveKickoffMessage(session, invocation) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const content = `${formatSkillActivation(skill)}${args ? `
|
|
26
|
-
|
|
27
|
-
ARGUMENTS: ${args}` : ""}`.trim();
|
|
28
|
-
return `<skill name="${skill.name}">
|
|
29
|
-
${escapeSkillBoundary(content)}
|
|
30
|
-
</skill>`;
|
|
16
|
+
if (!invocation) return null;
|
|
17
|
+
if (invocation.type === "prompt") return invocation.prompt;
|
|
18
|
+
const skills = session.getWorkspace().skills;
|
|
19
|
+
await skills?.maybeRefresh();
|
|
20
|
+
const skill = await skills?.get(invocation.skillName);
|
|
21
|
+
if (!skill || skill["user-invocable"] === false) throw new Error(`Skill not found: ${invocation.skillName}.`);
|
|
22
|
+
const args = invocation.arguments.trim();
|
|
23
|
+
const content = `${formatSkillActivation(skill)}${args ? `\n\nARGUMENTS: ${args}` : ""}`.trim();
|
|
24
|
+
return `<skill name="${skill.name}">\n${escapeSkillBoundary(content)}\n</skill>`;
|
|
31
25
|
}
|
|
32
26
|
async function resolveSourceSession(storage, request) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return session;
|
|
27
|
+
const session = await storage.sessions.getBySessionId(request.sessionId);
|
|
28
|
+
if (!session || session.orgId !== request.orgId || session.userId !== request.userId) throw new Error("Factory session not found");
|
|
29
|
+
const projectRepository = await storage.projectRepositories.get({
|
|
30
|
+
orgId: request.orgId,
|
|
31
|
+
id: session.projectRepositoryId
|
|
32
|
+
});
|
|
33
|
+
if (!projectRepository) throw new Error("Factory session repository not found");
|
|
34
|
+
const connection = await storage.connections.get({
|
|
35
|
+
orgId: request.orgId,
|
|
36
|
+
id: projectRepository.connectionId
|
|
37
|
+
});
|
|
38
|
+
if (!connection || connection.factoryProjectId !== request.factoryProjectId) throw new Error("Factory session does not belong to this project");
|
|
39
|
+
return session;
|
|
47
40
|
}
|
|
48
41
|
async function configureThread(session, request) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
const threadId = session.thread.requireId();
|
|
43
|
+
await session.thread.rename({ title: request.threadTitle });
|
|
44
|
+
const settings = {
|
|
45
|
+
...request.threadTags ?? {},
|
|
46
|
+
factorySessionId: request.sessionId
|
|
47
|
+
};
|
|
48
|
+
await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({
|
|
49
|
+
key,
|
|
50
|
+
value
|
|
51
|
+
})));
|
|
52
|
+
return threadId;
|
|
54
53
|
}
|
|
55
54
|
async function applyMemorySettings(session, record) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });
|
|
56
|
+
if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });
|
|
57
|
+
const state = {
|
|
58
|
+
...record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {},
|
|
59
|
+
...record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {},
|
|
60
|
+
...record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}
|
|
61
|
+
};
|
|
62
|
+
if (Object.keys(state).length > 0) await session.state.set(state);
|
|
64
63
|
}
|
|
65
64
|
var FactoryStartCoordinator = class {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
65
|
+
#controller;
|
|
66
|
+
#storage;
|
|
67
|
+
#transitionService;
|
|
68
|
+
#sourceControl;
|
|
69
|
+
#memorySettings;
|
|
70
|
+
constructor(controller, storage, transitionService, sourceControl, memorySettings) {
|
|
71
|
+
this.#controller = controller;
|
|
72
|
+
this.#storage = storage;
|
|
73
|
+
this.#transitionService = transitionService;
|
|
74
|
+
this.#sourceControl = sourceControl;
|
|
75
|
+
this.#memorySettings = memorySettings;
|
|
76
|
+
}
|
|
77
|
+
async prepare(request) {
|
|
78
|
+
const storage = this.#storage;
|
|
79
|
+
if (!this.#sourceControl) throw new Error("Factory source control storage is unavailable");
|
|
80
|
+
const sourceSession = await resolveSourceSession(this.#sourceControl, request);
|
|
81
|
+
const requestContext = request.requestContext ?? new RequestContext();
|
|
82
|
+
if (!request.requestContext) requestContext.set("user", {
|
|
83
|
+
workosId: request.userId,
|
|
84
|
+
organizationId: request.orgId
|
|
85
|
+
});
|
|
86
|
+
const sessionState = {
|
|
87
|
+
factoryProjectId: request.factoryProjectId,
|
|
88
|
+
projectRepositoryId: sourceSession.projectRepositoryId
|
|
89
|
+
};
|
|
90
|
+
const session = await this.#controller.createSession({
|
|
91
|
+
id: sourceSession.sessionId,
|
|
92
|
+
ownerId: request.userId,
|
|
93
|
+
resourceId: sourceSession.sessionId,
|
|
94
|
+
threadId: sourceSession.sessionId,
|
|
95
|
+
requestContext,
|
|
96
|
+
tags: sessionState
|
|
97
|
+
});
|
|
98
|
+
await session.state.set(sessionState);
|
|
99
|
+
if (this.#memorySettings) try {
|
|
100
|
+
await applyMemorySettings(session, await this.#memorySettings.get({
|
|
101
|
+
orgId: request.orgId,
|
|
102
|
+
userId: request.userId
|
|
103
|
+
}));
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.warn("[Factory Start] Failed to apply observational-memory settings", { error: error instanceof Error ? error.message : String(error) });
|
|
106
|
+
}
|
|
107
|
+
if (request.defaultModelId) try {
|
|
108
|
+
await session.model.switch({ modelId: request.defaultModelId });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.warn("[Factory Start] Failed to apply factory default model", {
|
|
111
|
+
modelId: request.defaultModelId,
|
|
112
|
+
error: error instanceof Error ? error.message : String(error)
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const threadId = await configureThread(session, request);
|
|
116
|
+
const kickoffMessage = await resolveKickoffMessage(session, request.invocation);
|
|
117
|
+
const prepared = await storage.prepareRunStart({
|
|
118
|
+
orgId: request.orgId,
|
|
119
|
+
userId: request.userId,
|
|
120
|
+
factoryProjectId: request.factoryProjectId,
|
|
121
|
+
workItem: {
|
|
122
|
+
id: request.workItem.id,
|
|
123
|
+
input: request.workItem.input
|
|
124
|
+
},
|
|
125
|
+
role: request.workItem.role,
|
|
126
|
+
session: {
|
|
127
|
+
sessionId: sourceSession.sessionId,
|
|
128
|
+
branch: sourceSession.branch,
|
|
129
|
+
threadId
|
|
130
|
+
},
|
|
131
|
+
resourceId: sourceSession.sessionId,
|
|
132
|
+
kickoffKey: request.kickoffKey,
|
|
133
|
+
kickoffMessage
|
|
134
|
+
});
|
|
135
|
+
await session.thread.setSetting({
|
|
136
|
+
key: "factoryWorkItemId",
|
|
137
|
+
value: prepared.item.id
|
|
138
|
+
});
|
|
139
|
+
let revision = prepared.item.revision;
|
|
140
|
+
if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {
|
|
141
|
+
if (!this.#transitionService) throw new Error("Factory transition service is unavailable.");
|
|
142
|
+
const transition = await this.#transitionService.transition({
|
|
143
|
+
orgId: request.orgId,
|
|
144
|
+
factoryProjectId: request.factoryProjectId,
|
|
145
|
+
workItemId: prepared.item.id,
|
|
146
|
+
board: prepared.item.externalSource?.type === "pull-request" ? "review" : "work",
|
|
147
|
+
stage: request.destinationStage,
|
|
148
|
+
expectedRevision: prepared.item.revision,
|
|
149
|
+
actor: {
|
|
150
|
+
type: "human",
|
|
151
|
+
id: request.userId
|
|
152
|
+
},
|
|
153
|
+
ingress: {
|
|
154
|
+
type: "human",
|
|
155
|
+
identity: `start:${request.kickoffKey}:transition`
|
|
156
|
+
},
|
|
157
|
+
cause: "run_start"
|
|
158
|
+
});
|
|
159
|
+
if (transition.status === "rejected") {
|
|
160
|
+
await storage.markPendingStart(prepared.binding.id, "failed", transition.reason);
|
|
161
|
+
throw new FactoryStartTransitionError(transition);
|
|
162
|
+
}
|
|
163
|
+
revision = transition.revision;
|
|
164
|
+
}
|
|
165
|
+
if (kickoffMessage === null) {
|
|
166
|
+
await storage.markPendingStart(prepared.binding.id, "sent");
|
|
167
|
+
prepared.pendingStart.status = "sent";
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
workItemId: prepared.item.id,
|
|
171
|
+
bindingId: prepared.binding.id,
|
|
172
|
+
threadId,
|
|
173
|
+
resourceId: sourceSession.sessionId,
|
|
174
|
+
sessionId: sourceSession.sessionId,
|
|
175
|
+
branch: sourceSession.branch,
|
|
176
|
+
revision,
|
|
177
|
+
kickoffStatus: prepared.pendingStart.status,
|
|
178
|
+
replayed: prepared.replayed
|
|
179
|
+
};
|
|
180
|
+
}
|
|
173
181
|
};
|
|
182
|
+
//#endregion
|
|
183
|
+
export { FactoryStartCoordinator, FactoryStartTransitionError };
|
|
184
|
+
|
|
174
185
|
//# sourceMappingURL=start-coordinator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rules/start-coordinator.ts"],"sourcesContent":["import type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { formatSkillActivation } from '@mastra/core/workspace';\n\nimport type { MemorySettingsRecord, MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { SourceControlSession, SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport type { CreateWorkItemInput, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { FactoryTransitionService } from './transition-service.js';\nimport type { FactoryRuleStage, FactoryTransitionResult } from './types.js';\n\nexport interface FactoryStartRequest {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sessionId: string;\n threadTitle: string;\n threadTags?: Record<string, string>;\n kickoffKey: string;\n invocation?: { type: 'prompt'; prompt: string } | { type: 'skill'; skillName: string; arguments: string };\n destinationStage: FactoryRuleStage;\n defaultModelId?: string;\n workItem: {\n id?: string;\n role: string;\n input: CreateWorkItemInput;\n };\n requestContext?: RequestContext;\n}\n\nexport class FactoryStartTransitionError extends Error {\n readonly result: Extract<FactoryTransitionResult, { status: 'rejected' }>;\n\n constructor(result: Extract<FactoryTransitionResult, { status: 'rejected' }>) {\n super(result.reason);\n this.name = 'FactoryStartTransitionError';\n this.result = result;\n }\n}\n\nexport interface FactoryStartPreparedResult {\n workItemId: string;\n bindingId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n revision: number;\n kickoffStatus: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n replayed: boolean;\n}\n\ntype FactoryController = AgentController<MastraCodeState>;\ntype FactorySession = Awaited<ReturnType<FactoryController['createSession']>>;\n\nfunction escapeSkillBoundary(value: string): string {\n return value.replaceAll('</skill>', '</skill>');\n}\n\nasync function resolveKickoffMessage(\n session: FactorySession,\n invocation: FactoryStartRequest['invocation'],\n): Promise<string | null> {\n if (!invocation) return null;\n if (invocation.type === 'prompt') return invocation.prompt;\n\n const skills = session.getWorkspace().skills;\n await skills?.maybeRefresh();\n const skill = await skills?.get(invocation.skillName);\n if (!skill || skill['user-invocable'] === false) {\n throw new Error(`Skill not found: ${invocation.skillName}.`);\n }\n const args = invocation.arguments.trim();\n const content = `${formatSkillActivation(skill)}${args ? `\\n\\nARGUMENTS: ${args}` : ''}`.trim();\n return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n storage: SourceControlStorageHandle,\n request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n const session = await storage.sessions.getBySessionId(request.sessionId);\n if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n throw new Error('Factory session not found');\n }\n const projectRepository = await storage.projectRepositories.get({\n orgId: request.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('Factory session repository not found');\n const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n throw new Error('Factory session does not belong to this project');\n }\n return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n const threadId = session.thread.requireId();\n await session.thread.rename({ title: request.threadTitle });\n const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n return threadId;\n}\n\nasync function applyMemorySettings(session: FactorySession, record: MemorySettingsRecord | null): Promise<void> {\n if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });\n if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });\n\n const state = {\n ...(record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {}),\n ...(record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {}),\n ...(record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}),\n };\n if (Object.keys(state).length > 0) await session.state.set(state);\n}\n\nexport class FactoryStartCoordinator {\n readonly #controller: FactoryController;\n readonly #storage: WorkItemsStorage;\n readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n readonly #sourceControl?: SourceControlStorageHandle;\n readonly #memorySettings?: MemorySettingsStorage;\n\n constructor(\n controller: FactoryController,\n storage: WorkItemsStorage,\n transitionService?: Pick<FactoryTransitionService, 'transition'>,\n sourceControl?: SourceControlStorageHandle,\n memorySettings?: MemorySettingsStorage,\n ) {\n this.#controller = controller;\n this.#storage = storage;\n this.#transitionService = transitionService;\n this.#sourceControl = sourceControl;\n this.#memorySettings = memorySettings;\n }\n\n async prepare(request: FactoryStartRequest): Promise<FactoryStartPreparedResult> {\n const storage = this.#storage;\n if (!this.#sourceControl) throw new Error('Factory source control storage is unavailable');\n const sourceSession = await resolveSourceSession(this.#sourceControl, request);\n const requestContext = request.requestContext ?? new RequestContext();\n if (!request.requestContext) {\n requestContext.set('user', { workosId: request.userId, organizationId: request.orgId });\n }\n const sessionState = {\n factoryProjectId: request.factoryProjectId,\n projectRepositoryId: sourceSession.projectRepositoryId,\n };\n const session = await this.#controller.createSession({\n id: sourceSession.sessionId,\n ownerId: request.userId,\n resourceId: sourceSession.sessionId,\n threadId: sourceSession.sessionId,\n requestContext,\n tags: sessionState,\n });\n // Bound-agent authority gates (the transition tool, the factory-phase\n // processor, workspace token selection) resolve the session address from\n // controller state. Seed it server-side — `tags` covers fresh creation,\n // the explicit setState covers get-or-create returning a session another\n // caller created without them — so autonomous runs never depend on a\n // browser connecting to populate the state.\n await session.state.set(sessionState);\n if (this.#memorySettings) {\n try {\n const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });\n await applyMemorySettings(session, record);\n } catch (error) {\n console.warn('[Factory Start] Failed to apply observational-memory settings', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n if (request.defaultModelId) {\n try {\n await session.model.switch({ modelId: request.defaultModelId });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default model', {\n modelId: request.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n const threadId = await configureThread(session, request);\n const kickoffMessage = await resolveKickoffMessage(session, request.invocation);\n const prepared = await storage.prepareRunStart({\n orgId: request.orgId,\n userId: request.userId,\n factoryProjectId: request.factoryProjectId,\n workItem: { id: request.workItem.id, input: request.workItem.input },\n role: request.workItem.role,\n session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n resourceId: sourceSession.sessionId,\n kickoffKey: request.kickoffKey,\n kickoffMessage,\n });\n await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n let revision = prepared.item.revision;\n if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n const transition = await this.#transitionService.transition({\n orgId: request.orgId,\n factoryProjectId: request.factoryProjectId,\n workItemId: prepared.item.id,\n board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: request.destinationStage,\n expectedRevision: prepared.item.revision,\n actor: { type: 'human', id: request.userId },\n ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n cause: 'run_start',\n });\n if (transition.status === 'rejected') {\n await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n throw new FactoryStartTransitionError(transition);\n }\n revision = transition.revision;\n }\n\n if (kickoffMessage === null) {\n await storage.markPendingStart(prepared.binding.id, 'sent');\n prepared.pendingStart.status = 'sent';\n }\n\n return {\n workItemId: prepared.item.id,\n bindingId: prepared.binding.id,\n threadId,\n resourceId: sourceSession.sessionId,\n sessionId: sourceSession.sessionId,\n branch: sourceSession.branch,\n revision,\n kickoffStatus: prepared.pendingStart.status,\n replayed: prepared.replayed,\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"file":"start-coordinator.js","names":["#controller","#storage","#transitionService","#sourceControl","#memorySettings"],"sources":["../../src/rules/start-coordinator.ts"],"sourcesContent":["import type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { formatSkillActivation } from '@mastra/core/workspace';\n\nimport type { MemorySettingsRecord, MemorySettingsStorage } from '../storage/domains/memory-settings/base.js';\nimport type { SourceControlSession, SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport type { CreateWorkItemInput, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { FactoryTransitionService } from './transition-service.js';\nimport type { FactoryRuleStage, FactoryTransitionResult } from './types.js';\n\nexport interface FactoryStartRequest {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sessionId: string;\n threadTitle: string;\n threadTags?: Record<string, string>;\n kickoffKey: string;\n invocation?: { type: 'prompt'; prompt: string } | { type: 'skill'; skillName: string; arguments: string };\n destinationStage: FactoryRuleStage;\n defaultModelId?: string;\n workItem: {\n id?: string;\n role: string;\n input: CreateWorkItemInput;\n };\n requestContext?: RequestContext;\n}\n\nexport class FactoryStartTransitionError extends Error {\n readonly result: Extract<FactoryTransitionResult, { status: 'rejected' }>;\n\n constructor(result: Extract<FactoryTransitionResult, { status: 'rejected' }>) {\n super(result.reason);\n this.name = 'FactoryStartTransitionError';\n this.result = result;\n }\n}\n\nexport interface FactoryStartPreparedResult {\n workItemId: string;\n bindingId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n revision: number;\n kickoffStatus: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n replayed: boolean;\n}\n\ntype FactoryController = AgentController<MastraCodeState>;\ntype FactorySession = Awaited<ReturnType<FactoryController['createSession']>>;\n\nfunction escapeSkillBoundary(value: string): string {\n return value.replaceAll('</skill>', '</skill>');\n}\n\nasync function resolveKickoffMessage(\n session: FactorySession,\n invocation: FactoryStartRequest['invocation'],\n): Promise<string | null> {\n if (!invocation) return null;\n if (invocation.type === 'prompt') return invocation.prompt;\n\n const skills = session.getWorkspace().skills;\n await skills?.maybeRefresh();\n const skill = await skills?.get(invocation.skillName);\n if (!skill || skill['user-invocable'] === false) {\n throw new Error(`Skill not found: ${invocation.skillName}.`);\n }\n const args = invocation.arguments.trim();\n const content = `${formatSkillActivation(skill)}${args ? `\\n\\nARGUMENTS: ${args}` : ''}`.trim();\n return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n storage: SourceControlStorageHandle,\n request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n const session = await storage.sessions.getBySessionId(request.sessionId);\n if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n throw new Error('Factory session not found');\n }\n const projectRepository = await storage.projectRepositories.get({\n orgId: request.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('Factory session repository not found');\n const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n throw new Error('Factory session does not belong to this project');\n }\n return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n const threadId = session.thread.requireId();\n await session.thread.rename({ title: request.threadTitle });\n const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n return threadId;\n}\n\nasync function applyMemorySettings(session: FactorySession, record: MemorySettingsRecord | null): Promise<void> {\n if (record?.observerModelId) await session.om.observer.switchModel({ modelId: record.observerModelId });\n if (record?.reflectorModelId) await session.om.reflector.switchModel({ modelId: record.reflectorModelId });\n\n const state = {\n ...(record?.observationThreshold != null ? { observationThreshold: record.observationThreshold } : {}),\n ...(record?.reflectionThreshold != null ? { reflectionThreshold: record.reflectionThreshold } : {}),\n ...(record?.observeAttachments != null ? { observeAttachments: record.observeAttachments } : {}),\n };\n if (Object.keys(state).length > 0) await session.state.set(state);\n}\n\nexport class FactoryStartCoordinator {\n readonly #controller: FactoryController;\n readonly #storage: WorkItemsStorage;\n readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n readonly #sourceControl?: SourceControlStorageHandle;\n readonly #memorySettings?: MemorySettingsStorage;\n\n constructor(\n controller: FactoryController,\n storage: WorkItemsStorage,\n transitionService?: Pick<FactoryTransitionService, 'transition'>,\n sourceControl?: SourceControlStorageHandle,\n memorySettings?: MemorySettingsStorage,\n ) {\n this.#controller = controller;\n this.#storage = storage;\n this.#transitionService = transitionService;\n this.#sourceControl = sourceControl;\n this.#memorySettings = memorySettings;\n }\n\n async prepare(request: FactoryStartRequest): Promise<FactoryStartPreparedResult> {\n const storage = this.#storage;\n if (!this.#sourceControl) throw new Error('Factory source control storage is unavailable');\n const sourceSession = await resolveSourceSession(this.#sourceControl, request);\n const requestContext = request.requestContext ?? new RequestContext();\n if (!request.requestContext) {\n requestContext.set('user', { workosId: request.userId, organizationId: request.orgId });\n }\n const sessionState = {\n factoryProjectId: request.factoryProjectId,\n projectRepositoryId: sourceSession.projectRepositoryId,\n };\n const session = await this.#controller.createSession({\n id: sourceSession.sessionId,\n ownerId: request.userId,\n resourceId: sourceSession.sessionId,\n threadId: sourceSession.sessionId,\n requestContext,\n tags: sessionState,\n });\n // Bound-agent authority gates (the transition tool, the factory-phase\n // processor, workspace token selection) resolve the session address from\n // controller state. Seed it server-side — `tags` covers fresh creation,\n // the explicit setState covers get-or-create returning a session another\n // caller created without them — so autonomous runs never depend on a\n // browser connecting to populate the state.\n await session.state.set(sessionState);\n if (this.#memorySettings) {\n try {\n const record = await this.#memorySettings.get({ orgId: request.orgId, userId: request.userId });\n await applyMemorySettings(session, record);\n } catch (error) {\n console.warn('[Factory Start] Failed to apply observational-memory settings', {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n if (request.defaultModelId) {\n try {\n await session.model.switch({ modelId: request.defaultModelId });\n } catch (error) {\n console.warn('[Factory Start] Failed to apply factory default model', {\n modelId: request.defaultModelId,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n const threadId = await configureThread(session, request);\n const kickoffMessage = await resolveKickoffMessage(session, request.invocation);\n const prepared = await storage.prepareRunStart({\n orgId: request.orgId,\n userId: request.userId,\n factoryProjectId: request.factoryProjectId,\n workItem: { id: request.workItem.id, input: request.workItem.input },\n role: request.workItem.role,\n session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n resourceId: sourceSession.sessionId,\n kickoffKey: request.kickoffKey,\n kickoffMessage,\n });\n await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n let revision = prepared.item.revision;\n if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n const transition = await this.#transitionService.transition({\n orgId: request.orgId,\n factoryProjectId: request.factoryProjectId,\n workItemId: prepared.item.id,\n board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: request.destinationStage,\n expectedRevision: prepared.item.revision,\n actor: { type: 'human', id: request.userId },\n ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n cause: 'run_start',\n });\n if (transition.status === 'rejected') {\n await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n throw new FactoryStartTransitionError(transition);\n }\n revision = transition.revision;\n }\n\n if (kickoffMessage === null) {\n await storage.markPendingStart(prepared.binding.id, 'sent');\n prepared.pendingStart.status = 'sent';\n }\n\n return {\n workItemId: prepared.item.id,\n bindingId: prepared.binding.id,\n threadId,\n resourceId: sourceSession.sessionId,\n sessionId: sourceSession.sessionId,\n branch: sourceSession.branch,\n revision,\n kickoffStatus: prepared.pendingStart.status,\n replayed: prepared.replayed,\n };\n }\n}\n"],"mappings":"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"}
|
package/dist/rules/tools.js
CHANGED
|
@@ -1,93 +1,58 @@
|
|
|
1
|
-
|
|
1
|
+
import { FACTORY_RULE_STAGES } from "./types.js";
|
|
2
|
+
import { getFactorySessionAddress } from "./binding-context.js";
|
|
2
3
|
import { createTool } from "@mastra/core/tools";
|
|
3
4
|
import { z } from "zod";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
isAuthHttpHandler,
|
|
10
|
-
isCredentialsProvider,
|
|
11
|
-
isOrganizationsProvider,
|
|
12
|
-
isSessionProvider,
|
|
13
|
-
isSSOProvider
|
|
14
|
-
} from "@mastra/core/server";
|
|
15
|
-
function getFactoryAuthOrgId(user) {
|
|
16
|
-
return user?.organizationId;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// src/rules/binding-context.ts
|
|
20
|
-
function getFactorySessionCoordinates(requestContext) {
|
|
21
|
-
if (!requestContext || typeof requestContext.get !== "function") return null;
|
|
22
|
-
const context = requestContext.get("controller");
|
|
23
|
-
const factoryProjectId = context?.getState().factoryProjectId;
|
|
24
|
-
if (!context?.threadId || !context.resourceId || !factoryProjectId) return null;
|
|
25
|
-
return {
|
|
26
|
-
factoryProjectId,
|
|
27
|
-
threadId: context.threadId,
|
|
28
|
-
resourceId: context.resourceId,
|
|
29
|
-
sessionId: context.resourceId
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function getFactorySessionAddress(requestContext) {
|
|
33
|
-
const coordinates = getFactorySessionCoordinates(requestContext);
|
|
34
|
-
if (!coordinates || !requestContext || typeof requestContext.get !== "function") return null;
|
|
35
|
-
const user = requestContext.get("user");
|
|
36
|
-
const orgId = getFactoryAuthOrgId(user);
|
|
37
|
-
if (!orgId) return null;
|
|
38
|
-
return { orgId, ...coordinates };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// src/rules/types.ts
|
|
42
|
-
var FACTORY_RULE_STAGES = ["intake", "triage", "planning", "execute", "review", "done", "canceled"];
|
|
43
|
-
|
|
44
|
-
// src/rules/tools.ts
|
|
45
|
-
var transitionInputSchema = z.object({
|
|
46
|
-
stage: z.enum(FACTORY_RULE_STAGES),
|
|
47
|
-
expectedRevision: z.number().int().positive(),
|
|
48
|
-
rationale: z.string().trim().min(1).max(1e3)
|
|
5
|
+
//#region src/rules/tools.ts
|
|
6
|
+
const transitionInputSchema = z.object({
|
|
7
|
+
stage: z.enum(FACTORY_RULE_STAGES),
|
|
8
|
+
expectedRevision: z.number().int().positive(),
|
|
9
|
+
rationale: z.string().trim().min(1).max(1e3)
|
|
49
10
|
}).strict();
|
|
50
11
|
function boardForSource(type) {
|
|
51
|
-
|
|
12
|
+
return type === "pull-request" ? "review" : "work";
|
|
52
13
|
}
|
|
53
14
|
async function createFactoryTransitionTools(options) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
15
|
+
const address = getFactorySessionAddress(options.requestContext);
|
|
16
|
+
if (!address) return {};
|
|
17
|
+
const availableBinding = await options.storage.findActiveRunBinding(address);
|
|
18
|
+
if (!availableBinding) return {};
|
|
19
|
+
return { factory_transition_work_item: createTool({
|
|
20
|
+
id: "factory_transition_work_item",
|
|
21
|
+
description: "Request a governed stage transition for the Factory work item exactly bound to this thread. Use the current revision from the factory-phase signal and explain why the transition is appropriate.",
|
|
22
|
+
inputSchema: transitionInputSchema,
|
|
23
|
+
execute: async ({ stage, expectedRevision, rationale }, execution) => {
|
|
24
|
+
const currentAddress = getFactorySessionAddress(execution.requestContext);
|
|
25
|
+
const toolCallId = execution.agent?.toolCallId;
|
|
26
|
+
if (!currentAddress || !toolCallId) throw new Error("Factory transitions require an authenticated bound agent tool call.");
|
|
27
|
+
const binding = await options.storage.findActiveRunBinding(currentAddress);
|
|
28
|
+
if (!binding || binding.id !== availableBinding.id) throw new Error("Factory agent binding is unavailable, revoked, or no longer matches this session.");
|
|
29
|
+
const item = await options.storage.get({
|
|
30
|
+
orgId: binding.orgId,
|
|
31
|
+
id: binding.workItemId
|
|
32
|
+
});
|
|
33
|
+
if (!item) throw new Error("Bound Factory work item not found.");
|
|
34
|
+
return options.transitionService.transition({
|
|
35
|
+
orgId: binding.orgId,
|
|
36
|
+
factoryProjectId: binding.factoryProjectId,
|
|
37
|
+
workItemId: binding.workItemId,
|
|
38
|
+
board: boardForSource(item.externalSource?.type),
|
|
39
|
+
stage,
|
|
40
|
+
expectedRevision,
|
|
41
|
+
actor: {
|
|
42
|
+
type: "agent",
|
|
43
|
+
bindingId: binding.id,
|
|
44
|
+
role: binding.role
|
|
45
|
+
},
|
|
46
|
+
ingress: {
|
|
47
|
+
type: "agent",
|
|
48
|
+
identity: `${binding.id}:${toolCallId}`
|
|
49
|
+
},
|
|
50
|
+
cause: rationale
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}) };
|
|
89
54
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
55
|
+
//#endregion
|
|
56
|
+
export { createFactoryTransitionTools };
|
|
57
|
+
|
|
93
58
|
//# sourceMappingURL=tools.js.map
|