@letta-ai/letta-code 0.21.8 → 0.21.9
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 +273 -115
- package/package.json +1 -1
package/letta.js
CHANGED
|
@@ -3269,7 +3269,7 @@ var package_default;
|
|
|
3269
3269
|
var init_package = __esm(() => {
|
|
3270
3270
|
package_default = {
|
|
3271
3271
|
name: "@letta-ai/letta-code",
|
|
3272
|
-
version: "0.21.
|
|
3272
|
+
version: "0.21.9",
|
|
3273
3273
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
3274
3274
|
type: "module",
|
|
3275
3275
|
bin: {
|
|
@@ -77004,8 +77004,8 @@ function isValidApprovalResponseBody(value) {
|
|
|
77004
77004
|
if (decision.behavior === "allow") {
|
|
77005
77005
|
const hasMessage = decision.message === undefined || typeof decision.message === "string";
|
|
77006
77006
|
const hasUpdatedInput = decision.updated_input === undefined || decision.updated_input === null || typeof decision.updated_input === "object";
|
|
77007
|
-
const
|
|
77008
|
-
return hasMessage && hasUpdatedInput &&
|
|
77007
|
+
const hasSelectedPermissionSuggestionIds = decision.selected_permission_suggestion_ids === undefined || Array.isArray(decision.selected_permission_suggestion_ids) && decision.selected_permission_suggestion_ids.every((entry) => typeof entry === "string");
|
|
77008
|
+
return hasMessage && hasUpdatedInput && hasSelectedPermissionSuggestionIds;
|
|
77009
77009
|
}
|
|
77010
77010
|
if (decision.behavior === "deny") {
|
|
77011
77011
|
return typeof decision.message === "string";
|
|
@@ -77565,99 +77565,6 @@ var init_permissionMode = __esm(() => {
|
|
|
77565
77565
|
init_remote_settings();
|
|
77566
77566
|
});
|
|
77567
77567
|
|
|
77568
|
-
// src/cli/helpers/safeJsonParse.ts
|
|
77569
|
-
function safeJsonParse(json) {
|
|
77570
|
-
try {
|
|
77571
|
-
const data = JSON.parse(json);
|
|
77572
|
-
return { success: true, data };
|
|
77573
|
-
} catch (error) {
|
|
77574
|
-
return {
|
|
77575
|
-
success: false,
|
|
77576
|
-
error: error instanceof Error ? error.message : String(error)
|
|
77577
|
-
};
|
|
77578
|
-
}
|
|
77579
|
-
}
|
|
77580
|
-
function safeJsonParseOr(json, defaultValue) {
|
|
77581
|
-
const result = safeJsonParse(json);
|
|
77582
|
-
return result.success ? result.data : defaultValue;
|
|
77583
|
-
}
|
|
77584
|
-
|
|
77585
|
-
// src/cli/helpers/approvalClassification.ts
|
|
77586
|
-
async function getMissingRequiredArgs(toolName, parsedArgs) {
|
|
77587
|
-
const schema = getToolSchema(toolName);
|
|
77588
|
-
const required = schema?.input_schema?.required || [];
|
|
77589
|
-
return required.filter((key) => !(key in parsedArgs) || parsedArgs[key] == null);
|
|
77590
|
-
}
|
|
77591
|
-
async function classifyApprovals(approvals, opts = {}) {
|
|
77592
|
-
const needsUserInput = [];
|
|
77593
|
-
const autoAllowed = [];
|
|
77594
|
-
const autoDenied = [];
|
|
77595
|
-
const denyReasonForAsk = opts.denyReasonForAsk ?? "Tool requires approval (headless mode)";
|
|
77596
|
-
const missingNameReason = opts.missingNameReason ?? "Tool call incomplete - missing name";
|
|
77597
|
-
for (const approval of approvals) {
|
|
77598
|
-
const toolName = approval.toolName;
|
|
77599
|
-
if (!toolName) {
|
|
77600
|
-
autoDenied.push({
|
|
77601
|
-
approval,
|
|
77602
|
-
permission: { decision: "deny", reason: missingNameReason },
|
|
77603
|
-
context: null,
|
|
77604
|
-
parsedArgs: {},
|
|
77605
|
-
denyReason: missingNameReason
|
|
77606
|
-
});
|
|
77607
|
-
continue;
|
|
77608
|
-
}
|
|
77609
|
-
const parsedArgs = safeJsonParseOr(approval.toolArgs || "{}", {});
|
|
77610
|
-
const permission = await checkToolPermission(toolName, parsedArgs, opts.workingDirectory, opts.permissionModeState);
|
|
77611
|
-
const context3 = opts.getContext ? await opts.getContext(toolName, parsedArgs, opts.workingDirectory) : null;
|
|
77612
|
-
let decision = permission.decision;
|
|
77613
|
-
if (opts.alwaysRequiresUserInput?.(toolName) && decision === "allow") {
|
|
77614
|
-
decision = "ask";
|
|
77615
|
-
}
|
|
77616
|
-
if (decision === "ask" && opts.treatAskAsDeny) {
|
|
77617
|
-
autoDenied.push({
|
|
77618
|
-
approval,
|
|
77619
|
-
permission,
|
|
77620
|
-
context: context3,
|
|
77621
|
-
parsedArgs,
|
|
77622
|
-
denyReason: denyReasonForAsk
|
|
77623
|
-
});
|
|
77624
|
-
continue;
|
|
77625
|
-
}
|
|
77626
|
-
if (decision === "allow" && opts.requireArgsForAutoApprove) {
|
|
77627
|
-
const missingRequiredArgs = await getMissingRequiredArgs(toolName, parsedArgs);
|
|
77628
|
-
if (missingRequiredArgs.length > 0) {
|
|
77629
|
-
const denyReason = opts.missingArgsReason ? opts.missingArgsReason(missingRequiredArgs) : `Missing required parameter${missingRequiredArgs.length > 1 ? "s" : ""}: ${missingRequiredArgs.join(", ")}`;
|
|
77630
|
-
autoDenied.push({
|
|
77631
|
-
approval,
|
|
77632
|
-
permission,
|
|
77633
|
-
context: context3,
|
|
77634
|
-
parsedArgs,
|
|
77635
|
-
missingRequiredArgs,
|
|
77636
|
-
denyReason
|
|
77637
|
-
});
|
|
77638
|
-
continue;
|
|
77639
|
-
}
|
|
77640
|
-
}
|
|
77641
|
-
const entry = {
|
|
77642
|
-
approval,
|
|
77643
|
-
permission,
|
|
77644
|
-
context: context3,
|
|
77645
|
-
parsedArgs
|
|
77646
|
-
};
|
|
77647
|
-
if (decision === "ask") {
|
|
77648
|
-
needsUserInput.push(entry);
|
|
77649
|
-
} else if (decision === "deny") {
|
|
77650
|
-
autoDenied.push(entry);
|
|
77651
|
-
} else {
|
|
77652
|
-
autoAllowed.push(entry);
|
|
77653
|
-
}
|
|
77654
|
-
}
|
|
77655
|
-
return { needsUserInput, autoAllowed, autoDenied };
|
|
77656
|
-
}
|
|
77657
|
-
var init_approvalClassification = __esm(async () => {
|
|
77658
|
-
await init_manager3();
|
|
77659
|
-
});
|
|
77660
|
-
|
|
77661
77568
|
// node_modules/diff/libesm/diff/base.js
|
|
77662
77569
|
class Diff {
|
|
77663
77570
|
diff(oldStr, newStr, options = {}) {
|
|
@@ -79017,6 +78924,162 @@ async function computeDiffPreviews(toolName, toolArgs, workingDirectory = proces
|
|
|
79017
78924
|
var cachedDiffDeps = null;
|
|
79018
78925
|
var init_diffPreview = () => {};
|
|
79019
78926
|
|
|
78927
|
+
// src/cli/helpers/safeJsonParse.ts
|
|
78928
|
+
function safeJsonParse(json) {
|
|
78929
|
+
try {
|
|
78930
|
+
const data = JSON.parse(json);
|
|
78931
|
+
return { success: true, data };
|
|
78932
|
+
} catch (error) {
|
|
78933
|
+
return {
|
|
78934
|
+
success: false,
|
|
78935
|
+
error: error instanceof Error ? error.message : String(error)
|
|
78936
|
+
};
|
|
78937
|
+
}
|
|
78938
|
+
}
|
|
78939
|
+
function safeJsonParseOr(json, defaultValue) {
|
|
78940
|
+
const result = safeJsonParse(json);
|
|
78941
|
+
return result.success ? result.data : defaultValue;
|
|
78942
|
+
}
|
|
78943
|
+
|
|
78944
|
+
// src/cli/helpers/approvalClassification.ts
|
|
78945
|
+
async function getMissingRequiredArgs(toolName, parsedArgs) {
|
|
78946
|
+
const schema = getToolSchema(toolName);
|
|
78947
|
+
const required = schema?.input_schema?.required || [];
|
|
78948
|
+
return required.filter((key) => !(key in parsedArgs) || parsedArgs[key] == null);
|
|
78949
|
+
}
|
|
78950
|
+
async function classifyApprovals(approvals, opts = {}) {
|
|
78951
|
+
const needsUserInput = [];
|
|
78952
|
+
const autoAllowed = [];
|
|
78953
|
+
const autoDenied = [];
|
|
78954
|
+
const denyReasonForAsk = opts.denyReasonForAsk ?? "Tool requires approval (headless mode)";
|
|
78955
|
+
const missingNameReason = opts.missingNameReason ?? "Tool call incomplete - missing name";
|
|
78956
|
+
for (const approval of approvals) {
|
|
78957
|
+
const toolName = approval.toolName;
|
|
78958
|
+
if (!toolName) {
|
|
78959
|
+
autoDenied.push({
|
|
78960
|
+
approval,
|
|
78961
|
+
permission: { decision: "deny", reason: missingNameReason },
|
|
78962
|
+
context: null,
|
|
78963
|
+
parsedArgs: {},
|
|
78964
|
+
denyReason: missingNameReason
|
|
78965
|
+
});
|
|
78966
|
+
continue;
|
|
78967
|
+
}
|
|
78968
|
+
const parsedArgs = safeJsonParseOr(approval.toolArgs || "{}", {});
|
|
78969
|
+
const permission = await checkToolPermission(toolName, parsedArgs, opts.workingDirectory, opts.permissionModeState);
|
|
78970
|
+
const context3 = opts.getContext ? await opts.getContext(toolName, parsedArgs, opts.workingDirectory) : null;
|
|
78971
|
+
let decision = permission.decision;
|
|
78972
|
+
if (opts.alwaysRequiresUserInput?.(toolName) && decision === "allow") {
|
|
78973
|
+
decision = "ask";
|
|
78974
|
+
}
|
|
78975
|
+
if (decision === "ask" && opts.treatAskAsDeny) {
|
|
78976
|
+
autoDenied.push({
|
|
78977
|
+
approval,
|
|
78978
|
+
permission,
|
|
78979
|
+
context: context3,
|
|
78980
|
+
parsedArgs,
|
|
78981
|
+
denyReason: denyReasonForAsk
|
|
78982
|
+
});
|
|
78983
|
+
continue;
|
|
78984
|
+
}
|
|
78985
|
+
if (decision === "allow" && opts.requireArgsForAutoApprove) {
|
|
78986
|
+
const missingRequiredArgs = await getMissingRequiredArgs(toolName, parsedArgs);
|
|
78987
|
+
if (missingRequiredArgs.length > 0) {
|
|
78988
|
+
const denyReason = opts.missingArgsReason ? opts.missingArgsReason(missingRequiredArgs) : `Missing required parameter${missingRequiredArgs.length > 1 ? "s" : ""}: ${missingRequiredArgs.join(", ")}`;
|
|
78989
|
+
autoDenied.push({
|
|
78990
|
+
approval,
|
|
78991
|
+
permission,
|
|
78992
|
+
context: context3,
|
|
78993
|
+
parsedArgs,
|
|
78994
|
+
missingRequiredArgs,
|
|
78995
|
+
denyReason
|
|
78996
|
+
});
|
|
78997
|
+
continue;
|
|
78998
|
+
}
|
|
78999
|
+
}
|
|
79000
|
+
const entry = {
|
|
79001
|
+
approval,
|
|
79002
|
+
permission,
|
|
79003
|
+
context: context3,
|
|
79004
|
+
parsedArgs
|
|
79005
|
+
};
|
|
79006
|
+
if (decision === "ask") {
|
|
79007
|
+
needsUserInput.push(entry);
|
|
79008
|
+
} else if (decision === "deny") {
|
|
79009
|
+
autoDenied.push(entry);
|
|
79010
|
+
} else {
|
|
79011
|
+
autoAllowed.push(entry);
|
|
79012
|
+
}
|
|
79013
|
+
}
|
|
79014
|
+
return { needsUserInput, autoAllowed, autoDenied };
|
|
79015
|
+
}
|
|
79016
|
+
var init_approvalClassification = __esm(async () => {
|
|
79017
|
+
await init_manager3();
|
|
79018
|
+
});
|
|
79019
|
+
|
|
79020
|
+
// src/websocket/listener/approval-suggestions.ts
|
|
79021
|
+
function getSuggestedPermissionRule(context3) {
|
|
79022
|
+
if (!context3?.allowPersistence || context3.recommendedRule.trim().length === 0) {
|
|
79023
|
+
return null;
|
|
79024
|
+
}
|
|
79025
|
+
return context3.recommendedRule;
|
|
79026
|
+
}
|
|
79027
|
+
function getApprovalPermissionSuggestions(context3) {
|
|
79028
|
+
const suggestedRule = getSuggestedPermissionRule(context3);
|
|
79029
|
+
if (suggestedRule === null || !context3) {
|
|
79030
|
+
return [];
|
|
79031
|
+
}
|
|
79032
|
+
const text = context3.approveAlwaysText.trim();
|
|
79033
|
+
if (text.length === 0) {
|
|
79034
|
+
return [];
|
|
79035
|
+
}
|
|
79036
|
+
return [
|
|
79037
|
+
{
|
|
79038
|
+
suggestion: {
|
|
79039
|
+
id: "save-default",
|
|
79040
|
+
text
|
|
79041
|
+
},
|
|
79042
|
+
rule: suggestedRule,
|
|
79043
|
+
scope: context3.defaultScope
|
|
79044
|
+
}
|
|
79045
|
+
];
|
|
79046
|
+
}
|
|
79047
|
+
function buildApprovalSuggestionPayload(context3) {
|
|
79048
|
+
return {
|
|
79049
|
+
permission_suggestions: getApprovalPermissionSuggestions(context3).map(({ suggestion }) => suggestion)
|
|
79050
|
+
};
|
|
79051
|
+
}
|
|
79052
|
+
async function classifyApprovalsWithSuggestions(approvals, opts = {}) {
|
|
79053
|
+
return classifyApprovals(approvals, {
|
|
79054
|
+
...opts,
|
|
79055
|
+
getContext: async (toolName, parsedArgs, workingDirectory) => analyzeToolApproval(toolName, parsedArgs, workingDirectory)
|
|
79056
|
+
});
|
|
79057
|
+
}
|
|
79058
|
+
async function applySuggestedPermissionsForApproval(params) {
|
|
79059
|
+
const { decision, context: context3, workingDirectory } = params;
|
|
79060
|
+
if (!context3?.allowPersistence || context3.defaultScope === undefined) {
|
|
79061
|
+
return false;
|
|
79062
|
+
}
|
|
79063
|
+
const selectedIds = decision.selected_permission_suggestion_ids ?? [];
|
|
79064
|
+
if (selectedIds.length === 0) {
|
|
79065
|
+
return false;
|
|
79066
|
+
}
|
|
79067
|
+
const matchedSuggestions = getApprovalPermissionSuggestions(context3).filter(({ suggestion }) => selectedIds.includes(suggestion.id));
|
|
79068
|
+
if (matchedSuggestions.length === 0) {
|
|
79069
|
+
return false;
|
|
79070
|
+
}
|
|
79071
|
+
for (const matchedSuggestion of matchedSuggestions) {
|
|
79072
|
+
await savePermissionRule2(matchedSuggestion.rule, "allow", matchedSuggestion.scope, workingDirectory);
|
|
79073
|
+
}
|
|
79074
|
+
return true;
|
|
79075
|
+
}
|
|
79076
|
+
var init_approval_suggestions = __esm(async () => {
|
|
79077
|
+
await __promiseAll([
|
|
79078
|
+
init_approvalClassification(),
|
|
79079
|
+
init_manager3()
|
|
79080
|
+
]);
|
|
79081
|
+
});
|
|
79082
|
+
|
|
79020
79083
|
// src/websocket/listener/recovery.ts
|
|
79021
79084
|
function isApprovalToolCallDesyncError(detail) {
|
|
79022
79085
|
if (isInvalidToolCallIdsError(detail) || isApprovalPendingError(detail)) {
|
|
@@ -79232,12 +79295,13 @@ async function recoverApprovalStateForSync(runtime, scope) {
|
|
|
79232
79295
|
return;
|
|
79233
79296
|
}
|
|
79234
79297
|
const workingDirectory = getConversationWorkingDirectory(runtime.listener, scope.agent_id, scope.conversation_id);
|
|
79235
|
-
const
|
|
79298
|
+
const permissionModeState = getOrCreateConversationPermissionModeStateRef(runtime.listener, scope.agent_id, scope.conversation_id);
|
|
79299
|
+
const { needsUserInput, autoAllowed, autoDenied } = await classifyApprovalsWithSuggestions(pendingApprovals, {
|
|
79236
79300
|
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
79237
79301
|
requireArgsForAutoApprove: true,
|
|
79238
79302
|
missingNameReason: "Tool call incomplete - missing name",
|
|
79239
79303
|
workingDirectory,
|
|
79240
|
-
permissionModeState
|
|
79304
|
+
permissionModeState
|
|
79241
79305
|
});
|
|
79242
79306
|
const autoDecisions = buildRecoveredAutoDecisions(autoAllowed, autoDenied);
|
|
79243
79307
|
if (needsUserInput.length === 0) {
|
|
@@ -79252,6 +79316,7 @@ async function recoverApprovalStateForSync(runtime, scope) {
|
|
|
79252
79316
|
const diffs = await computeDiffPreviews(approval.toolName, input, workingDirectory);
|
|
79253
79317
|
approvalsByRequestId.set(requestId, {
|
|
79254
79318
|
approval,
|
|
79319
|
+
approvalContext: approvalEntry.context,
|
|
79255
79320
|
controlRequest: {
|
|
79256
79321
|
type: "control_request",
|
|
79257
79322
|
request_id: requestId,
|
|
@@ -79260,7 +79325,7 @@ async function recoverApprovalStateForSync(runtime, scope) {
|
|
|
79260
79325
|
tool_name: approval.toolName,
|
|
79261
79326
|
input,
|
|
79262
79327
|
tool_call_id: approval.toolCallId,
|
|
79263
|
-
|
|
79328
|
+
...buildApprovalSuggestionPayload(approvalEntry.context),
|
|
79264
79329
|
blocked_path: null,
|
|
79265
79330
|
...diffs.length > 0 ? { diffs } : {}
|
|
79266
79331
|
},
|
|
@@ -79290,6 +79355,40 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
79290
79355
|
}
|
|
79291
79356
|
recovered.responsesByRequestId.set(requestId, response);
|
|
79292
79357
|
recovered.pendingRequestIds.delete(requestId);
|
|
79358
|
+
const workingDirectory = getConversationWorkingDirectory(runtime.listener, recovered.agentId, recovered.conversationId);
|
|
79359
|
+
const respondedEntry = recovered.approvalsByRequestId.get(requestId);
|
|
79360
|
+
if (respondedEntry && "decision" in response && response.decision.behavior === "allow") {
|
|
79361
|
+
const savedSuggestions = await applySuggestedPermissionsForApproval({
|
|
79362
|
+
decision: response.decision,
|
|
79363
|
+
context: respondedEntry.approvalContext,
|
|
79364
|
+
workingDirectory
|
|
79365
|
+
});
|
|
79366
|
+
if (savedSuggestions && recovered.pendingRequestIds.size > 0) {
|
|
79367
|
+
const remainingRecoveredEntries = [...recovered.pendingRequestIds].map((id) => recovered.approvalsByRequestId.get(id)).filter((entry) => !!entry);
|
|
79368
|
+
const reclassified = await classifyApprovalsWithSuggestions(remainingRecoveredEntries.map((entry) => entry.approval), {
|
|
79369
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
79370
|
+
requireArgsForAutoApprove: true,
|
|
79371
|
+
missingNameReason: "Tool call incomplete - missing name",
|
|
79372
|
+
workingDirectory,
|
|
79373
|
+
permissionModeState: getOrCreateConversationPermissionModeStateRef(runtime.listener, recovered.agentId, recovered.conversationId)
|
|
79374
|
+
});
|
|
79375
|
+
if (reclassified.autoAllowed.length > 0 || reclassified.autoDenied.length > 0) {
|
|
79376
|
+
recovered.autoDecisions = [
|
|
79377
|
+
...recovered.autoDecisions ?? [],
|
|
79378
|
+
...buildRecoveredAutoDecisions(reclassified.autoAllowed, reclassified.autoDenied)
|
|
79379
|
+
];
|
|
79380
|
+
const reclassifiedToolCallIds = new Set([...reclassified.autoAllowed, ...reclassified.autoDenied].map((entry) => entry.approval.toolCallId));
|
|
79381
|
+
for (const pendingId of [...recovered.pendingRequestIds]) {
|
|
79382
|
+
const pendingEntry = recovered.approvalsByRequestId.get(pendingId);
|
|
79383
|
+
if (pendingEntry && reclassifiedToolCallIds.has(pendingEntry.approval.toolCallId)) {
|
|
79384
|
+
recovered.pendingRequestIds.delete(pendingId);
|
|
79385
|
+
recovered.approvalsByRequestId.delete(pendingId);
|
|
79386
|
+
recovered.responsesByRequestId.delete(pendingId);
|
|
79387
|
+
}
|
|
79388
|
+
}
|
|
79389
|
+
}
|
|
79390
|
+
}
|
|
79391
|
+
}
|
|
79293
79392
|
if (recovered.pendingRequestIds.size > 0) {
|
|
79294
79393
|
emitRuntimeStateUpdates(runtime, {
|
|
79295
79394
|
agent_id: recovered.agentId,
|
|
@@ -79342,7 +79441,7 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
79342
79441
|
recovered.pendingRequestIds.clear();
|
|
79343
79442
|
emitRuntimeStateUpdates(runtime, scope);
|
|
79344
79443
|
runtime.isProcessing = true;
|
|
79345
|
-
runtime.activeWorkingDirectory =
|
|
79444
|
+
runtime.activeWorkingDirectory = workingDirectory;
|
|
79346
79445
|
runtime.activeExecutingToolCallIds = [...approvedToolCallIds];
|
|
79347
79446
|
setLoopStatus(runtime, "EXECUTING_CLIENT_SIDE_TOOL", scope);
|
|
79348
79447
|
emitRuntimeStateUpdates(runtime, scope);
|
|
@@ -79367,7 +79466,7 @@ async function resolveRecoveredApprovalResponse(runtime, socket, response, proce
|
|
|
79367
79466
|
const approvalResults = await executeApprovalBatch(decisions, undefined, {
|
|
79368
79467
|
abortSignal: recoveryAbortController.signal,
|
|
79369
79468
|
toolContextId: preparedToolContext.preparedToolContext.contextId,
|
|
79370
|
-
workingDirectory
|
|
79469
|
+
workingDirectory,
|
|
79371
79470
|
parentScope: recovered.agentId && recovered.conversationId ? {
|
|
79372
79471
|
agentId: recovered.agentId,
|
|
79373
79472
|
conversationId: recovered.conversationId
|
|
@@ -79434,9 +79533,9 @@ var init_recovery = __esm(async () => {
|
|
|
79434
79533
|
init_approval_execution(),
|
|
79435
79534
|
init_client2(),
|
|
79436
79535
|
init_accumulator(),
|
|
79437
|
-
init_approvalClassification(),
|
|
79438
79536
|
init_stream(),
|
|
79439
79537
|
init_toolset(),
|
|
79538
|
+
init_approval_suggestions(),
|
|
79440
79539
|
init_interrupts(),
|
|
79441
79540
|
init_protocol_outbound(),
|
|
79442
79541
|
init_queue()
|
|
@@ -79526,12 +79625,13 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
79526
79625
|
throw new Error("Ambiguous pending approval batch mapping during recovery");
|
|
79527
79626
|
}
|
|
79528
79627
|
rememberPendingApprovalBatchIds(runtime, pendingApprovals, recoveryBatchId);
|
|
79529
|
-
const
|
|
79628
|
+
const permissionModeState = getOrCreateConversationPermissionModeStateRef(runtime.listener, runtime.agentId, runtime.conversationId);
|
|
79629
|
+
const { autoAllowed, autoDenied, needsUserInput } = await classifyApprovalsWithSuggestions(pendingApprovals, {
|
|
79530
79630
|
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
79531
79631
|
requireArgsForAutoApprove: true,
|
|
79532
79632
|
missingNameReason: "Tool call incomplete - missing name",
|
|
79533
79633
|
workingDirectory: recoveryWorkingDirectory,
|
|
79534
|
-
permissionModeState
|
|
79634
|
+
permissionModeState
|
|
79535
79635
|
});
|
|
79536
79636
|
const decisions = [
|
|
79537
79637
|
...autoAllowed.map((ac) => ({
|
|
@@ -79544,11 +79644,16 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
79544
79644
|
reason: ac.denyReason || ac.permission.reason || "Permission denied"
|
|
79545
79645
|
}))
|
|
79546
79646
|
];
|
|
79547
|
-
|
|
79647
|
+
let pendingNeedsUserInput = [...needsUserInput];
|
|
79648
|
+
if (pendingNeedsUserInput.length > 0) {
|
|
79548
79649
|
runtime.lastStopReason = "requires_approval";
|
|
79549
79650
|
setLoopStatus(runtime, "WAITING_ON_APPROVAL", scope);
|
|
79550
79651
|
emitRuntimeStateUpdates(runtime, scope);
|
|
79551
|
-
|
|
79652
|
+
while (pendingNeedsUserInput.length > 0) {
|
|
79653
|
+
const ac = pendingNeedsUserInput.shift();
|
|
79654
|
+
if (!ac) {
|
|
79655
|
+
break;
|
|
79656
|
+
}
|
|
79552
79657
|
if (abortSignal.aborted)
|
|
79553
79658
|
throw new Error("Cancelled");
|
|
79554
79659
|
const requestId = `perm-${ac.approval.toolCallId}`;
|
|
@@ -79561,7 +79666,7 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
79561
79666
|
tool_name: ac.approval.toolName,
|
|
79562
79667
|
input: ac.parsedArgs,
|
|
79563
79668
|
tool_call_id: ac.approval.toolCallId,
|
|
79564
|
-
|
|
79669
|
+
...buildApprovalSuggestionPayload(ac.context),
|
|
79565
79670
|
blocked_path: null,
|
|
79566
79671
|
...diffs.length > 0 ? { diffs } : {}
|
|
79567
79672
|
},
|
|
@@ -79572,6 +79677,11 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
79572
79677
|
if ("decision" in responseBody) {
|
|
79573
79678
|
const response = responseBody.decision;
|
|
79574
79679
|
if (response.behavior === "allow") {
|
|
79680
|
+
const savedSuggestions = await applySuggestedPermissionsForApproval({
|
|
79681
|
+
decision: response,
|
|
79682
|
+
context: ac.context,
|
|
79683
|
+
workingDirectory: recoveryWorkingDirectory
|
|
79684
|
+
});
|
|
79575
79685
|
decisions.push({
|
|
79576
79686
|
type: "approve",
|
|
79577
79687
|
approval: response.updated_input ? {
|
|
@@ -79580,6 +79690,24 @@ async function resolveStaleApprovals(runtime, socket, abortSignal, deps = {}) {
|
|
|
79580
79690
|
} : ac.approval,
|
|
79581
79691
|
reason: response.message
|
|
79582
79692
|
});
|
|
79693
|
+
if (savedSuggestions && pendingNeedsUserInput.length > 0) {
|
|
79694
|
+
const reclassified = await classifyApprovalsWithSuggestions(pendingNeedsUserInput.map((entry) => entry.approval), {
|
|
79695
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
79696
|
+
requireArgsForAutoApprove: true,
|
|
79697
|
+
missingNameReason: "Tool call incomplete - missing name",
|
|
79698
|
+
workingDirectory: recoveryWorkingDirectory,
|
|
79699
|
+
permissionModeState
|
|
79700
|
+
});
|
|
79701
|
+
decisions.push(...reclassified.autoAllowed.map((entry) => ({
|
|
79702
|
+
type: "approve",
|
|
79703
|
+
approval: entry.approval
|
|
79704
|
+
})), ...reclassified.autoDenied.map((entry) => ({
|
|
79705
|
+
type: "deny",
|
|
79706
|
+
approval: entry.approval,
|
|
79707
|
+
reason: entry.denyReason || entry.permission.reason || "Permission denied"
|
|
79708
|
+
})));
|
|
79709
|
+
pendingNeedsUserInput = [...reclassified.needsUserInput];
|
|
79710
|
+
}
|
|
79583
79711
|
} else {
|
|
79584
79712
|
decisions.push({
|
|
79585
79713
|
type: "deny",
|
|
@@ -79929,9 +80057,9 @@ var init_send = __esm(async () => {
|
|
|
79929
80057
|
init_approval_recovery(),
|
|
79930
80058
|
init_client2(),
|
|
79931
80059
|
init_message(),
|
|
79932
|
-
init_approvalClassification(),
|
|
79933
80060
|
init_toolset(),
|
|
79934
80061
|
init_approval(),
|
|
80062
|
+
init_approval_suggestions(),
|
|
79935
80063
|
init_interrupts(),
|
|
79936
80064
|
init_protocol_outbound(),
|
|
79937
80065
|
init_queue(),
|
|
@@ -79997,7 +80125,7 @@ async function handleApprovalStop(params) {
|
|
|
79997
80125
|
}
|
|
79998
80126
|
clearPendingApprovalBatchIds(runtime, approvals);
|
|
79999
80127
|
rememberPendingApprovalBatchIds(runtime, approvals, dequeuedBatchId);
|
|
80000
|
-
const { autoAllowed, autoDenied, needsUserInput } = await
|
|
80128
|
+
const { autoAllowed, autoDenied, needsUserInput } = await classifyApprovalsWithSuggestions(approvals, {
|
|
80001
80129
|
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
80002
80130
|
treatAskAsDeny: false,
|
|
80003
80131
|
requireArgsForAutoApprove: true,
|
|
@@ -80005,7 +80133,8 @@ async function handleApprovalStop(params) {
|
|
|
80005
80133
|
workingDirectory: turnWorkingDirectory,
|
|
80006
80134
|
permissionModeState: turnPermissionModeState
|
|
80007
80135
|
});
|
|
80008
|
-
|
|
80136
|
+
let pendingNeedsUserInput = [...needsUserInput];
|
|
80137
|
+
let lastNeedsUserInputToolCallIds = pendingNeedsUserInput.map((ac) => ac.approval.toolCallId);
|
|
80009
80138
|
let lastExecutionResults = null;
|
|
80010
80139
|
let lastExecutingToolCallIds = [];
|
|
80011
80140
|
const shouldInterrupt = () => abortController.signal.aborted || runtime.cancelRequested;
|
|
@@ -80044,7 +80173,7 @@ async function handleApprovalStop(params) {
|
|
|
80044
80173
|
if (shouldInterrupt()) {
|
|
80045
80174
|
return interruptTermination();
|
|
80046
80175
|
}
|
|
80047
|
-
if (
|
|
80176
|
+
if (pendingNeedsUserInput.length > 0) {
|
|
80048
80177
|
if (shouldInterrupt()) {
|
|
80049
80178
|
return interruptTermination();
|
|
80050
80179
|
}
|
|
@@ -80053,7 +80182,11 @@ async function handleApprovalStop(params) {
|
|
|
80053
80182
|
agent_id: agentId,
|
|
80054
80183
|
conversation_id: conversationId
|
|
80055
80184
|
});
|
|
80056
|
-
|
|
80185
|
+
while (pendingNeedsUserInput.length > 0) {
|
|
80186
|
+
const ac = pendingNeedsUserInput.shift();
|
|
80187
|
+
if (!ac) {
|
|
80188
|
+
break;
|
|
80189
|
+
}
|
|
80057
80190
|
if (shouldInterrupt()) {
|
|
80058
80191
|
return interruptTermination();
|
|
80059
80192
|
}
|
|
@@ -80070,7 +80203,7 @@ async function handleApprovalStop(params) {
|
|
|
80070
80203
|
tool_name: ac.approval.toolName,
|
|
80071
80204
|
input: ac.parsedArgs,
|
|
80072
80205
|
tool_call_id: ac.approval.toolCallId,
|
|
80073
|
-
|
|
80206
|
+
...buildApprovalSuggestionPayload(ac.context),
|
|
80074
80207
|
blocked_path: null,
|
|
80075
80208
|
...diffs.length > 0 ? { diffs } : {}
|
|
80076
80209
|
},
|
|
@@ -80092,6 +80225,11 @@ async function handleApprovalStop(params) {
|
|
|
80092
80225
|
if ("decision" in responseBody) {
|
|
80093
80226
|
const response = responseBody.decision;
|
|
80094
80227
|
if (response.behavior === "allow") {
|
|
80228
|
+
const savedSuggestions = await applySuggestedPermissionsForApproval({
|
|
80229
|
+
decision: response,
|
|
80230
|
+
context: ac.context,
|
|
80231
|
+
workingDirectory: turnWorkingDirectory
|
|
80232
|
+
});
|
|
80095
80233
|
const finalApproval = response.updated_input ? {
|
|
80096
80234
|
...ac.approval,
|
|
80097
80235
|
toolArgs: JSON.stringify(response.updated_input)
|
|
@@ -80101,6 +80239,26 @@ async function handleApprovalStop(params) {
|
|
|
80101
80239
|
approval: finalApproval,
|
|
80102
80240
|
reason: response.message
|
|
80103
80241
|
});
|
|
80242
|
+
if (savedSuggestions && pendingNeedsUserInput.length > 0) {
|
|
80243
|
+
const reclassified = await classifyApprovalsWithSuggestions(pendingNeedsUserInput.map((entry) => entry.approval), {
|
|
80244
|
+
alwaysRequiresUserInput: isInteractiveApprovalTool,
|
|
80245
|
+
treatAskAsDeny: false,
|
|
80246
|
+
requireArgsForAutoApprove: true,
|
|
80247
|
+
missingNameReason: "Tool call incomplete - missing name",
|
|
80248
|
+
workingDirectory: turnWorkingDirectory,
|
|
80249
|
+
permissionModeState: turnPermissionModeState
|
|
80250
|
+
});
|
|
80251
|
+
decisions.push(...reclassified.autoAllowed.map((entry) => ({
|
|
80252
|
+
type: "approve",
|
|
80253
|
+
approval: entry.approval
|
|
80254
|
+
})), ...reclassified.autoDenied.map((entry) => ({
|
|
80255
|
+
type: "deny",
|
|
80256
|
+
approval: entry.approval,
|
|
80257
|
+
reason: entry.denyReason || entry.permission.reason || "Permission denied"
|
|
80258
|
+
})));
|
|
80259
|
+
pendingNeedsUserInput = [...reclassified.needsUserInput];
|
|
80260
|
+
lastNeedsUserInputToolCallIds = pendingNeedsUserInput.map((entry) => entry.approval.toolCallId);
|
|
80261
|
+
}
|
|
80104
80262
|
} else {
|
|
80105
80263
|
decisions.push({
|
|
80106
80264
|
type: "deny",
|
|
@@ -80248,8 +80406,8 @@ var init_turn_approval = __esm(async () => {
|
|
|
80248
80406
|
init_skill_injection();
|
|
80249
80407
|
await __promiseAll([
|
|
80250
80408
|
init_approval_execution(),
|
|
80251
|
-
init_approvalClassification(),
|
|
80252
80409
|
init_approval(),
|
|
80410
|
+
init_approval_suggestions(),
|
|
80253
80411
|
init_interrupts(),
|
|
80254
80412
|
init_protocol_outbound(),
|
|
80255
80413
|
init_queue(),
|
|
@@ -152041,4 +152199,4 @@ Error during initialization: ${message}`);
|
|
|
152041
152199
|
}
|
|
152042
152200
|
main();
|
|
152043
152201
|
|
|
152044
|
-
//# debugId=
|
|
152202
|
+
//# debugId=594F8E4675FBE99864756E2164756E21
|