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.
@@ -1,8 +1,61 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProcessingEyeOrchestrator = void 0;
3
+ exports.ProcessingEyeOrchestrator = exports.BOT_TOPIC_ROOT_LIMIT = void 0;
4
+ exports.shouldShowProcessingEye = shouldShowProcessingEye;
5
+ exports.listBotTopicRoots = listBotTopicRoots;
6
+ exports.rememberBotTopicRoot = rememberBotTopicRoot;
7
+ exports.persistBotTopicRoot = persistBotTopicRoot;
8
+ exports.isBotStartedTopic = isBotStartedTopic;
4
9
  const node_child_process_1 = require("node:child_process");
5
10
  const agent_lark_cli_workspace_js_1 = require("../app/agent-lark-cli-workspace.cjs");
11
+ exports.BOT_TOPIC_ROOT_LIMIT = 256;
12
+ const BOT_TOPIC_ID = /^om[t]?_[A-Za-z0-9_-]+$/;
13
+ function isPrivateChat(input) {
14
+ const chatType = String(input.chatType || "").toLowerCase();
15
+ if (chatType === "p2p" || chatType === "dm")
16
+ return true;
17
+ if (String(input.channelType || "").toLowerCase() === "dm")
18
+ return true;
19
+ return String(input.parentChannelType || "").toLowerCase() === "dm";
20
+ }
21
+ /** OnIt 给私聊、入站 @bot(含 @all),或用户在 AI 消息下发起的话题里说话。群未@且非 AI 话题不点。 */
22
+ function shouldShowProcessingEye(input) {
23
+ if (isPrivateChat(input))
24
+ return true;
25
+ if (input.mentionedBot === true)
26
+ return true;
27
+ return input.botStartedTopic === true;
28
+ }
29
+ function listBotTopicRoots(state) {
30
+ if (!Array.isArray(state?.bot_topic_roots))
31
+ return [];
32
+ return state.bot_topic_roots.filter((id) => typeof id === "string" && BOT_TOPIC_ID.test(id));
33
+ }
34
+ function rememberBotTopicRoot(ids, candidate) {
35
+ const id = String(candidate || "");
36
+ if (!BOT_TOPIC_ID.test(id) || ids.includes(id))
37
+ return [...ids];
38
+ return [...ids, id].slice(-exports.BOT_TOPIC_ROOT_LIMIT);
39
+ }
40
+ /** 机器人成功发出的 `om_`/`omt_` 记为话题根,供后续「AI 发起的话题」判定,不做飞书回查。 */
41
+ function persistBotTopicRoot(store, candidate) {
42
+ const id = String(candidate || "");
43
+ if (!BOT_TOPIC_ID.test(id))
44
+ return;
45
+ store.mutateJson("freshnessState", { version: 1, cursors: {} }, (state) => {
46
+ state.bot_topic_roots = rememberBotTopicRoot(listBotTopicRoots(state), id);
47
+ });
48
+ }
49
+ function isBotStartedTopic(input) {
50
+ const threadId = String(input.threadId || "");
51
+ if (!threadId)
52
+ return false;
53
+ const owned = new Set(input.ownedIds || []);
54
+ if (owned.has(threadId))
55
+ return true;
56
+ const rootId = String(input.rootId || "");
57
+ return Boolean(rootId) && owned.has(rootId);
58
+ }
6
59
  function errorMessage(error) {
7
60
  return error instanceof Error ? error.message : String(error || "?");
8
61
  }
@@ -1,5 +1,53 @@
1
1
  import { execFile as nodeExecFile } from "node:child_process";
2
2
  import { managedOfficialLarkCli } from "../app/agent-lark-cli-workspace.mjs";
3
+ export const BOT_TOPIC_ROOT_LIMIT = 256;
4
+ const BOT_TOPIC_ID = /^om[t]?_[A-Za-z0-9_-]+$/;
5
+ function isPrivateChat(input) {
6
+ const chatType = String(input.chatType || "").toLowerCase();
7
+ if (chatType === "p2p" || chatType === "dm")
8
+ return true;
9
+ if (String(input.channelType || "").toLowerCase() === "dm")
10
+ return true;
11
+ return String(input.parentChannelType || "").toLowerCase() === "dm";
12
+ }
13
+ /** OnIt 给私聊、入站 @bot(含 @all),或用户在 AI 消息下发起的话题里说话。群未@且非 AI 话题不点。 */
14
+ export function shouldShowProcessingEye(input) {
15
+ if (isPrivateChat(input))
16
+ return true;
17
+ if (input.mentionedBot === true)
18
+ return true;
19
+ return input.botStartedTopic === true;
20
+ }
21
+ export function listBotTopicRoots(state) {
22
+ if (!Array.isArray(state?.bot_topic_roots))
23
+ return [];
24
+ return state.bot_topic_roots.filter((id) => typeof id === "string" && BOT_TOPIC_ID.test(id));
25
+ }
26
+ export function rememberBotTopicRoot(ids, candidate) {
27
+ const id = String(candidate || "");
28
+ if (!BOT_TOPIC_ID.test(id) || ids.includes(id))
29
+ return [...ids];
30
+ return [...ids, id].slice(-BOT_TOPIC_ROOT_LIMIT);
31
+ }
32
+ /** 机器人成功发出的 `om_`/`omt_` 记为话题根,供后续「AI 发起的话题」判定,不做飞书回查。 */
33
+ export function persistBotTopicRoot(store, candidate) {
34
+ const id = String(candidate || "");
35
+ if (!BOT_TOPIC_ID.test(id))
36
+ return;
37
+ store.mutateJson("freshnessState", { version: 1, cursors: {} }, (state) => {
38
+ state.bot_topic_roots = rememberBotTopicRoot(listBotTopicRoots(state), id);
39
+ });
40
+ }
41
+ export function isBotStartedTopic(input) {
42
+ const threadId = String(input.threadId || "");
43
+ if (!threadId)
44
+ return false;
45
+ const owned = new Set(input.ownedIds || []);
46
+ if (owned.has(threadId))
47
+ return true;
48
+ const rootId = String(input.rootId || "");
49
+ return Boolean(rootId) && owned.has(rootId);
50
+ }
3
51
  function errorMessage(error) {
4
52
  return error instanceof Error ? error.message : String(error || "?");
5
53
  }
@@ -509,15 +509,6 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
509
509
  });
510
510
  const seenEventIds = new Set();
511
511
  const inFlightEventIds = new Set();
512
- const processingEyeEnabled = (agent) => {
513
- // 缺 key / 读配置失败都关闭,避免升级后继续自动点 OnIt。
514
- try {
515
- return (0, config_js_1.resolveProcessingEye)((0, config_js_1.loadConfig)(env).config, agent.agentId).enabled;
516
- }
517
- catch {
518
- return false;
519
- }
520
- };
521
512
  const onFeishuMessage = async (agent, event, options) => {
522
513
  const wake = options?.wake !== false;
523
514
  const eventKey = `${agent.agentId}:${event.event_id || event.message_id || ""}`;
@@ -608,12 +599,30 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
608
599
  excerpt: (0, host_business_state_js_1.safeConversationExcerpt)(event.content, 180),
609
600
  at: new Date().toISOString(),
610
601
  }, 30);
611
- if ((inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent")
612
- && processingEyeEnabled(agent)) {
613
- processingEyes.add(agent, String(inboxEnvelope.message_id || ""), {
614
- replyInThread: String(inboxEnvelope.target || "").startsWith("thread:"),
615
- target: String(inboxEnvelope.target || ""),
602
+ if (inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent") {
603
+ // 私聊、入站 @bot,或 inbound root/thread 落在本 bot 已发出的话题根上才点 OnIt。
604
+ const botStartedTopic = (0, host_processing_eye_js_1.isBotStartedTopic)({
605
+ threadId: event.thread_id,
606
+ rootId: event.root_id,
607
+ ownedIds: (0, host_processing_eye_js_1.listBotTopicRoots)(stateStore(agent).readJson("freshnessState", {})),
616
608
  });
609
+ if ((0, host_processing_eye_js_1.shouldShowProcessingEye)({
610
+ chatType: event.chat_type,
611
+ channelType: typeof inboxEnvelope.channel_type === "string" ? inboxEnvelope.channel_type : undefined,
612
+ parentChannelType: typeof inboxEnvelope.parent_channel_type === "string" ? inboxEnvelope.parent_channel_type : undefined,
613
+ mentionedBot: event._mentioned_bot === true,
614
+ botStartedTopic,
615
+ })) {
616
+ if (botStartedTopic)
617
+ (0, host_processing_eye_js_1.persistBotTopicRoot)(stateStore(agent), event.thread_id);
618
+ processingEyes.add(agent, String(inboxEnvelope.message_id || ""), {
619
+ replyInThread: String(inboxEnvelope.target || "").startsWith("thread:"),
620
+ target: String(inboxEnvelope.target || ""),
621
+ });
622
+ }
623
+ else {
624
+ log(`👀 跳过群未@且非 AI 话题消息 agent=${agent.name} chat=${event.chat_id}`);
625
+ }
617
626
  }
618
627
  if (receipt.status === "deferred")
619
628
  log(`Runtime 暂缓投递,消息保留在 inbox seq=${inboxEnvelope.seq}: ${receipt.reason}`);
@@ -8,7 +8,7 @@ import { currentProcessMetadata } from "../platform/process-inspect.cjs";
8
8
  import { reconcileAgentWorkspace } from "../platform/workspace-service.mjs";
9
9
  import { createAgentStateStore } from "../agent/agent-state-store.mjs";
10
10
  import { HostEnvelopeProjector, HostStateProjection, SenderIdentityCache, projectActivityStatus, projectSessionStatus, safeConversationExcerpt, shouldPreventiveReconnect, } from "./host-business-state.mjs";
11
- import { ProcessingEyeOrchestrator } from "./host-processing-eye.mjs";
11
+ import { isBotStartedTopic, listBotTopicRoots, persistBotTopicRoot, ProcessingEyeOrchestrator, shouldShowProcessingEye, } from "./host-processing-eye.mjs";
12
12
  import { feishuImTarget, serializeFeishuImTarget } from "./im-freshness-adapter.mjs";
13
13
  import { projectInboxEnvelope, targetKeyOfInboxEnvelope } from "../agent/inbox-projection.mjs";
14
14
  import { HostReminderOrchestrator } from "../agent/host-reminder-orchestrator.mjs";
@@ -20,7 +20,7 @@ import { targetFor } from "./message-policy.mjs";
20
20
  import { authFailureAppliesTo, parsePersistedAuthFailure, providerAuthenticationFailureReadiness, readinessForPersistedAuthFailure, RuntimePrerequisiteError, } from "../runtime/runtime-readiness.mjs";
21
21
  import { providerFinishReason, safeProviderDiagnostic } from "../runtime/provider-error-classifier.mjs";
22
22
  import { readDocumentCommentSubscription, verifyCallbackProbe } from "../platform/callback-capability.mjs";
23
- import { loadConfig, resolveInboxAuditSchedule, resolveMentionPolicy, resolveProcessingEye } from "../platform/config.mjs";
23
+ import { loadConfig, resolveInboxAuditSchedule, resolveMentionPolicy } from "../platform/config.mjs";
24
24
  import { processCommandToken } from "../app/internal-command.mjs";
25
25
  import { managedOfficialLarkCli } from "../app/agent-lark-cli-workspace.mjs";
26
26
  import { isChannelReconnecting, isRuntimeReadinessCurrent, isSessionCurrent } from "../app/agent-readiness.mjs";
@@ -468,15 +468,6 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
468
468
  });
469
469
  const seenEventIds = new Set();
470
470
  const inFlightEventIds = new Set();
471
- const processingEyeEnabled = (agent) => {
472
- // 缺 key / 读配置失败都关闭,避免升级后继续自动点 OnIt。
473
- try {
474
- return resolveProcessingEye(loadConfig(env).config, agent.agentId).enabled;
475
- }
476
- catch {
477
- return false;
478
- }
479
- };
480
471
  const onFeishuMessage = async (agent, event, options) => {
481
472
  const wake = options?.wake !== false;
482
473
  const eventKey = `${agent.agentId}:${event.event_id || event.message_id || ""}`;
@@ -567,12 +558,30 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
567
558
  excerpt: safeConversationExcerpt(event.content, 180),
568
559
  at: new Date().toISOString(),
569
560
  }, 30);
570
- if ((inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent")
571
- && processingEyeEnabled(agent)) {
572
- processingEyes.add(agent, String(inboxEnvelope.message_id || ""), {
573
- replyInThread: String(inboxEnvelope.target || "").startsWith("thread:"),
574
- target: String(inboxEnvelope.target || ""),
561
+ if (inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent") {
562
+ // 私聊、入站 @bot,或 inbound root/thread 落在本 bot 已发出的话题根上才点 OnIt。
563
+ const botStartedTopic = isBotStartedTopic({
564
+ threadId: event.thread_id,
565
+ rootId: event.root_id,
566
+ ownedIds: listBotTopicRoots(stateStore(agent).readJson("freshnessState", {})),
575
567
  });
568
+ if (shouldShowProcessingEye({
569
+ chatType: event.chat_type,
570
+ channelType: typeof inboxEnvelope.channel_type === "string" ? inboxEnvelope.channel_type : undefined,
571
+ parentChannelType: typeof inboxEnvelope.parent_channel_type === "string" ? inboxEnvelope.parent_channel_type : undefined,
572
+ mentionedBot: event._mentioned_bot === true,
573
+ botStartedTopic,
574
+ })) {
575
+ if (botStartedTopic)
576
+ persistBotTopicRoot(stateStore(agent), event.thread_id);
577
+ processingEyes.add(agent, String(inboxEnvelope.message_id || ""), {
578
+ replyInThread: String(inboxEnvelope.target || "").startsWith("thread:"),
579
+ target: String(inboxEnvelope.target || ""),
580
+ });
581
+ }
582
+ else {
583
+ log(`👀 跳过群未@且非 AI 话题消息 agent=${agent.name} chat=${event.chat_id}`);
584
+ }
576
585
  }
577
586
  if (receipt.status === "deferred")
578
587
  log(`Runtime 暂缓投递,消息保留在 inbox seq=${inboxEnvelope.seq}: ${receipt.reason}`);
@@ -36,6 +36,7 @@ function normalizeChannelMessage(message) {
36
36
  content: String(message.content || ""),
37
37
  create_time: message.createTime,
38
38
  thread_id: message.threadId || null,
39
+ root_id: message.rootId || null,
39
40
  _mentioned_bot: Boolean(message.mentionedBot || message.mentionAll),
40
41
  _mention_all: Boolean(message.mentionAll),
41
42
  _sender_is_bot: message.senderIsBot === true,
@@ -23,6 +23,7 @@ export function normalizeChannelMessage(message) {
23
23
  content: String(message.content || ""),
24
24
  create_time: message.createTime,
25
25
  thread_id: message.threadId || null,
26
+ root_id: message.rootId || null,
26
27
  _mentioned_bot: Boolean(message.mentionedBot || message.mentionAll),
27
28
  _mention_all: Boolean(message.mentionAll),
28
29
  _sender_is_bot: message.senderIsBot === true,
@@ -46,7 +46,6 @@ exports.assertInboxAuditInterval = assertInboxAuditInterval;
46
46
  exports.parseInboxAuditInterval = parseInboxAuditInterval;
47
47
  exports.formatInboxAuditInterval = formatInboxAuditInterval;
48
48
  exports.inboxAuditMutationFromCli = inboxAuditMutationFromCli;
49
- exports.processingEyeMutationFromCli = processingEyeMutationFromCli;
50
49
  exports.hydrateAgent = hydrateAgent;
51
50
  exports.normalizeConfig = normalizeConfig;
52
51
  exports.assertPrivateConfigMetadata = assertPrivateConfigMetadata;
@@ -56,7 +55,6 @@ exports.toStored = toStored;
56
55
  exports.resolveMentionPolicy = resolveMentionPolicy;
57
56
  exports.resolveAgentGlobalMentionPolicy = resolveAgentGlobalMentionPolicy;
58
57
  exports.resolveInboxAuditSchedule = resolveInboxAuditSchedule;
59
- exports.resolveProcessingEye = resolveProcessingEye;
60
58
  exports.runtimeConfigSignature = runtimeConfigSignature;
61
59
  exports.configApplyState = configApplyState;
62
60
  exports.markConfigApplied = markConfigApplied;
@@ -88,12 +86,11 @@ exports.MIN_INBOX_AUDIT_INTERVAL_MS = 60_000;
88
86
  exports.MAX_INBOX_AUDIT_INTERVAL_MS = 24 * 60 * 60_000;
89
87
  const TOP_FIELDS_V3 = new Set(["version", "serverId", "activeAgent", "agents"]);
90
88
  const TOP_FIELDS_V4 = new Set(["version", "serverId", "mentionPolicy", "activeAgent", "agents"]);
91
- const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit", "processingEye"]);
89
+ const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit"]);
92
90
  const AGENT_FIELDS_V3 = new Set(["runtime", "model", "effort", "noMentionChats", "createdAt"]);
93
- const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "processingEye", "createdAt"]);
94
- const LEGACY_AGENT_FIELDS = new Set(["piDistribution", "runtimeOption"]);
91
+ const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "createdAt"]);
92
+ const LEGACY_AGENT_FIELDS = new Set(["piDistribution", "runtimeOption", "processingEye"]);
95
93
  const INBOX_AUDIT_FIELDS = new Set(["enabled", "intervalMs"]);
96
- const PROCESSING_EYE_FIELDS = new Set(["enabled"]);
97
94
  const APP_ID = /^cli_[A-Za-z0-9]+$/;
98
95
  const CHAT_ID = /^oc_[A-Za-z0-9_-]+$/;
99
96
  const PI_EFFORTS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
@@ -206,21 +203,14 @@ function resolvedInboxAudit(settings) {
206
203
  intervalMs: settings?.intervalMs ?? exports.DEFAULT_INBOX_AUDIT_INTERVAL_MS,
207
204
  };
208
205
  }
209
- function parseStoredProcessingEye(value, label) {
210
- if (!isPlainObject(value))
211
- throw new Error(`${label} 必须是普通 object`);
212
- assertAllowedFields(value, PROCESSING_EYE_FIELDS, label);
213
- const settings = {};
214
- if (Object.hasOwn(value, "enabled")) {
215
- if (typeof value.enabled !== "boolean")
216
- throw new Error(`${label}.enabled 必须是 boolean`);
217
- settings.enabled = value.enabled;
206
+ function dropRetiredProcessingEye(raw) {
207
+ delete raw.processingEye;
208
+ if (!isPlainObject(raw.agents))
209
+ return;
210
+ for (const agent of Object.values(raw.agents)) {
211
+ if (isPlainObject(agent))
212
+ delete agent.processingEye;
218
213
  }
219
- return settings;
220
- }
221
- function resolvedProcessingEye(settings) {
222
- // 缺 key 视为关闭。升级后不再保留旧的自动 OnIt 行为,除非用户显式开启。
223
- return { enabled: settings?.enabled ?? false };
224
214
  }
225
215
  function inboxAuditMutationFromCli(input) {
226
216
  if (input.scope === "global") {
@@ -252,25 +242,6 @@ function inboxAuditMutationFromCli(input) {
252
242
  }
253
243
  throw new Error("inbox-audit scope 只支持 global/agent");
254
244
  }
255
- function processingEyeMutationFromCli(input) {
256
- if (input.scope === "global") {
257
- if (input.enabled !== "on" && input.enabled !== "off") {
258
- throw new Error("用法: larkin config processing-eye global <on|off>");
259
- }
260
- return { kind: "set-global-processing-eye", enabled: input.enabled === "on" };
261
- }
262
- if (input.scope === "agent") {
263
- if (input.enabled !== "on" && input.enabled !== "off" && input.enabled !== "inherit") {
264
- throw new Error("用法: larkin config processing-eye agent <inherit|on|off> [--agent <App ID>]");
265
- }
266
- return {
267
- kind: "set-agent-processing-eye",
268
- agentId: input.agentId,
269
- enabled: input.enabled === "inherit" ? "inherit" : input.enabled === "on",
270
- };
271
- }
272
- throw new Error("processing-eye scope 只支持 global/agent");
273
- }
274
245
  function assertModel(runtime, model) {
275
246
  if (model === "default")
276
247
  return;
@@ -340,8 +311,6 @@ function validateStoredAgent(key, agent, version) {
340
311
  assertPolicy(agent.mentionPolicy, `Agent ${key}.mentionPolicy`);
341
312
  if (version === 4 && Object.hasOwn(agent, "inboxAudit"))
342
313
  parseStoredInboxAudit(agent.inboxAudit, `Agent ${key}.inboxAudit`);
343
- if (version === 4 && Object.hasOwn(agent, "processingEye"))
344
- parseStoredProcessingEye(agent.processingEye, `Agent ${key}.processingEye`);
345
314
  if (version === 4 && Object.hasOwn(agent, "chatMentionPolicies")) {
346
315
  if (!isPlainObject(agent.chatMentionPolicies))
347
316
  throw new Error(`Agent ${key}.chatMentionPolicies 必须是普通 object`);
@@ -371,7 +340,6 @@ function hydratedStoredAgent(key, agent, version) {
371
340
  ...(typeof agent.effort === "string" ? { effort: agent.effort } : {}),
372
341
  ...(version === 4 && (agent.mentionPolicy === "require" || agent.mentionPolicy === "free") ? { mentionPolicy: agent.mentionPolicy } : {}),
373
342
  ...(version === 4 && Object.hasOwn(agent, "inboxAudit") ? { inboxAudit: parseStoredInboxAudit(agent.inboxAudit, `Agent ${key}.inboxAudit`) } : {}),
374
- ...(version === 4 && Object.hasOwn(agent, "processingEye") ? { processingEye: parseStoredProcessingEye(agent.processingEye, `Agent ${key}.processingEye`) } : {}),
375
343
  ...(Object.keys(chatMentionPolicies).length ? { chatMentionPolicies, noMentionChats: Object.entries(chatMentionPolicies).filter(([, policy]) => policy === "free").map(([chatId]) => chatId) } : {}),
376
344
  ...(typeof agent.createdAt === "string" ? { createdAt: agent.createdAt } : {}),
377
345
  };
@@ -386,7 +354,6 @@ function hydrateAgent(key, agent, configDir) {
386
354
  ...(agent.effort ? { effort: agent.effort } : {}),
387
355
  ...(agent.mentionPolicy ? { mentionPolicy: agent.mentionPolicy } : {}),
388
356
  ...(agent.inboxAudit ? { inboxAudit: { ...agent.inboxAudit } } : {}),
389
- ...(agent.processingEye ? { processingEye: { ...agent.processingEye } } : {}),
390
357
  ...(agent.chatMentionPolicies ? { chatMentionPolicies: { ...agent.chatMentionPolicies } } : {}),
391
358
  ...(agent.noMentionChats ? { noMentionChats: [...agent.noMentionChats] } : {}),
392
359
  ...(agent.createdAt ? { createdAt: agent.createdAt } : {}),
@@ -401,6 +368,7 @@ function normalizeConfig(raw, configDir, { mint } = {}) {
401
368
  };
402
369
  if (!isPlainObject(raw))
403
370
  throw new Error("config 必须是普通 object");
371
+ dropRetiredProcessingEye(raw);
404
372
  const version = raw.version;
405
373
  if (version !== 3 && version !== 4)
406
374
  throw new Error("不支持该配置格式:larkin 只接受 version=3/4");
@@ -427,13 +395,9 @@ function normalizeConfig(raw, configDir, { mint } = {}) {
427
395
  const inboxAudit = version === 4 && Object.hasOwn(raw, "inboxAudit")
428
396
  ? resolvedInboxAudit(parseStoredInboxAudit(raw.inboxAudit, "config.inboxAudit"))
429
397
  : undefined;
430
- const processingEye = version === 4 && Object.hasOwn(raw, "processingEye")
431
- ? resolvedProcessingEye(parseStoredProcessingEye(raw.processingEye, "config.processingEye"))
432
- : undefined;
433
398
  return {
434
399
  version: 4, serverId: raw.serverId, mentionPolicy: version === 4 ? raw.mentionPolicy : "require",
435
400
  ...(inboxAudit ? { inboxAudit } : {}),
436
- ...(processingEye ? { processingEye } : {}),
437
401
  configDir: layout.configDir, larkinHome: layout.larkinHome, larkConfigDir: resolveLarkConfigDir({}, layout.root), activeAgent: raw.activeAgent, agents,
438
402
  };
439
403
  }
@@ -664,8 +628,6 @@ function toStored(config) {
664
628
  };
665
629
  if (config.inboxAudit)
666
630
  out.inboxAudit = { enabled: config.inboxAudit.enabled, intervalMs: config.inboxAudit.intervalMs };
667
- if (config.processingEye)
668
- out.processingEye = { enabled: config.processingEye.enabled };
669
631
  for (const [key, agent] of Object.entries(config.agents || {})) {
670
632
  const stored = { runtime: agent.runtime, model: agent.model };
671
633
  if (typeof agent.effort === "string" && agent.effort)
@@ -677,9 +639,6 @@ function toStored(config) {
677
639
  if (agent.inboxAudit && (agent.inboxAudit.enabled !== undefined || agent.inboxAudit.intervalMs !== undefined)) {
678
640
  stored.inboxAudit = { ...agent.inboxAudit };
679
641
  }
680
- if (agent.processingEye && agent.processingEye.enabled !== undefined) {
681
- stored.processingEye = { enabled: agent.processingEye.enabled };
682
- }
683
642
  if (typeof agent.createdAt === "string" && agent.createdAt)
684
643
  stored.createdAt = agent.createdAt;
685
644
  out.agents[key] = stored;
@@ -720,16 +679,6 @@ function resolveInboxAuditSchedule(config, agentId) {
720
679
  intervalSource: agent.inboxAudit?.intervalMs !== undefined ? "agent" : config.inboxAudit?.intervalMs !== undefined ? "global" : "default",
721
680
  };
722
681
  }
723
- function resolveProcessingEye(config, agentId) {
724
- const agent = config.agents[agentId];
725
- if (!agent)
726
- throw new Error(`Agent 不存在:${agentId}`);
727
- const enabled = agent.processingEye?.enabled ?? config.processingEye?.enabled ?? false;
728
- return {
729
- enabled,
730
- enabledSource: agent.processingEye?.enabled !== undefined ? "agent" : config.processingEye ? "global" : "default",
731
- };
732
- }
733
682
  function revision(bytes) {
734
683
  return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
735
684
  }
@@ -743,7 +692,8 @@ function agentSignature(config, agentId) {
743
692
  runtime: agent.runtime, model: agent.model, effort: agent.effort ?? null,
744
693
  globalMentionPolicy: config.mentionPolicy, agentMentionPolicy: agent.mentionPolicy ?? null, chatMentionPolicies: chats,
745
694
  globalInboxAudit: config.inboxAudit ?? null, agentInboxAudit: agent.inboxAudit ?? null,
746
- globalProcessingEye: config.processingEye ?? null, agentProcessingEye: agent.processingEye ?? null,
695
+ // 0.5.19 起不再有 processingEye 开关;固定 null 以免未配过该 key 的 Agent 升级后无意义 pending apply。
696
+ globalProcessingEye: null, agentProcessingEye: null,
747
697
  }));
748
698
  }
749
699
  function runtimeConfigSignature(config, agentId) {
@@ -894,10 +844,6 @@ function applyMutation(config, mutation) {
894
844
  config.inboxAudit = current;
895
845
  return { scope: "global", runtimeChange: false, affectedAgentIds: Object.keys(config.agents) };
896
846
  }
897
- if (mutation.kind === "set-global-processing-eye") {
898
- config.processingEye = { enabled: mutation.enabled };
899
- return { scope: "global", runtimeChange: false, affectedAgentIds: Object.keys(config.agents) };
900
- }
901
847
  if (!APP_ID.test(mutation.agentId) || !config.agents[mutation.agentId])
902
848
  throw new Error(`Agent 不存在:${mutation.agentId}`);
903
849
  const agent = config.agents[mutation.agentId];
@@ -930,13 +876,6 @@ function applyMutation(config, mutation) {
930
876
  agent.inboxAudit = current;
931
877
  return { scope: "agent", agentId: mutation.agentId, runtimeChange: false, affectedAgentIds: [mutation.agentId] };
932
878
  }
933
- if (mutation.kind === "set-agent-processing-eye") {
934
- if (mutation.enabled === "inherit")
935
- delete agent.processingEye;
936
- else
937
- agent.processingEye = { enabled: mutation.enabled };
938
- return { scope: "agent", agentId: mutation.agentId, runtimeChange: false, affectedAgentIds: [mutation.agentId] };
939
- }
940
879
  if (mutation.kind === "set-chat-mention") {
941
880
  if (!CHAT_ID.test(mutation.chatId))
942
881
  throw new Error(`群 ID 格式无效:${mutation.chatId}`);
@@ -1434,23 +1373,13 @@ function safeConfigView(config, onlyAgentId, chatId, applyState) {
1434
1373
  source: { enabled: resolved.enabledSource, intervalMs: resolved.intervalSource },
1435
1374
  };
1436
1375
  })(),
1437
- processingEye: (() => {
1438
- const resolved = resolveProcessingEye(config, agentId);
1439
- return {
1440
- override: { enabled: agent.processingEye?.enabled === undefined ? "inherit" : agent.processingEye.enabled ? "on" : "off" },
1441
- effective: { enabled: resolved.enabled },
1442
- source: { enabled: resolved.enabledSource },
1443
- };
1444
- })(),
1445
1376
  chatMentionPolicies: { ...(agent.chatMentionPolicies || {}) },
1446
1377
  apply: applyState?.agents?.[agentId] ?? { applyState: "unknown" },
1447
1378
  }));
1448
1379
  const inboxAudit = resolvedInboxAudit(config.inboxAudit);
1449
- const processingEye = resolvedProcessingEye(config.processingEye);
1450
1380
  return {
1451
1381
  version: 4, mentionPolicy: config.mentionPolicy,
1452
1382
  inboxAudit: { enabled: inboxAudit.enabled, intervalMs: inboxAudit.intervalMs },
1453
- processingEye: { enabled: processingEye.enabled },
1454
1383
  persistedRevision: applyState?.persistedRevision ?? "unknown", agents,
1455
1384
  };
1456
1385
  }