@deepmaid/maid-cron 0.1.0-alpha.1 → 0.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/index.d.ts +28 -1
  2. package/lib/index.js +150 -46
  3. package/package.json +12 -9
package/lib/index.d.ts CHANGED
@@ -24,6 +24,12 @@ interface JobDeclaration {
24
24
  maidId: string;
25
25
  type?: string;
26
26
  name?: string;
27
+ /**
28
+ * M3f:该 job 的基底模式壳(默认 = maid 的 basePreset ?? preset)。声明为非 maid 自带
29
+ * preset(如 cordis/standard)时,cron 会话 = 基底壳 + maidComposer 差异层(persona/
30
+ * anchor/gestures/veil);maidComposer 未挂 → fail-loud 拒绝生成(半人格防线)。
31
+ */
32
+ basePreset?: string;
27
33
  enabled?: boolean;
28
34
  schedule: JobSchedule;
29
35
  promptTemplate?: string;
@@ -45,6 +51,7 @@ interface CompiledJob {
45
51
  jobId: string;
46
52
  type: string;
47
53
  maidId: string;
54
+ basePreset: string | undefined;
48
55
  enabled: boolean;
49
56
  kind: 'script' | 'llm';
50
57
  promptTemplate: string;
@@ -74,12 +81,24 @@ declare function renderBriefingPrompt(template: string, vars: {
74
81
  //#endregion
75
82
  //#region src/state.d.ts
76
83
  type RunStatus = 'ok' | 'ok-silent' | 'script-failed' | 'gen-failed' | 'deliver-failed' | 'misfire-skipped' | 'overlap-skipped';
84
+ /** M3e §4.1:跨版本稳定受控读面(ok=成功/error=执行失败/skipped=未执行)。 */
85
+ type RunOutcome = 'ok' | 'error' | 'skipped';
86
+ /** M3e §4.1:失败分类受控枚举(调用点赋值,不从 lastError 反解析)。 */
87
+ type RunFailureKind = 'script' | 'generation' | 'delivery' | 'timeout' | 'cancelled' | 'unknown';
88
+ type RunSkipReason = 'overlap' | 'misfire';
77
89
  interface JobRunState {
78
90
  lastRunAt: string | undefined;
79
91
  lastStatus: RunStatus | undefined;
80
92
  lastError: string | undefined;
81
93
  misfireCount: number;
82
94
  nextDueAt: number | undefined;
95
+ /** M3e 可观测:受控三态读面(旧档经 loadState 归一化补水)。 */
96
+ lastOutcome?: RunOutcome | undefined;
97
+ failureKind?: RunFailureKind | undefined;
98
+ skipReason?: RunSkipReason | undefined;
99
+ lastSuccessAt?: string | undefined;
100
+ lastFailureAt?: string | undefined;
101
+ consecutiveFailures?: number | undefined;
83
102
  }
84
103
  type RunStateMap = Record<string, JobRunState>;
85
104
  declare function loadState(file: string): RunStateMap;
@@ -96,7 +115,9 @@ interface RecentMemory {
96
115
  //#region src/engine.d.ts
97
116
  interface EnginePorts {
98
117
  identity: {
99
- presetOf(maidId: string): string | undefined;
118
+ /** M3f:basePreset 合成面——job.basePreset ?? record.basePreset ?? record.preset(job 级覆写进 engine)。 */
119
+ basePresetOf(maidId: string, jobBasePreset?: string): string | undefined;
120
+ maidOwnPresetOf(maidId: string): string | undefined;
100
121
  addressOf(maidId: string): {
101
122
  botId: string;
102
123
  targetId: string;
@@ -144,6 +165,9 @@ interface ResolvedCronConfig {
144
165
  } | undefined;
145
166
  agentSetup: ((agentCtx: unknown) => Promise<void>) | undefined;
146
167
  stateFile: string;
168
+ /** M3e §4.2:连续失败指数退避(base/max,毫秒;缺省不退避 = 行为零变化)。 */
169
+ failureBackoffBaseMs?: number;
170
+ failureBackoffMaxMs?: number;
147
171
  /** 终局观测回调:每次终局迁移(finish 各终局 + overlap-skipped/misfire-skipped)在 persist 之后触发,携带同一 status/error。 */
148
172
  onTerminal?: (jobId: string, status: RunStatus, error: string | undefined) => void;
149
173
  }
@@ -158,6 +182,9 @@ declare function createCronEngine(config: ResolvedCronConfig, jobs: readonly Com
158
182
  interface MaidCronConfig {
159
183
  tickIntervalMs?: number;
160
184
  misfireWindowMs?: number;
185
+ /** M3e §4.2:连续失败指数退避基数/封顶(毫秒);缺省不退避。 */
186
+ failureBackoffBaseMs?: number;
187
+ failureBackoffMaxMs?: number;
161
188
  recentLimit?: number;
162
189
  recentMaxChars?: number;
163
190
  timezone?: string;
package/lib/index.js CHANGED
@@ -794,6 +794,7 @@ function compileJobs(jobs, warn) {
794
794
  jobId,
795
795
  type: decl.type ?? "briefing",
796
796
  maidId: decl.maidId,
797
+ basePreset: decl.basePreset,
797
798
  enabled: decl.enabled !== false,
798
799
  kind,
799
800
  promptTemplate: decl.promptTemplate ?? "",
@@ -851,13 +852,25 @@ function freshRunState() {
851
852
  lastStatus: void 0,
852
853
  lastError: void 0,
853
854
  misfireCount: 0,
854
- nextDueAt: void 0
855
+ nextDueAt: void 0,
856
+ lastOutcome: void 0,
857
+ failureKind: void 0,
858
+ skipReason: void 0,
859
+ lastSuccessAt: void 0,
860
+ lastFailureAt: void 0,
861
+ consecutiveFailures: 0
855
862
  };
856
863
  }
857
864
  function loadState(file) {
858
865
  if (!existsSync(file)) return {};
859
866
  try {
860
- return JSON.parse(readFileSync(file, "utf8"));
867
+ const raw = JSON.parse(readFileSync(file, "utf8"));
868
+ const normalized = {};
869
+ for (const [jobId, state] of Object.entries(raw)) normalized[jobId] = {
870
+ ...freshRunState(),
871
+ ...state
872
+ };
873
+ return normalized;
861
874
  } catch {
862
875
  return {};
863
876
  }
@@ -869,6 +882,47 @@ function saveState(file, map) {
869
882
  renameSync(tmp, file);
870
883
  }
871
884
  //#endregion
885
+ //#region src/observability.ts
886
+ const iso = (ms) => new Date(ms).toISOString();
887
+ function applyOutcome(state, input) {
888
+ const { status, now } = input;
889
+ const next = {
890
+ ...state,
891
+ lastStatus: status,
892
+ lastRunAt: iso(now)
893
+ };
894
+ if (status === "ok" || status === "ok-silent") {
895
+ next.lastOutcome = "ok";
896
+ next.lastSuccessAt = iso(now);
897
+ next.consecutiveFailures = 0;
898
+ next.failureKind = void 0;
899
+ next.lastError = void 0;
900
+ next.lastFailureAt = void 0;
901
+ next.skipReason = void 0;
902
+ return next;
903
+ }
904
+ if (status === "overlap-skipped" || status === "misfire-skipped") {
905
+ next.lastOutcome = "skipped";
906
+ next.skipReason = status === "overlap-skipped" ? "overlap" : "misfire";
907
+ next.lastError = void 0;
908
+ return next;
909
+ }
910
+ next.lastOutcome = "error";
911
+ next.failureKind = input.kind ?? "unknown";
912
+ next.lastError = input.error;
913
+ next.lastFailureAt = iso(now);
914
+ next.consecutiveFailures = (state.consecutiveFailures ?? 0) + 1;
915
+ next.skipReason = void 0;
916
+ return next;
917
+ }
918
+ function nextDueWithBackoff(input) {
919
+ const chained = nextDueAfter(input.schedule, input.due);
920
+ if (chained === null) return null;
921
+ if (input.consecutiveFailures <= 0) return Math.max(input.previousNextDueAt ?? 0, chained);
922
+ const backoff = input.now + Math.min(input.maxMs, input.baseMs * 2 ** (input.consecutiveFailures - 1));
923
+ return Math.max(input.previousNextDueAt ?? 0, chained, backoff);
924
+ }
925
+ //#endregion
872
926
  //#region src/script-runner.ts
873
927
  const KILL_GRACE_MS = 5e3;
874
928
  /**
@@ -997,12 +1051,25 @@ function createCronEngine(config, jobs, ports) {
997
1051
  }
998
1052
  async function runJob(job, due) {
999
1053
  const state = stateOf(job.jobId);
1000
- const finish = (status, error, runAt) => {
1054
+ let deliveryPhase = false;
1055
+ const finish = (status, error, runAt, kind) => {
1056
+ const nowMs = ports.now();
1057
+ Object.assign(state, applyOutcome(state, {
1058
+ status,
1059
+ now: nowMs,
1060
+ ...kind !== void 0 ? { kind } : {},
1061
+ ...error !== void 0 ? { error } : {}
1062
+ }));
1001
1063
  state.lastRunAt = new Date(runAt).toISOString();
1002
- state.lastStatus = status;
1003
- state.lastError = error;
1004
- const chained = nextDueAfter(job.schedule, due);
1005
- state.nextDueAt = chained === null ? void 0 : Math.max(state.nextDueAt ?? Number.NEGATIVE_INFINITY, chained);
1064
+ state.nextDueAt = nextDueWithBackoff({
1065
+ schedule: job.schedule,
1066
+ due,
1067
+ now: nowMs,
1068
+ previousNextDueAt: state.nextDueAt,
1069
+ consecutiveFailures: state.consecutiveFailures ?? 0,
1070
+ baseMs: config.failureBackoffBaseMs ?? 0,
1071
+ maxMs: config.failureBackoffMaxMs ?? 0
1072
+ }) ?? void 0;
1006
1073
  persist();
1007
1074
  config.onTerminal?.(job.jobId, status, error);
1008
1075
  };
@@ -1021,13 +1088,13 @@ function createCronEngine(config, jobs, ports) {
1021
1088
  };
1022
1089
  })();
1023
1090
  if (dest === void 0) {
1024
- finish("gen-failed", `no delivery address for maid '${job.maidId}'`, due);
1091
+ finish("gen-failed", `no delivery address for maid '${job.maidId}'`, due, "generation");
1025
1092
  return;
1026
1093
  }
1027
1094
  if (job.kind === "script") {
1028
1095
  const res = await runScript(job.script);
1029
1096
  if (!res.ok) {
1030
- finish("script-failed", `${res.reason}: ${res.stderrTail}`.slice(0, 500), due);
1097
+ finish("script-failed", `${res.reason}: ${res.stderrTail}`.slice(0, 500), due, "script");
1031
1098
  return;
1032
1099
  }
1033
1100
  if (res.stdout.trim().length === 0) {
@@ -1044,17 +1111,18 @@ function createCronEngine(config, jobs, ports) {
1044
1111
  finish("ok", void 0, due);
1045
1112
  return;
1046
1113
  }
1114
+ deliveryPhase = true;
1047
1115
  if ((await ports.delivery.send(job.maidId, dest.address, res.stdout)).sent) {
1048
1116
  finish("ok", void 0, due);
1049
1117
  return;
1050
1118
  }
1051
1119
  if (config.deliverRetryDelayMs > 0) await sleep(config.deliverRetryDelayMs);
1052
1120
  const second = await ports.delivery.send(job.maidId, dest.address, res.stdout);
1053
- finish(second.sent ? "ok" : "deliver-failed", second.sent ? void 0 : `delivery failed: ${second.code}`, due);
1121
+ finish(second.sent ? "ok" : "deliver-failed", second.sent ? void 0 : `delivery failed: ${second.code}`, due, second.sent ? void 0 : "delivery");
1054
1122
  return;
1055
1123
  }
1056
1124
  if (config.agent === void 0) {
1057
- finish("gen-failed", "config.agent (provider/model) required", due);
1125
+ finish("gen-failed", "config.agent (provider/model) required", due, "generation");
1058
1126
  return;
1059
1127
  }
1060
1128
  const limit = job.recentLimit ?? config.recentLimit;
@@ -1063,7 +1131,7 @@ function createCronEngine(config, jobs, ports) {
1063
1131
  if (job.script !== void 0) {
1064
1132
  const res = await runScript(job.script);
1065
1133
  if (!res.ok) {
1066
- finish("script-failed", `${res.reason}: ${res.stderrTail}`.slice(0, 500), due);
1134
+ finish("script-failed", `${res.reason}: ${res.stderrTail}`.slice(0, 500), due, "script");
1067
1135
  return;
1068
1136
  }
1069
1137
  if (res.stdout.trim().length === 0 && job.skipOnEmptyScriptOutput) {
@@ -1084,7 +1152,8 @@ function createCronEngine(config, jobs, ports) {
1084
1152
  handle = await ports.agents.create({
1085
1153
  sessionId,
1086
1154
  meta: {
1087
- agentPreset: ports.identity.presetOf(job.maidId),
1155
+ agentPreset: ports.identity.basePresetOf(job.maidId, job.basePreset),
1156
+ maidId: job.maidId,
1088
1157
  ...config.agent.cwd !== void 0 ? { cwd: config.agent.cwd } : {}
1089
1158
  },
1090
1159
  agentOptions: {
@@ -1118,12 +1187,12 @@ function createCronEngine(config, jobs, ports) {
1118
1187
  }, job.genTimeoutMs).unref?.();
1119
1188
  await handle.agent.whenIdle();
1120
1189
  if (timedOut) {
1121
- finish("gen-failed", `generation timeout after ${job.genTimeoutMs}ms`, due);
1190
+ finish("gen-failed", `generation timeout after ${job.genTimeoutMs}ms`, due, "timeout");
1122
1191
  return;
1123
1192
  }
1124
1193
  const text = texts.at(-1);
1125
1194
  if (text === void 0) {
1126
- finish("gen-failed", "no assistant output", due);
1195
+ finish("gen-failed", "no assistant output", due, "generation");
1127
1196
  return;
1128
1197
  }
1129
1198
  if (dest.kind === "persist") {
@@ -1136,20 +1205,21 @@ function createCronEngine(config, jobs, ports) {
1136
1205
  finish("ok", void 0, due);
1137
1206
  return;
1138
1207
  }
1208
+ deliveryPhase = true;
1139
1209
  if ((await ports.delivery.send(job.maidId, dest.address, text)).sent) {
1140
1210
  finish("ok", void 0, due);
1141
1211
  return;
1142
1212
  }
1143
1213
  if (config.deliverRetryDelayMs > 0) await sleep(config.deliverRetryDelayMs);
1144
1214
  const second = await ports.delivery.send(job.maidId, dest.address, text);
1145
- finish(second.sent ? "ok" : "deliver-failed", second.sent ? void 0 : `delivery failed: ${second.code}`, due);
1215
+ finish(second.sent ? "ok" : "deliver-failed", second.sent ? void 0 : `delivery failed: ${second.code}`, due, second.sent ? void 0 : "delivery");
1146
1216
  } finally {
1147
1217
  cancels.delete(job.jobId);
1148
1218
  off();
1149
1219
  await handle?.dispose();
1150
1220
  }
1151
1221
  } catch (error) {
1152
- finish("gen-failed", error instanceof Error ? error.message : String(error), due);
1222
+ finish("gen-failed", error instanceof Error ? error.message : String(error), due, deliveryPhase ? "delivery" : "generation");
1153
1223
  }
1154
1224
  }
1155
1225
  function tick(nowMs = ports.now()) {
@@ -1160,17 +1230,21 @@ function createCronEngine(config, jobs, ports) {
1160
1230
  if (nowMs < state.nextDueAt) continue;
1161
1231
  const due = state.nextDueAt;
1162
1232
  if (inFlight.has(job.jobId)) {
1233
+ Object.assign(state, applyOutcome(state, {
1234
+ status: "overlap-skipped",
1235
+ now: nowMs
1236
+ }));
1163
1237
  state.lastRunAt = new Date(nowMs).toISOString();
1164
- state.lastStatus = "overlap-skipped";
1165
- state.lastError = void 0;
1166
1238
  state.nextDueAt = nextDueAfter(job.schedule, due) ?? void 0;
1167
1239
  persist();
1168
1240
  config.onTerminal?.(job.jobId, "overlap-skipped", void 0);
1169
1241
  continue;
1170
1242
  }
1171
1243
  if (nowMs - due > config.misfireWindowMs) {
1172
- state.lastRunAt = new Date(nowMs).toISOString();
1173
- state.lastStatus = "misfire-skipped";
1244
+ Object.assign(state, applyOutcome(state, {
1245
+ status: "misfire-skipped",
1246
+ now: nowMs
1247
+ }));
1174
1248
  state.misfireCount += 1;
1175
1249
  state.nextDueAt = nextDueAfter(job.schedule, nowMs) ?? void 0;
1176
1250
  persist();
@@ -1194,32 +1268,34 @@ function createCronEngine(config, jobs, ports) {
1194
1268
  };
1195
1269
  }
1196
1270
  //#endregion
1197
- //#region src/preset-mount.ts
1271
+ //#region src/maid-mount.ts
1198
1272
  /** registry 服务消费入口:reflect 免 inject 直读(照 maid-cron maidMemory 同款探测纪律)。 */
1199
1273
  function presetRegistryOf(ctx, serviceName) {
1200
1274
  return ctx?.reflect.get(serviceName, false);
1201
1275
  }
1202
1276
  /**
1203
- * 包装 agents.create:job 带 meta.agentPreset 时注入 setup 钩子,在 agent 装配期把
1204
- * maid preset 挂进 agent scope(persona/工具/技能目录全部继承);与既有 opts.setup
1205
- * (引擎侧 config.agentSetup)链式组合,挂载在前。
1206
- * - 无 preset id → 不注入,fail-open(无 preset 的 job 与现状同);
1207
- * - registry 缺失 / resolve 抛(未注册) / mount throw → 拒绝 create(fail-loud,
1208
- * job 以 gen-failed 落 state 可观测)。
1277
+ * 包装 agents.create(M3f):meta.maidId 在场且 mountPresets 通道开启时注入 setup 链——
1278
+ * registry.mount(meta.agentPreset) → (需差异层时)composer.setup(agentCtx, maidId) →
1279
+ * 既有 opts.setup。无 maidId / 无 agentPreset → 不注入(fail-open,现状行为)。
1209
1280
  */
1210
- function createPresetMountingAgents(base, registry) {
1211
- return async (opts) => {
1212
- const presetId = opts.meta?.agentPreset;
1213
- if (typeof presetId !== "string" || presetId.length === 0) return base(opts);
1281
+ function createMaidMountingAgents(base, registry, opts) {
1282
+ return async (createOpts) => {
1283
+ const meta = createOpts.meta;
1284
+ const maidId = meta?.maidId;
1285
+ const presetId = meta?.agentPreset;
1286
+ if (typeof maidId !== "string" || maidId.length === 0 || typeof presetId !== "string" || presetId.length === 0) return base(createOpts);
1287
+ const needsComposer = presetId !== opts.maidOwnPresetOf(maidId);
1214
1288
  if (registry === void 0) throw new Error("maid-cron: mountPresets 开启但 agentPresets registry 服务不可用——0.2.0 起预设须经插件行声明(profile patch 的 preset-doris 行),且宿主组合须含 @deepseek-ai/dsh-agent-preset-registry");
1289
+ if (needsComposer && opts.composer === void 0) throw new Error(`maid-cron: job 声明 basePreset '${presetId}'(≠ maid 自带 preset)但 maidComposer 未挂载——差异层缺位即半人格会话,拒绝生成;请安装 @deepmaid/maid-composer 或改用 maid 自带 preset`);
1215
1290
  const resolved = await registry.resolve(presetId);
1216
- const chained = typeof opts.setup === "function" ? opts.setup : void 0;
1291
+ const chained = typeof createOpts.setup === "function" ? createOpts.setup : void 0;
1217
1292
  const setup = async (agentCtx) => {
1218
1293
  await registry.mount(agentCtx, resolved.id);
1294
+ if (needsComposer) await opts.composer.setup(agentCtx, maidId);
1219
1295
  await chained?.(agentCtx);
1220
1296
  };
1221
1297
  return base({
1222
- ...opts,
1298
+ ...createOpts,
1223
1299
  setup
1224
1300
  });
1225
1301
  };
@@ -1233,6 +1309,8 @@ const apply = (ctx, config) => {
1233
1309
  const resolved = {
1234
1310
  tickIntervalMs: config.tickIntervalMs ?? 3e4,
1235
1311
  misfireWindowMs: config.misfireWindowMs ?? 36e5,
1312
+ ...config.failureBackoffBaseMs !== void 0 ? { failureBackoffBaseMs: config.failureBackoffBaseMs } : {},
1313
+ ...config.failureBackoffMaxMs !== void 0 ? { failureBackoffMaxMs: config.failureBackoffMaxMs } : {},
1236
1314
  recentLimit: config.recentLimit ?? 10,
1237
1315
  recentMaxChars: config.recentMaxChars ?? 1500,
1238
1316
  timezone: config.timezone ?? "Asia/Shanghai",
@@ -1242,29 +1320,55 @@ const apply = (ctx, config) => {
1242
1320
  stateFile: config.stateFile,
1243
1321
  onTerminal: (jobId, status, error) => warn(`maid-cron: ${jobId} → ${status}${error !== void 0 ? ` (${error})` : ""}`)
1244
1322
  };
1245
- const maidMemoryService = ctx.reflect.get("maidMemory", false);
1246
- if (maidMemoryService === void 0) warn("maid-cron: maidMemory 未挂载——晨报将不带记忆摘要");
1247
- const memory = maidMemoryService === void 0 ? void 0 : {
1323
+ const lazyReflect = (name, onMiss) => {
1324
+ let cached;
1325
+ let warned = false;
1326
+ return () => {
1327
+ if (cached !== void 0) return cached;
1328
+ const found = ctx.reflect.get(name, false);
1329
+ if (found !== void 0) {
1330
+ cached = found;
1331
+ return found;
1332
+ }
1333
+ if (!warned) {
1334
+ warned = true;
1335
+ warn(onMiss);
1336
+ }
1337
+ };
1338
+ };
1339
+ const maidMemoryOf = lazyReflect("maidMemory", "maid-cron: maidMemory 未挂载——晨报将不带记忆摘要");
1340
+ const memory = {
1248
1341
  recent: (maidId, limit) => {
1249
- const ns = maidMemoryService.resolveNamespace(ctx.maidIdentity.get(maidId)?.preset);
1342
+ const maidMemoryService = maidMemoryOf();
1343
+ if (maidMemoryService === void 0) return Promise.resolve([]);
1344
+ const ns = maidMemoryService.namespaceForMaid(maidId);
1250
1345
  return ns === void 0 ? Promise.resolve([]) : maidMemoryService.recent(ns, limit);
1251
1346
  },
1252
1347
  markSkip: (sessionId) => {
1253
- maidMemoryService.markSkipMemory(sessionId);
1348
+ maidMemoryOf()?.markSkipMemory(sessionId);
1254
1349
  }
1255
1350
  };
1256
- const maidVoiceService = ctx.reflect?.get?.("maidVoice", false);
1257
- if (maidVoiceService === void 0) warn("maid-cron: maidVoice 未挂载——{{nightContext}}/{{overnightSentence}} 将渲染为空");
1258
- const voice = maidVoiceService === void 0 ? void 0 : {
1259
- buildNightContext: (maidId) => maidVoiceService.buildNightContext(maidId) ?? "",
1260
- getMorningSentence: (maidId) => maidVoiceService.getMorningSentence(maidId) ?? ""
1351
+ const maidVoiceOf = lazyReflect("maidVoice", "maid-cron: maidVoice 未挂载——{{nightContext}}/{{overnightSentence}} 将渲染为空");
1352
+ const voice = {
1353
+ buildNightContext: (maidId) => maidVoiceOf()?.buildNightContext(maidId) ?? "",
1354
+ getMorningSentence: (maidId) => maidVoiceOf()?.getMorningSentence(maidId) ?? ""
1261
1355
  };
1262
1356
  const baseCreate = (opts) => ctx.agents.create(opts);
1263
1357
  const presetRegistry = config.mountPresets === true ? presetRegistryOf(ctx, config.presetRegistryService ?? "agentPresets") : void 0;
1264
- const agentsCreate = config.mountPresets === true ? createPresetMountingAgents(baseCreate, presetRegistry) : baseCreate;
1358
+ const composerOf = lazyReflect("maidComposer", "maid-cron: maidComposer 未挂载");
1359
+ const recordOf = (maidId) => ctx.maidIdentity.get(maidId);
1360
+ const agentsCreate = config.mountPresets === true ? createMaidMountingAgents(baseCreate, presetRegistry, {
1361
+ maidOwnPresetOf: (maidId) => recordOf(maidId)?.preset,
1362
+ composer: { setup: (agentCtx, maidId) => {
1363
+ const c = composerOf();
1364
+ if (c === void 0) throw new Error("maid-cron: maidComposer 未挂载(执行时探测)——差异层缺位,拒绝生成");
1365
+ return c.setup(agentCtx, maidId);
1366
+ } }
1367
+ }) : baseCreate;
1265
1368
  const engine = createCronEngine(resolved, jobs, {
1266
1369
  identity: {
1267
- presetOf: (maidId) => ctx.maidIdentity.get(maidId)?.preset,
1370
+ basePresetOf: (maidId, jobBasePreset) => jobBasePreset ?? recordOf(maidId)?.basePreset ?? recordOf(maidId)?.preset,
1371
+ maidOwnPresetOf: (maidId) => recordOf(maidId)?.preset,
1268
1372
  addressOf: (maidId) => ctx.maidIdentity.deliveryTargets(maidId)?.[0]
1269
1373
  },
1270
1374
  memory,
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@deepmaid/maid-cron",
3
- "version": "0.1.0-alpha.1",
4
- "license": "MIT",
3
+ "version": "0.1.0-alpha.3",
5
4
  "type": "module",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
6
9
  "main": "lib/index.js",
7
10
  "types": "lib/index.d.ts",
8
11
  "exports": {
@@ -28,18 +31,18 @@
28
31
  }
29
32
  },
30
33
  "dependencies": {
31
- "@deepseek-ai/dsh-llm": "0.2.1-rc.2",
32
34
  "croner": "10.0.1",
33
- "@deepmaid/maid-delivery": "0.1.0-alpha.1"
35
+ "@deepmaid/maid-delivery": "0.1.0-alpha.3"
36
+ },
37
+ "peerDependencies": {
38
+ "@deepseek-ai/dsh-llm": "0.2.2-rc.1"
34
39
  },
35
40
  "devDependencies": {
36
- "@deepseek-ai/cordis": "4.0.5",
41
+ "@deepseek-ai/cordis": "4.1.0",
37
42
  "tsdown": "0.22.14",
38
43
  "typescript": "6.0.3",
39
- "@deepmaid/maid-memory": "0.1.0-alpha.1"
40
- },
41
- "publishConfig": {
42
- "access": "public"
44
+ "@deepseek-ai/dsh-llm": "0.2.1-rc.2",
45
+ "@deepmaid/maid-memory": "0.1.0-alpha.3"
43
46
  },
44
47
  "scripts": {
45
48
  "build": "tsdown"