@sema-agent/core 2.10.0 → 2.12.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/dist/agents/send-message-tool.js +15 -20
- package/dist/agents/subagent.js +4 -2
- package/dist/core/checkpoint-store.d.ts +1 -0
- package/dist/core/checkpoint-store.js +3 -0
- package/dist/core/consolidate-scope.js +4 -2
- package/dist/core/context-edit.js +8 -12
- package/dist/core/mcp.d.ts +2 -0
- package/dist/core/mcp.js +89 -6
- package/dist/core/memory.d.ts +4 -2
- package/dist/core/message-utils.d.ts +2 -1
- package/dist/core/remote-env.d.ts +3 -0
- package/dist/core/remote-env.js +19 -1
- package/dist/core/runner/assemble-result.d.ts +3 -0
- package/dist/core/runner/assemble-result.js +4 -1
- package/dist/core/runner/prepare-task.d.ts +5 -0
- package/dist/core/runner/prepare-task.js +126 -34
- package/dist/core/runner/runtask.js +22 -2
- package/dist/core/session-store.d.ts +3 -0
- package/dist/core/session-store.js +10 -0
- package/dist/core/session.d.ts +2 -0
- package/dist/core/tool-result-budget.js +2 -0
- package/dist/core/types.d.ts +9 -0
- package/dist/engine/harness/types.d.ts +1 -1
- package/dist/engine/session/session.js +2 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/tools/fs/fs-bash.js +14 -0
- package/dist/tools/fs/fs-write.js +2 -1
- package/dist/tools/fs/safety.d.ts +1 -1
- package/dist/tools/fs/safety.js +1 -1
- package/dist/tools/scheduler-tools.js +29 -15
- package/package.json +1 -1
package/dist/tools/fs/safety.js
CHANGED
|
@@ -276,7 +276,7 @@ export function checkNoChange(oldString, newString) {
|
|
|
276
276
|
return undefined;
|
|
277
277
|
}
|
|
278
278
|
export function checkStale(entry, currentHash) {
|
|
279
|
-
if (entry.hash !== currentHash) {
|
|
279
|
+
if (entry === undefined || entry.hash !== currentHash) {
|
|
280
280
|
return { code: "stale", message: "File has been modified since read, either by the user or by a linter. Read it again before attempting to write it." };
|
|
281
281
|
}
|
|
282
282
|
return undefined;
|
|
@@ -83,16 +83,13 @@ function expandCronField(field, { min, max }) {
|
|
|
83
83
|
return out.size > 0 ? [...out].sort((a, b) => a - b) : null;
|
|
84
84
|
}
|
|
85
85
|
export function cronScheduleError(expr) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
return `invalid seconds field "${parts[0]}" — allowed 0-59 (syntax: N, N-M, */N, comma lists).`;
|
|
91
|
-
}
|
|
92
|
-
std = parts.slice(1);
|
|
86
|
+
const std = expr.trim().split(/\s+/);
|
|
87
|
+
if (std.length === 6) {
|
|
88
|
+
return (`its leading seconds field is not supported — the resident scheduler fires on 5-field cron, so one ` +
|
|
89
|
+
`minute is the finest granularity available. Pass "${std.slice(1).join(" ")}" if that cadence works.`);
|
|
93
90
|
}
|
|
94
|
-
|
|
95
|
-
return `expected 5 fields (minute hour day-of-month month day-of-week)
|
|
91
|
+
if (std.length !== 5) {
|
|
92
|
+
return `expected 5 fields (minute hour day-of-month month day-of-week), got ${std.length}.`;
|
|
96
93
|
}
|
|
97
94
|
const expanded = [];
|
|
98
95
|
for (let i = 0; i < 5; i++) {
|
|
@@ -117,9 +114,12 @@ export function cronScheduleError(expr) {
|
|
|
117
114
|
return null;
|
|
118
115
|
}
|
|
119
116
|
const DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
117
|
+
function cronExprFromSummary(when) {
|
|
118
|
+
const trimmed = when.trim();
|
|
119
|
+
return trimmed.startsWith("cron ") ? trimmed.slice("cron ".length).trim() : trimmed;
|
|
120
|
+
}
|
|
120
121
|
export function cronToHuman(expr) {
|
|
121
|
-
const
|
|
122
|
-
const std = parts.length === 6 ? parts.slice(1) : parts;
|
|
122
|
+
const std = cronExprFromSummary(expr).split(/\s+/);
|
|
123
123
|
if (std.length !== 5)
|
|
124
124
|
return expr;
|
|
125
125
|
const [minute = "", hour = "", dom = "", month = "", dow = ""] = std;
|
|
@@ -191,7 +191,10 @@ Only use minute 0 or 30 when the user names that exact time and clearly means it
|
|
|
191
191
|
parameters: Type.Object({
|
|
192
192
|
prompt: Type.String({ description: "Self-contained instructions for the future task (it runs unattended)." }),
|
|
193
193
|
schedule: Type.Optional(Type.Union([
|
|
194
|
-
Type.Object({
|
|
194
|
+
Type.Object({
|
|
195
|
+
kind: Type.Literal("cron"),
|
|
196
|
+
expr: Type.String({ description: "5-field cron expression (minute hour day-of-month month day-of-week)." }),
|
|
197
|
+
}),
|
|
195
198
|
Type.Object({ kind: Type.Literal("at"), atMs: Type.Number({ description: "Absolute epoch ms to fire once." }) }),
|
|
196
199
|
Type.Object({ kind: Type.Literal("delay"), delaySec: Type.Number({ description: "Seconds from now to fire once." }) }),
|
|
197
200
|
], { description: 'When to fire. Pass exactly one of `schedule` or `cron`. Defaults to `durable: true`.' })),
|
|
@@ -246,22 +249,32 @@ Only use minute 0 or 30 when the user names that exact time and clearly means it
|
|
|
246
249
|
...(!durable ? { lifetime: "session" } : {}),
|
|
247
250
|
...(a.recurring !== undefined ? { recurring: a.recurring } : {}),
|
|
248
251
|
};
|
|
252
|
+
const before = await sched.list(schedCtx);
|
|
253
|
+
const knownIds = before.ok ? new Set(before.value.map((s) => s.id)) : undefined;
|
|
249
254
|
const r = await sched.schedule(intent, schedCtx);
|
|
250
255
|
if (!r.ok)
|
|
251
256
|
return errorResult(`Error (CronCreate): ${r.error.message}`);
|
|
257
|
+
const replaced = knownIds?.has(r.value.id);
|
|
252
258
|
const humanSchedule = when.kind === "cron"
|
|
253
259
|
? cronToHuman(when.expr)
|
|
254
260
|
: when.kind === "delay"
|
|
255
261
|
? `once in ${when.delaySec}s`
|
|
256
262
|
: `once at ${new Date(when.atMs).toISOString()}`;
|
|
263
|
+
const named = `${r.value.id}${a.label ? ` (${a.label})` : ""}`;
|
|
264
|
+
const content = replaced === true
|
|
265
|
+
? `Updated scheduled task ${named} — it replaced an existing job with the same schedule and label, whose prompt is now gone.`
|
|
266
|
+
: replaced === false
|
|
267
|
+
? `Scheduled task ${named}.`
|
|
268
|
+
: `Scheduled (or updated) task ${named} — the scheduler's listing was unavailable, so whether this replaced an existing job with the same schedule and label is unknown.`;
|
|
257
269
|
return {
|
|
258
|
-
content
|
|
270
|
+
content,
|
|
259
271
|
details: {
|
|
260
272
|
type: "cron-create",
|
|
261
273
|
id: r.value.id,
|
|
262
274
|
humanSchedule,
|
|
263
275
|
recurring: when.kind === "cron" && a.recurring !== false,
|
|
264
276
|
durable,
|
|
277
|
+
...(replaced !== undefined ? { replaced } : {}),
|
|
265
278
|
},
|
|
266
279
|
};
|
|
267
280
|
},
|
|
@@ -298,17 +311,18 @@ Only use minute 0 or 30 when the user names that exact time and clearly means it
|
|
|
298
311
|
}
|
|
299
312
|
const content = r.value
|
|
300
313
|
.map((s) => {
|
|
314
|
+
const shown = cronExprFromSummary(s.when);
|
|
301
315
|
const human = cronToHuman(s.when);
|
|
302
316
|
const tier = s.lifetime === "session" ? " [session]" : "";
|
|
303
317
|
const once = s.recurring === false ? " [once]" : "";
|
|
304
|
-
return `- ${s.id}: ${
|
|
318
|
+
return `- ${s.id}: ${shown}${human !== s.when ? ` — ${human}` : ""}${s.label ? ` (${s.label})` : ""}${tier}${once}`;
|
|
305
319
|
})
|
|
306
320
|
.join("\n");
|
|
307
321
|
const jobs = r.value.map((s) => {
|
|
308
322
|
const human = cronToHuman(s.when);
|
|
309
323
|
return {
|
|
310
324
|
id: s.id,
|
|
311
|
-
cron: s.when,
|
|
325
|
+
cron: cronExprFromSummary(s.when),
|
|
312
326
|
humanSchedule: human !== s.when ? human : s.when,
|
|
313
327
|
...(s.label !== undefined ? { label: s.label } : {}),
|
|
314
328
|
...(s.recurring !== undefined ? { recurring: s.recurring } : {}),
|