@mastra/code-sdk 1.9.0-alpha.9 → 1.10.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 +23 -0
- package/dist/agent-connections/tools.d.ts.map +1 -1
- package/dist/agent-connections/tools.js +5 -5
- package/dist/agent-connections/tools.js.map +1 -1
- package/dist/agents/tools.d.ts +1 -1
- package/dist/agents/tools.d.ts.map +1 -1
- package/dist/agents/tools.js +2 -1
- package/dist/agents/tools.js.map +1 -1
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +2 -3
- package/dist/analytics.js.map +1 -1
- package/dist/auth/account-rotation-processor.d.ts.map +1 -1
- package/dist/auth/account-rotation-processor.js +17 -10
- package/dist/auth/account-rotation-processor.js.map +1 -1
- package/dist/auth/providers/kimi-coding.d.ts.map +1 -1
- package/dist/auth/providers/kimi-coding.js +1 -2
- package/dist/auth/providers/kimi-coding.js.map +1 -1
- package/dist/auth/providers/openai-codex.d.ts +1 -1
- package/dist/auth/providers/openai-codex.d.ts.map +1 -1
- package/dist/auth/providers/openai-codex.js +7 -19
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/storage.js +3 -3
- package/dist/auth/storage.js.map +1 -1
- package/dist/experimental-agent.d.ts +11 -0
- package/dist/experimental-agent.d.ts.map +1 -0
- package/dist/experimental-agent.js +36 -0
- package/dist/experimental-agent.js.map +1 -0
- package/dist/goal-manager.d.ts +39 -3
- package/dist/goal-manager.d.ts.map +1 -1
- package/dist/goal-manager.js +113 -31
- package/dist/goal-manager.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +95 -12
- package/dist/index.js.map +1 -1
- package/dist/knowledge-inspector.d.ts.map +1 -1
- package/dist/knowledge-inspector.js +1 -2
- package/dist/knowledge-inspector.js.map +1 -1
- package/dist/onboarding/settings.d.ts +11 -0
- package/dist/onboarding/settings.d.ts.map +1 -1
- package/dist/onboarding/settings.js +39 -5
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +6 -1
- package/dist/permissions.js.map +1 -1
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +1 -2
- package/dist/plugins/loader.js.map +1 -1
- package/dist/process-memory-diagnostics.d.ts.map +1 -1
- package/dist/process-memory-diagnostics.js +2 -3
- package/dist/process-memory-diagnostics.js.map +1 -1
- package/dist/schedules/index.d.ts +10 -0
- package/dist/schedules/index.d.ts.map +1 -0
- package/dist/schedules/index.js +6 -0
- package/dist/schedules/interval.d.ts +49 -0
- package/dist/schedules/interval.d.ts.map +1 -0
- package/dist/schedules/interval.js +215 -0
- package/dist/schedules/interval.js.map +1 -0
- package/dist/schedules/prompt.d.ts +36 -0
- package/dist/schedules/prompt.d.ts.map +1 -0
- package/dist/schedules/prompt.js +39 -0
- package/dist/schedules/prompt.js.map +1 -0
- package/dist/schedules/run-script.d.ts +8 -0
- package/dist/schedules/run-script.d.ts.map +1 -0
- package/dist/schedules/run-script.js +83 -0
- package/dist/schedules/run-script.js.map +1 -0
- package/dist/schedules/scheduler.d.ts +101 -0
- package/dist/schedules/scheduler.d.ts.map +1 -0
- package/dist/schedules/scheduler.js +169 -0
- package/dist/schedules/scheduler.js.map +1 -0
- package/dist/schedules/tools.d.ts +57 -0
- package/dist/schedules/tools.d.ts.map +1 -0
- package/dist/schedules/tools.js +220 -0
- package/dist/schedules/tools.js.map +1 -0
- package/dist/tools/workflows/ephemeral-memory.d.ts +21 -0
- package/dist/tools/workflows/ephemeral-memory.d.ts.map +1 -1
- package/dist/tools/workflows/ephemeral-memory.js +1 -2
- package/dist/tools/workflows/ephemeral-memory.js.map +1 -1
- package/dist/utils/discarding-scores-storage.d.ts +33 -0
- package/dist/utils/discarding-scores-storage.d.ts.map +1 -0
- package/dist/utils/discarding-scores-storage.js +54 -0
- package/dist/utils/discarding-scores-storage.js.map +1 -0
- package/dist/utils/maintenance-lock.d.ts +42 -0
- package/dist/utils/maintenance-lock.d.ts.map +1 -0
- package/dist/utils/maintenance-lock.js +199 -0
- package/dist/utils/maintenance-lock.js.map +1 -0
- package/dist/utils/prune-cli.d.ts +24 -0
- package/dist/utils/prune-cli.d.ts.map +1 -0
- package/dist/utils/prune-cli.js +125 -0
- package/dist/utils/prune-cli.js.map +1 -0
- package/dist/utils/signals-pubsub.d.ts.map +1 -1
- package/dist/utils/signals-pubsub.js +1 -2
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/storage-maintenance.d.ts.map +1 -1
- package/dist/utils/storage-maintenance.js +33 -3
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/package.json +21 -15
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { parseInterval, validateInterval } from "./interval.js";
|
|
2
|
+
import { describeScheduleSource, shortScheduleId } from "./scheduler.js";
|
|
3
|
+
import { resolveScriptCommand } from "./run-script.js";
|
|
4
|
+
import * as path$1 from "path";
|
|
5
|
+
import { createTool } from "@mastra/core/tools";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
//#region src/schedules/tools.ts
|
|
8
|
+
/**
|
|
9
|
+
* Agent-facing tools for the process-local `/schedules` scheduler.
|
|
10
|
+
*
|
|
11
|
+
* Opt-in (experimental setting). Every tool is bound to the thread of the run
|
|
12
|
+
* that calls it — the model never picks a thread or resource — and can only
|
|
13
|
+
* see or manage schedules on that thread.
|
|
14
|
+
*/
|
|
15
|
+
const SCHEDULE_TOOL_IDS = {
|
|
16
|
+
create: "schedule_create",
|
|
17
|
+
list: "schedule_list",
|
|
18
|
+
update: "schedule_update",
|
|
19
|
+
resume: "schedule_resume",
|
|
20
|
+
run: "schedule_run"
|
|
21
|
+
};
|
|
22
|
+
const resultSchema = z.object({
|
|
23
|
+
content: z.string(),
|
|
24
|
+
isError: z.boolean().optional()
|
|
25
|
+
});
|
|
26
|
+
const intervalSchema = z.string().min(1).transform((value, ctx) => {
|
|
27
|
+
const interval = parseInterval(value);
|
|
28
|
+
if ("error" in interval) {
|
|
29
|
+
ctx.addIssue({
|
|
30
|
+
code: "custom",
|
|
31
|
+
message: interval.error
|
|
32
|
+
});
|
|
33
|
+
return z.NEVER;
|
|
34
|
+
}
|
|
35
|
+
const check = validateInterval(interval);
|
|
36
|
+
if ("error" in check) {
|
|
37
|
+
const suggestion = check.suggestion ? ` Try ${check.suggestion}.` : "";
|
|
38
|
+
ctx.addIssue({
|
|
39
|
+
code: "custom",
|
|
40
|
+
message: `${check.error}${suggestion}`
|
|
41
|
+
});
|
|
42
|
+
return z.NEVER;
|
|
43
|
+
}
|
|
44
|
+
return interval;
|
|
45
|
+
}).describe("Cadence such as \"5m\", \"2h\", or \"1d\". Minute steps must divide 60, hour steps must divide 24.");
|
|
46
|
+
const triggerSchema = z.discriminatedUnion("kind", [z.object({
|
|
47
|
+
kind: z.literal("every"),
|
|
48
|
+
interval: intervalSchema
|
|
49
|
+
})]).describe("When the schedule fires. \"every\" repeats on wall-clock boundaries (5m fires at :00, :05, …).");
|
|
50
|
+
const idSchema = z.string().min(1).describe("Schedule id, or a unique prefix of it (the 8-character short id works).");
|
|
51
|
+
function threadOf(context) {
|
|
52
|
+
const agent = context?.agent;
|
|
53
|
+
return agent?.threadId && agent.resourceId ? {
|
|
54
|
+
threadId: agent.threadId,
|
|
55
|
+
resourceId: agent.resourceId
|
|
56
|
+
} : void 0;
|
|
57
|
+
}
|
|
58
|
+
const NO_THREAD = {
|
|
59
|
+
content: "Schedules require a memory-backed thread.",
|
|
60
|
+
isError: true
|
|
61
|
+
};
|
|
62
|
+
function resolveFile(token, mode, options) {
|
|
63
|
+
const expanded = token.startsWith("~/") && options.homeDir ? path$1.join(options.homeDir, token.slice(2)) : token;
|
|
64
|
+
const absPath = path$1.resolve(options.cwd, expanded);
|
|
65
|
+
return options.fileExists(absPath) ? {
|
|
66
|
+
path: absPath,
|
|
67
|
+
displayPath: token,
|
|
68
|
+
mode
|
|
69
|
+
} : void 0;
|
|
70
|
+
}
|
|
71
|
+
function formatSchedule(schedule) {
|
|
72
|
+
const timing = schedule.status === "paused" ? "paused" : `next at ${new Date(schedule.nextFireAt).toLocaleTimeString()}`;
|
|
73
|
+
return `${shortScheduleId(schedule.id)} every ${schedule.trigger.interval.label} ${timing} ${describeScheduleSource(schedule)} (created by ${schedule.createdBy})`;
|
|
74
|
+
}
|
|
75
|
+
function errorMessage(error) {
|
|
76
|
+
return error instanceof Error ? error.message : String(error);
|
|
77
|
+
}
|
|
78
|
+
function findOne(scheduler, threadId, id) {
|
|
79
|
+
const needle = id.toLowerCase();
|
|
80
|
+
const matches = scheduler.list({ threadId }).filter((schedule) => schedule.id.toLowerCase().startsWith(needle));
|
|
81
|
+
if (matches.length === 1) return { schedule: matches[0] };
|
|
82
|
+
return {
|
|
83
|
+
content: matches.length === 0 ? `No schedule "${id}" on this thread.` : `"${id}" matches several schedules.`,
|
|
84
|
+
isError: true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function createScheduleTools({ scheduler, fileOptions }) {
|
|
88
|
+
const scheduleCreateTool = createTool({
|
|
89
|
+
id: SCHEDULE_TOOL_IDS.create,
|
|
90
|
+
description: `Schedule a recurring prompt on this thread. Each fire arrives as a new user turn labelled "schedule".
|
|
91
|
+
|
|
92
|
+
Pass exactly one source: "prompt" (text sent each fire), "promptFile" (a file re-read and sent as the prompt each fire), or "script" (run each fire; its output is sent, followed by "extraPrompt" if given). Schedules live only until Mastra Code exits.`,
|
|
93
|
+
inputSchema: z.object({
|
|
94
|
+
trigger: triggerSchema,
|
|
95
|
+
prompt: z.string().trim().min(1).optional().describe("Prompt text to send on every fire."),
|
|
96
|
+
promptFile: z.string().trim().min(1).optional().describe("Path to a file to re-read and send on every fire."),
|
|
97
|
+
script: z.string().trim().min(1).optional().describe("Path to a script to run on every fire."),
|
|
98
|
+
extraPrompt: z.string().trim().min(1).optional().describe("Text sent after the script output.")
|
|
99
|
+
}).refine((input) => [
|
|
100
|
+
input.prompt,
|
|
101
|
+
input.promptFile,
|
|
102
|
+
input.script
|
|
103
|
+
].filter(Boolean).length === 1, { message: "Provide exactly one of \"prompt\", \"promptFile\", or \"script\"." }).refine((input) => !input.extraPrompt || input.script, { message: "\"extraPrompt\" only applies with \"script\"." }),
|
|
104
|
+
outputSchema: resultSchema,
|
|
105
|
+
execute: async (input, context) => {
|
|
106
|
+
const target = threadOf(context);
|
|
107
|
+
if (!target) return NO_THREAD;
|
|
108
|
+
let schedule;
|
|
109
|
+
if (input.prompt) schedule = scheduler.create({
|
|
110
|
+
trigger: input.trigger,
|
|
111
|
+
prompt: input.prompt,
|
|
112
|
+
createdBy: "agent"
|
|
113
|
+
}, target);
|
|
114
|
+
else {
|
|
115
|
+
const token = input.script ?? input.promptFile;
|
|
116
|
+
const file = resolveFile(token, input.script ? "script" : "prompt", fileOptions());
|
|
117
|
+
if (!file) return {
|
|
118
|
+
content: `File not found: ${token}`,
|
|
119
|
+
isError: true
|
|
120
|
+
};
|
|
121
|
+
if (file.mode === "script") try {
|
|
122
|
+
resolveScriptCommand(file.path);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
content: `Can't run ${token}: ${error instanceof Error ? error.message : String(error)}`,
|
|
126
|
+
isError: true
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
schedule = scheduler.create({
|
|
130
|
+
trigger: input.trigger,
|
|
131
|
+
file,
|
|
132
|
+
...input.extraPrompt ? { extraPrompt: input.extraPrompt } : {},
|
|
133
|
+
createdBy: "agent"
|
|
134
|
+
}, target);
|
|
135
|
+
}
|
|
136
|
+
return { content: `Created schedule ${formatSchedule(schedule)}` };
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const scheduleListTool = createTool({
|
|
140
|
+
id: SCHEDULE_TOOL_IDS.list,
|
|
141
|
+
description: "List the recurring prompt schedules on this thread, including ones the user created with /schedules.",
|
|
142
|
+
inputSchema: z.object({}),
|
|
143
|
+
outputSchema: resultSchema,
|
|
144
|
+
execute: async (_input, context) => {
|
|
145
|
+
const target = threadOf(context);
|
|
146
|
+
if (!target) return NO_THREAD;
|
|
147
|
+
const schedules = scheduler.list({ threadId: target.threadId });
|
|
148
|
+
if (schedules.length === 0) return { content: "No schedules on this thread." };
|
|
149
|
+
return { content: [`Schedules on this thread (${schedules.length}):`, ...schedules.map(formatSchedule)].join("\n") };
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
const scheduleUpdateTool = createTool({
|
|
153
|
+
id: SCHEDULE_TOOL_IDS.update,
|
|
154
|
+
description: "Pause or delete a schedule on this thread. Use schedule_resume to resume a paused one.",
|
|
155
|
+
inputSchema: z.object({
|
|
156
|
+
id: idSchema,
|
|
157
|
+
action: z.enum(["pause", "delete"])
|
|
158
|
+
}),
|
|
159
|
+
outputSchema: resultSchema,
|
|
160
|
+
execute: async ({ id, action }, context) => {
|
|
161
|
+
const target = threadOf(context);
|
|
162
|
+
if (!target) return NO_THREAD;
|
|
163
|
+
const found = findOne(scheduler, target.threadId, id);
|
|
164
|
+
if (!("schedule" in found)) return found;
|
|
165
|
+
scheduler[action](found.schedule.id);
|
|
166
|
+
return { content: `${action === "pause" ? "Paused" : "Deleted"} schedule ${shortScheduleId(found.schedule.id)}.` };
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
const scheduleResumeTool = createTool({
|
|
170
|
+
id: SCHEDULE_TOOL_IDS.resume,
|
|
171
|
+
description: "Resume a paused schedule on this thread. It fires again from the next clock boundary.",
|
|
172
|
+
inputSchema: z.object({ id: idSchema }),
|
|
173
|
+
outputSchema: resultSchema,
|
|
174
|
+
execute: async ({ id }, context) => {
|
|
175
|
+
const target = threadOf(context);
|
|
176
|
+
if (!target) return NO_THREAD;
|
|
177
|
+
const found = findOne(scheduler, target.threadId, id);
|
|
178
|
+
if (!("schedule" in found)) return found;
|
|
179
|
+
scheduler.resume(found.schedule.id);
|
|
180
|
+
return { content: `Resumed schedule ${shortScheduleId(found.schedule.id)}.` };
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
const scheduleRunTool = createTool({
|
|
184
|
+
id: SCHEDULE_TOOL_IDS.run,
|
|
185
|
+
description: "Fire a schedule on this thread once now, even if it is paused, without changing its cadence. Its prompt arrives as the next user turn.",
|
|
186
|
+
inputSchema: z.object({ id: idSchema }),
|
|
187
|
+
outputSchema: resultSchema,
|
|
188
|
+
execute: async ({ id }, context) => {
|
|
189
|
+
const target = threadOf(context);
|
|
190
|
+
if (!target) return NO_THREAD;
|
|
191
|
+
const found = findOne(scheduler, target.threadId, id);
|
|
192
|
+
if (!("schedule" in found)) return found;
|
|
193
|
+
const short = shortScheduleId(found.schedule.id);
|
|
194
|
+
const result = await scheduler.run(found.schedule.id);
|
|
195
|
+
switch (result.status) {
|
|
196
|
+
case "fired": return { content: `Triggered schedule ${short}; its prompt arrives as the next turn.` };
|
|
197
|
+
case "busy": return { content: `Schedule ${short} is already firing; skipped so its prompt isn't sent twice.` };
|
|
198
|
+
case "not-found": return {
|
|
199
|
+
content: `Schedule ${short} was deleted before it fired.`,
|
|
200
|
+
isError: true
|
|
201
|
+
};
|
|
202
|
+
case "failed": return {
|
|
203
|
+
content: `Schedule ${short} failed to fire: ${errorMessage(result.error)}`,
|
|
204
|
+
isError: true
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return {
|
|
210
|
+
[SCHEDULE_TOOL_IDS.create]: scheduleCreateTool,
|
|
211
|
+
[SCHEDULE_TOOL_IDS.list]: scheduleListTool,
|
|
212
|
+
[SCHEDULE_TOOL_IDS.update]: scheduleUpdateTool,
|
|
213
|
+
[SCHEDULE_TOOL_IDS.resume]: scheduleResumeTool,
|
|
214
|
+
[SCHEDULE_TOOL_IDS.run]: scheduleRunTool
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//#endregion
|
|
218
|
+
export { SCHEDULE_TOOL_IDS, createScheduleTools };
|
|
219
|
+
|
|
220
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","names":["path"],"sources":["../../src/schedules/tools.ts"],"sourcesContent":["/**\n * Agent-facing tools for the process-local `/schedules` scheduler.\n *\n * Opt-in (experimental setting). Every tool is bound to the thread of the run\n * that calls it — the model never picks a thread or resource — and can only\n * see or manage schedules on that thread.\n */\nimport * as path from 'node:path';\nimport { createTool } from '@mastra/core/tools';\nimport { z } from 'zod';\n\nimport { parseInterval, validateInterval } from './interval.js';\nimport { resolveScriptCommand } from './run-script.js';\nimport { describeScheduleSource, shortScheduleId } from './scheduler.js';\nimport type { ScheduleFile, ThreadSchedule, ThreadScheduler } from './scheduler.js';\n\nexport const SCHEDULE_TOOL_IDS = {\n create: 'schedule_create',\n list: 'schedule_list',\n update: 'schedule_update',\n resume: 'schedule_resume',\n run: 'schedule_run',\n} as const;\n\nexport type ScheduleFileOptions = {\n /** Directory relative paths resolve against (the project root). */\n cwd: string;\n homeDir?: string;\n fileExists: (absPath: string) => boolean;\n};\n\nexport type ScheduleToolsOptions = {\n scheduler: ThreadScheduler;\n fileOptions: () => ScheduleFileOptions;\n};\n\ntype ToolRunContext = { agent?: { threadId?: string; resourceId?: string } };\n\nconst resultSchema = z.object({\n content: z.string(),\n isError: z.boolean().optional(),\n});\ntype ScheduleToolResult = z.infer<typeof resultSchema>;\n\nconst intervalSchema = z\n .string()\n .min(1)\n .transform((value, ctx) => {\n const interval = parseInterval(value);\n if ('error' in interval) {\n ctx.addIssue({ code: 'custom', message: interval.error });\n return z.NEVER;\n }\n const check = validateInterval(interval);\n if ('error' in check) {\n const suggestion = check.suggestion ? ` Try ${check.suggestion}.` : '';\n ctx.addIssue({ code: 'custom', message: `${check.error}${suggestion}` });\n return z.NEVER;\n }\n return interval;\n })\n .describe('Cadence such as \"5m\", \"2h\", or \"1d\". Minute steps must divide 60, hour steps must divide 24.');\n\nconst triggerSchema = z\n .discriminatedUnion('kind', [\n z.object({\n kind: z.literal('every'),\n interval: intervalSchema,\n }),\n ])\n .describe('When the schedule fires. \"every\" repeats on wall-clock boundaries (5m fires at :00, :05, …).');\n\nconst idSchema = z.string().min(1).describe('Schedule id, or a unique prefix of it (the 8-character short id works).');\n\nfunction threadOf(context: unknown): { threadId: string; resourceId: string } | undefined {\n const agent = (context as ToolRunContext | undefined)?.agent;\n return agent?.threadId && agent.resourceId ? { threadId: agent.threadId, resourceId: agent.resourceId } : undefined;\n}\n\nconst NO_THREAD: ScheduleToolResult = { content: 'Schedules require a memory-backed thread.', isError: true };\n\nfunction resolveFile(\n token: string,\n mode: ScheduleFile['mode'],\n options: ScheduleFileOptions,\n): ScheduleFile | undefined {\n const expanded = token.startsWith('~/') && options.homeDir ? path.join(options.homeDir, token.slice(2)) : token;\n const absPath = path.resolve(options.cwd, expanded);\n return options.fileExists(absPath) ? { path: absPath, displayPath: token, mode } : undefined;\n}\n\nfunction formatSchedule(schedule: ThreadSchedule): string {\n const timing =\n schedule.status === 'paused' ? 'paused' : `next at ${new Date(schedule.nextFireAt).toLocaleTimeString()}`;\n return `${shortScheduleId(schedule.id)} every ${schedule.trigger.interval.label} ${timing} ${describeScheduleSource(schedule)} (created by ${schedule.createdBy})`;\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction findOne(\n scheduler: ThreadScheduler,\n threadId: string,\n id: string,\n): { schedule: ThreadSchedule } | ScheduleToolResult {\n const needle = id.toLowerCase();\n const matches = scheduler.list({ threadId }).filter(schedule => schedule.id.toLowerCase().startsWith(needle));\n if (matches.length === 1) return { schedule: matches[0]! };\n return {\n content: matches.length === 0 ? `No schedule \"${id}\" on this thread.` : `\"${id}\" matches several schedules.`,\n isError: true,\n };\n}\n\nexport function createScheduleTools({ scheduler, fileOptions }: ScheduleToolsOptions) {\n const scheduleCreateTool = createTool({\n id: SCHEDULE_TOOL_IDS.create,\n description: `Schedule a recurring prompt on this thread. Each fire arrives as a new user turn labelled \"schedule\".\n\nPass exactly one source: \"prompt\" (text sent each fire), \"promptFile\" (a file re-read and sent as the prompt each fire), or \"script\" (run each fire; its output is sent, followed by \"extraPrompt\" if given). Schedules live only until Mastra Code exits.`,\n inputSchema: z\n .object({\n trigger: triggerSchema,\n prompt: z.string().trim().min(1).optional().describe('Prompt text to send on every fire.'),\n promptFile: z.string().trim().min(1).optional().describe('Path to a file to re-read and send on every fire.'),\n script: z.string().trim().min(1).optional().describe('Path to a script to run on every fire.'),\n extraPrompt: z.string().trim().min(1).optional().describe('Text sent after the script output.'),\n })\n .refine(input => [input.prompt, input.promptFile, input.script].filter(Boolean).length === 1, {\n message: 'Provide exactly one of \"prompt\", \"promptFile\", or \"script\".',\n })\n .refine(input => !input.extraPrompt || input.script, {\n message: '\"extraPrompt\" only applies with \"script\".',\n }),\n outputSchema: resultSchema,\n execute: async (input, context): Promise<ScheduleToolResult> => {\n const target = threadOf(context);\n if (!target) return NO_THREAD;\n let schedule: ThreadSchedule;\n if (input.prompt) {\n schedule = scheduler.create({ trigger: input.trigger, prompt: input.prompt, createdBy: 'agent' }, target);\n } else {\n const token = (input.script ?? input.promptFile)!;\n const file = resolveFile(token, input.script ? 'script' : 'prompt', fileOptions());\n if (!file) return { content: `File not found: ${token}`, isError: true };\n if (file.mode === 'script') {\n try {\n resolveScriptCommand(file.path);\n } catch (error) {\n return {\n content: `Can't run ${token}: ${error instanceof Error ? error.message : String(error)}`,\n isError: true,\n };\n }\n }\n schedule = scheduler.create(\n {\n trigger: input.trigger,\n file,\n ...(input.extraPrompt ? { extraPrompt: input.extraPrompt } : {}),\n createdBy: 'agent',\n },\n target,\n );\n }\n return { content: `Created schedule ${formatSchedule(schedule)}` };\n },\n });\n\n const scheduleListTool = createTool({\n id: SCHEDULE_TOOL_IDS.list,\n description: 'List the recurring prompt schedules on this thread, including ones the user created with /schedules.',\n inputSchema: z.object({}),\n outputSchema: resultSchema,\n execute: async (_input, context): Promise<ScheduleToolResult> => {\n const target = threadOf(context);\n if (!target) return NO_THREAD;\n const schedules = scheduler.list({ threadId: target.threadId });\n if (schedules.length === 0) return { content: 'No schedules on this thread.' };\n return {\n content: [`Schedules on this thread (${schedules.length}):`, ...schedules.map(formatSchedule)].join('\\n'),\n };\n },\n });\n\n const scheduleUpdateTool = createTool({\n id: SCHEDULE_TOOL_IDS.update,\n description: 'Pause or delete a schedule on this thread. Use schedule_resume to resume a paused one.',\n inputSchema: z.object({\n id: idSchema,\n action: z.enum(['pause', 'delete']),\n }),\n outputSchema: resultSchema,\n execute: async ({ id, action }, context): Promise<ScheduleToolResult> => {\n const target = threadOf(context);\n if (!target) return NO_THREAD;\n const found = findOne(scheduler, target.threadId, id);\n if (!('schedule' in found)) return found;\n scheduler[action](found.schedule.id);\n const verb = action === 'pause' ? 'Paused' : 'Deleted';\n return { content: `${verb} schedule ${shortScheduleId(found.schedule.id)}.` };\n },\n });\n\n // Separate from schedule_update: resuming lets the timer run the schedule's\n // script again, so it needs the same approval as creating or running one.\n const scheduleResumeTool = createTool({\n id: SCHEDULE_TOOL_IDS.resume,\n description: 'Resume a paused schedule on this thread. It fires again from the next clock boundary.',\n inputSchema: z.object({ id: idSchema }),\n outputSchema: resultSchema,\n execute: async ({ id }, context): Promise<ScheduleToolResult> => {\n const target = threadOf(context);\n if (!target) return NO_THREAD;\n const found = findOne(scheduler, target.threadId, id);\n if (!('schedule' in found)) return found;\n scheduler.resume(found.schedule.id);\n return { content: `Resumed schedule ${shortScheduleId(found.schedule.id)}.` };\n },\n });\n\n const scheduleRunTool = createTool({\n id: SCHEDULE_TOOL_IDS.run,\n description:\n 'Fire a schedule on this thread once now, even if it is paused, without changing its cadence. Its prompt arrives as the next user turn.',\n inputSchema: z.object({ id: idSchema }),\n outputSchema: resultSchema,\n execute: async ({ id }, context): Promise<ScheduleToolResult> => {\n const target = threadOf(context);\n if (!target) return NO_THREAD;\n const found = findOne(scheduler, target.threadId, id);\n if (!('schedule' in found)) return found;\n const short = shortScheduleId(found.schedule.id);\n const result = await scheduler.run(found.schedule.id);\n switch (result.status) {\n case 'fired':\n return { content: `Triggered schedule ${short}; its prompt arrives as the next turn.` };\n case 'busy':\n return { content: `Schedule ${short} is already firing; skipped so its prompt isn't sent twice.` };\n case 'not-found':\n return { content: `Schedule ${short} was deleted before it fired.`, isError: true };\n case 'failed':\n return { content: `Schedule ${short} failed to fire: ${errorMessage(result.error)}`, isError: true };\n }\n },\n });\n\n return {\n [SCHEDULE_TOOL_IDS.create]: scheduleCreateTool,\n [SCHEDULE_TOOL_IDS.list]: scheduleListTool,\n [SCHEDULE_TOOL_IDS.update]: scheduleUpdateTool,\n [SCHEDULE_TOOL_IDS.resume]: scheduleResumeTool,\n [SCHEDULE_TOOL_IDS.run]: scheduleRunTool,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sub-invocations launched from a parent chat turn (workflow agent steps,
|
|
3
|
+
* sub-agent tool calls) must run under a fresh isolated Mastra memory scope
|
|
4
|
+
* so they don't:
|
|
5
|
+
*
|
|
6
|
+
* - write their prompts/responses into the parent chat thread's history, or
|
|
7
|
+
* - contend with the parent turn's memory-dependent processors
|
|
8
|
+
* (observational-memory, task-state, working-memory-state).
|
|
9
|
+
*
|
|
10
|
+
* `withEphemeralMemory` copies the caller's request context into a child,
|
|
11
|
+
* replaces its MastraMemory with a fresh thread id and inherited resource id,
|
|
12
|
+
* then passes that isolated child to `fn`. The parent context is never mutated,
|
|
13
|
+
* so concurrent sub-invocations cannot overwrite or restore each other's
|
|
14
|
+
* memory values. Isolation writes the ephemeral ids instead of scrubbing them:
|
|
15
|
+
* inner agent invocations resolve their thread/resource via those reserved
|
|
16
|
+
* keys, and leaving them unset causes downstream storage saves to throw
|
|
17
|
+
* "Thread ID is required".
|
|
18
|
+
*
|
|
19
|
+
* Callers can override the ephemeral thread id (e.g. for tests) via
|
|
20
|
+
* `options.threadId`.
|
|
21
|
+
*/
|
|
1
22
|
import { RequestContext } from '@mastra/core/request-context';
|
|
2
23
|
interface EphemeralMemoryOptions {
|
|
3
24
|
threadId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ephemeral-memory.d.ts","sourceRoot":"","sources":["../../../src/tools/workflows/ephemeral-memory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ephemeral-memory.d.ts","sourceRoot":"","sources":["../../../src/tools/workflows/ephemeral-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAgD,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE5G,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,cAAc,EAAE,cAAc,GAAG,SAAS,EAC1C,EAAE,EAAE,CAAC,cAAc,EAAE,cAAc,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,EAC9D,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,CAAC,CAAC,CA6BZ"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "crypto";
|
|
2
1
|
import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, RequestContext } from "@mastra/core/request-context";
|
|
3
2
|
//#region src/tools/workflows/ephemeral-memory.ts
|
|
4
3
|
/**
|
|
@@ -27,7 +26,7 @@ async function withEphemeralMemory(requestContext, fn, options = {}) {
|
|
|
27
26
|
const childRequestContext = new RequestContext(requestContext.entries());
|
|
28
27
|
const mastraMemory = requestContext.get("MastraMemory");
|
|
29
28
|
const resourceId = requestContext.get(MASTRA_RESOURCE_ID_KEY);
|
|
30
|
-
const ephemeralThreadId = options.threadId ?? randomUUID();
|
|
29
|
+
const ephemeralThreadId = options.threadId ?? globalThis.crypto.randomUUID();
|
|
31
30
|
const parentResourceId = mastraMemory?.resourceId ?? resourceId ?? "";
|
|
32
31
|
childRequestContext.set("MastraMemory", {
|
|
33
32
|
thread: { id: ephemeralThreadId },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ephemeral-memory.js","names":[],"sources":["../../../src/tools/workflows/ephemeral-memory.ts"],"sourcesContent":["/**\n * Sub-invocations launched from a parent chat turn (workflow agent steps,\n * sub-agent tool calls) must run under a fresh isolated Mastra memory scope\n * so they don't:\n *\n * - write their prompts/responses into the parent chat thread's history, or\n * - contend with the parent turn's memory-dependent processors\n * (observational-memory, task-state, working-memory-state).\n *\n * `withEphemeralMemory` copies the caller's request context into a child,\n * replaces its MastraMemory with a fresh thread id and inherited resource id,\n * then passes that isolated child to `fn`. The parent context is never mutated,\n * so concurrent sub-invocations cannot overwrite or restore each other's\n * memory values. Isolation writes the ephemeral ids instead of scrubbing them:\n * inner agent invocations resolve their thread/resource via those reserved\n * keys, and leaving them unset causes downstream storage saves to throw\n * \"Thread ID is required\".\n *\n * Callers can override the ephemeral thread id (e.g. for tests) via\n * `options.threadId`.\n */\nimport {
|
|
1
|
+
{"version":3,"file":"ephemeral-memory.js","names":[],"sources":["../../../src/tools/workflows/ephemeral-memory.ts"],"sourcesContent":["/**\n * Sub-invocations launched from a parent chat turn (workflow agent steps,\n * sub-agent tool calls) must run under a fresh isolated Mastra memory scope\n * so they don't:\n *\n * - write their prompts/responses into the parent chat thread's history, or\n * - contend with the parent turn's memory-dependent processors\n * (observational-memory, task-state, working-memory-state).\n *\n * `withEphemeralMemory` copies the caller's request context into a child,\n * replaces its MastraMemory with a fresh thread id and inherited resource id,\n * then passes that isolated child to `fn`. The parent context is never mutated,\n * so concurrent sub-invocations cannot overwrite or restore each other's\n * memory values. Isolation writes the ephemeral ids instead of scrubbing them:\n * inner agent invocations resolve their thread/resource via those reserved\n * keys, and leaving them unset causes downstream storage saves to throw\n * \"Thread ID is required\".\n *\n * Callers can override the ephemeral thread id (e.g. for tests) via\n * `options.threadId`.\n */\nimport { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, RequestContext } from '@mastra/core/request-context';\n\ninterface EphemeralMemoryOptions {\n threadId?: string;\n}\n\nexport async function withEphemeralMemory<T>(\n requestContext: RequestContext | undefined,\n fn: (requestContext: RequestContext | undefined) => Promise<T>,\n options: EphemeralMemoryOptions = {},\n): Promise<T> {\n if (!requestContext) return fn(undefined);\n\n const childRequestContext = new RequestContext(requestContext.entries());\n const mastraMemory = requestContext.get('MastraMemory') as\n | { thread?: { id?: string }; resourceId?: string; memoryConfig?: unknown }\n | undefined;\n const resourceId = requestContext.get(MASTRA_RESOURCE_ID_KEY) as string | undefined;\n const ephemeralThreadId = options.threadId ?? globalThis.crypto.randomUUID();\n const parentResourceId = mastraMemory?.resourceId ?? resourceId ?? '';\n\n childRequestContext.set('MastraMemory', {\n thread: { id: ephemeralThreadId },\n resourceId: parentResourceId,\n memoryConfig: undefined,\n });\n // Stamp the reserved thread/resource-key context values with the same\n // ephemeral ids. Inner agent invocations (workflow agent steps, sub-agent\n // tool calls) read these keys to resolve their runtime thread; leaving\n // MASTRA_THREAD_ID_KEY unset causes prepare-memory-step to build a\n // MessageList without a threadId, which storage rejects downstream.\n childRequestContext.set(MASTRA_THREAD_ID_KEY, ephemeralThreadId);\n if (parentResourceId) {\n childRequestContext.set(MASTRA_RESOURCE_ID_KEY, parentResourceId);\n } else {\n childRequestContext.delete(MASTRA_RESOURCE_ID_KEY);\n }\n\n return fn(childRequestContext);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA2BA,eAAsB,oBACpB,gBACA,IACA,UAAkC,CAAC,GACvB;CACZ,IAAI,CAAC,gBAAgB,OAAO,GAAG,KAAA,CAAS;CAExC,MAAM,sBAAsB,IAAI,eAAe,eAAe,QAAQ,CAAC;CACvE,MAAM,eAAe,eAAe,IAAI,cAAc;CAGtD,MAAM,aAAa,eAAe,IAAI,sBAAsB;CAC5D,MAAM,oBAAoB,QAAQ,YAAY,WAAW,OAAO,WAAW;CAC3E,MAAM,mBAAmB,cAAc,cAAc,cAAc;CAEnE,oBAAoB,IAAI,gBAAgB;EACtC,QAAQ,EAAE,IAAI,kBAAkB;EAChC,YAAY;EACZ,cAAc,KAAA;CAChB,CAAC;CAMD,oBAAoB,IAAI,sBAAsB,iBAAiB;CAC/D,IAAI,kBACF,oBAAoB,IAAI,wBAAwB,gBAAgB;MAEhE,oBAAoB,OAAO,sBAAsB;CAGnD,OAAO,GAAG,mBAAmB;AAC/B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ListScoresResponse, SaveScorePayload, ScoreRowData } from '@mastra/core/evals';
|
|
2
|
+
import { ScoresStorage } from '@mastra/core/storage';
|
|
3
|
+
import type { StoragePagination } from '@mastra/core/storage';
|
|
4
|
+
/**
|
|
5
|
+
* A scores domain that accepts writes and keeps nothing.
|
|
6
|
+
*
|
|
7
|
+
* mastracode's `outcome` and `efficiency` scorers persist every result through
|
|
8
|
+
* the scores domain (`validateAndSaveScore` → `getStore('scores')`), but nothing
|
|
9
|
+
* in mastracode reads scores back. Writing them to libsql grew mastra.db without
|
|
10
|
+
* bound, and an in-memory store would grow the heap for the life of the process
|
|
11
|
+
* instead (each payload carries the system prompt, messages, input and output).
|
|
12
|
+
* Disabling the domain is not an option: core throws
|
|
13
|
+
* MASTRA_SCORES_STORAGE_NOT_AVAILABLE on every scorer run when it is missing.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DiscardingScoresStorage extends ScoresStorage {
|
|
16
|
+
getScoreById(): Promise<ScoreRowData | null>;
|
|
17
|
+
saveScore(score: SaveScorePayload): Promise<{
|
|
18
|
+
score: ScoreRowData;
|
|
19
|
+
}>;
|
|
20
|
+
listScoresByScorerId({ pagination }: {
|
|
21
|
+
pagination: StoragePagination;
|
|
22
|
+
}): Promise<ListScoresResponse>;
|
|
23
|
+
listScoresByRunId({ pagination }: {
|
|
24
|
+
pagination: StoragePagination;
|
|
25
|
+
}): Promise<ListScoresResponse>;
|
|
26
|
+
listScoresByEntityId({ pagination }: {
|
|
27
|
+
pagination: StoragePagination;
|
|
28
|
+
}): Promise<ListScoresResponse>;
|
|
29
|
+
listScoresBySpan({ pagination }: {
|
|
30
|
+
pagination: StoragePagination;
|
|
31
|
+
}): Promise<ListScoresResponse>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=discarding-scores-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discarding-scores-storage.d.ts","sourceRoot":"","sources":["../../src/utils/discarding-scores-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;;;;;;;;GAUG;AACH,qBAAa,uBAAwB,SAAQ,aAAa;IAClD,YAAY,IAAI,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAI5C,SAAS,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,YAAY,CAAA;KAAE,CAAC;IAKpE,oBAAoB,CAAC,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,iBAAiB,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIpG,iBAAiB,CAAC,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,iBAAiB,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIjG,oBAAoB,CAAC,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,iBAAiB,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIpG,gBAAgB,CAAC,EAAE,UAAU,EAAE,EAAE;QAAE,UAAU,EAAE,iBAAiB,CAAA;KAAE,GAAG,OAAO,CAAC,kBAAkB,CAAC;CAGvG"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ScoresStorage } from "@mastra/core/storage";
|
|
2
|
+
//#region src/utils/discarding-scores-storage.ts
|
|
3
|
+
/**
|
|
4
|
+
* A scores domain that accepts writes and keeps nothing.
|
|
5
|
+
*
|
|
6
|
+
* mastracode's `outcome` and `efficiency` scorers persist every result through
|
|
7
|
+
* the scores domain (`validateAndSaveScore` → `getStore('scores')`), but nothing
|
|
8
|
+
* in mastracode reads scores back. Writing them to libsql grew mastra.db without
|
|
9
|
+
* bound, and an in-memory store would grow the heap for the life of the process
|
|
10
|
+
* instead (each payload carries the system prompt, messages, input and output).
|
|
11
|
+
* Disabling the domain is not an option: core throws
|
|
12
|
+
* MASTRA_SCORES_STORAGE_NOT_AVAILABLE on every scorer run when it is missing.
|
|
13
|
+
*/
|
|
14
|
+
var DiscardingScoresStorage = class extends ScoresStorage {
|
|
15
|
+
async getScoreById() {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
async saveScore(score) {
|
|
19
|
+
const now = /* @__PURE__ */ new Date();
|
|
20
|
+
return { score: {
|
|
21
|
+
...score,
|
|
22
|
+
id: score.id ?? crypto.randomUUID(),
|
|
23
|
+
createdAt: now,
|
|
24
|
+
updatedAt: now
|
|
25
|
+
} };
|
|
26
|
+
}
|
|
27
|
+
async listScoresByScorerId({ pagination }) {
|
|
28
|
+
return empty(pagination);
|
|
29
|
+
}
|
|
30
|
+
async listScoresByRunId({ pagination }) {
|
|
31
|
+
return empty(pagination);
|
|
32
|
+
}
|
|
33
|
+
async listScoresByEntityId({ pagination }) {
|
|
34
|
+
return empty(pagination);
|
|
35
|
+
}
|
|
36
|
+
async listScoresBySpan({ pagination }) {
|
|
37
|
+
return empty(pagination);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
function empty(pagination) {
|
|
41
|
+
return {
|
|
42
|
+
pagination: {
|
|
43
|
+
total: 0,
|
|
44
|
+
page: pagination.page,
|
|
45
|
+
perPage: pagination.perPage,
|
|
46
|
+
hasMore: false
|
|
47
|
+
},
|
|
48
|
+
scores: []
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { DiscardingScoresStorage };
|
|
53
|
+
|
|
54
|
+
//# sourceMappingURL=discarding-scores-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discarding-scores-storage.js","names":[],"sources":["../../src/utils/discarding-scores-storage.ts"],"sourcesContent":["import type { ListScoresResponse, SaveScorePayload, ScoreRowData } from '@mastra/core/evals';\nimport { ScoresStorage } from '@mastra/core/storage';\nimport type { StoragePagination } from '@mastra/core/storage';\n\n/**\n * A scores domain that accepts writes and keeps nothing.\n *\n * mastracode's `outcome` and `efficiency` scorers persist every result through\n * the scores domain (`validateAndSaveScore` → `getStore('scores')`), but nothing\n * in mastracode reads scores back. Writing them to libsql grew mastra.db without\n * bound, and an in-memory store would grow the heap for the life of the process\n * instead (each payload carries the system prompt, messages, input and output).\n * Disabling the domain is not an option: core throws\n * MASTRA_SCORES_STORAGE_NOT_AVAILABLE on every scorer run when it is missing.\n */\nexport class DiscardingScoresStorage extends ScoresStorage {\n async getScoreById(): Promise<ScoreRowData | null> {\n return null;\n }\n\n async saveScore(score: SaveScorePayload): Promise<{ score: ScoreRowData }> {\n const now = new Date();\n return { score: { ...score, id: score.id ?? crypto.randomUUID(), createdAt: now, updatedAt: now } as ScoreRowData };\n }\n\n async listScoresByScorerId({ pagination }: { pagination: StoragePagination }): Promise<ListScoresResponse> {\n return empty(pagination);\n }\n\n async listScoresByRunId({ pagination }: { pagination: StoragePagination }): Promise<ListScoresResponse> {\n return empty(pagination);\n }\n\n async listScoresByEntityId({ pagination }: { pagination: StoragePagination }): Promise<ListScoresResponse> {\n return empty(pagination);\n }\n\n async listScoresBySpan({ pagination }: { pagination: StoragePagination }): Promise<ListScoresResponse> {\n return empty(pagination);\n }\n}\n\nfunction empty(pagination: StoragePagination): ListScoresResponse {\n return { pagination: { total: 0, page: pagination.page, perPage: pagination.perPage, hasMore: false }, scores: [] };\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAa,0BAAb,cAA6C,cAAc;CACzD,MAAM,eAA6C;EACjD,OAAO;CACT;CAEA,MAAM,UAAU,OAA2D;EACzE,MAAM,sBAAM,IAAI,KAAK;EACrB,OAAO,EAAE,OAAO;GAAE,GAAG;GAAO,IAAI,MAAM,MAAM,OAAO,WAAW;GAAG,WAAW;GAAK,WAAW;EAAI,EAAkB;CACpH;CAEA,MAAM,qBAAqB,EAAE,cAA8E;EACzG,OAAO,MAAM,UAAU;CACzB;CAEA,MAAM,kBAAkB,EAAE,cAA8E;EACtG,OAAO,MAAM,UAAU;CACzB;CAEA,MAAM,qBAAqB,EAAE,cAA8E;EACzG,OAAO,MAAM,UAAU;CACzB;CAEA,MAAM,iBAAiB,EAAE,cAA8E;EACrG,OAAO,MAAM,UAAU;CACzB;AACF;AAEA,SAAS,MAAM,YAAmD;CAChE,OAAO;EAAE,YAAY;GAAE,OAAO;GAAG,MAAM,WAAW;GAAM,SAAS,WAAW;GAAS,SAAS;EAAM;EAAG,QAAQ,CAAC;CAAE;AACpH"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare class MaintenanceLockError extends Error {
|
|
2
|
+
readonly ownerPids: number[];
|
|
3
|
+
constructor(message: string, ownerPids: number[]);
|
|
4
|
+
}
|
|
5
|
+
export declare function getMaintenanceLockPath(): string;
|
|
6
|
+
/** Owner of a lock whose pid file is still being written (PID not known yet). */
|
|
7
|
+
export declare const UNKNOWN_OWNER = -1;
|
|
8
|
+
/**
|
|
9
|
+
* Creating a pid file (open, then write) is not atomic, so an empty or
|
|
10
|
+
* unparseable file may belong to a process that is mid-write. Only treat it as
|
|
11
|
+
* stale once it is older than this.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MALFORMED_PID_FILE_GRACE_MS = 5000;
|
|
14
|
+
/**
|
|
15
|
+
* PID holding the maintenance lock, `UNKNOWN_OWNER` while its pid file is still
|
|
16
|
+
* being written, or null. Stale locks are removed.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getMaintenanceLockOwner(): number | null;
|
|
19
|
+
/** PIDs of other live registered sessions. Stale registrations are removed. */
|
|
20
|
+
export declare function getLiveSessionPids(): number[];
|
|
21
|
+
/** Test-only: drop every registration held by this process and forget lock ownership. */
|
|
22
|
+
export declare function resetSessionRegistrationsForTesting(): void;
|
|
23
|
+
/** Register one running session in this process. Pair with exactly one unregisterSession(). */
|
|
24
|
+
export declare function registerSession(): void;
|
|
25
|
+
/** Release one registration made by registerSession(). */
|
|
26
|
+
export declare function unregisterSession(): void;
|
|
27
|
+
/**
|
|
28
|
+
* Register this session, then wait for any running maintenance to finish.
|
|
29
|
+
* Waits indefinitely by default: a vacuum on a multi-GB database can take
|
|
30
|
+
* minutes. With `timeoutMs`, throws after that long naming the holder.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerSessionAndWaitForMaintenance({ timeoutMs, pollMs, onWait, }?: {
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
pollMs?: number;
|
|
35
|
+
onWait?: (ownerPid: number) => void;
|
|
36
|
+
}): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Acquire the maintenance lock, then refuse if any mastracode session is live.
|
|
39
|
+
* Returns a release function.
|
|
40
|
+
*/
|
|
41
|
+
export declare function acquireMaintenanceLock(): () => void;
|
|
42
|
+
//# sourceMappingURL=maintenance-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maintenance-lock.d.ts","sourceRoot":"","sources":["../../src/utils/maintenance-lock.ts"],"names":[],"mappings":"AAiBA,qBAAa,oBAAqB,SAAQ,KAAK;aAG3B,SAAS,EAAE,MAAM,EAAE;gBADnC,OAAO,EAAE,MAAM,EACC,SAAS,EAAE,MAAM,EAAE;CAKtC;AAcD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,iFAAiF;AACjF,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,OAAQ,CAAC;AAuCjD;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAgBvD;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAmB7C;AAOD,yFAAyF;AACzF,wBAAgB,mCAAmC,IAAI,IAAI,CAG1D;AAYD,+FAA+F;AAC/F,wBAAgB,eAAe,IAAI,IAAI,CAStC;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,IAAI,IAAI,CAIxC;AAED;;;;GAIG;AACH,wBAAsB,oCAAoC,CAAC,EACzD,SAAoB,EACpB,MAAY,EACZ,MAAM,GACP,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBnG;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,IAAI,CA0CnD"}
|