larkin 0.4.28 → 0.4.29

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.
@@ -14,6 +14,7 @@ const inbox_projection_js_1 = require("../agent/inbox-projection.cjs");
14
14
  const api_1 = require("@opentelemetry/api");
15
15
  const provider_error_classifier_js_1 = require("./provider-error-classifier.cjs");
16
16
  const runtime_readiness_js_1 = require("./runtime-readiness.cjs");
17
+ const pi_official_auth_js_1 = require("./pi-official-auth.cjs");
17
18
  const official_lark_cli_js_1 = require("../app/official-lark-cli.cjs");
18
19
  const agent_lark_cli_workspace_js_1 = require("../app/agent-lark-cli-workspace.cjs");
19
20
  const pi_compaction_recovery_js_1 = require("./pi-compaction-recovery.cjs");
@@ -102,6 +103,121 @@ function persistPreviousSession(agent, previous) {
102
103
  // In-memory ref still holds for this process; restart will miss it only if this write failed.
103
104
  }
104
105
  }
106
+ function isBuiltinPiAgent(agent) {
107
+ return agent.adapter.id === "pi"
108
+ && ((0, runtime_readiness_js_1.isBuiltinPiDistribution)(agent.config.piDistribution) || agent.config.runtime === "builtin-pi");
109
+ }
110
+ function authFailureScopeOf(agent) {
111
+ return {
112
+ runtime: agent.config.runtime,
113
+ model: agent.config.model,
114
+ piDistribution: agent.config.piDistribution,
115
+ adapterId: agent.adapter.id,
116
+ };
117
+ }
118
+ function currentAuthFailure(agent) {
119
+ if (!agent.authFailureActive)
120
+ return null;
121
+ const kind = agent.authFailureKind
122
+ ?? (agent.authFailureProvider ? "missing-provider" : "generic");
123
+ if (kind === "missing-provider") {
124
+ if (!agent.authFailureProvider)
125
+ return null;
126
+ return { kind: "missing-provider", runtime: "pi", piDistribution: "builtin", provider: agent.authFailureProvider };
127
+ }
128
+ const runtime = agent.adapter.id === "codex" || agent.adapter.id === "claude" || agent.adapter.id === "pi"
129
+ ? agent.adapter.id : null;
130
+ if (!runtime)
131
+ return null;
132
+ return {
133
+ kind: "generic",
134
+ runtime,
135
+ ...(runtime === "pi" && (agent.config.piDistribution === "builtin" || agent.config.piDistribution === "external")
136
+ ? { piDistribution: agent.config.piDistribution } : {}),
137
+ provider: agent.authFailureProvider,
138
+ };
139
+ }
140
+ function genericAuthProvider(agent, upstream) {
141
+ return (0, runtime_readiness_js_1.safeProviderId)(upstream?.provider) ?? (0, runtime_readiness_js_1.configuredProviderId)(agent.config.model);
142
+ }
143
+ function persistAuthFailure(agent) {
144
+ const store = agent.stateStore;
145
+ if (!store)
146
+ return;
147
+ try {
148
+ const write = () => {
149
+ const current = store.readJson("agentState", { sessions: {} });
150
+ if (Array.isArray(current.records) && !("sessions" in current))
151
+ return;
152
+ const { authFailureProvider: _legacy, authFailure: _scoped, ...rest } = current;
153
+ const failure = currentAuthFailure(agent);
154
+ if (!failure) {
155
+ if (!("authFailureProvider" in current) && !("authFailure" in current))
156
+ return;
157
+ store.writeJson("agentState", rest);
158
+ return;
159
+ }
160
+ store.writeJson("agentState", {
161
+ ...rest,
162
+ authFailure: failure,
163
+ ...(failure.kind === "missing-provider" && failure.provider
164
+ ? { authFailureProvider: failure.provider } : {}),
165
+ });
166
+ };
167
+ if (store.withInboxTransaction)
168
+ store.withInboxTransaction(write);
169
+ else
170
+ write();
171
+ }
172
+ catch {
173
+ // In-memory flags and the delivery ledger still hold for this process.
174
+ }
175
+ }
176
+ function loadPersistedAuthFailure(store) {
177
+ if (!store)
178
+ return null;
179
+ try {
180
+ return (0, runtime_readiness_js_1.parsePersistedAuthFailure)(store.readJson("agentState", {}));
181
+ }
182
+ catch {
183
+ return null;
184
+ }
185
+ }
186
+ function applyAuthFailure(agent, failure) {
187
+ agent.authFailureActive = true;
188
+ agent.authFailureKind = failure.kind;
189
+ agent.authFailureProvider = failure.provider ?? null;
190
+ agent.readiness = (0, runtime_readiness_js_1.readinessForPersistedAuthFailure)(failure);
191
+ }
192
+ function clearAuthFailure(agent, persist = true) {
193
+ agent.authFailureActive = false;
194
+ agent.authFailureKind = null;
195
+ agent.authFailureProvider = null;
196
+ if (persist)
197
+ persistAuthFailure(agent);
198
+ }
199
+ function restoreAuthFailure(agent) {
200
+ const persisted = loadPersistedAuthFailure(agent.stateStore);
201
+ if (!persisted)
202
+ return;
203
+ // 只恢复仍绑定当前 candidate 的当前作用域 auth;不从历史 delivery 回灌。
204
+ if (!(0, runtime_readiness_js_1.authFailureAppliesTo)(authFailureScopeOf(agent), persisted)) {
205
+ clearAuthFailure(agent);
206
+ return;
207
+ }
208
+ applyAuthFailure(agent, persisted);
209
+ }
210
+ function clearLedgerAuthProviders(agent) {
211
+ let changed = false;
212
+ for (const record of agent.records.values()) {
213
+ if (!record.authProvider)
214
+ continue;
215
+ delete record.authProvider;
216
+ changed = true;
217
+ }
218
+ if (changed)
219
+ persist(agent);
220
+ }
105
221
  const REPLAY_FAILURE_CODES = new Set([
106
222
  "canonical_inbox_row_missing", "canonical_inbox_malformed", "duplicate_message_id",
107
223
  "inbox_state_conflict", "delivery_target_conflict", "structured_target_invalid",
@@ -490,6 +606,34 @@ function createRuntimeHost(options) {
490
606
  messageId: record.messageId, status: "consumed" });
491
607
  }
492
608
  };
609
+ const ownedConfigDir = () => {
610
+ const value = process.env.LARKIN_CONFIG_DIR?.trim();
611
+ return value || null;
612
+ };
613
+ const projectAuthFailure = (agent, readiness, failure) => {
614
+ agent.authFailureActive = true;
615
+ agent.authFailureKind = failure.kind;
616
+ agent.authFailureProvider = failure.provider;
617
+ agent.readiness = {
618
+ ...readiness,
619
+ ...(agent.readiness?.executable ? { executable: agent.readiness.executable } : {}),
620
+ ...(agent.readiness?.version ? { version: agent.readiness.version } : {}),
621
+ };
622
+ persistAuthFailure(agent);
623
+ emit({ type: "agent-status", agentId: agent.config.agentId, status: "error",
624
+ error: `${agent.readiness.reason} ${agent.readiness.nextAction}`, readiness: agent.readiness });
625
+ };
626
+ const namedAuthProviderPresent = (agent) => {
627
+ if (agent.authFailureKind !== "missing-provider" || !agent.authFailureProvider)
628
+ return true;
629
+ const failure = currentAuthFailure(agent);
630
+ if (!failure || !(0, runtime_readiness_js_1.authFailureAppliesTo)(authFailureScopeOf(agent), failure))
631
+ return false;
632
+ const configDir = ownedConfigDir();
633
+ if (!configDir)
634
+ return false;
635
+ return (0, pi_official_auth_js_1.officialPiHasStoredProvider)(configDir, agent.config.agentId, agent.authFailureProvider);
636
+ };
493
637
  const resultFor = (agent, record, result) => {
494
638
  if (result.status === "accepted") {
495
639
  if (record.errorCategory !== "context_window") {
@@ -503,6 +647,28 @@ function createRuntimeHost(options) {
503
647
  deliveryId: record.deliveryId, messageId: record.messageId, status: "accepted" });
504
648
  return { status: "accepted", deliveryId: record.deliveryId };
505
649
  }
650
+ const missing = result.status === "rejected" && isBuiltinPiAgent(agent)
651
+ ? (0, runtime_readiness_js_1.classifyPiMissingCredentialRejection)(result.reason)
652
+ : null;
653
+ if (missing) {
654
+ const readiness = (0, runtime_readiness_js_1.missingProviderCredentialReadiness)(agent.adapter.id, missing.provider);
655
+ const reason = readiness.reason ?? `Provider ${missing.provider} is missing from this Agent's official credential store.`;
656
+ if (record.status !== "error") {
657
+ record.reason = reason;
658
+ record.retryable = false;
659
+ record.errorCategory = "auth";
660
+ record.authProvider = missing.provider;
661
+ const finalRecord = setRecord(agent, record, "error");
662
+ if (finalRecord.status !== "consumed")
663
+ emit({ type: "delivery", agentId: agent.config.agentId,
664
+ deliveryId: record.deliveryId, messageId: record.messageId, status: "error", reason });
665
+ projectAuthFailure(agent, readiness, { kind: "missing-provider", provider: missing.provider });
666
+ }
667
+ return { status: "error", deliveryId: record.deliveryId, reason: record.reason ?? reason, retryable: false };
668
+ }
669
+ if (record.status === "error") {
670
+ return { status: "error", deliveryId: record.deliveryId, reason: record.reason ?? result.reason, retryable: false };
671
+ }
506
672
  if (record.errorCategory !== "context_window")
507
673
  delete record.errorCategory;
508
674
  const retryable = result.status === "deferred" || result.retryable;
@@ -1347,7 +1513,7 @@ function createRuntimeHost(options) {
1347
1513
  agent.compactionMachines.delete(inputId);
1348
1514
  }
1349
1515
  const recoveredAuthentication = agent.authFailureActive && agent.turnInProgress
1350
- && agent.turnHadAuthenticatedOutput && !agent.turnHadFailure;
1516
+ && agent.turnHadAuthenticatedOutput && !agent.turnHadFailure && namedAuthProviderPresent(agent);
1351
1517
  agent.turnInProgress = false;
1352
1518
  agent.busy = false;
1353
1519
  emit({ type: "activity", agentId: agent.config.agentId, activity: "idle", activityKind: "idle", detailKind: "turn_ended" });
@@ -1369,7 +1535,8 @@ function createRuntimeHost(options) {
1369
1535
  reconcileSubagentLedger(agent);
1370
1536
  telemetry?.runtimeEvent(agent.config.agentId, event);
1371
1537
  if (recoveredAuthentication) {
1372
- agent.authFailureActive = false;
1538
+ clearAuthFailure(agent);
1539
+ clearLedgerAuthProviders(agent);
1373
1540
  const prior = agent.readiness;
1374
1541
  agent.readiness = {
1375
1542
  runtime: agent.adapter.id,
@@ -1462,21 +1629,24 @@ function createRuntimeHost(options) {
1462
1629
  record.errorCategory = classifiedCategory;
1463
1630
  else
1464
1631
  delete record.errorCategory;
1632
+ const missing = event.errorCategory === "auth" && !event.retryable && isBuiltinPiAgent(agent)
1633
+ ? (0, runtime_readiness_js_1.classifyPiMissingCredentialRejection)(event.upstream?.message)
1634
+ ?? (0, runtime_readiness_js_1.classifyPiMissingCredentialRejection)(event.message)
1635
+ : null;
1636
+ if (missing)
1637
+ record.authProvider = missing.provider;
1465
1638
  const finalRecord = setRecord(agent, record, event.retryable ? "pending" : "error");
1466
1639
  if (finalRecord.status !== "consumed")
1467
1640
  emit({ type: "delivery", agentId: agent.config.agentId,
1468
1641
  deliveryId: record.deliveryId, messageId: record.messageId,
1469
1642
  status: event.retryable ? "deferred" : "error", reason: event.message });
1470
1643
  if (event.errorCategory === "auth" && !event.retryable) {
1471
- const readiness = (0, runtime_readiness_js_1.providerAuthenticationFailureReadiness)(agent.adapter.id, event.upstream?.provider);
1472
- agent.authFailureActive = true;
1473
- agent.readiness = {
1474
- ...readiness,
1475
- ...(agent.readiness?.executable ? { executable: agent.readiness.executable } : {}),
1476
- ...(agent.readiness?.version ? { version: agent.readiness.version } : {}),
1477
- };
1478
- emit({ type: "agent-status", agentId: agent.config.agentId, status: "error",
1479
- error: `${agent.readiness.reason} ${agent.readiness.nextAction}`, readiness: agent.readiness });
1644
+ const readiness = missing
1645
+ ? (0, runtime_readiness_js_1.missingProviderCredentialReadiness)(agent.adapter.id, missing.provider)
1646
+ : (0, runtime_readiness_js_1.providerAuthenticationFailureReadiness)(agent.adapter.id, event.upstream?.provider);
1647
+ projectAuthFailure(agent, readiness, missing
1648
+ ? { kind: "missing-provider", provider: missing.provider }
1649
+ : { kind: "generic", provider: genericAuthProvider(agent, event.upstream) });
1480
1650
  }
1481
1651
  if (event.retryable && !agent.busy && !agent.turnInProgress)
1482
1652
  void retryPending(agent);
@@ -1748,14 +1918,27 @@ function createRuntimeHost(options) {
1748
1918
  clearTimeout(previous.backgroundCompletionRetryTimer);
1749
1919
  if (previous.subagentReconcileTimer)
1750
1920
  clearInterval(previous.subagentReconcileTimer);
1921
+ const previousFailure = currentAuthFailure(previous);
1922
+ const scoped = Boolean(previousFailure
1923
+ && (0, runtime_readiness_js_1.authFailureAppliesTo)({
1924
+ runtime: config.runtime,
1925
+ model: config.model,
1926
+ piDistribution: config.piDistribution,
1927
+ adapterId: adapter.id,
1928
+ }, previousFailure));
1751
1929
  const candidate = {
1752
1930
  ...previous, config, adapter, session, launchId: node_crypto_1.default.randomUUID(), busy: false, submitting: false,
1753
1931
  starting: null, retryAfterSubmit: false, generation: 0, poller: null, retryTimer: null,
1754
1932
  recreateAttempts: 0, stabilityTimer: null, recreateReason: null, stopped: false,
1755
1933
  backgroundCompletionRetryTimer: null, subagentReconcileTimer: null,
1756
1934
  disabledReason: null, configurationRecovery: null,
1757
- readiness: previous.authFailureActive ? previous.readiness : readiness,
1935
+ authFailureActive: scoped && previous.authFailureActive,
1936
+ authFailureKind: scoped ? previous.authFailureKind : null,
1937
+ authFailureProvider: scoped ? previous.authFailureProvider : null,
1938
+ readiness: scoped && previous.authFailureActive ? previous.readiness : readiness,
1758
1939
  };
1940
+ if (previous.authFailureActive && !candidate.authFailureActive)
1941
+ clearAuthFailure(candidate);
1759
1942
  managed.set(config.agentId, candidate);
1760
1943
  session.subscribe((event) => observe(candidate, session, event));
1761
1944
  if (session.sessionId) {
@@ -1850,7 +2033,8 @@ function createRuntimeHost(options) {
1850
2033
  agent.config.sessionId = null;
1851
2034
  agent.session = fresh;
1852
2035
  persistPreviousSession(agent, previousRef);
1853
- agent.readiness = readiness;
2036
+ if (!agent.authFailureActive)
2037
+ agent.readiness = readiness;
1854
2038
  agent.disabledReason = null;
1855
2039
  };
1856
2040
  try {
@@ -1871,7 +2055,13 @@ function createRuntimeHost(options) {
1871
2055
  ...(fresh.effectiveReasoningEffort ? { reasoningEffort: fresh.effectiveReasoningEffort } : {}),
1872
2056
  ...(agent.previousSession ? { previousSession: agent.previousSession } : {}) });
1873
2057
  }
1874
- emit({ type: "agent-status", agentId, status: "active", readiness });
2058
+ emit({
2059
+ type: "agent-status",
2060
+ agentId,
2061
+ status: agent.authFailureActive ? "error" : "active",
2062
+ ...(agent.authFailureActive ? { error: `${agent.readiness?.reason} ${agent.readiness?.nextAction}` } : {}),
2063
+ readiness: agent.authFailureActive ? agent.readiness ?? readiness : readiness,
2064
+ });
1875
2065
  agent.piSessionOwner = probeEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
1876
2066
  await oldSession.close("fresh session reset committed")
1877
2067
  .catch((error) => log("previous runtime close after fresh reset failed", String(error)));
@@ -2009,7 +2199,8 @@ function createRuntimeHost(options) {
2009
2199
  agent.config.sessionId = null;
2010
2200
  agent.session = fresh;
2011
2201
  persistPreviousSession(agent, previousRef);
2012
- agent.readiness = readiness;
2202
+ if (!agent.authFailureActive)
2203
+ agent.readiness = readiness;
2013
2204
  agent.disabledReason = null;
2014
2205
  for (const record of agent.records.values()) {
2015
2206
  if (!messageIds.includes(record.messageId))
@@ -2027,7 +2218,13 @@ function createRuntimeHost(options) {
2027
2218
  ...(fresh.effectiveReasoningEffort ? { reasoningEffort: fresh.effectiveReasoningEffort } : {}),
2028
2219
  ...(agent.previousSession ? { previousSession: agent.previousSession } : {}) });
2029
2220
  }
2030
- emit({ type: "agent-status", agentId, status: "active", readiness });
2221
+ emit({
2222
+ type: "agent-status",
2223
+ agentId,
2224
+ status: agent.authFailureActive ? "error" : "active",
2225
+ ...(agent.authFailureActive ? { error: `${agent.readiness?.reason} ${agent.readiness?.nextAction}` } : {}),
2226
+ readiness: agent.authFailureActive ? agent.readiness ?? readiness : readiness,
2227
+ });
2031
2228
  durableRollback = null;
2032
2229
  agent.piSessionOwner = probeEnv[pi_subagent_ledger_js_1.PI_SUBAGENT_SESSION_OWNER_ENV];
2033
2230
  await oldSession.close("context-window recovery committed")
@@ -2117,11 +2314,13 @@ function createRuntimeHost(options) {
2117
2314
  piProactiveCompactionFailedGeneration: null,
2118
2315
  previousSession: loadPersistedPreviousSession(config, stateStore), readiness: null,
2119
2316
  turnInProgress: false, turnHadFailure: false, turnHadAuthenticatedOutput: false, authFailureActive: false,
2317
+ authFailureKind: null, authFailureProvider: null,
2120
2318
  promotedInboxUpdateIds: new Set(),
2121
2319
  backgroundCompletionQueue: [], backgroundCompletionKeys: new Set(),
2122
2320
  backgroundCompletionInFlight: null, backgroundCompletionWakeInputId: null,
2123
2321
  backgroundCompletionRejectStreak: 0, backgroundCompletionRetryTimer: null,
2124
2322
  subagentLedger: loadSubagentLedger(config), subagentReconcileTimer: null };
2323
+ restoreAuthFailure(agent);
2125
2324
  const startupConsumed = [];
2126
2325
  const startupQuarantined = [];
2127
2326
  for (const record of agent.records.values()) {