larkin 0.5.18 → 0.5.20

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.
@@ -13,12 +13,11 @@ export const MIN_INBOX_AUDIT_INTERVAL_MS = 60_000;
13
13
  export const MAX_INBOX_AUDIT_INTERVAL_MS = 24 * 60 * 60_000;
14
14
  const TOP_FIELDS_V3 = new Set(["version", "serverId", "activeAgent", "agents"]);
15
15
  const TOP_FIELDS_V4 = new Set(["version", "serverId", "mentionPolicy", "activeAgent", "agents"]);
16
- const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit", "processingEye"]);
16
+ const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit"]);
17
17
  const AGENT_FIELDS_V3 = new Set(["runtime", "model", "effort", "noMentionChats", "createdAt"]);
18
- const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "processingEye", "createdAt"]);
19
- const LEGACY_AGENT_FIELDS = new Set(["piDistribution", "runtimeOption"]);
18
+ const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "createdAt"]);
19
+ const LEGACY_AGENT_FIELDS = new Set(["piDistribution", "runtimeOption", "processingEye"]);
20
20
  const INBOX_AUDIT_FIELDS = new Set(["enabled", "intervalMs"]);
21
- const PROCESSING_EYE_FIELDS = new Set(["enabled"]);
22
21
  const APP_ID = /^cli_[A-Za-z0-9]+$/;
23
22
  const CHAT_ID = /^oc_[A-Za-z0-9_-]+$/;
24
23
  const PI_EFFORTS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
@@ -131,21 +130,14 @@ function resolvedInboxAudit(settings) {
131
130
  intervalMs: settings?.intervalMs ?? DEFAULT_INBOX_AUDIT_INTERVAL_MS,
132
131
  };
133
132
  }
134
- function parseStoredProcessingEye(value, label) {
135
- if (!isPlainObject(value))
136
- throw new Error(`${label} 必须是普通 object`);
137
- assertAllowedFields(value, PROCESSING_EYE_FIELDS, label);
138
- const settings = {};
139
- if (Object.hasOwn(value, "enabled")) {
140
- if (typeof value.enabled !== "boolean")
141
- throw new Error(`${label}.enabled 必须是 boolean`);
142
- settings.enabled = value.enabled;
133
+ function dropRetiredProcessingEye(raw) {
134
+ delete raw.processingEye;
135
+ if (!isPlainObject(raw.agents))
136
+ return;
137
+ for (const agent of Object.values(raw.agents)) {
138
+ if (isPlainObject(agent))
139
+ delete agent.processingEye;
143
140
  }
144
- return settings;
145
- }
146
- function resolvedProcessingEye(settings) {
147
- // 缺 key 视为关闭。升级后不再保留旧的自动 OnIt 行为,除非用户显式开启。
148
- return { enabled: settings?.enabled ?? false };
149
141
  }
150
142
  export function inboxAuditMutationFromCli(input) {
151
143
  if (input.scope === "global") {
@@ -177,25 +169,6 @@ export function inboxAuditMutationFromCli(input) {
177
169
  }
178
170
  throw new Error("inbox-audit scope 只支持 global/agent");
179
171
  }
180
- export function processingEyeMutationFromCli(input) {
181
- if (input.scope === "global") {
182
- if (input.enabled !== "on" && input.enabled !== "off") {
183
- throw new Error("用法: larkin config processing-eye global <on|off>");
184
- }
185
- return { kind: "set-global-processing-eye", enabled: input.enabled === "on" };
186
- }
187
- if (input.scope === "agent") {
188
- if (input.enabled !== "on" && input.enabled !== "off" && input.enabled !== "inherit") {
189
- throw new Error("用法: larkin config processing-eye agent <inherit|on|off> [--agent <App ID>]");
190
- }
191
- return {
192
- kind: "set-agent-processing-eye",
193
- agentId: input.agentId,
194
- enabled: input.enabled === "inherit" ? "inherit" : input.enabled === "on",
195
- };
196
- }
197
- throw new Error("processing-eye scope 只支持 global/agent");
198
- }
199
172
  function assertModel(runtime, model) {
200
173
  if (model === "default")
201
174
  return;
@@ -265,8 +238,6 @@ function validateStoredAgent(key, agent, version) {
265
238
  assertPolicy(agent.mentionPolicy, `Agent ${key}.mentionPolicy`);
266
239
  if (version === 4 && Object.hasOwn(agent, "inboxAudit"))
267
240
  parseStoredInboxAudit(agent.inboxAudit, `Agent ${key}.inboxAudit`);
268
- if (version === 4 && Object.hasOwn(agent, "processingEye"))
269
- parseStoredProcessingEye(agent.processingEye, `Agent ${key}.processingEye`);
270
241
  if (version === 4 && Object.hasOwn(agent, "chatMentionPolicies")) {
271
242
  if (!isPlainObject(agent.chatMentionPolicies))
272
243
  throw new Error(`Agent ${key}.chatMentionPolicies 必须是普通 object`);
@@ -296,7 +267,6 @@ function hydratedStoredAgent(key, agent, version) {
296
267
  ...(typeof agent.effort === "string" ? { effort: agent.effort } : {}),
297
268
  ...(version === 4 && (agent.mentionPolicy === "require" || agent.mentionPolicy === "free") ? { mentionPolicy: agent.mentionPolicy } : {}),
298
269
  ...(version === 4 && Object.hasOwn(agent, "inboxAudit") ? { inboxAudit: parseStoredInboxAudit(agent.inboxAudit, `Agent ${key}.inboxAudit`) } : {}),
299
- ...(version === 4 && Object.hasOwn(agent, "processingEye") ? { processingEye: parseStoredProcessingEye(agent.processingEye, `Agent ${key}.processingEye`) } : {}),
300
270
  ...(Object.keys(chatMentionPolicies).length ? { chatMentionPolicies, noMentionChats: Object.entries(chatMentionPolicies).filter(([, policy]) => policy === "free").map(([chatId]) => chatId) } : {}),
301
271
  ...(typeof agent.createdAt === "string" ? { createdAt: agent.createdAt } : {}),
302
272
  };
@@ -311,7 +281,6 @@ export function hydrateAgent(key, agent, configDir) {
311
281
  ...(agent.effort ? { effort: agent.effort } : {}),
312
282
  ...(agent.mentionPolicy ? { mentionPolicy: agent.mentionPolicy } : {}),
313
283
  ...(agent.inboxAudit ? { inboxAudit: { ...agent.inboxAudit } } : {}),
314
- ...(agent.processingEye ? { processingEye: { ...agent.processingEye } } : {}),
315
284
  ...(agent.chatMentionPolicies ? { chatMentionPolicies: { ...agent.chatMentionPolicies } } : {}),
316
285
  ...(agent.noMentionChats ? { noMentionChats: [...agent.noMentionChats] } : {}),
317
286
  ...(agent.createdAt ? { createdAt: agent.createdAt } : {}),
@@ -326,6 +295,7 @@ export function normalizeConfig(raw, configDir, { mint } = {}) {
326
295
  };
327
296
  if (!isPlainObject(raw))
328
297
  throw new Error("config 必须是普通 object");
298
+ dropRetiredProcessingEye(raw);
329
299
  const version = raw.version;
330
300
  if (version !== 3 && version !== 4)
331
301
  throw new Error("不支持该配置格式:larkin 只接受 version=3/4");
@@ -352,13 +322,9 @@ export function normalizeConfig(raw, configDir, { mint } = {}) {
352
322
  const inboxAudit = version === 4 && Object.hasOwn(raw, "inboxAudit")
353
323
  ? resolvedInboxAudit(parseStoredInboxAudit(raw.inboxAudit, "config.inboxAudit"))
354
324
  : undefined;
355
- const processingEye = version === 4 && Object.hasOwn(raw, "processingEye")
356
- ? resolvedProcessingEye(parseStoredProcessingEye(raw.processingEye, "config.processingEye"))
357
- : undefined;
358
325
  return {
359
326
  version: 4, serverId: raw.serverId, mentionPolicy: version === 4 ? raw.mentionPolicy : "require",
360
327
  ...(inboxAudit ? { inboxAudit } : {}),
361
- ...(processingEye ? { processingEye } : {}),
362
328
  configDir: layout.configDir, larkinHome: layout.larkinHome, larkConfigDir: resolveLarkConfigDir({}, layout.root), activeAgent: raw.activeAgent, agents,
363
329
  };
364
330
  }
@@ -589,8 +555,6 @@ export function toStored(config) {
589
555
  };
590
556
  if (config.inboxAudit)
591
557
  out.inboxAudit = { enabled: config.inboxAudit.enabled, intervalMs: config.inboxAudit.intervalMs };
592
- if (config.processingEye)
593
- out.processingEye = { enabled: config.processingEye.enabled };
594
558
  for (const [key, agent] of Object.entries(config.agents || {})) {
595
559
  const stored = { runtime: agent.runtime, model: agent.model };
596
560
  if (typeof agent.effort === "string" && agent.effort)
@@ -602,9 +566,6 @@ export function toStored(config) {
602
566
  if (agent.inboxAudit && (agent.inboxAudit.enabled !== undefined || agent.inboxAudit.intervalMs !== undefined)) {
603
567
  stored.inboxAudit = { ...agent.inboxAudit };
604
568
  }
605
- if (agent.processingEye && agent.processingEye.enabled !== undefined) {
606
- stored.processingEye = { enabled: agent.processingEye.enabled };
607
- }
608
569
  if (typeof agent.createdAt === "string" && agent.createdAt)
609
570
  stored.createdAt = agent.createdAt;
610
571
  out.agents[key] = stored;
@@ -645,16 +606,6 @@ export function resolveInboxAuditSchedule(config, agentId) {
645
606
  intervalSource: agent.inboxAudit?.intervalMs !== undefined ? "agent" : config.inboxAudit?.intervalMs !== undefined ? "global" : "default",
646
607
  };
647
608
  }
648
- export function resolveProcessingEye(config, agentId) {
649
- const agent = config.agents[agentId];
650
- if (!agent)
651
- throw new Error(`Agent 不存在:${agentId}`);
652
- const enabled = agent.processingEye?.enabled ?? config.processingEye?.enabled ?? false;
653
- return {
654
- enabled,
655
- enabledSource: agent.processingEye?.enabled !== undefined ? "agent" : config.processingEye ? "global" : "default",
656
- };
657
- }
658
609
  function revision(bytes) {
659
610
  return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
660
611
  }
@@ -668,7 +619,8 @@ function agentSignature(config, agentId) {
668
619
  runtime: agent.runtime, model: agent.model, effort: agent.effort ?? null,
669
620
  globalMentionPolicy: config.mentionPolicy, agentMentionPolicy: agent.mentionPolicy ?? null, chatMentionPolicies: chats,
670
621
  globalInboxAudit: config.inboxAudit ?? null, agentInboxAudit: agent.inboxAudit ?? null,
671
- globalProcessingEye: config.processingEye ?? null, agentProcessingEye: agent.processingEye ?? null,
622
+ // 0.5.19 起不再有 processingEye 开关;固定 null 以免未配过该 key 的 Agent 升级后无意义 pending apply。
623
+ globalProcessingEye: null, agentProcessingEye: null,
672
624
  }));
673
625
  }
674
626
  export function runtimeConfigSignature(config, agentId) {
@@ -819,10 +771,6 @@ function applyMutation(config, mutation) {
819
771
  config.inboxAudit = current;
820
772
  return { scope: "global", runtimeChange: false, affectedAgentIds: Object.keys(config.agents) };
821
773
  }
822
- if (mutation.kind === "set-global-processing-eye") {
823
- config.processingEye = { enabled: mutation.enabled };
824
- return { scope: "global", runtimeChange: false, affectedAgentIds: Object.keys(config.agents) };
825
- }
826
774
  if (!APP_ID.test(mutation.agentId) || !config.agents[mutation.agentId])
827
775
  throw new Error(`Agent 不存在:${mutation.agentId}`);
828
776
  const agent = config.agents[mutation.agentId];
@@ -855,13 +803,6 @@ function applyMutation(config, mutation) {
855
803
  agent.inboxAudit = current;
856
804
  return { scope: "agent", agentId: mutation.agentId, runtimeChange: false, affectedAgentIds: [mutation.agentId] };
857
805
  }
858
- if (mutation.kind === "set-agent-processing-eye") {
859
- if (mutation.enabled === "inherit")
860
- delete agent.processingEye;
861
- else
862
- agent.processingEye = { enabled: mutation.enabled };
863
- return { scope: "agent", agentId: mutation.agentId, runtimeChange: false, affectedAgentIds: [mutation.agentId] };
864
- }
865
806
  if (mutation.kind === "set-chat-mention") {
866
807
  if (!CHAT_ID.test(mutation.chatId))
867
808
  throw new Error(`群 ID 格式无效:${mutation.chatId}`);
@@ -1359,23 +1300,13 @@ export function safeConfigView(config, onlyAgentId, chatId, applyState) {
1359
1300
  source: { enabled: resolved.enabledSource, intervalMs: resolved.intervalSource },
1360
1301
  };
1361
1302
  })(),
1362
- processingEye: (() => {
1363
- const resolved = resolveProcessingEye(config, agentId);
1364
- return {
1365
- override: { enabled: agent.processingEye?.enabled === undefined ? "inherit" : agent.processingEye.enabled ? "on" : "off" },
1366
- effective: { enabled: resolved.enabled },
1367
- source: { enabled: resolved.enabledSource },
1368
- };
1369
- })(),
1370
1303
  chatMentionPolicies: { ...(agent.chatMentionPolicies || {}) },
1371
1304
  apply: applyState?.agents?.[agentId] ?? { applyState: "unknown" },
1372
1305
  }));
1373
1306
  const inboxAudit = resolvedInboxAudit(config.inboxAudit);
1374
- const processingEye = resolvedProcessingEye(config.processingEye);
1375
1307
  return {
1376
1308
  version: 4, mentionPolicy: config.mentionPolicy,
1377
1309
  inboxAudit: { enabled: inboxAudit.enabled, intervalMs: inboxAudit.intervalMs },
1378
- processingEye: { enabled: processingEye.enabled },
1379
1310
  persistedRevision: applyState?.persistedRevision ?? "unknown", agents,
1380
1311
  };
1381
1312
  }
@@ -1221,6 +1221,9 @@ function createRuntimeHost(options) {
1221
1221
  agent.config.sessionId = event.sessionId;
1222
1222
  emit({ type: "session", agentId: agent.config.agentId, runtime: agent.adapter.id, sessionId: event.sessionId, launchId: agent.launchId,
1223
1223
  ...(event.model ? { model: event.model } : {}), ...(event.reasoningEffort ? { reasoningEffort: event.reasoningEffort } : {}) });
1224
+ // A runtime can defer input until its session is ready (Codex before thread/start or thread/resume returns);
1225
+ // nothing else would resubmit that delivery, so retry pending work once the session reports in.
1226
+ void retryPending(agent);
1224
1227
  }
1225
1228
  else if (event.type === "turn-start") {
1226
1229
  // Clear a source left by a crashed/aborted prior turn before a new turn
@@ -1212,6 +1212,9 @@ export function createRuntimeHost(options) {
1212
1212
  agent.config.sessionId = event.sessionId;
1213
1213
  emit({ type: "session", agentId: agent.config.agentId, runtime: agent.adapter.id, sessionId: event.sessionId, launchId: agent.launchId,
1214
1214
  ...(event.model ? { model: event.model } : {}), ...(event.reasoningEffort ? { reasoningEffort: event.reasoningEffort } : {}) });
1215
+ // A runtime can defer input until its session is ready (Codex before thread/start or thread/resume returns);
1216
+ // nothing else would resubmit that delivery, so retry pending work once the session reports in.
1217
+ void retryPending(agent);
1215
1218
  }
1216
1219
  else if (event.type === "turn-start") {
1217
1220
  // Clear a source left by a crashed/aborted prior turn before a new turn
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "larkin",
3
- "version": "0.5.18",
3
+ "version": "0.5.20",
4
4
  "private": false,
5
5
  "larkinPackageRole": "npm-published",
6
6
  "files": [