larkin 0.5.17 → 0.5.18

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.
@@ -509,6 +509,15 @@ 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
+ };
512
521
  const onFeishuMessage = async (agent, event, options) => {
513
522
  const wake = options?.wake !== false;
514
523
  const eventKey = `${agent.agentId}:${event.event_id || event.message_id || ""}`;
@@ -599,7 +608,8 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
599
608
  excerpt: (0, host_business_state_js_1.safeConversationExcerpt)(event.content, 180),
600
609
  at: new Date().toISOString(),
601
610
  }, 30);
602
- if (inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent") {
611
+ if ((inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent")
612
+ && processingEyeEnabled(agent)) {
603
613
  processingEyes.add(agent, String(inboxEnvelope.message_id || ""), {
604
614
  replyInThread: String(inboxEnvelope.target || "").startsWith("thread:"),
605
615
  target: String(inboxEnvelope.target || ""),
@@ -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 } from "../platform/config.mjs";
23
+ import { loadConfig, resolveInboxAuditSchedule, resolveMentionPolicy, resolveProcessingEye } 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,6 +468,15 @@ 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
+ };
471
480
  const onFeishuMessage = async (agent, event, options) => {
472
481
  const wake = options?.wake !== false;
473
482
  const eventKey = `${agent.agentId}:${event.event_id || event.message_id || ""}`;
@@ -558,7 +567,8 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
558
567
  excerpt: safeConversationExcerpt(event.content, 180),
559
568
  at: new Date().toISOString(),
560
569
  }, 30);
561
- if (inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent") {
570
+ if ((inboxEnvelope.sender_type === "human" || inboxEnvelope.sender_type === "agent")
571
+ && processingEyeEnabled(agent)) {
562
572
  processingEyes.add(agent, String(inboxEnvelope.message_id || ""), {
563
573
  replyInThread: String(inboxEnvelope.target || "").startsWith("thread:"),
564
574
  target: String(inboxEnvelope.target || ""),
@@ -46,6 +46,7 @@ exports.assertInboxAuditInterval = assertInboxAuditInterval;
46
46
  exports.parseInboxAuditInterval = parseInboxAuditInterval;
47
47
  exports.formatInboxAuditInterval = formatInboxAuditInterval;
48
48
  exports.inboxAuditMutationFromCli = inboxAuditMutationFromCli;
49
+ exports.processingEyeMutationFromCli = processingEyeMutationFromCli;
49
50
  exports.hydrateAgent = hydrateAgent;
50
51
  exports.normalizeConfig = normalizeConfig;
51
52
  exports.assertPrivateConfigMetadata = assertPrivateConfigMetadata;
@@ -55,6 +56,7 @@ exports.toStored = toStored;
55
56
  exports.resolveMentionPolicy = resolveMentionPolicy;
56
57
  exports.resolveAgentGlobalMentionPolicy = resolveAgentGlobalMentionPolicy;
57
58
  exports.resolveInboxAuditSchedule = resolveInboxAuditSchedule;
59
+ exports.resolveProcessingEye = resolveProcessingEye;
58
60
  exports.runtimeConfigSignature = runtimeConfigSignature;
59
61
  exports.configApplyState = configApplyState;
60
62
  exports.markConfigApplied = markConfigApplied;
@@ -86,11 +88,12 @@ exports.MIN_INBOX_AUDIT_INTERVAL_MS = 60_000;
86
88
  exports.MAX_INBOX_AUDIT_INTERVAL_MS = 24 * 60 * 60_000;
87
89
  const TOP_FIELDS_V3 = new Set(["version", "serverId", "activeAgent", "agents"]);
88
90
  const TOP_FIELDS_V4 = new Set(["version", "serverId", "mentionPolicy", "activeAgent", "agents"]);
89
- const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit"]);
91
+ const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit", "processingEye"]);
90
92
  const AGENT_FIELDS_V3 = new Set(["runtime", "model", "effort", "noMentionChats", "createdAt"]);
91
- const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "createdAt"]);
93
+ const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "processingEye", "createdAt"]);
92
94
  const LEGACY_AGENT_FIELDS = new Set(["piDistribution", "runtimeOption"]);
93
95
  const INBOX_AUDIT_FIELDS = new Set(["enabled", "intervalMs"]);
96
+ const PROCESSING_EYE_FIELDS = new Set(["enabled"]);
94
97
  const APP_ID = /^cli_[A-Za-z0-9]+$/;
95
98
  const CHAT_ID = /^oc_[A-Za-z0-9_-]+$/;
96
99
  const PI_EFFORTS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
@@ -203,6 +206,22 @@ function resolvedInboxAudit(settings) {
203
206
  intervalMs: settings?.intervalMs ?? exports.DEFAULT_INBOX_AUDIT_INTERVAL_MS,
204
207
  };
205
208
  }
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;
218
+ }
219
+ return settings;
220
+ }
221
+ function resolvedProcessingEye(settings) {
222
+ // 缺 key 视为关闭。升级后不再保留旧的自动 OnIt 行为,除非用户显式开启。
223
+ return { enabled: settings?.enabled ?? false };
224
+ }
206
225
  function inboxAuditMutationFromCli(input) {
207
226
  if (input.scope === "global") {
208
227
  if (input.enabled !== "on" && input.enabled !== "off") {
@@ -233,6 +252,25 @@ function inboxAuditMutationFromCli(input) {
233
252
  }
234
253
  throw new Error("inbox-audit scope 只支持 global/agent");
235
254
  }
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
+ }
236
274
  function assertModel(runtime, model) {
237
275
  if (model === "default")
238
276
  return;
@@ -302,6 +340,8 @@ function validateStoredAgent(key, agent, version) {
302
340
  assertPolicy(agent.mentionPolicy, `Agent ${key}.mentionPolicy`);
303
341
  if (version === 4 && Object.hasOwn(agent, "inboxAudit"))
304
342
  parseStoredInboxAudit(agent.inboxAudit, `Agent ${key}.inboxAudit`);
343
+ if (version === 4 && Object.hasOwn(agent, "processingEye"))
344
+ parseStoredProcessingEye(agent.processingEye, `Agent ${key}.processingEye`);
305
345
  if (version === 4 && Object.hasOwn(agent, "chatMentionPolicies")) {
306
346
  if (!isPlainObject(agent.chatMentionPolicies))
307
347
  throw new Error(`Agent ${key}.chatMentionPolicies 必须是普通 object`);
@@ -331,6 +371,7 @@ function hydratedStoredAgent(key, agent, version) {
331
371
  ...(typeof agent.effort === "string" ? { effort: agent.effort } : {}),
332
372
  ...(version === 4 && (agent.mentionPolicy === "require" || agent.mentionPolicy === "free") ? { mentionPolicy: agent.mentionPolicy } : {}),
333
373
  ...(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`) } : {}),
334
375
  ...(Object.keys(chatMentionPolicies).length ? { chatMentionPolicies, noMentionChats: Object.entries(chatMentionPolicies).filter(([, policy]) => policy === "free").map(([chatId]) => chatId) } : {}),
335
376
  ...(typeof agent.createdAt === "string" ? { createdAt: agent.createdAt } : {}),
336
377
  };
@@ -345,6 +386,7 @@ function hydrateAgent(key, agent, configDir) {
345
386
  ...(agent.effort ? { effort: agent.effort } : {}),
346
387
  ...(agent.mentionPolicy ? { mentionPolicy: agent.mentionPolicy } : {}),
347
388
  ...(agent.inboxAudit ? { inboxAudit: { ...agent.inboxAudit } } : {}),
389
+ ...(agent.processingEye ? { processingEye: { ...agent.processingEye } } : {}),
348
390
  ...(agent.chatMentionPolicies ? { chatMentionPolicies: { ...agent.chatMentionPolicies } } : {}),
349
391
  ...(agent.noMentionChats ? { noMentionChats: [...agent.noMentionChats] } : {}),
350
392
  ...(agent.createdAt ? { createdAt: agent.createdAt } : {}),
@@ -385,9 +427,13 @@ function normalizeConfig(raw, configDir, { mint } = {}) {
385
427
  const inboxAudit = version === 4 && Object.hasOwn(raw, "inboxAudit")
386
428
  ? resolvedInboxAudit(parseStoredInboxAudit(raw.inboxAudit, "config.inboxAudit"))
387
429
  : undefined;
430
+ const processingEye = version === 4 && Object.hasOwn(raw, "processingEye")
431
+ ? resolvedProcessingEye(parseStoredProcessingEye(raw.processingEye, "config.processingEye"))
432
+ : undefined;
388
433
  return {
389
434
  version: 4, serverId: raw.serverId, mentionPolicy: version === 4 ? raw.mentionPolicy : "require",
390
435
  ...(inboxAudit ? { inboxAudit } : {}),
436
+ ...(processingEye ? { processingEye } : {}),
391
437
  configDir: layout.configDir, larkinHome: layout.larkinHome, larkConfigDir: resolveLarkConfigDir({}, layout.root), activeAgent: raw.activeAgent, agents,
392
438
  };
393
439
  }
@@ -618,6 +664,8 @@ function toStored(config) {
618
664
  };
619
665
  if (config.inboxAudit)
620
666
  out.inboxAudit = { enabled: config.inboxAudit.enabled, intervalMs: config.inboxAudit.intervalMs };
667
+ if (config.processingEye)
668
+ out.processingEye = { enabled: config.processingEye.enabled };
621
669
  for (const [key, agent] of Object.entries(config.agents || {})) {
622
670
  const stored = { runtime: agent.runtime, model: agent.model };
623
671
  if (typeof agent.effort === "string" && agent.effort)
@@ -629,6 +677,9 @@ function toStored(config) {
629
677
  if (agent.inboxAudit && (agent.inboxAudit.enabled !== undefined || agent.inboxAudit.intervalMs !== undefined)) {
630
678
  stored.inboxAudit = { ...agent.inboxAudit };
631
679
  }
680
+ if (agent.processingEye && agent.processingEye.enabled !== undefined) {
681
+ stored.processingEye = { enabled: agent.processingEye.enabled };
682
+ }
632
683
  if (typeof agent.createdAt === "string" && agent.createdAt)
633
684
  stored.createdAt = agent.createdAt;
634
685
  out.agents[key] = stored;
@@ -669,6 +720,16 @@ function resolveInboxAuditSchedule(config, agentId) {
669
720
  intervalSource: agent.inboxAudit?.intervalMs !== undefined ? "agent" : config.inboxAudit?.intervalMs !== undefined ? "global" : "default",
670
721
  };
671
722
  }
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
+ }
672
733
  function revision(bytes) {
673
734
  return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
674
735
  }
@@ -682,6 +743,7 @@ function agentSignature(config, agentId) {
682
743
  runtime: agent.runtime, model: agent.model, effort: agent.effort ?? null,
683
744
  globalMentionPolicy: config.mentionPolicy, agentMentionPolicy: agent.mentionPolicy ?? null, chatMentionPolicies: chats,
684
745
  globalInboxAudit: config.inboxAudit ?? null, agentInboxAudit: agent.inboxAudit ?? null,
746
+ globalProcessingEye: config.processingEye ?? null, agentProcessingEye: agent.processingEye ?? null,
685
747
  }));
686
748
  }
687
749
  function runtimeConfigSignature(config, agentId) {
@@ -832,6 +894,10 @@ function applyMutation(config, mutation) {
832
894
  config.inboxAudit = current;
833
895
  return { scope: "global", runtimeChange: false, affectedAgentIds: Object.keys(config.agents) };
834
896
  }
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
+ }
835
901
  if (!APP_ID.test(mutation.agentId) || !config.agents[mutation.agentId])
836
902
  throw new Error(`Agent 不存在:${mutation.agentId}`);
837
903
  const agent = config.agents[mutation.agentId];
@@ -864,6 +930,13 @@ function applyMutation(config, mutation) {
864
930
  agent.inboxAudit = current;
865
931
  return { scope: "agent", agentId: mutation.agentId, runtimeChange: false, affectedAgentIds: [mutation.agentId] };
866
932
  }
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
+ }
867
940
  if (mutation.kind === "set-chat-mention") {
868
941
  if (!CHAT_ID.test(mutation.chatId))
869
942
  throw new Error(`群 ID 格式无效:${mutation.chatId}`);
@@ -1361,13 +1434,23 @@ function safeConfigView(config, onlyAgentId, chatId, applyState) {
1361
1434
  source: { enabled: resolved.enabledSource, intervalMs: resolved.intervalSource },
1362
1435
  };
1363
1436
  })(),
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
+ })(),
1364
1445
  chatMentionPolicies: { ...(agent.chatMentionPolicies || {}) },
1365
1446
  apply: applyState?.agents?.[agentId] ?? { applyState: "unknown" },
1366
1447
  }));
1367
1448
  const inboxAudit = resolvedInboxAudit(config.inboxAudit);
1449
+ const processingEye = resolvedProcessingEye(config.processingEye);
1368
1450
  return {
1369
1451
  version: 4, mentionPolicy: config.mentionPolicy,
1370
1452
  inboxAudit: { enabled: inboxAudit.enabled, intervalMs: inboxAudit.intervalMs },
1453
+ processingEye: { enabled: processingEye.enabled },
1371
1454
  persistedRevision: applyState?.persistedRevision ?? "unknown", agents,
1372
1455
  };
1373
1456
  }
@@ -13,11 +13,12 @@ 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"]);
16
+ const OPTIONAL_TOP_FIELDS_V4 = new Set(["inboxAudit", "processingEye"]);
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", "createdAt"]);
18
+ const AGENT_FIELDS_V4 = new Set(["runtime", "model", "effort", "mentionPolicy", "chatMentionPolicies", "inboxAudit", "processingEye", "createdAt"]);
19
19
  const LEGACY_AGENT_FIELDS = new Set(["piDistribution", "runtimeOption"]);
20
20
  const INBOX_AUDIT_FIELDS = new Set(["enabled", "intervalMs"]);
21
+ const PROCESSING_EYE_FIELDS = new Set(["enabled"]);
21
22
  const APP_ID = /^cli_[A-Za-z0-9]+$/;
22
23
  const CHAT_ID = /^oc_[A-Za-z0-9_-]+$/;
23
24
  const PI_EFFORTS = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
@@ -130,6 +131,22 @@ function resolvedInboxAudit(settings) {
130
131
  intervalMs: settings?.intervalMs ?? DEFAULT_INBOX_AUDIT_INTERVAL_MS,
131
132
  };
132
133
  }
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;
143
+ }
144
+ return settings;
145
+ }
146
+ function resolvedProcessingEye(settings) {
147
+ // 缺 key 视为关闭。升级后不再保留旧的自动 OnIt 行为,除非用户显式开启。
148
+ return { enabled: settings?.enabled ?? false };
149
+ }
133
150
  export function inboxAuditMutationFromCli(input) {
134
151
  if (input.scope === "global") {
135
152
  if (input.enabled !== "on" && input.enabled !== "off") {
@@ -160,6 +177,25 @@ export function inboxAuditMutationFromCli(input) {
160
177
  }
161
178
  throw new Error("inbox-audit scope 只支持 global/agent");
162
179
  }
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
+ }
163
199
  function assertModel(runtime, model) {
164
200
  if (model === "default")
165
201
  return;
@@ -229,6 +265,8 @@ function validateStoredAgent(key, agent, version) {
229
265
  assertPolicy(agent.mentionPolicy, `Agent ${key}.mentionPolicy`);
230
266
  if (version === 4 && Object.hasOwn(agent, "inboxAudit"))
231
267
  parseStoredInboxAudit(agent.inboxAudit, `Agent ${key}.inboxAudit`);
268
+ if (version === 4 && Object.hasOwn(agent, "processingEye"))
269
+ parseStoredProcessingEye(agent.processingEye, `Agent ${key}.processingEye`);
232
270
  if (version === 4 && Object.hasOwn(agent, "chatMentionPolicies")) {
233
271
  if (!isPlainObject(agent.chatMentionPolicies))
234
272
  throw new Error(`Agent ${key}.chatMentionPolicies 必须是普通 object`);
@@ -258,6 +296,7 @@ function hydratedStoredAgent(key, agent, version) {
258
296
  ...(typeof agent.effort === "string" ? { effort: agent.effort } : {}),
259
297
  ...(version === 4 && (agent.mentionPolicy === "require" || agent.mentionPolicy === "free") ? { mentionPolicy: agent.mentionPolicy } : {}),
260
298
  ...(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`) } : {}),
261
300
  ...(Object.keys(chatMentionPolicies).length ? { chatMentionPolicies, noMentionChats: Object.entries(chatMentionPolicies).filter(([, policy]) => policy === "free").map(([chatId]) => chatId) } : {}),
262
301
  ...(typeof agent.createdAt === "string" ? { createdAt: agent.createdAt } : {}),
263
302
  };
@@ -272,6 +311,7 @@ export function hydrateAgent(key, agent, configDir) {
272
311
  ...(agent.effort ? { effort: agent.effort } : {}),
273
312
  ...(agent.mentionPolicy ? { mentionPolicy: agent.mentionPolicy } : {}),
274
313
  ...(agent.inboxAudit ? { inboxAudit: { ...agent.inboxAudit } } : {}),
314
+ ...(agent.processingEye ? { processingEye: { ...agent.processingEye } } : {}),
275
315
  ...(agent.chatMentionPolicies ? { chatMentionPolicies: { ...agent.chatMentionPolicies } } : {}),
276
316
  ...(agent.noMentionChats ? { noMentionChats: [...agent.noMentionChats] } : {}),
277
317
  ...(agent.createdAt ? { createdAt: agent.createdAt } : {}),
@@ -312,9 +352,13 @@ export function normalizeConfig(raw, configDir, { mint } = {}) {
312
352
  const inboxAudit = version === 4 && Object.hasOwn(raw, "inboxAudit")
313
353
  ? resolvedInboxAudit(parseStoredInboxAudit(raw.inboxAudit, "config.inboxAudit"))
314
354
  : undefined;
355
+ const processingEye = version === 4 && Object.hasOwn(raw, "processingEye")
356
+ ? resolvedProcessingEye(parseStoredProcessingEye(raw.processingEye, "config.processingEye"))
357
+ : undefined;
315
358
  return {
316
359
  version: 4, serverId: raw.serverId, mentionPolicy: version === 4 ? raw.mentionPolicy : "require",
317
360
  ...(inboxAudit ? { inboxAudit } : {}),
361
+ ...(processingEye ? { processingEye } : {}),
318
362
  configDir: layout.configDir, larkinHome: layout.larkinHome, larkConfigDir: resolveLarkConfigDir({}, layout.root), activeAgent: raw.activeAgent, agents,
319
363
  };
320
364
  }
@@ -545,6 +589,8 @@ export function toStored(config) {
545
589
  };
546
590
  if (config.inboxAudit)
547
591
  out.inboxAudit = { enabled: config.inboxAudit.enabled, intervalMs: config.inboxAudit.intervalMs };
592
+ if (config.processingEye)
593
+ out.processingEye = { enabled: config.processingEye.enabled };
548
594
  for (const [key, agent] of Object.entries(config.agents || {})) {
549
595
  const stored = { runtime: agent.runtime, model: agent.model };
550
596
  if (typeof agent.effort === "string" && agent.effort)
@@ -556,6 +602,9 @@ export function toStored(config) {
556
602
  if (agent.inboxAudit && (agent.inboxAudit.enabled !== undefined || agent.inboxAudit.intervalMs !== undefined)) {
557
603
  stored.inboxAudit = { ...agent.inboxAudit };
558
604
  }
605
+ if (agent.processingEye && agent.processingEye.enabled !== undefined) {
606
+ stored.processingEye = { enabled: agent.processingEye.enabled };
607
+ }
559
608
  if (typeof agent.createdAt === "string" && agent.createdAt)
560
609
  stored.createdAt = agent.createdAt;
561
610
  out.agents[key] = stored;
@@ -596,6 +645,16 @@ export function resolveInboxAuditSchedule(config, agentId) {
596
645
  intervalSource: agent.inboxAudit?.intervalMs !== undefined ? "agent" : config.inboxAudit?.intervalMs !== undefined ? "global" : "default",
597
646
  };
598
647
  }
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
+ }
599
658
  function revision(bytes) {
600
659
  return `sha256:${crypto.createHash("sha256").update(bytes).digest("hex")}`;
601
660
  }
@@ -609,6 +668,7 @@ function agentSignature(config, agentId) {
609
668
  runtime: agent.runtime, model: agent.model, effort: agent.effort ?? null,
610
669
  globalMentionPolicy: config.mentionPolicy, agentMentionPolicy: agent.mentionPolicy ?? null, chatMentionPolicies: chats,
611
670
  globalInboxAudit: config.inboxAudit ?? null, agentInboxAudit: agent.inboxAudit ?? null,
671
+ globalProcessingEye: config.processingEye ?? null, agentProcessingEye: agent.processingEye ?? null,
612
672
  }));
613
673
  }
614
674
  export function runtimeConfigSignature(config, agentId) {
@@ -759,6 +819,10 @@ function applyMutation(config, mutation) {
759
819
  config.inboxAudit = current;
760
820
  return { scope: "global", runtimeChange: false, affectedAgentIds: Object.keys(config.agents) };
761
821
  }
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
+ }
762
826
  if (!APP_ID.test(mutation.agentId) || !config.agents[mutation.agentId])
763
827
  throw new Error(`Agent 不存在:${mutation.agentId}`);
764
828
  const agent = config.agents[mutation.agentId];
@@ -791,6 +855,13 @@ function applyMutation(config, mutation) {
791
855
  agent.inboxAudit = current;
792
856
  return { scope: "agent", agentId: mutation.agentId, runtimeChange: false, affectedAgentIds: [mutation.agentId] };
793
857
  }
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
+ }
794
865
  if (mutation.kind === "set-chat-mention") {
795
866
  if (!CHAT_ID.test(mutation.chatId))
796
867
  throw new Error(`群 ID 格式无效:${mutation.chatId}`);
@@ -1288,13 +1359,23 @@ export function safeConfigView(config, onlyAgentId, chatId, applyState) {
1288
1359
  source: { enabled: resolved.enabledSource, intervalMs: resolved.intervalSource },
1289
1360
  };
1290
1361
  })(),
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
+ })(),
1291
1370
  chatMentionPolicies: { ...(agent.chatMentionPolicies || {}) },
1292
1371
  apply: applyState?.agents?.[agentId] ?? { applyState: "unknown" },
1293
1372
  }));
1294
1373
  const inboxAudit = resolvedInboxAudit(config.inboxAudit);
1374
+ const processingEye = resolvedProcessingEye(config.processingEye);
1295
1375
  return {
1296
1376
  version: 4, mentionPolicy: config.mentionPolicy,
1297
1377
  inboxAudit: { enabled: inboxAudit.enabled, intervalMs: inboxAudit.intervalMs },
1378
+ processingEye: { enabled: processingEye.enabled },
1298
1379
  persistedRevision: applyState?.persistedRevision ?? "unknown", agents,
1299
1380
  };
1300
1381
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "larkin",
3
- "version": "0.5.17",
3
+ "version": "0.5.18",
4
4
  "private": false,
5
5
  "larkinPackageRole": "npm-published",
6
6
  "files": [