@letta-ai/letta-code 0.27.5 → 0.27.6

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.
package/letta.js CHANGED
@@ -5077,7 +5077,7 @@ var package_default;
5077
5077
  var init_package = __esm(() => {
5078
5078
  package_default = {
5079
5079
  name: "@letta-ai/letta-code",
5080
- version: "0.27.5",
5080
+ version: "0.27.6",
5081
5081
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5082
5082
  type: "module",
5083
5083
  packageManager: "bun@1.3.0",
@@ -5272,6 +5272,7 @@ var init_request = __esm(() => {
5272
5272
  var exports_conversations = {};
5273
5273
  __export(exports_conversations, {
5274
5274
  updateConversationDescription: () => updateConversationDescription,
5275
+ summarizeConversation: () => summarizeConversation,
5275
5276
  forkConversation: () => forkConversation
5276
5277
  });
5277
5278
  async function forkConversation(conversationId, options = {}) {
@@ -5284,12 +5285,15 @@ async function forkConversation(conversationId, options = {}) {
5284
5285
  async function updateConversationDescription(conversationId, body) {
5285
5286
  return apiRequest("PATCH", `/v1/conversations/${encodeURIComponent(conversationId)}`, body);
5286
5287
  }
5288
+ async function summarizeConversation(conversationId, body, options = {}) {
5289
+ return apiRequest("POST", `/v1/conversations/${encodeURIComponent(conversationId)}/summarize`, body, options);
5290
+ }
5287
5291
  var init_conversations2 = __esm(() => {
5288
5292
  init_request();
5289
5293
  });
5290
5294
 
5291
5295
  // src/constants.ts
5292
- var DEFAULT_SUMMARIZATION_MODEL = "letta/auto", DEFAULT_AGENT_NAME = "Letta Code", INTERRUPTED_BY_USER = "Interrupted by user", TURN_DID_NOT_COMPLETE = "Turn did not complete", SYSTEM_REMINDER_TAG = "system-reminder", SYSTEM_REMINDER_OPEN, SYSTEM_REMINDER_CLOSE, SYSTEM_ALERT_TAG = "system-alert", SYSTEM_ALERT_OPEN, SYSTEM_ALERT_CLOSE, COMPACTION_SUMMARY_HEADER = "(Earlier messages in this conversation have been compacted to free up context, summarized below)", TOKEN_DISPLAY_THRESHOLD = 100, ELAPSED_DISPLAY_THRESHOLD_MS;
5296
+ var DEFAULT_SUMMARIZATION_MODEL = "letta/auto", DEFAULT_TITLE_SUMMARIZATION_MODEL = "letta/auto-fast", DEFAULT_AGENT_NAME = "Letta Code", INTERRUPTED_BY_USER = "Interrupted by user", TURN_DID_NOT_COMPLETE = "Turn did not complete", SYSTEM_REMINDER_TAG = "system-reminder", SYSTEM_REMINDER_OPEN, SYSTEM_REMINDER_CLOSE, SYSTEM_ALERT_TAG = "system-alert", SYSTEM_ALERT_OPEN, SYSTEM_ALERT_CLOSE, COMPACTION_SUMMARY_HEADER = "(Earlier messages in this conversation have been compacted to free up context, summarized below)", TOKEN_DISPLAY_THRESHOLD = 100, ELAPSED_DISPLAY_THRESHOLD_MS;
5293
5297
  var init_constants = __esm(() => {
5294
5298
  SYSTEM_REMINDER_OPEN = `<${SYSTEM_REMINDER_TAG}>`;
5295
5299
  SYSTEM_REMINDER_CLOSE = `</${SYSTEM_REMINDER_TAG}>`;
@@ -5322,63 +5326,28 @@ function normalizeConversationTitle(value) {
5322
5326
  }
5323
5327
  return normalized.slice(0, CONVERSATION_TITLE_MAX_LENGTH);
5324
5328
  }
5325
- function extractAssistantText(content) {
5326
- if (typeof content === "string") {
5327
- return content;
5328
- }
5329
- if (Array.isArray(content)) {
5330
- let collected = "";
5331
- for (const part of content) {
5332
- if (part && typeof part === "object" && "text" in part && typeof part.text === "string") {
5333
- collected += part.text;
5334
- }
5335
- }
5336
- return collected;
5329
+ async function generateConversationTitleFromSummary(conversationId, messages, model = DEFAULT_TITLE_SUMMARIZATION_MODEL) {
5330
+ if (messages.length === 0) {
5331
+ return null;
5337
5332
  }
5338
- return "";
5339
- }
5340
- async function generateConversationTitleFromFork(client, conversationId) {
5341
- let forkId = null;
5342
5333
  const abortController = new AbortController;
5343
5334
  const timeoutId = setTimeout(() => abortController.abort(), CONVERSATION_TITLE_TIMEOUT_MS);
5344
5335
  try {
5345
- const fork = await forkConversation(conversationId, { hidden: true });
5346
- forkId = fork.id;
5347
- const stream = await client.conversations.messages.create(forkId, {
5348
- messages: [
5349
- {
5350
- role: "user",
5351
- content: CONVERSATION_TITLE_USER_PROMPT
5352
- }
5353
- ],
5354
- override_model: DEFAULT_SUMMARIZATION_MODEL,
5355
- override_system: CONVERSATION_TITLE_SYSTEM_PROMPT,
5356
- max_steps: 1,
5357
- streaming: true,
5358
- stream_tokens: false,
5359
- include_pings: false
5360
- }, { signal: abortController.signal });
5361
- let titleText = "";
5362
- for await (const chunk of stream) {
5363
- if (chunk && typeof chunk === "object" && "message_type" in chunk && chunk.message_type === "assistant_message") {
5364
- titleText += extractAssistantText(chunk.content);
5365
- }
5366
- }
5367
- return normalizeConversationTitle(titleText);
5336
+ const response = await summarizeConversation(conversationId, {
5337
+ prompt: CONVERSATION_TITLE_SYSTEM_PROMPT,
5338
+ messages,
5339
+ model
5340
+ }, {
5341
+ signal: abortController.signal
5342
+ });
5343
+ return normalizeConversationTitle(response.summary);
5368
5344
  } catch (err) {
5369
5345
  if (isDebugEnabled()) {
5370
- console.error("[DEBUG] generateConversationTitleFromFork failed:", err);
5346
+ console.error("[DEBUG] generateConversationTitleFromSummary failed:", err);
5371
5347
  }
5372
5348
  return null;
5373
5349
  } finally {
5374
5350
  clearTimeout(timeoutId);
5375
- if (forkId) {
5376
- client.conversations.delete(forkId).catch((err) => {
5377
- if (isDebugEnabled()) {
5378
- console.error("[DEBUG] failed to delete title-fork conversation:", err);
5379
- }
5380
- });
5381
- }
5382
5351
  }
5383
5352
  }
5384
5353
  var CONVERSATION_TITLE_MAX_LENGTH = 100, CONVERSATION_TITLE_TIMEOUT_MS = 30000, CONVERSATION_TITLE_SYSTEM_PROMPT = `You are a conversation title generator.
@@ -5389,7 +5358,7 @@ Rules:
5389
5358
  - describe the actual topic, not the mood
5390
5359
  - no quotes, markdown, prefixes, or trailing punctuation
5391
5360
  - never call any tools — reply with plain text only
5392
- - avoid generic titles like "New conversation" or "Help request"`, CONVERSATION_TITLE_USER_PROMPT = "Based on the conversation above, output a short title (2-7 words) describing the topic. Reply with ONLY the title text — no quotes, no tools, no preamble.";
5361
+ - avoid generic titles like "New conversation" or "Help request"`;
5393
5362
  var init_conversation_title = __esm(() => {
5394
5363
  init_conversations2();
5395
5364
  init_constants();
@@ -161725,6 +161694,104 @@ function disableExtensionsForProcess() {
161725
161694
  }
161726
161695
  var LETTA_DISABLE_EXTENSIONS_ENV = "LETTA_DISABLE_EXTENSIONS";
161727
161696
 
161697
+ // src/extensions/permission-registry.ts
161698
+ function getMutableExtensionPermissionsRegistry() {
161699
+ const global2 = globalThis;
161700
+ if (!global2[EXTENSION_PERMISSIONS_KEY]) {
161701
+ global2[EXTENSION_PERMISSIONS_KEY] = new Map;
161702
+ }
161703
+ return global2[EXTENSION_PERMISSIONS_KEY];
161704
+ }
161705
+ function getAvailableExtensionPermissionsRegistry() {
161706
+ if (areExtensionsDisabled())
161707
+ return new Map;
161708
+ return new Map(Array.from(getMutableExtensionPermissionsRegistry().entries()).filter(([, permission]) => {
161709
+ if (permission.activationSignal.aborted)
161710
+ return false;
161711
+ try {
161712
+ return permission.isAvailable();
161713
+ } catch {
161714
+ return false;
161715
+ }
161716
+ }));
161717
+ }
161718
+ function registerExtensionPermission(permission) {
161719
+ if (areExtensionsDisabled())
161720
+ return;
161721
+ getMutableExtensionPermissionsRegistry().set(permission.id, permission);
161722
+ }
161723
+ function unregisterExtensionPermission(id2, owner) {
161724
+ const registry2 = getMutableExtensionPermissionsRegistry();
161725
+ const existing = registry2.get(id2);
161726
+ if (existing?.owner?.id === owner.id) {
161727
+ registry2.delete(id2);
161728
+ }
161729
+ }
161730
+ function unregisterExtensionPermissionsForOwner(owner) {
161731
+ const registry2 = getMutableExtensionPermissionsRegistry();
161732
+ for (const [id2, permission] of registry2.entries()) {
161733
+ if (permission.owner?.id === owner.id) {
161734
+ registry2.delete(id2);
161735
+ }
161736
+ }
161737
+ }
161738
+ function clearExtensionPermissions() {
161739
+ getMutableExtensionPermissionsRegistry().clear();
161740
+ }
161741
+ function getExtensionPermissionDefinition(id2, registry2 = getMutableExtensionPermissionsRegistry()) {
161742
+ if (areExtensionsDisabled())
161743
+ return;
161744
+ return registry2.get(id2);
161745
+ }
161746
+ function normalizePermissionResult(result) {
161747
+ if (result === undefined)
161748
+ return;
161749
+ if (result.decision === "allow" || result.decision === "ask" || result.decision === "deny") {
161750
+ return result;
161751
+ }
161752
+ return;
161753
+ }
161754
+ function composePermissionDecision(decisions) {
161755
+ return decisions.find((result) => result.decision === "deny") ?? decisions.find((result) => result.decision === "ask") ?? decisions.find((result) => result.decision === "allow");
161756
+ }
161757
+ async function checkExtensionPermissions(event2, registry2 = getAvailableExtensionPermissionsRegistry()) {
161758
+ if (areExtensionsDisabled())
161759
+ return;
161760
+ const decisions = [];
161761
+ for (const permission of registry2.values()) {
161762
+ if (permission.activationSignal.aborted)
161763
+ continue;
161764
+ let rawResult;
161765
+ try {
161766
+ if (!permission.isAvailable())
161767
+ continue;
161768
+ rawResult = await permission.check(event2, {
161769
+ getContext: permission.getContext,
161770
+ signal: permission.activationSignal
161771
+ });
161772
+ } catch (error54) {
161773
+ return {
161774
+ decision: "deny",
161775
+ matchedRule: `extension permission:${permission.id}`,
161776
+ reason: `Extension permission '${permission.id}' failed: ${error54 instanceof Error ? error54.message : String(error54)}`
161777
+ };
161778
+ }
161779
+ const result = normalizePermissionResult(rawResult);
161780
+ if (!result)
161781
+ continue;
161782
+ decisions.push({
161783
+ decision: result.decision,
161784
+ matchedRule: `extension permission:${permission.id}`,
161785
+ reason: result.reason
161786
+ });
161787
+ }
161788
+ return composePermissionDecision(decisions);
161789
+ }
161790
+ var EXTENSION_PERMISSIONS_KEY;
161791
+ var init_permission_registry = __esm(() => {
161792
+ EXTENSION_PERMISSIONS_KEY = Symbol.for("@letta/extensionPermissions");
161793
+ });
161794
+
161728
161795
  // src/extensions/tool-registry.ts
161729
161796
  function getMutableExtensionToolsRegistry() {
161730
161797
  const global2 = globalThis;
@@ -193099,8 +193166,28 @@ function getDefaultDecision(toolName, toolArgs) {
193099
193166
  }
193100
193167
  return "ask";
193101
193168
  }
193102
- async function checkPermissionWithHooks(toolName, toolArgs, permissions, workingDirectory = process.cwd(), modeState, agentId) {
193103
- const result = checkPermission(toolName, toolArgs, permissions, workingDirectory, modeState, agentId);
193169
+ async function checkPermissionWithHooks(toolName, toolArgs, permissions, workingDirectory = process.cwd(), modeState, agentId, extensionPermissions = getAvailableExtensionPermissionsRegistry(), extensionPermissionOptions = {}) {
193170
+ let result = checkPermission(toolName, toolArgs, permissions, workingDirectory, modeState, agentId);
193171
+ if (result.decision !== "deny") {
193172
+ const extensionDecision = await checkExtensionPermissions({
193173
+ agentId: agentId ?? null,
193174
+ conversationId: extensionPermissionOptions.conversationId ?? null,
193175
+ toolCallId: extensionPermissionOptions.toolCallId ?? null,
193176
+ toolName,
193177
+ args: toolArgs,
193178
+ cwd: workingDirectory,
193179
+ workingDirectory,
193180
+ permissionMode: modeState?.mode ?? permissionMode.getMode(),
193181
+ phase: extensionPermissionOptions.phase ?? "approval"
193182
+ }, extensionPermissions);
193183
+ if (extensionDecision) {
193184
+ result = {
193185
+ decision: extensionDecision.decision,
193186
+ matchedRule: extensionDecision.matchedRule,
193187
+ reason: extensionDecision.reason ?? `Matched ${extensionDecision.matchedRule}`
193188
+ };
193189
+ }
193190
+ }
193104
193191
  if (result.decision === "ask") {
193105
193192
  const hookResult = await runPermissionRequestHooks(toolName, toolArgs, "ask", undefined, workingDirectory, agentId);
193106
193193
  if (hookResult.blocked) {
@@ -193126,6 +193213,7 @@ async function checkPermissionWithHooks(toolName, toolArgs, permissions, working
193126
193213
  var WORKING_DIRECTORY_TOOLS_V2, WORKING_DIRECTORY_TOOLS_V1, READ_ONLY_SHELL_TOOLS, FILE_TOOLS_V2, FILE_TOOLS_V1, SAFE_AUTO_APPROVE_SUBAGENT_TYPES;
193127
193214
  var init_checker = __esm(() => {
193128
193215
  init_context();
193216
+ init_permission_registry();
193129
193217
  init_tool_registry();
193130
193218
  init_hooks2();
193131
193219
  init_canonical();
@@ -195235,6 +195323,7 @@ function capturePreparedToolExecutionContext(snapshot, options3) {
195235
195323
  externalTools: filterExternalToolsByClientAllowlist(snapshot.externalTools, options3?.clientToolAllowlist),
195236
195324
  externalExecutor: snapshot.externalExecutor,
195237
195325
  extensionEvents: options3?.extensionEvents ?? snapshot.extensionEvents,
195326
+ extensionPermissions: snapshot.extensionPermissions,
195238
195327
  extensionTools: filterExtensionToolsByClientAllowlist(snapshot.extensionTools, options3?.clientToolAllowlist),
195239
195328
  workingDirectory: runtimeContext.workingDirectory ?? getCurrentWorkingDirectory(),
195240
195329
  runtimeContext,
@@ -195253,6 +195342,7 @@ function captureToolExecutionContext(workingDirectory = getCurrentWorkingDirecto
195253
195342
  toolRegistry: new Map(toolRegistry),
195254
195343
  externalTools: new Map(getExternalToolsRegistry()),
195255
195344
  externalExecutor: getExternalToolExecutor(),
195345
+ extensionPermissions: getAvailableExtensionPermissionsRegistry(),
195256
195346
  extensionTools: getAvailableExtensionToolsRegistry()
195257
195347
  }, {
195258
195348
  workingDirectory,
@@ -195268,6 +195358,7 @@ async function prepareCurrentToolExecutionContext(options3) {
195268
195358
  externalTools: new Map(getExternalToolsRegistry()),
195269
195359
  externalExecutor: getExternalToolExecutor(),
195270
195360
  extensionEvents: options3?.extensionEvents,
195361
+ extensionPermissions: getAvailableExtensionPermissionsRegistry(),
195271
195362
  extensionTools: getAvailableExtensionToolsRegistry()
195272
195363
  }, options3);
195273
195364
  }
@@ -195278,6 +195369,7 @@ async function prepareToolExecutionContextForSpecificTools(toolNames, options3)
195278
195369
  externalTools: new Map(getExternalToolsRegistry()),
195279
195370
  externalExecutor: getExternalToolExecutor(),
195280
195371
  extensionEvents: options3?.extensionEvents,
195372
+ extensionPermissions: getAvailableExtensionPermissionsRegistry(),
195281
195373
  extensionTools: getAvailableExtensionToolsRegistry()
195282
195374
  }, options3);
195283
195375
  }
@@ -195288,6 +195380,7 @@ async function prepareToolExecutionContextForModel(modelIdentifier, options3) {
195288
195380
  externalTools: new Map(getExternalToolsRegistry()),
195289
195381
  externalExecutor: getExternalToolExecutor(),
195290
195382
  extensionEvents: options3?.extensionEvents,
195383
+ extensionPermissions: getAvailableExtensionPermissionsRegistry(),
195291
195384
  extensionTools: getAvailableExtensionToolsRegistry()
195292
195385
  }, options3);
195293
195386
  }
@@ -195302,15 +195395,38 @@ function isExtensionToolParallelSafeForContext(toolName, contextId) {
195302
195395
  const context2 = contextId ? getExecutionContextById(contextId) : undefined;
195303
195396
  return isExtensionToolParallelSafe(toolName, context2?.extensionTools ?? getAvailableExtensionToolsRegistry());
195304
195397
  }
195305
- async function checkToolPermission(toolName, toolArgs, workingDirectory = process.cwd(), permissionModeStateArg, agentIdArg) {
195398
+ async function checkExtensionPermissionForContext(options3) {
195399
+ const runtimeContext = options3.context?.runtimeContext;
195400
+ const permissionModeState = options3.context?.permissionModeState;
195401
+ return checkExtensionPermissions({
195402
+ agentId: runtimeContext?.agentId ?? null,
195403
+ conversationId: runtimeContext?.conversationId ?? null,
195404
+ toolCallId: options3.toolCallId ?? null,
195405
+ toolName: options3.toolName,
195406
+ args: options3.args,
195407
+ cwd: options3.workingDirectory,
195408
+ workingDirectory: options3.workingDirectory,
195409
+ permissionMode: permissionModeState?.mode ?? runtimeContext?.permissionMode ?? null,
195410
+ phase: options3.phase
195411
+ }, options3.context?.extensionPermissions ?? getAvailableExtensionPermissionsRegistry());
195412
+ }
195413
+ async function checkToolPermission(toolName, toolArgs, workingDirectory, permissionModeStateArg, agentIdArg, toolContextIdArg, toolCallIdArg) {
195306
195414
  const { checkPermissionWithHooks: checkPermissionWithHooks2 } = await Promise.resolve().then(() => (init_checker(), exports_checker));
195307
195415
  const { loadPermissions: loadPermissions2 } = await Promise.resolve().then(() => (init_loader2(), exports_loader));
195308
- const permissions = await loadPermissions2(workingDirectory);
195416
+ const context2 = toolContextIdArg ? getExecutionContextById(toolContextIdArg) : undefined;
195417
+ const effectiveWorkingDirectory = workingDirectory ?? context2?.workingDirectory ?? process.cwd();
195418
+ const effectivePermissionModeState = permissionModeStateArg ?? context2?.permissionModeState;
195419
+ const effectiveAgentId = agentIdArg ?? context2?.runtimeContext.agentId ?? undefined;
195420
+ const permissions = await loadPermissions2(effectiveWorkingDirectory);
195309
195421
  return runWithRuntimeContext({
195310
- ...agentIdArg ? { agentId: agentIdArg } : {},
195311
- workingDirectory,
195312
- permissionMode: permissionModeStateArg?.mode
195313
- }, () => checkPermissionWithHooks2(toolName, toolArgs, permissions, workingDirectory, permissionModeStateArg, agentIdArg));
195422
+ ...effectiveAgentId ? { agentId: effectiveAgentId } : {},
195423
+ workingDirectory: effectiveWorkingDirectory,
195424
+ permissionMode: effectivePermissionModeState?.mode
195425
+ }, () => checkPermissionWithHooks2(toolName, toolArgs, permissions, effectiveWorkingDirectory, effectivePermissionModeState, effectiveAgentId, context2?.extensionPermissions ?? getAvailableExtensionPermissionsRegistry(), {
195426
+ conversationId: context2?.runtimeContext.conversationId ?? null,
195427
+ phase: "approval",
195428
+ toolCallId: toolCallIdArg ?? null
195429
+ }));
195314
195430
  }
195315
195431
  async function savePermissionRule2(rule, ruleType, scope, workingDirectory = process.cwd()) {
195316
195432
  if (scope === "session") {
@@ -195687,9 +195803,12 @@ function cloneToolArgsForExtensionEvent(args) {
195687
195803
  return { ...args };
195688
195804
  }
195689
195805
  }
195690
- function createExtensionDenialToolResult(denial) {
195806
+ function createExtensionPermissionToolResult(decision) {
195807
+ const isApprovalRequest = decision.decision === "ask";
195808
+ const action3 = isApprovalRequest ? "blocked" : "denied";
195809
+ const fallbackReason = isApprovalRequest ? "Approval requested but cannot reopen during execution." : "No reason given.";
195691
195810
  return {
195692
- toolReturn: `Error: Tool execution denied by extension. ${denial.reason ?? "No reason given."}`,
195811
+ toolReturn: `Error: Tool execution ${action3} by ${decision.matchedRule}. ${decision.reason ?? fallbackReason}`,
195693
195812
  status: "error"
195694
195813
  };
195695
195814
  }
@@ -195704,21 +195823,12 @@ async function emitToolStartEvent(options3) {
195704
195823
  toolName: options3.toolName,
195705
195824
  args: cloneToolArgsForExtensionEvent(options3.args)
195706
195825
  };
195707
- let emitResult;
195708
195826
  try {
195709
- emitResult = await emitExtensionEvent(options3.events, "tool_start", event2);
195827
+ await emitExtensionEvent(options3.events, "tool_start", event2);
195710
195828
  } catch (error54) {
195711
195829
  debugLog("extensions", "tool_start event failed", error54);
195712
195830
  return { args: options3.args };
195713
195831
  }
195714
- const firstDenial = emitResult?.results?.find((r2) => typeof r2 === "object" && r2 !== null && r2.deny === true);
195715
- if (firstDenial) {
195716
- debugLog("extensions", `tool_start denied: ${firstDenial.reason ?? "no reason given"}`);
195717
- return {
195718
- args: isToolStartArgs(event2.args) ? event2.args : options3.args,
195719
- denied: { reason: firstDenial.reason }
195720
- };
195721
- }
195722
195832
  return { args: isToolStartArgs(event2.args) ? event2.args : options3.args };
195723
195833
  }
195724
195834
  async function executeExtensionTool(toolName, tool2, args, executionScope, options3) {
@@ -195858,15 +195968,25 @@ async function executeTool(name, args, options3) {
195858
195968
  status: "error"
195859
195969
  };
195860
195970
  }
195861
- const { args: eventArgs2, denied: extDenial2 } = await emitToolStartEvent({
195971
+ const { args: eventArgs2 } = await emitToolStartEvent({
195862
195972
  args,
195863
195973
  events: extensionEvents,
195864
195974
  executionScope,
195865
195975
  toolCallId: options3?.toolCallId,
195866
195976
  toolName: name
195867
195977
  });
195868
- if (extDenial2) {
195869
- return createExtensionDenialToolResult(extDenial2);
195978
+ const permissionDecision2 = await checkExtensionPermissionForContext({
195979
+ args: eventArgs2,
195980
+ context: context2,
195981
+ phase: "execution",
195982
+ toolCallId: options3?.toolCallId,
195983
+ toolName: name,
195984
+ workingDirectory
195985
+ });
195986
+ if (permissionDecision2?.decision !== undefined) {
195987
+ if (permissionDecision2.decision !== "allow") {
195988
+ return createExtensionPermissionToolResult(permissionDecision2);
195989
+ }
195870
195990
  }
195871
195991
  return executeExtensionTool(name, extensionTool, eventArgs2, executionScope, {
195872
195992
  signal: options3?.signal,
@@ -195877,15 +195997,25 @@ async function executeTool(name, args, options3) {
195877
195997
  });
195878
195998
  }
195879
195999
  if (activeExternalTools.has(name)) {
195880
- const { args: eventArgs2, denied: extDenial2 } = await emitToolStartEvent({
196000
+ const { args: eventArgs2 } = await emitToolStartEvent({
195881
196001
  args,
195882
196002
  events: extensionEvents,
195883
196003
  executionScope,
195884
196004
  toolCallId: options3?.toolCallId,
195885
196005
  toolName: name
195886
196006
  });
195887
- if (extDenial2) {
195888
- return createExtensionDenialToolResult(extDenial2);
196007
+ const permissionDecision2 = await checkExtensionPermissionForContext({
196008
+ args: eventArgs2,
196009
+ context: context2,
196010
+ phase: "execution",
196011
+ toolCallId: options3?.toolCallId,
196012
+ toolName: name,
196013
+ workingDirectory
196014
+ });
196015
+ if (permissionDecision2?.decision !== undefined) {
196016
+ if (permissionDecision2.decision !== "allow") {
196017
+ return createExtensionPermissionToolResult(permissionDecision2);
196018
+ }
195889
196019
  }
195890
196020
  return executeExternalTool(options3?.toolCallId ?? `ext-${Date.now()}`, name, eventArgs2, activeExternalExecutor);
195891
196021
  }
@@ -195913,7 +196043,7 @@ async function executeTool(name, args, options3) {
195913
196043
  status: "error"
195914
196044
  };
195915
196045
  }
195916
- const { args: eventArgs, denied: extDenial } = await emitToolStartEvent({
196046
+ const { args: eventArgs } = await emitToolStartEvent({
195917
196047
  args,
195918
196048
  events: extensionEvents,
195919
196049
  executionScope,
@@ -195921,8 +196051,18 @@ async function executeTool(name, args, options3) {
195921
196051
  toolName: internalName
195922
196052
  });
195923
196053
  args = eventArgs;
195924
- if (extDenial) {
195925
- return createExtensionDenialToolResult(extDenial);
196054
+ const permissionDecision = await checkExtensionPermissionForContext({
196055
+ args,
196056
+ context: context2,
196057
+ phase: "execution",
196058
+ toolCallId: options3?.toolCallId,
196059
+ toolName: internalName,
196060
+ workingDirectory
196061
+ });
196062
+ if (permissionDecision?.decision !== undefined) {
196063
+ if (permissionDecision.decision !== "allow") {
196064
+ return createExtensionPermissionToolResult(permissionDecision);
196065
+ }
195926
196066
  }
195927
196067
  const startTime = Date.now();
195928
196068
  const run = async () => {
@@ -196173,6 +196313,7 @@ var init_manager4 = __esm(async () => {
196173
196313
  init_registry();
196174
196314
  init_constants();
196175
196315
  init_conversation_handle();
196316
+ init_permission_registry();
196176
196317
  init_tool_registry();
196177
196318
  init_hooks2();
196178
196319
  init_mode();
@@ -257157,7 +257298,7 @@ async function classifyApprovals(approvals, opts = {}) {
257157
257298
  continue;
257158
257299
  }
257159
257300
  }
257160
- const permission = await checkToolPermission(toolName, parsedArgs, opts.workingDirectory, opts.permissionModeState, opts.agentId);
257301
+ const permission = await checkToolPermission(toolName, parsedArgs, opts.workingDirectory, opts.permissionModeState, opts.agentId, opts.toolContextId, approval.toolCallId);
257161
257302
  const context3 = opts.getContext ? await opts.getContext(toolName, parsedArgs, opts.workingDirectory) : null;
257162
257303
  let decision = permission.decision;
257163
257304
  if (opts.alwaysRequiresUserInput?.(toolName) && decision === "allow") {
@@ -257823,7 +257964,7 @@ function normalizeConversationDescription(value) {
257823
257964
  }
257824
257965
  return trimToWordLimit(normalized, CONVERSATION_DESCRIPTION_MAX_WORDS);
257825
257966
  }
257826
- function extractAssistantText2(content) {
257967
+ function extractAssistantText(content) {
257827
257968
  if (typeof content === "string") {
257828
257969
  return content;
257829
257970
  }
@@ -257862,7 +258003,7 @@ async function generateConversationDescriptionFromFork(client, conversationId) {
257862
258003
  let descriptionText = "";
257863
258004
  for await (const chunk of stream5) {
257864
258005
  if (chunk && typeof chunk === "object" && "message_type" in chunk && chunk.message_type === "assistant_message") {
257865
- descriptionText += extractAssistantText2(chunk.content);
258006
+ descriptionText += extractAssistantText(chunk.content);
257866
258007
  }
257867
258008
  }
257868
258009
  return normalizeConversationDescription(descriptionText);
@@ -264270,6 +264411,7 @@ function cloneExtensionCapabilities(capabilities) {
264270
264411
  tools: capabilities.events.tools,
264271
264412
  turns: capabilities.events.turns
264272
264413
  },
264414
+ permissions: capabilities.permissions,
264273
264415
  providers: capabilities.providers,
264274
264416
  ui: {
264275
264417
  panels: capabilities.ui.panels,
@@ -264291,6 +264433,7 @@ var init_capabilities = __esm(() => {
264291
264433
  tools: true,
264292
264434
  turns: true
264293
264435
  },
264436
+ permissions: true,
264294
264437
  providers: true,
264295
264438
  ui: {
264296
264439
  panels: true,
@@ -264306,6 +264449,7 @@ var init_capabilities = __esm(() => {
264306
264449
  tools: false,
264307
264450
  turns: false
264308
264451
  },
264452
+ permissions: false,
264309
264453
  providers: false,
264310
264454
  ui: {
264311
264455
  panels: false,
@@ -264327,6 +264471,7 @@ function createDisabledExtensionRegistry() {
264327
264471
  loadedPaths: [],
264328
264472
  ownerAbortControllers: {},
264329
264473
  owners: {},
264474
+ permissions: {},
264330
264475
  sources: [],
264331
264476
  tools: {},
264332
264477
  ui: {
@@ -264357,6 +264502,7 @@ function createDisabledExtensionEngine(registry2) {
264357
264502
  };
264358
264503
  }
264359
264504
  function createDisabledExtensionAdapter(options3) {
264505
+ clearExtensionPermissions();
264360
264506
  clearExtensionTools();
264361
264507
  clearRegisteredPiProviders();
264362
264508
  let context3 = options3.initialContext;
@@ -264402,6 +264548,7 @@ function createDisabledExtensionAdapter(options3) {
264402
264548
  var init_disabled_extension_adapter = __esm(() => {
264403
264549
  init_pi_provider_extension_registry();
264404
264550
  init_capabilities();
264551
+ init_permission_registry();
264405
264552
  init_tool_registry();
264406
264553
  });
264407
264554
 
@@ -433270,6 +433417,7 @@ function createEmptyExtensionRegistry(sources, generation, capabilities) {
433270
433417
  loadedPaths: [],
433271
433418
  ownerAbortControllers: {},
433272
433419
  owners: {},
433420
+ permissions: {},
433273
433421
  sources,
433274
433422
  tools: {},
433275
433423
  ui: {
@@ -433305,6 +433453,7 @@ function snapshotRegistryForReaders(registry2) {
433305
433453
  loadedPaths: [...registry2.loadedPaths],
433306
433454
  ownerAbortControllers: { ...registry2.ownerAbortControllers },
433307
433455
  owners: { ...registry2.owners },
433456
+ permissions: { ...registry2.permissions },
433308
433457
  sources: registry2.sources.map((source2) => ({
433309
433458
  ...source2,
433310
433459
  files: [...source2.files]
@@ -433526,6 +433675,25 @@ function normalizeExtensionCommand(command, owner) {
433526
433675
  run: command.run
433527
433676
  };
433528
433677
  }
433678
+ function validateExtensionPermissionId(id2) {
433679
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(id2)) {
433680
+ throw new Error("Extension permission id must be a lowercase slug using letters, numbers, and hyphens");
433681
+ }
433682
+ }
433683
+ function normalizeExtensionPermission(permission, owner) {
433684
+ validateExtensionPermissionId(permission.id);
433685
+ if (typeof permission.check !== "function") {
433686
+ throw new Error(`Extension permission '${permission.id}' must include check()`);
433687
+ }
433688
+ return {
433689
+ id: permission.id,
433690
+ ...permission.description ? { description: permission.description } : {},
433691
+ owner,
433692
+ path: owner.path,
433693
+ ...permission.isEnabled ? { isEnabled: permission.isEnabled } : {},
433694
+ check: permission.check
433695
+ };
433696
+ }
433529
433697
  function validateExtensionToolName(name) {
433530
433698
  if (!/^[a-zA-Z0-9_-]{1,64}$/.test(name)) {
433531
433699
  throw new Error("Extension tool name must be 1-64 characters using letters, numbers, underscores, or hyphens");
@@ -433631,6 +433799,19 @@ function createLettaExtensionApi(registry2, owner, capabilities, getClient2, get
433631
433799
  onChange();
433632
433800
  }
433633
433801
  };
433802
+ const unregisterPermission = (id2) => {
433803
+ if (!capabilities.permissions)
433804
+ return;
433805
+ validateExtensionPermissionId(id2);
433806
+ if (!guardLive({ id: id2, kind: "permission" }))
433807
+ return;
433808
+ const existing = registry2.permissions[id2];
433809
+ if (existing?.owner?.id === owner.id) {
433810
+ delete registry2.permissions[id2];
433811
+ unregisterExtensionPermission(id2, owner);
433812
+ onChange();
433813
+ }
433814
+ };
433634
433815
  const clearPanel = (id2) => {
433635
433816
  if (!capabilities.ui.panels)
433636
433817
  return;
@@ -433827,6 +434008,40 @@ function createLettaExtensionApi(registry2, owner, capabilities, getClient2, get
433827
434008
  off: unregisterEvent,
433828
434009
  on: onEvent
433829
434010
  },
434011
+ permissions: {
434012
+ register(permission) {
434013
+ if (!capabilities.permissions) {
434014
+ return () => {
434015
+ return;
434016
+ };
434017
+ }
434018
+ if (!guardLive({ id: permission.id, kind: "permission" })) {
434019
+ return () => {
434020
+ return;
434021
+ };
434022
+ }
434023
+ const normalized = normalizeExtensionPermission(permission, owner);
434024
+ const existing = registry2.permissions[normalized.id];
434025
+ const existingGlobal = getExtensionPermissionDefinition(normalized.id);
434026
+ if (existing || existingGlobal) {
434027
+ throw new Error(`Extension permission '${normalized.id}' is already registered by ${existing?.path ?? existingGlobal?.path}`);
434028
+ }
434029
+ registry2.permissions[normalized.id] = normalized;
434030
+ registerExtensionPermission({
434031
+ ...normalized,
434032
+ activationSignal: signal,
434033
+ getContext: getContext3,
434034
+ isAvailable: () => {
434035
+ if (signal.aborted)
434036
+ return false;
434037
+ return normalized.isEnabled?.(getContext3()) ?? true;
434038
+ }
434039
+ });
434040
+ onChange();
434041
+ return () => unregisterPermission(normalized.id);
434042
+ },
434043
+ unregister: unregisterPermission
434044
+ },
433830
434045
  diagnostics: {
433831
434046
  report: reportDiagnostic
433832
434047
  },
@@ -434053,6 +434268,7 @@ function disposeLocalExtensions(registry2) {
434053
434268
  }
434054
434269
  for (const owner of Object.values(registry2.owners)) {
434055
434270
  unregisterPiProvidersForOwner(owner.id);
434271
+ unregisterExtensionPermissionsForOwner(owner);
434056
434272
  unregisterExtensionToolsForOwner(owner);
434057
434273
  }
434058
434274
  clearAvailableModelsCache();
@@ -434060,6 +434276,7 @@ function disposeLocalExtensions(registry2) {
434060
434276
  registry2.events = {};
434061
434277
  registry2.ownerAbortControllers = {};
434062
434278
  registry2.owners = {};
434279
+ registry2.permissions = {};
434063
434280
  registry2.tools = {};
434064
434281
  registry2.ui.panels = {};
434065
434282
  registry2.ui.statusOwners = {};
@@ -434164,6 +434381,7 @@ var init_extension_engine = __esm(async () => {
434164
434381
  init_pi_provider_extension_registry();
434165
434382
  init_capabilities();
434166
434383
  init_conversation_handle();
434384
+ init_permission_registry();
434167
434385
  init_tool_registry();
434168
434386
  await init_message();
434169
434387
  ts = __toESM(require_typescript(), 1);
@@ -434446,6 +434664,7 @@ var init_extension_adapter2 = __esm(async () => {
434446
434664
  tools: false,
434447
434665
  turns: false
434448
434666
  },
434667
+ permissions: false,
434449
434668
  providers: true,
434450
434669
  ui: {
434451
434670
  panels: false,
@@ -442568,6 +442787,7 @@ var init_headless_extension_adapter = __esm(async () => {
442568
442787
  tools: true,
442569
442788
  turns: true
442570
442789
  },
442790
+ permissions: true,
442571
442791
  providers: true,
442572
442792
  ui: {
442573
442793
  panels: false,
@@ -448050,6 +448270,7 @@ var init_capabilities2 = __esm(() => {
448050
448270
  tools: true,
448051
448271
  turns: true
448052
448272
  },
448273
+ permissions: true,
448053
448274
  providers: true,
448054
448275
  ui: {
448055
448276
  panels: true,
@@ -451057,7 +451278,11 @@ var init_InlineMemoryApproval = __esm(async () => {
451057
451278
  });
451058
451279
 
451059
451280
  // src/cli/components/InlineQuestionApproval.tsx
451060
- var import_react52, jsx_dev_runtime26, SOLID_LINE8 = "─", InlineQuestionApproval;
451281
+ function shouldRenderQuestionAsMarkdown(question) {
451282
+ return question.includes(`
451283
+ `) || MARKDOWN_QUESTION_PATTERNS.some((pattern4) => pattern4.test(question));
451284
+ }
451285
+ var import_react52, jsx_dev_runtime26, SOLID_LINE8 = "─", MARKDOWN_QUESTION_PATTERNS, InlineQuestionApproval;
451061
451286
  var init_InlineQuestionApproval = __esm(async () => {
451062
451287
  init_use_progress_indicator();
451063
451288
  init_use_terminal_width();
@@ -451065,10 +451290,21 @@ var init_InlineQuestionApproval = __esm(async () => {
451065
451290
  init_colors();
451066
451291
  await __promiseAll([
451067
451292
  init_build4(),
451293
+ init_MarkdownDisplay(),
451068
451294
  init_Text2()
451069
451295
  ]);
451070
451296
  import_react52 = __toESM(require_react(), 1);
451071
451297
  jsx_dev_runtime26 = __toESM(require_jsx_dev_runtime(), 1);
451298
+ MARKDOWN_QUESTION_PATTERNS = [
451299
+ /^#{1,6}\s+/m,
451300
+ /^\s*[-*+]\s+/m,
451301
+ /^\s*\d+\.\s+/m,
451302
+ /^>\s+/m,
451303
+ /^```/m,
451304
+ /\|.+\|\n\|[\s:]*-+/m,
451305
+ /\*\*[^*]+\*\*/,
451306
+ /`[^`]+`/
451307
+ ];
451072
451308
  InlineQuestionApproval = import_react52.memo(({ questions, onSubmit, onCancel, isFocused = true }) => {
451073
451309
  const [currentQuestionIndex, setCurrentQuestionIndex] = import_react52.useState(0);
451074
451310
  const [answers, setAnswers] = import_react52.useState({});
@@ -451251,6 +451487,8 @@ var init_InlineQuestionApproval = __esm(async () => {
451251
451487
  }
451252
451488
  }, { isActive: isFocused });
451253
451489
  const solidLine = SOLID_LINE8.repeat(Math.max(columns, 10));
451490
+ const questionText = currentQuestion?.question ?? "";
451491
+ const renderQuestionAsMarkdown = shouldRenderQuestionAsMarkdown(questionText);
451254
451492
  const memoizedHeaderContent = import_react52.useMemo(() => /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(jsx_dev_runtime26.Fragment, {
451255
451493
  children: [
451256
451494
  /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text2, {
@@ -451263,9 +451501,11 @@ var init_InlineQuestionApproval = __esm(async () => {
451263
451501
  /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
451264
451502
  height: 1
451265
451503
  }, undefined, false, undefined, this),
451266
- /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text2, {
451504
+ renderQuestionAsMarkdown ? /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(MarkdownDisplay, {
451505
+ text: questionText
451506
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Text2, {
451267
451507
  bold: true,
451268
- children: currentQuestion?.question
451508
+ children: questionText
451269
451509
  }, undefined, false, undefined, this),
451270
451510
  /* @__PURE__ */ jsx_dev_runtime26.jsxDEV(Box_default, {
451271
451511
  height: 1
@@ -451285,9 +451525,10 @@ var init_InlineQuestionApproval = __esm(async () => {
451285
451525
  ]
451286
451526
  }, undefined, true, undefined, this), [
451287
451527
  currentQuestion?.header,
451288
- currentQuestion?.question,
451289
451528
  currentQuestionIndex,
451290
451529
  questions.length,
451530
+ questionText,
451531
+ renderQuestionAsMarkdown,
451291
451532
  solidLine
451292
451533
  ]);
451293
451534
  const hintText = currentQuestion?.multiSelect ? "Enter to toggle · Arrow to navigate · Esc to cancel" : "Enter to select · Arrow to navigate · Esc to cancel";
@@ -468230,6 +468471,11 @@ function providerSelectionFlow(provider, connectedProviderId) {
468230
468471
  return "multiInput";
468231
468472
  return "input";
468232
468473
  }
468474
+ function fieldValuesFromProviderPlaceholders(fields) {
468475
+ if (!fields)
468476
+ return {};
468477
+ return Object.fromEntries(fields.filter((field) => !field.secret && field.placeholder).map((field) => [field.key, field.placeholder]));
468478
+ }
468233
468479
  function isProviderTargetLoading(input) {
468234
468480
  return input.connectedProvidersByTarget[input.selectedTarget] === undefined && (input.selectedTarget === "local" || input.showProviderStoreTabs);
468235
468481
  }
@@ -468431,7 +468677,7 @@ function ProviderSelector({
468431
468677
  setMethodIndex(0);
468432
468678
  } else if (flow === "multiInput") {
468433
468679
  setViewState({ type: "multiInput", provider });
468434
- setFieldValues({});
468680
+ setFieldValues(fieldValuesFromProviderPlaceholders(provider.fields));
468435
468681
  setFocusedFieldIndex(0);
468436
468682
  setValidationState("idle");
468437
468683
  setValidationError(null);
@@ -490746,7 +490992,7 @@ function useApprovalFlow(ctx) {
490746
490992
  if (remainingApprovals.length > 0) {
490747
490993
  const recheckResults = await Promise.all(remainingApprovals.map(async (approval) => {
490748
490994
  const parsedArgs2 = safeJsonParseOr(approval.toolArgs, {});
490749
- const permission = await checkToolPermission(approval.toolName, parsedArgs2);
490995
+ const permission = await checkToolPermission(approval.toolName, parsedArgs2, undefined, undefined, undefined, approvalToolContextIdRef.current, approval.toolCallId);
490750
490996
  return { approval, permission };
490751
490997
  }));
490752
490998
  const nowAutoAllowed = recheckResults.filter((r5) => r5.permission.decision === "allow");
@@ -490862,7 +491108,8 @@ function useApprovalFlow(ctx) {
490862
491108
  setAutoHandledResults,
490863
491109
  setIsExecutingTool,
490864
491110
  setPendingApprovals,
490865
- setThinkingMessage
491111
+ setThinkingMessage,
491112
+ approvalToolContextIdRef
490866
491113
  ]);
490867
491114
  const handleDenyCurrent = import_react113.useCallback(async (reason) => {
490868
491115
  if (isExecutingTool)
@@ -492989,11 +493236,14 @@ ${feedback}
492989
493236
  }
492990
493237
  if (shouldAutoGenerateConversationTitleRef.current && !isAutoConversationTitleInFlightRef.current && conversationIdRef.current !== "default") {
492991
493238
  isAutoConversationTitleInFlightRef.current = true;
493239
+ const titleConversationId = conversationIdRef.current;
492992
493240
  const conversationTitle = await generateConversationTitle();
492993
493241
  if (!conversationTitle) {
492994
493242
  isAutoConversationTitleInFlightRef.current = false;
493243
+ } else if (!shouldAutoGenerateConversationTitleRef.current || conversationIdRef.current !== titleConversationId) {
493244
+ isAutoConversationTitleInFlightRef.current = false;
492995
493245
  } else {
492996
- getBackend().updateConversation(conversationIdRef.current, {
493246
+ getBackend().updateConversation(titleConversationId, {
492997
493247
  summary: conversationTitle
492998
493248
  }).then(() => {
492999
493249
  shouldAutoGenerateConversationTitleRef.current = false;
@@ -493148,7 +493398,8 @@ ${feedback}
493148
493398
  const { needsUserInput, autoAllowed, autoDenied } = await classifyApprovals(approvalsToProcess, {
493149
493399
  getContext: analyzeToolApproval,
493150
493400
  alwaysRequiresUserInput,
493151
- missingNameReason: "Tool call incomplete - missing name or arguments"
493401
+ missingNameReason: "Tool call incomplete - missing name or arguments",
493402
+ toolContextId: approvalToolContextIdRef.current
493152
493403
  });
493153
493404
  for (const ac of [...autoAllowed, ...needsUserInput]) {
493154
493405
  const toolName = ac.approval.toolName;
@@ -499973,12 +500224,14 @@ function App2({
499973
500224
  const _queuedSystemPromptRecompileByConversationRef = import_react123.useRef(new Set);
499974
500225
  const shouldAutoGenerateConversationTitleRef = import_react123.useRef(!resumedExistingConversation);
499975
500226
  const isAutoConversationTitleInFlightRef = import_react123.useRef(false);
500227
+ const autoConversationTitleStartIndexRef = import_react123.useRef(!resumedExistingConversation ? 0 : null);
499976
500228
  const shouldAutoGenerateConversationDescriptionRef = import_react123.useRef(!resumedExistingConversation);
499977
500229
  const isAutoConversationDescriptionInFlightRef = import_react123.useRef(false);
499978
500230
  const firstUserQueryRef = import_react123.useRef(null);
499979
500231
  const setConversationAutoTitleEligibility = import_react123.useCallback((enabled) => {
499980
500232
  shouldAutoGenerateConversationTitleRef.current = enabled;
499981
500233
  isAutoConversationTitleInFlightRef.current = false;
500234
+ autoConversationTitleStartIndexRef.current = enabled ? buffersRef.current.order.length : null;
499982
500235
  shouldAutoGenerateConversationDescriptionRef.current = enabled;
499983
500236
  isAutoConversationDescriptionInFlightRef.current = false;
499984
500237
  firstUserQueryRef.current = null;
@@ -500012,8 +500265,30 @@ function App2({
500012
500265
  return fallback;
500013
500266
  }
500014
500267
  try {
500015
- const client = await getClient();
500016
- const aiTitle = await generateConversationTitleFromFork(client, conversationId2);
500268
+ const messages = [];
500269
+ const startIndex = autoConversationTitleStartIndexRef.current ?? 0;
500270
+ const titleLineIds = buffersRef.current.order.slice(Math.min(startIndex, buffersRef.current.order.length));
500271
+ for (const lineId of titleLineIds) {
500272
+ const line = buffersRef.current.byId.get(lineId);
500273
+ if (line?.kind === "user" || line?.kind === "assistant") {
500274
+ const content = line.text.trim();
500275
+ if (content) {
500276
+ messages.push({ role: line.kind, content });
500277
+ }
500278
+ }
500279
+ }
500280
+ let summaryModel;
500281
+ if (currentModelLabel) {
500282
+ try {
500283
+ const providers = await listProviders2();
500284
+ const byokProviderAliases = buildByokProviderAliases(providers);
500285
+ summaryModel = isByokHandleForSelector(currentModelLabel, byokProviderAliases) ? currentModelLabel : undefined;
500286
+ } catch {
500287
+ const byokProviderAliases = buildByokProviderAliases([]);
500288
+ summaryModel = isByokHandleForSelector(currentModelLabel, byokProviderAliases) ? currentModelLabel : undefined;
500289
+ }
500290
+ }
500291
+ const aiTitle = await generateConversationTitleFromSummary(conversationId2, messages, summaryModel);
500017
500292
  return aiTitle ?? fallback;
500018
500293
  } catch (err) {
500019
500294
  if (isDebugEnabled()) {
@@ -500021,7 +500296,7 @@ function App2({
500021
500296
  }
500022
500297
  return fallback;
500023
500298
  }
500024
- }, [deriveAutoConversationTitle]);
500299
+ }, [deriveAutoConversationTitle, currentModelLabel]);
500025
500300
  const generateConversationDescription = import_react123.useCallback(async (options3) => {
500026
500301
  if (!experimentManager.isEnabled("desktop_conversation_bootstrap")) {
500027
500302
  return;
@@ -502634,6 +502909,7 @@ var init_AppCoordinator = __esm(async () => {
502634
502909
  init_goal_loop_mode();
502635
502910
  init_hooks2();
502636
502911
  init_mode();
502912
+ init_byok_providers();
502637
502913
  init_openai_codex_provider();
502638
502914
  init_queue_runtime();
502639
502915
  init_runtime_context();
@@ -514658,6 +514934,7 @@ init_message_tool();
514658
514934
  init_registry();
514659
514935
  init_constants();
514660
514936
  init_conversation_handle();
514937
+ init_permission_registry();
514661
514938
  init_tool_registry();
514662
514939
  init_hooks2();
514663
514940
  init_mode();
@@ -516848,4 +517125,4 @@ Error during initialization: ${message}`);
516848
517125
  }
516849
517126
  main2();
516850
517127
 
516851
- //# debugId=F89FB8A13230037564756E2164756E21
517128
+ //# debugId=0844D2D27038729C64756E2164756E21