@letta-ai/letta-code 0.26.0 → 0.26.1
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 +343 -162
- package/package.json +1 -1
package/letta.js
CHANGED
|
@@ -6429,7 +6429,7 @@ var package_default;
|
|
|
6429
6429
|
var init_package = __esm(() => {
|
|
6430
6430
|
package_default = {
|
|
6431
6431
|
name: "@letta-ai/letta-code",
|
|
6432
|
-
version: "0.26.
|
|
6432
|
+
version: "0.26.1",
|
|
6433
6433
|
description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
|
|
6434
6434
|
type: "module",
|
|
6435
6435
|
packageManager: "bun@1.3.0",
|
|
@@ -235572,57 +235572,13 @@ var init_local_agent_listing = __esm(() => {
|
|
|
235572
235572
|
init_paths();
|
|
235573
235573
|
});
|
|
235574
235574
|
|
|
235575
|
-
// src/cli/helpers/recent-agent-options.ts
|
|
235576
|
-
function sortRecentAgents(agents, currentAgentId) {
|
|
235577
|
-
return agents.toSorted((a2, b3) => {
|
|
235578
|
-
if (currentAgentId) {
|
|
235579
|
-
if (a2.agent.id === currentAgentId)
|
|
235580
|
-
return -1;
|
|
235581
|
-
if (b3.agent.id === currentAgentId)
|
|
235582
|
-
return 1;
|
|
235583
|
-
}
|
|
235584
|
-
const aTime = a2.agent.last_run_completion ? new Date(a2.agent.last_run_completion).getTime() : 0;
|
|
235585
|
-
const bTime = b3.agent.last_run_completion ? new Date(b3.agent.last_run_completion).getTime() : 0;
|
|
235586
|
-
return bTime - aTime;
|
|
235587
|
-
});
|
|
235588
|
-
}
|
|
235589
|
-
async function getRecentAgentOptions(options3) {
|
|
235590
|
-
const includeLocal = options3?.includeLocal !== false;
|
|
235591
|
-
const includeConstellation = options3?.includeConstellation !== false;
|
|
235592
|
-
const limit3 = options3?.limit ?? 5;
|
|
235593
|
-
const localAgents = includeLocal ? listLocalAgentsFromDisk().map((agent2) => ({ agent: agent2, isLocal: true })) : [];
|
|
235594
|
-
const constellationAgents = includeConstellation ? await (async () => {
|
|
235595
|
-
try {
|
|
235596
|
-
const client = await getClient();
|
|
235597
|
-
const result = await client.agents.list({
|
|
235598
|
-
limit: limit3,
|
|
235599
|
-
include: ["agent.blocks"],
|
|
235600
|
-
order: "desc",
|
|
235601
|
-
order_by: "last_run_completion"
|
|
235602
|
-
});
|
|
235603
|
-
return result.items.map((agent2) => ({ agent: agent2, isLocal: false }));
|
|
235604
|
-
} catch {
|
|
235605
|
-
return [];
|
|
235606
|
-
}
|
|
235607
|
-
})() : [];
|
|
235608
|
-
const seen = new Set;
|
|
235609
|
-
const deduped = sortRecentAgents([...localAgents, ...constellationAgents].filter((item) => {
|
|
235610
|
-
if (seen.has(item.agent.id))
|
|
235611
|
-
return false;
|
|
235612
|
-
seen.add(item.agent.id);
|
|
235613
|
-
return true;
|
|
235614
|
-
}), options3?.currentAgentId);
|
|
235615
|
-
return deduped.slice(0, limit3);
|
|
235616
|
-
}
|
|
235617
|
-
var init_recent_agent_options = __esm(() => {
|
|
235618
|
-
init_client2();
|
|
235619
|
-
init_local_agent_listing();
|
|
235620
|
-
});
|
|
235621
|
-
|
|
235622
235575
|
// src/cli/helpers/startup-model-display.ts
|
|
235576
|
+
function shouldHideReasoningForModelDisplay(modelDisplay) {
|
|
235577
|
+
return modelDisplay === STARTUP_NO_MODEL_LABEL;
|
|
235578
|
+
}
|
|
235623
235579
|
function getStartupModelDisplayOverride(options3) {
|
|
235624
|
-
const { isLocalBackend, startupHasAvailableLocalModels
|
|
235625
|
-
if (isLocalBackend && !startupHasAvailableLocalModels
|
|
235580
|
+
const { isLocalBackend, startupHasAvailableLocalModels } = options3;
|
|
235581
|
+
if (isLocalBackend && !startupHasAvailableLocalModels) {
|
|
235626
235582
|
return STARTUP_NO_MODEL_LABEL;
|
|
235627
235583
|
}
|
|
235628
235584
|
return null;
|
|
@@ -235830,7 +235786,6 @@ function WelcomeScreen({
|
|
|
235830
235786
|
loadingState,
|
|
235831
235787
|
continueSession,
|
|
235832
235788
|
agentState,
|
|
235833
|
-
agentProvenance,
|
|
235834
235789
|
startupHasAvailableLocalModels = true
|
|
235835
235790
|
}) {
|
|
235836
235791
|
useTerminalWidth();
|
|
@@ -235841,8 +235796,7 @@ function WelcomeScreen({
|
|
|
235841
235796
|
const fullModel = llmConfig?.model_endpoint_type && llmConfig?.model ? `${llmConfig.model_endpoint_type}/${llmConfig.model}` : llmConfig?.model ?? null;
|
|
235842
235797
|
const startupModelDisplayOverride = getStartupModelDisplayOverride({
|
|
235843
235798
|
isLocalBackend: isLocalBackendEnabled(),
|
|
235844
|
-
startupHasAvailableLocalModels
|
|
235845
|
-
agentProvenance
|
|
235799
|
+
startupHasAvailableLocalModels
|
|
235846
235800
|
});
|
|
235847
235801
|
const model = startupModelDisplayOverride ?? (fullModel ? getModelDisplayName(fullModel) ?? fullModel.split("/").pop() : undefined);
|
|
235848
235802
|
const initialAuth = getInitialAuthMethod();
|
|
@@ -237767,8 +237721,37 @@ async function generatePKCE2() {
|
|
|
237767
237721
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
237768
237722
|
return { codeVerifier, codeChallenge };
|
|
237769
237723
|
}
|
|
237770
|
-
function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaultPort) {
|
|
237724
|
+
function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaultPort, signal) {
|
|
237771
237725
|
return new Promise((resolve29, reject) => {
|
|
237726
|
+
if (signal?.aborted) {
|
|
237727
|
+
const error54 = new Error("OAuth callback server cancelled");
|
|
237728
|
+
error54.name = "AbortError";
|
|
237729
|
+
reject(error54);
|
|
237730
|
+
return;
|
|
237731
|
+
}
|
|
237732
|
+
let settled = false;
|
|
237733
|
+
let timeout = null;
|
|
237734
|
+
const finish = (callback) => {
|
|
237735
|
+
if (settled)
|
|
237736
|
+
return;
|
|
237737
|
+
settled = true;
|
|
237738
|
+
if (timeout) {
|
|
237739
|
+
clearTimeout(timeout);
|
|
237740
|
+
timeout = null;
|
|
237741
|
+
}
|
|
237742
|
+
if (signal) {
|
|
237743
|
+
signal.removeEventListener("abort", onAbort);
|
|
237744
|
+
}
|
|
237745
|
+
callback();
|
|
237746
|
+
};
|
|
237747
|
+
const onAbort = () => {
|
|
237748
|
+
server.close();
|
|
237749
|
+
finish(() => {
|
|
237750
|
+
const error54 = new Error("OAuth callback server cancelled");
|
|
237751
|
+
error54.name = "AbortError";
|
|
237752
|
+
reject(error54);
|
|
237753
|
+
});
|
|
237754
|
+
};
|
|
237772
237755
|
const server = http3.createServer((req, res) => {
|
|
237773
237756
|
const url2 = new URL(req.url || "", `http://localhost:${port}`);
|
|
237774
237757
|
if (url2.pathname === OPENAI_OAUTH_CONFIG.callbackPath) {
|
|
@@ -237784,7 +237767,9 @@ function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaul
|
|
|
237784
237767
|
message: `Error: ${error54}`,
|
|
237785
237768
|
detail: errorDescription || undefined
|
|
237786
237769
|
}));
|
|
237787
|
-
|
|
237770
|
+
finish(() => {
|
|
237771
|
+
reject(new Error(`OAuth error: ${error54} - ${errorDescription || ""}`));
|
|
237772
|
+
});
|
|
237788
237773
|
return;
|
|
237789
237774
|
}
|
|
237790
237775
|
if (!code2 || !state) {
|
|
@@ -237794,7 +237779,9 @@ function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaul
|
|
|
237794
237779
|
title: "Authentication Failed",
|
|
237795
237780
|
message: "Missing authorization code or state parameter."
|
|
237796
237781
|
}));
|
|
237797
|
-
|
|
237782
|
+
finish(() => {
|
|
237783
|
+
reject(new Error("Missing authorization code or state parameter"));
|
|
237784
|
+
});
|
|
237798
237785
|
return;
|
|
237799
237786
|
}
|
|
237800
237787
|
if (state !== expectedState) {
|
|
@@ -237804,7 +237791,9 @@ function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaul
|
|
|
237804
237791
|
title: "Authentication Failed",
|
|
237805
237792
|
message: "State mismatch - the authorization may have been tampered with."
|
|
237806
237793
|
}));
|
|
237807
|
-
|
|
237794
|
+
finish(() => {
|
|
237795
|
+
reject(new Error("State mismatch - the authorization may have been tampered with"));
|
|
237796
|
+
});
|
|
237808
237797
|
return;
|
|
237809
237798
|
}
|
|
237810
237799
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
@@ -237814,7 +237803,9 @@ function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaul
|
|
|
237814
237803
|
message: "You can close this window and return to Letta Code.",
|
|
237815
237804
|
autoClose: true
|
|
237816
237805
|
}));
|
|
237817
|
-
|
|
237806
|
+
finish(() => {
|
|
237807
|
+
resolve29({ result: { code: code2, state }, server });
|
|
237808
|
+
});
|
|
237818
237809
|
} else {
|
|
237819
237810
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
237820
237811
|
res.end("Not found");
|
|
@@ -237822,15 +237813,24 @@ function startLocalOAuthServer2(expectedState, port = OPENAI_OAUTH_CONFIG.defaul
|
|
|
237822
237813
|
});
|
|
237823
237814
|
server.on("error", (err) => {
|
|
237824
237815
|
if (err.code === "EADDRINUSE") {
|
|
237825
|
-
|
|
237816
|
+
finish(() => {
|
|
237817
|
+
reject(new Error(`Port ${port} is already in use. Please close any application using this port and try again.`));
|
|
237818
|
+
});
|
|
237826
237819
|
} else {
|
|
237827
|
-
|
|
237820
|
+
finish(() => {
|
|
237821
|
+
reject(err);
|
|
237822
|
+
});
|
|
237828
237823
|
}
|
|
237829
237824
|
});
|
|
237825
|
+
if (signal) {
|
|
237826
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
237827
|
+
}
|
|
237830
237828
|
server.listen(port, "127.0.0.1", () => {});
|
|
237831
|
-
setTimeout(() => {
|
|
237829
|
+
timeout = setTimeout(() => {
|
|
237832
237830
|
server.close();
|
|
237833
|
-
|
|
237831
|
+
finish(() => {
|
|
237832
|
+
reject(new Error("OAuth timeout - no callback received within 5 minutes"));
|
|
237833
|
+
});
|
|
237834
237834
|
}, 5 * 60 * 1000);
|
|
237835
237835
|
});
|
|
237836
237836
|
}
|
|
@@ -238442,13 +238442,15 @@ Opening browser for authorization...
|
|
|
238442
238442
|
If the browser doesn't open automatically, visit:
|
|
238443
238443
|
|
|
238444
238444
|
${authorizationUrl}`);
|
|
238445
|
-
const serverPromise = mergedDeps.startCallbackServer(state, OPENAI_OAUTH_CONFIG.defaultPort);
|
|
238445
|
+
const serverPromise = mergedDeps.startCallbackServer(state, OPENAI_OAUTH_CONFIG.defaultPort, callbacks.signal);
|
|
238446
238446
|
await browserOpener(authorizationUrl);
|
|
238447
238447
|
await callbacks.onStatus(`Waiting for authorization...
|
|
238448
238448
|
|
|
238449
238449
|
Please complete the sign-in process in your browser.
|
|
238450
238450
|
The page will redirect automatically when done.
|
|
238451
238451
|
|
|
238452
|
+
Press Esc to cancel.
|
|
238453
|
+
|
|
238452
238454
|
If needed, visit:
|
|
238453
238455
|
${authorizationUrl}`);
|
|
238454
238456
|
const { result, server } = await serverPromise;
|
|
@@ -257327,6 +257329,10 @@ function ConstellationLoginView({
|
|
|
257327
257329
|
const startedRef = import_react32.useRef(false);
|
|
257328
257330
|
const cancelledRef = import_react32.useRef(false);
|
|
257329
257331
|
const abortControllerRef = import_react32.useRef(null);
|
|
257332
|
+
const onCompleteRef = import_react32.useRef(onComplete);
|
|
257333
|
+
const onAlreadyLoggedInRef = import_react32.useRef(onAlreadyLoggedIn);
|
|
257334
|
+
onCompleteRef.current = onComplete;
|
|
257335
|
+
onAlreadyLoggedInRef.current = onAlreadyLoggedIn;
|
|
257330
257336
|
use_input_default((input, key2) => {
|
|
257331
257337
|
if (key2.escape || key2.ctrl && input === "c") {
|
|
257332
257338
|
cancelledRef.current = true;
|
|
@@ -257344,7 +257350,7 @@ function ConstellationLoginView({
|
|
|
257344
257350
|
const currentSettings = await settingsManager.getSettingsWithSecureTokens();
|
|
257345
257351
|
const hasApiKey = process.env.LETTA_API_KEY || currentSettings.env?.LETTA_API_KEY;
|
|
257346
257352
|
if (hasApiKey) {
|
|
257347
|
-
|
|
257353
|
+
onAlreadyLoggedInRef.current?.();
|
|
257348
257354
|
return;
|
|
257349
257355
|
}
|
|
257350
257356
|
const deviceData = await requestDeviceCode();
|
|
@@ -257373,7 +257379,7 @@ function ConstellationLoginView({
|
|
|
257373
257379
|
await settingsManager.flush();
|
|
257374
257380
|
configureBackendMode("api");
|
|
257375
257381
|
setDoneMessage("Signed in to Constellation. Switch to a Constellation agent with /agents.");
|
|
257376
|
-
setTimeout(() =>
|
|
257382
|
+
setTimeout(() => onCompleteRef.current?.(), 500);
|
|
257377
257383
|
} catch (err) {
|
|
257378
257384
|
if (cancelledRef.current || err instanceof Error && err.name === "AbortError") {
|
|
257379
257385
|
return;
|
|
@@ -257386,7 +257392,7 @@ function ConstellationLoginView({
|
|
|
257386
257392
|
cancelledRef.current = true;
|
|
257387
257393
|
abortControllerRef.current?.abort();
|
|
257388
257394
|
};
|
|
257389
|
-
}, [
|
|
257395
|
+
}, []);
|
|
257390
257396
|
if (doneMessage) {
|
|
257391
257397
|
return /* @__PURE__ */ jsx_dev_runtime11.jsxDEV(Box_default, {
|
|
257392
257398
|
flexDirection: "column",
|
|
@@ -262711,6 +262717,22 @@ function recordSessionEnd(agentId, sessionId, stats, sessionInfo, cost, metadata
|
|
|
262711
262717
|
}
|
|
262712
262718
|
var init_session_history = () => {};
|
|
262713
262719
|
|
|
262720
|
+
// src/cli/commands/connect-command-state.ts
|
|
262721
|
+
function setActiveConnectAbortController(controller) {
|
|
262722
|
+
activeConnectAbortController = controller;
|
|
262723
|
+
}
|
|
262724
|
+
function isActiveConnectOperationCancellable() {
|
|
262725
|
+
return activeConnectAbortController !== null;
|
|
262726
|
+
}
|
|
262727
|
+
function cancelActiveConnectOperation() {
|
|
262728
|
+
if (!activeConnectAbortController) {
|
|
262729
|
+
return false;
|
|
262730
|
+
}
|
|
262731
|
+
activeConnectAbortController.abort();
|
|
262732
|
+
return true;
|
|
262733
|
+
}
|
|
262734
|
+
var activeConnectAbortController = null;
|
|
262735
|
+
|
|
262714
262736
|
// src/cli/commands/runner.ts
|
|
262715
262737
|
function upsertCommandLine(buffers, id2, input, update2) {
|
|
262716
262738
|
const existing = buffers.byId.get(id2);
|
|
@@ -265216,6 +265238,7 @@ function AgentSelector({
|
|
|
265216
265238
|
currentAgentId,
|
|
265217
265239
|
onSelect,
|
|
265218
265240
|
onCancel,
|
|
265241
|
+
onLogin,
|
|
265219
265242
|
onCreateNewAgent,
|
|
265220
265243
|
command = "/agents"
|
|
265221
265244
|
}) {
|
|
@@ -265236,7 +265259,6 @@ function AgentSelector({
|
|
|
265236
265259
|
}, [activeTab, hasLocalAgents]);
|
|
265237
265260
|
const [pinnedAgents, setPinnedAgents] = import_react41.useState([]);
|
|
265238
265261
|
const [pinnedLoading, setPinnedLoading] = import_react41.useState(true);
|
|
265239
|
-
const [pinnedFallbackAgents, setPinnedFallbackAgents] = import_react41.useState([]);
|
|
265240
265262
|
const [pinnedSelectedIndex, setPinnedSelectedIndex] = import_react41.useState(0);
|
|
265241
265263
|
const [pinnedPage, setPinnedPage] = import_react41.useState(0);
|
|
265242
265264
|
const [localAgents, setLocalAgents] = import_react41.useState([]);
|
|
@@ -265297,25 +265319,16 @@ function AgentSelector({
|
|
|
265297
265319
|
const validPinnedData = pinnedData.filter((p2) => p2.agent !== null);
|
|
265298
265320
|
if (validPinnedData.length === 0) {
|
|
265299
265321
|
setPinnedAgents([]);
|
|
265300
|
-
const recentAgents = await getRecentAgentOptions({
|
|
265301
|
-
includeLocal: true,
|
|
265302
|
-
includeConstellation: hasCloudCredentials(),
|
|
265303
|
-
limit: PINNED_FALLBACK_DISPLAY_SIZE,
|
|
265304
|
-
currentAgentId
|
|
265305
|
-
});
|
|
265306
|
-
setPinnedFallbackAgents(recentAgents.map((item) => ({ ...item, isPinnedFallback: true })));
|
|
265307
265322
|
setPinnedLoading(false);
|
|
265308
265323
|
return;
|
|
265309
265324
|
}
|
|
265310
265325
|
setPinnedAgents(pinnedData);
|
|
265311
|
-
setPinnedFallbackAgents([]);
|
|
265312
265326
|
} catch {
|
|
265313
265327
|
setPinnedAgents([]);
|
|
265314
|
-
setPinnedFallbackAgents([]);
|
|
265315
265328
|
} finally {
|
|
265316
265329
|
setPinnedLoading(false);
|
|
265317
265330
|
}
|
|
265318
|
-
}, [
|
|
265331
|
+
}, []);
|
|
265319
265332
|
const loadLocalAgents = import_react41.useCallback(() => {
|
|
265320
265333
|
setLocalLoading(true);
|
|
265321
265334
|
try {
|
|
@@ -265422,11 +265435,9 @@ function AgentSelector({
|
|
|
265422
265435
|
hasCloudAuth
|
|
265423
265436
|
]);
|
|
265424
265437
|
const validPinnedAgents = pinnedAgents.filter((p2) => p2.agent !== null);
|
|
265425
|
-
const
|
|
265426
|
-
const pinnedTotalPages = Math.ceil((showingPinnedFallback ? pinnedFallbackAgents.length : validPinnedAgents.length) / DISPLAY_PAGE_SIZE2);
|
|
265438
|
+
const pinnedTotalPages = Math.ceil(validPinnedAgents.length / DISPLAY_PAGE_SIZE2);
|
|
265427
265439
|
const pinnedStartIndex = pinnedPage * DISPLAY_PAGE_SIZE2;
|
|
265428
265440
|
const pinnedPageAgents = validPinnedAgents.slice(pinnedStartIndex, pinnedStartIndex + DISPLAY_PAGE_SIZE2);
|
|
265429
|
-
const pinnedFallbackPageAgents = pinnedFallbackAgents.slice(pinnedStartIndex, pinnedStartIndex + DISPLAY_PAGE_SIZE2);
|
|
265430
265441
|
const sortedLocalAgents = import_react41.useMemo(() => localAgents.toSorted((a2, b3) => {
|
|
265431
265442
|
if (a2.id === currentAgentId)
|
|
265432
265443
|
return -1;
|
|
@@ -265443,7 +265454,7 @@ function AgentSelector({
|
|
|
265443
265454
|
const constellationCanGoNext = constellationPage < constellationTotalPages - 1 || constellationHasMore;
|
|
265444
265455
|
const currentLoading = activeTab === "pinned" ? pinnedLoading : activeTab === "local" ? localLoading : constellationLoading;
|
|
265445
265456
|
const currentError = activeTab === "constellation" ? constellationError : null;
|
|
265446
|
-
const currentAgents = activeTab === "pinned" ?
|
|
265457
|
+
const currentAgents = activeTab === "pinned" ? pinnedPageAgents.map((p2) => p2.agent).filter(Boolean) : activeTab === "local" ? localPageAgents : constellationPageAgents;
|
|
265447
265458
|
const setCurrentSelectedIndex = activeTab === "pinned" ? setPinnedSelectedIndex : activeTab === "local" ? setLocalSelectedIndex : setConstellationSelectedIndex;
|
|
265448
265459
|
const submitSearch = import_react41.useCallback(() => {
|
|
265449
265460
|
if (searchInput !== activeQuery) {
|
|
@@ -265532,18 +265543,10 @@ function AgentSelector({
|
|
|
265532
265543
|
return;
|
|
265533
265544
|
}
|
|
265534
265545
|
if (activeTab === "pinned") {
|
|
265535
|
-
|
|
265536
|
-
|
|
265537
|
-
|
|
265538
|
-
|
|
265539
|
-
onSelect(selected.agent.id, mode);
|
|
265540
|
-
}
|
|
265541
|
-
} else {
|
|
265542
|
-
const selected = pinnedPageAgents[pinnedSelectedIndex];
|
|
265543
|
-
if (selected?.agent) {
|
|
265544
|
-
const mode = selected.isLocal ? "local" : "api";
|
|
265545
|
-
onSelect(selected.agentId, mode);
|
|
265546
|
-
}
|
|
265546
|
+
const selected = pinnedPageAgents[pinnedSelectedIndex];
|
|
265547
|
+
if (selected?.agent) {
|
|
265548
|
+
const mode = selected.isLocal ? "local" : "api";
|
|
265549
|
+
onSelect(selected.agentId, mode);
|
|
265547
265550
|
}
|
|
265548
265551
|
} else if (activeTab === "local") {
|
|
265549
265552
|
const selected = localPageAgents[localSelectedIndex];
|
|
@@ -265554,6 +265557,8 @@ function AgentSelector({
|
|
|
265554
265557
|
const selected = constellationPageAgents[constellationSelectedIndex];
|
|
265555
265558
|
if (selected?.id) {
|
|
265556
265559
|
onSelect(selected.id, "api");
|
|
265560
|
+
} else if (hasCloudAuth === false) {
|
|
265561
|
+
onLogin?.();
|
|
265557
265562
|
}
|
|
265558
265563
|
}
|
|
265559
265564
|
} else if (key2.escape) {
|
|
@@ -265606,26 +265611,14 @@ function AgentSelector({
|
|
|
265606
265611
|
}
|
|
265607
265612
|
}
|
|
265608
265613
|
} else if (activeTab === "pinned" && (input === "p" || input === "P")) {
|
|
265609
|
-
|
|
265610
|
-
|
|
265611
|
-
if (selected) {
|
|
265612
|
-
|
|
265613
|
-
|
|
265614
|
-
|
|
265615
|
-
settingsManager.pinGlobal(selected.agent.id);
|
|
265616
|
-
}
|
|
265617
|
-
loadPinnedAgents();
|
|
265618
|
-
}
|
|
265619
|
-
} else {
|
|
265620
|
-
const selected = pinnedPageAgents[pinnedSelectedIndex];
|
|
265621
|
-
if (selected) {
|
|
265622
|
-
if (selected.isLocal) {
|
|
265623
|
-
settingsManager.unpinLocal(selected.agentId);
|
|
265624
|
-
} else {
|
|
265625
|
-
settingsManager.unpinGlobal(selected.agentId);
|
|
265626
|
-
}
|
|
265627
|
-
loadPinnedAgents();
|
|
265614
|
+
const selected = pinnedPageAgents[pinnedSelectedIndex];
|
|
265615
|
+
if (selected) {
|
|
265616
|
+
if (selected.isLocal) {
|
|
265617
|
+
settingsManager.unpinLocal(selected.agentId);
|
|
265618
|
+
} else {
|
|
265619
|
+
settingsManager.unpinGlobal(selected.agentId);
|
|
265628
265620
|
}
|
|
265621
|
+
loadPinnedAgents();
|
|
265629
265622
|
}
|
|
265630
265623
|
} else if (input === "D") {
|
|
265631
265624
|
let selectedAgent = null;
|
|
@@ -265787,10 +265780,25 @@ function AgentSelector({
|
|
|
265787
265780
|
dimColor: true,
|
|
265788
265781
|
children: "Connect to Letta Constellation to see hosted agents here."
|
|
265789
265782
|
}, undefined, false, undefined, this),
|
|
265790
|
-
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(
|
|
265791
|
-
|
|
265792
|
-
|
|
265793
|
-
|
|
265783
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265784
|
+
height: 1
|
|
265785
|
+
}, undefined, false, undefined, this),
|
|
265786
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265787
|
+
flexDirection: "column",
|
|
265788
|
+
children: [
|
|
265789
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text2, {
|
|
265790
|
+
color: colors.selector.itemHighlighted,
|
|
265791
|
+
children: "> /login"
|
|
265792
|
+
}, undefined, false, undefined, this),
|
|
265793
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265794
|
+
paddingLeft: 2,
|
|
265795
|
+
children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text2, {
|
|
265796
|
+
dimColor: true,
|
|
265797
|
+
children: "Sign in to Letta Constellation"
|
|
265798
|
+
}, undefined, false, undefined, this)
|
|
265799
|
+
}, undefined, false, undefined, this)
|
|
265800
|
+
]
|
|
265801
|
+
}, undefined, true, undefined, this)
|
|
265794
265802
|
]
|
|
265795
265803
|
}, undefined, true, undefined, this);
|
|
265796
265804
|
const renderDeleteConfirm = () => {
|
|
@@ -265862,10 +265870,29 @@ function AgentSelector({
|
|
|
265862
265870
|
return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(OverlayShell, {
|
|
265863
265871
|
command,
|
|
265864
265872
|
title: "Swap to a different agent",
|
|
265865
|
-
footer: activeTab !== "new" && !currentLoading && (activeTab === "pinned"
|
|
265873
|
+
footer: activeTab !== "new" && !currentLoading && (activeTab === "pinned" || activeTab === "local" && localAgents.length > 0 || activeTab === "constellation" && !constellationError && constellationAgents.length > 0) ? (() => {
|
|
265866
265874
|
const footerWidth = Math.max(0, terminalWidth - 2);
|
|
265875
|
+
if (activeTab === "pinned" && validPinnedAgents.length === 0) {
|
|
265876
|
+
return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265877
|
+
flexDirection: "row",
|
|
265878
|
+
children: [
|
|
265879
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265880
|
+
width: 2,
|
|
265881
|
+
flexShrink: 0
|
|
265882
|
+
}, undefined, false, undefined, this),
|
|
265883
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265884
|
+
flexGrow: 1,
|
|
265885
|
+
width: footerWidth,
|
|
265886
|
+
children: /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(MarkdownDisplay, {
|
|
265887
|
+
text: "Tab switch · Esc cancel",
|
|
265888
|
+
dimColor: true
|
|
265889
|
+
}, undefined, false, undefined, this)
|
|
265890
|
+
}, undefined, false, undefined, this)
|
|
265891
|
+
]
|
|
265892
|
+
}, undefined, true, undefined, this);
|
|
265893
|
+
}
|
|
265867
265894
|
const pageText = activeTab === "pinned" ? `Page ${pinnedPage + 1}/${pinnedTotalPages || 1}` : activeTab === "local" ? `Page ${localPage + 1}/${localTotalPages || 1}` : `Page ${constellationPage + 1}${constellationHasMore ? "+" : `/${constellationTotalPages || 1}`}${constellationLoadingMore ? " (loading...)" : ""}`;
|
|
265868
|
-
const pinnedHint =
|
|
265895
|
+
const pinnedHint = " · Shift+P unpin";
|
|
265869
265896
|
const hintsText = `Enter select · ↑↓ ←→ navigate · Tab switch · Shift+D delete${activeTab === "pinned" ? pinnedHint : ""} · Esc cancel`;
|
|
265870
265897
|
return /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265871
265898
|
flexDirection: "column",
|
|
@@ -265925,19 +265952,7 @@ function AgentSelector({
|
|
|
265925
265952
|
TAB_DESCRIPTIONS[activeTab]
|
|
265926
265953
|
]
|
|
265927
265954
|
}, undefined, true, undefined, this),
|
|
265928
|
-
|
|
265929
|
-
height: 2
|
|
265930
|
-
}, undefined, false, undefined, this),
|
|
265931
|
-
activeTab === "pinned" && showingPinnedFallback && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text2, {
|
|
265932
|
-
dimColor: true,
|
|
265933
|
-
children: [
|
|
265934
|
-
" ",
|
|
265935
|
-
"No pinned agents yet, showing recent agents instead."
|
|
265936
|
-
]
|
|
265937
|
-
}, undefined, true, undefined, this),
|
|
265938
|
-
activeTab === "pinned" && showingPinnedFallback ? /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265939
|
-
height: 1
|
|
265940
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265955
|
+
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265941
265956
|
height: 2
|
|
265942
265957
|
}, undefined, false, undefined, this)
|
|
265943
265958
|
]
|
|
@@ -265988,26 +266003,21 @@ function AgentSelector({
|
|
|
265988
266003
|
}, undefined, true, undefined, this)
|
|
265989
266004
|
}, undefined, false, undefined, this),
|
|
265990
266005
|
activeTab === "constellation" && !currentLoading && hasCloudAuth === false && renderConstellationUpsell(),
|
|
265991
|
-
!currentLoading && (activeTab === "pinned" && validPinnedAgents.length === 0
|
|
266006
|
+
!currentLoading && (activeTab === "pinned" && validPinnedAgents.length === 0 || activeTab === "local" && localAgents.length === 0 || activeTab === "constellation" && !constellationError && hasCloudAuth && constellationAgents.length === 0) && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
265992
266007
|
flexDirection: "column",
|
|
266008
|
+
paddingLeft: activeTab === "pinned" ? 2 : 0,
|
|
265993
266009
|
children: [
|
|
265994
266010
|
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text2, {
|
|
265995
266011
|
dimColor: true,
|
|
265996
266012
|
children: TAB_EMPTY_STATES[activeTab]
|
|
265997
266013
|
}, undefined, false, undefined, this),
|
|
265998
|
-
/* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text2, {
|
|
266014
|
+
activeTab !== "pinned" && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Text2, {
|
|
265999
266015
|
dimColor: true,
|
|
266000
266016
|
children: "Press ESC to cancel"
|
|
266001
266017
|
}, undefined, false, undefined, this)
|
|
266002
266018
|
]
|
|
266003
266019
|
}, undefined, true, undefined, this),
|
|
266004
|
-
activeTab === "pinned" && !pinnedLoading &&
|
|
266005
|
-
flexDirection: "column",
|
|
266006
|
-
children: pinnedFallbackPageAgents.map((data, index) => renderAgentItem(data.agent, index, index === pinnedSelectedIndex, {
|
|
266007
|
-
backend: data.isLocal ? "local" : "constellation"
|
|
266008
|
-
}))
|
|
266009
|
-
}, undefined, false, undefined, this),
|
|
266010
|
-
activeTab === "pinned" && !pinnedLoading && !showingPinnedFallback && validPinnedAgents.length > 0 && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
266020
|
+
activeTab === "pinned" && !pinnedLoading && validPinnedAgents.length > 0 && /* @__PURE__ */ jsx_dev_runtime17.jsxDEV(Box_default, {
|
|
266011
266021
|
flexDirection: "column",
|
|
266012
266022
|
children: pinnedPageAgents.map((data, index) => renderPinnedItem(data, index, index === pinnedSelectedIndex))
|
|
266013
266023
|
}, undefined, false, undefined, this),
|
|
@@ -266129,12 +266139,11 @@ function AgentSelector({
|
|
|
266129
266139
|
]
|
|
266130
266140
|
}, undefined, true, undefined, this);
|
|
266131
266141
|
}
|
|
266132
|
-
var import_react41, jsx_dev_runtime17, ALL_TABS, TAB_DESCRIPTIONS, TAB_EMPTY_STATES, DISPLAY_PAGE_SIZE2 = 5, FETCH_PAGE_SIZE2 = 20,
|
|
266142
|
+
var import_react41, jsx_dev_runtime17, ALL_TABS, TAB_DESCRIPTIONS, TAB_EMPTY_STATES, DISPLAY_PAGE_SIZE2 = 5, FETCH_PAGE_SIZE2 = 20, NEW_AGENT_DEFAULT_BACKEND = "api";
|
|
266133
266143
|
var init_AgentSelector = __esm(async () => {
|
|
266134
266144
|
init_model();
|
|
266135
266145
|
init_backend();
|
|
266136
266146
|
init_local_agent_listing();
|
|
266137
|
-
init_recent_agent_options();
|
|
266138
266147
|
init_use_terminal_width();
|
|
266139
266148
|
init_constants2();
|
|
266140
266149
|
init_settings_manager();
|
|
@@ -275312,7 +275321,7 @@ var init_AgentInfoBar = __esm(async () => {
|
|
|
275312
275321
|
const isCloudUser = serverUrl?.includes("api.letta.com");
|
|
275313
275322
|
const adeConversationUrl = agentId && agentId !== "loading" ? buildChatUrl(agentId, { conversationId }) : "";
|
|
275314
275323
|
const showBottomBar = agentId && agentId !== "loading";
|
|
275315
|
-
const reasoningLabel = formatReasoningLabel(currentReasoningEffort);
|
|
275324
|
+
const reasoningLabel = shouldHideReasoningForModelDisplay(currentModel) ? null : formatReasoningLabel(currentReasoningEffort);
|
|
275316
275325
|
const modelLine = currentModel ? `${currentModel}${reasoningLabel ? ` (${reasoningLabel})` : ""}` : null;
|
|
275317
275326
|
if (!showBottomBar) {
|
|
275318
275327
|
return null;
|
|
@@ -277083,6 +277092,7 @@ function Input({
|
|
|
277083
277092
|
messageQueue,
|
|
277084
277093
|
onQueueEdit,
|
|
277085
277094
|
onEscapeCancel,
|
|
277095
|
+
onEscapeCommandCancel,
|
|
277086
277096
|
inputDisabled = false,
|
|
277087
277097
|
goalLoopActive = false,
|
|
277088
277098
|
onGoalLoopExit,
|
|
@@ -277097,7 +277107,8 @@ function Input({
|
|
|
277097
277107
|
statusLineRight,
|
|
277098
277108
|
statusLinePrompt,
|
|
277099
277109
|
onCycleReasoningEffort,
|
|
277100
|
-
footerNotification
|
|
277110
|
+
footerNotification,
|
|
277111
|
+
showInspirationalPromptHints = false
|
|
277101
277112
|
}) {
|
|
277102
277113
|
const [value, setValue] = import_react81.useState("");
|
|
277103
277114
|
const [escapePressed, setEscapePressed] = import_react81.useState(false);
|
|
@@ -277106,6 +277117,8 @@ function Input({
|
|
|
277106
277117
|
const ctrlCTimerRef = import_react81.useRef(null);
|
|
277107
277118
|
const previousValueRef = import_react81.useRef(value);
|
|
277108
277119
|
const [currentMode, setCurrentMode] = import_react81.useState(externalMode || permissionMode.getMode());
|
|
277120
|
+
const [emptyPromptHintIndex, setEmptyPromptHintIndex] = import_react81.useState(0);
|
|
277121
|
+
const [emptyPromptHintReady, setEmptyPromptHintReady] = import_react81.useState(false);
|
|
277109
277122
|
const [isAutocompleteActive, setIsAutocompleteActive] = import_react81.useState(false);
|
|
277110
277123
|
const [cursorPos, setCursorPos] = import_react81.useState(undefined);
|
|
277111
277124
|
const [currentCursorPosition, setCurrentCursorPosition] = import_react81.useState(0);
|
|
@@ -277197,6 +277210,28 @@ function Input({
|
|
|
277197
277210
|
onRestoredInputConsumed?.();
|
|
277198
277211
|
}
|
|
277199
277212
|
}, [restoredInput, value, onRestoredInputConsumed]);
|
|
277213
|
+
import_react81.useEffect(() => {
|
|
277214
|
+
if (!showInspirationalPromptHints || value !== "") {
|
|
277215
|
+
setEmptyPromptHintIndex(0);
|
|
277216
|
+
setEmptyPromptHintReady(false);
|
|
277217
|
+
return;
|
|
277218
|
+
}
|
|
277219
|
+
const timer = setTimeout(() => {
|
|
277220
|
+
setEmptyPromptHintReady(true);
|
|
277221
|
+
}, EMPTY_COMPOSER_PROMPT_ROTATION_MS);
|
|
277222
|
+
return () => clearTimeout(timer);
|
|
277223
|
+
}, [showInspirationalPromptHints, value]);
|
|
277224
|
+
import_react81.useEffect(() => {
|
|
277225
|
+
if (!showInspirationalPromptHints || value !== "" || !emptyPromptHintReady) {
|
|
277226
|
+
return;
|
|
277227
|
+
}
|
|
277228
|
+
const timer = setInterval(() => {
|
|
277229
|
+
setEmptyPromptHintIndex((prev) => (prev + 1) % EMPTY_COMPOSER_PROMPT_HINTS.length);
|
|
277230
|
+
}, EMPTY_COMPOSER_PROMPT_ROTATION_MS);
|
|
277231
|
+
return () => clearInterval(timer);
|
|
277232
|
+
}, [showInspirationalPromptHints, value, emptyPromptHintReady]);
|
|
277233
|
+
const inspirationalPlaceholder = showInspirationalPromptHints ? EMPTY_COMPOSER_PROMPT_HINTS[emptyPromptHintIndex] ?? undefined : undefined;
|
|
277234
|
+
const showInspirationalPlaceholder = showInspirationalPromptHints && emptyPromptHintReady && value === "" && !!inspirationalPlaceholder;
|
|
277200
277235
|
const handleBangAtEmpty = import_react81.useCallback(() => {
|
|
277201
277236
|
if (isBashMode)
|
|
277202
277237
|
return false;
|
|
@@ -277251,6 +277286,27 @@ function Input({
|
|
|
277251
277286
|
setIsAutocompleteActive(false);
|
|
277252
277287
|
}
|
|
277253
277288
|
}, [interactionEnabled]);
|
|
277289
|
+
const interactionEnabledRef = import_react81.useRef(interactionEnabled);
|
|
277290
|
+
import_react81.useEffect(() => {
|
|
277291
|
+
interactionEnabledRef.current = interactionEnabled;
|
|
277292
|
+
}, [interactionEnabled]);
|
|
277293
|
+
const onEscapeCommandCancelRef = import_react81.useRef(onEscapeCommandCancel);
|
|
277294
|
+
import_react81.useEffect(() => {
|
|
277295
|
+
onEscapeCommandCancelRef.current = onEscapeCommandCancel;
|
|
277296
|
+
}, [onEscapeCommandCancel]);
|
|
277297
|
+
import_react81.useEffect(() => {
|
|
277298
|
+
const handleRawInput = (data) => {
|
|
277299
|
+
if (!interactionEnabledRef.current)
|
|
277300
|
+
return;
|
|
277301
|
+
if (data.toString("utf8") !== "\x1B")
|
|
277302
|
+
return;
|
|
277303
|
+
onEscapeCommandCancelRef.current?.();
|
|
277304
|
+
};
|
|
277305
|
+
stdin.on("data", handleRawInput);
|
|
277306
|
+
return () => {
|
|
277307
|
+
stdin.off("data", handleRawInput);
|
|
277308
|
+
};
|
|
277309
|
+
}, []);
|
|
277254
277310
|
const settings3 = settingsManager.getSettings();
|
|
277255
277311
|
const serverUrl = process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL;
|
|
277256
277312
|
use_input_default((_input, key2) => {
|
|
@@ -277281,6 +277337,9 @@ function Input({
|
|
|
277281
277337
|
onInterrupt();
|
|
277282
277338
|
return;
|
|
277283
277339
|
}
|
|
277340
|
+
if (onEscapeCommandCancel?.()) {
|
|
277341
|
+
return;
|
|
277342
|
+
}
|
|
277284
277343
|
if (value) {
|
|
277285
277344
|
if (escapePressed) {
|
|
277286
277345
|
setValue("");
|
|
@@ -277632,6 +277691,7 @@ function Input({
|
|
|
277632
277691
|
value,
|
|
277633
277692
|
onChange: setValue,
|
|
277634
277693
|
onSubmit: handleSubmit,
|
|
277694
|
+
placeholder: showInspirationalPlaceholder ? inspirationalPlaceholder : undefined,
|
|
277635
277695
|
cursorPosition: cursorPos,
|
|
277636
277696
|
onCursorMove: setCurrentCursorPosition,
|
|
277637
277697
|
focus: interactionEnabled && !onEscapeCancel,
|
|
@@ -277701,6 +277761,7 @@ function Input({
|
|
|
277701
277761
|
contentWidth,
|
|
277702
277762
|
value,
|
|
277703
277763
|
handleSubmit,
|
|
277764
|
+
showInspirationalPlaceholder,
|
|
277704
277765
|
cursorPos,
|
|
277705
277766
|
onEscapeCancel,
|
|
277706
277767
|
handleBangAtEmpty,
|
|
@@ -277738,7 +277799,8 @@ function Input({
|
|
|
277738
277799
|
suppressDividers,
|
|
277739
277800
|
queueMode,
|
|
277740
277801
|
deferModeSupported,
|
|
277741
|
-
isLocalBackend
|
|
277802
|
+
isLocalBackend,
|
|
277803
|
+
inspirationalPlaceholder
|
|
277742
277804
|
]);
|
|
277743
277805
|
if (!visible) {
|
|
277744
277806
|
return null;
|
|
@@ -277784,7 +277846,7 @@ function formatElapsedLabel(ms) {
|
|
|
277784
277846
|
}
|
|
277785
277847
|
return seconds > 0 ? `${minutes}m ${seconds}s` : `${minutes}m`;
|
|
277786
277848
|
}
|
|
277787
|
-
var import_react81, jsx_dev_runtime56, ESC_CLEAR_WINDOW_MS = 2500, FOOTER_WIDTH_STREAMING_DELTA = 2, COMBINED_STYLE_REGEX, InputFooter, StreamingStatus;
|
|
277849
|
+
var import_react81, jsx_dev_runtime56, ESC_CLEAR_WINDOW_MS = 2500, FOOTER_WIDTH_STREAMING_DELTA = 2, EMPTY_COMPOSER_PROMPT_ROTATION_MS = 6000, EMPTY_COMPOSER_PROMPT_HINTS, COMBINED_STYLE_REGEX, InputFooter, StreamingStatus;
|
|
277788
277850
|
var init_InputRich = __esm(async () => {
|
|
277789
277851
|
init_source2();
|
|
277790
277852
|
init_string_width();
|
|
@@ -277813,6 +277875,13 @@ var init_InputRich = __esm(async () => {
|
|
|
277813
277875
|
]);
|
|
277814
277876
|
import_react81 = __toESM(require_react(), 1);
|
|
277815
277877
|
jsx_dev_runtime56 = __toESM(require_jsx_dev_runtime(), 1);
|
|
277878
|
+
EMPTY_COMPOSER_PROMPT_HINTS = [
|
|
277879
|
+
'Try "help me understand this codebase"',
|
|
277880
|
+
'Try "help me organize my desktop"',
|
|
277881
|
+
'Try "debug this error"',
|
|
277882
|
+
'Try "explain what this function does"',
|
|
277883
|
+
'Try "review this pull request"'
|
|
277884
|
+
];
|
|
277816
277885
|
COMBINED_STYLE_REGEX = /\x1b\[(\d+)(?:;(\d+)(?:;(\d+)(?:;(\d+)(?:;(\d+))?)?)?)?m|\x1b\]8;;([^\x1b]*)\x1b\\([^\x1b]*)\x1b\]8;;\x1b\\/g;
|
|
277817
277886
|
InputFooter = import_react81.memo(function InputFooter2({
|
|
277818
277887
|
ctrlCPressed,
|
|
@@ -277879,7 +277948,7 @@ var init_InputRich = __esm(async () => {
|
|
|
277879
277948
|
});
|
|
277880
277949
|
const maxAgentChars = Math.max(10, Math.floor(rightColumnWidth * 0.45));
|
|
277881
277950
|
const displayAgentName = truncateEnd(agentName || "Unnamed", maxAgentChars);
|
|
277882
|
-
const reasoningTag = getReasoningEffortTag(currentReasoningEffort);
|
|
277951
|
+
const reasoningTag = shouldHideReasoningForModelDisplay(currentModel) ? null : getReasoningEffortTag(currentReasoningEffort);
|
|
277883
277952
|
const byokExtraChars = isByokProvider ? 2 : 0;
|
|
277884
277953
|
const tempOverrideExtraChars = hasTemporaryModelOverride ? 2 : 0;
|
|
277885
277954
|
const baseReservedChars = displayAgentName.length + byokExtraChars + tempOverrideExtraChars + 4;
|
|
@@ -291473,9 +291542,12 @@ Use /disconnect chatgpt (or /disconnect codex) to remove the current connection
|
|
|
291473
291542
|
return;
|
|
291474
291543
|
}
|
|
291475
291544
|
ctx.setCommandRunning(true);
|
|
291545
|
+
const abortController = new AbortController;
|
|
291546
|
+
setActiveConnectAbortController(abortController);
|
|
291476
291547
|
const cmdId = addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, "Checking account eligibility...", true, "running");
|
|
291477
291548
|
try {
|
|
291478
291549
|
await runChatGPTOAuthConnectFlow({
|
|
291550
|
+
signal: abortController.signal,
|
|
291479
291551
|
onStatus: (status) => updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, status, true, "running")
|
|
291480
291552
|
});
|
|
291481
291553
|
updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Successfully connected to ChatGPT!
|
|
@@ -291486,8 +291558,10 @@ Use /disconnect chatgpt (or /disconnect codex) to remove the current connection
|
|
|
291486
291558
|
setTimeout(() => ctx.onCodexConnected?.(), 500);
|
|
291487
291559
|
}
|
|
291488
291560
|
} catch (error54) {
|
|
291489
|
-
|
|
291561
|
+
const isCancelled = error54 instanceof Error && error54.name === "AbortError";
|
|
291562
|
+
updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, isCancelled ? "Cancelled ChatGPT connection." : `✗ Failed to connect: ${getErrorMessage2(error54)}`, false, "finished");
|
|
291490
291563
|
} finally {
|
|
291564
|
+
setActiveConnectAbortController(null);
|
|
291491
291565
|
ctx.setCommandRunning(false);
|
|
291492
291566
|
}
|
|
291493
291567
|
}
|
|
@@ -291758,6 +291832,8 @@ function AppView(props) {
|
|
|
291758
291832
|
handleCtrlD,
|
|
291759
291833
|
feedbackPrefill,
|
|
291760
291834
|
footerUpdateText,
|
|
291835
|
+
showInspirationalPromptHints,
|
|
291836
|
+
onEscapeCommandCancel,
|
|
291761
291837
|
handleAgentSelect,
|
|
291762
291838
|
handleApproveAlways,
|
|
291763
291839
|
handleApproveCurrent,
|
|
@@ -291794,6 +291870,7 @@ function AppView(props) {
|
|
|
291794
291870
|
liveItems,
|
|
291795
291871
|
liveTrajectoryElapsedBaseMs,
|
|
291796
291872
|
loadingState,
|
|
291873
|
+
markLocalModelsAvailable,
|
|
291797
291874
|
maybeCarryOverActiveConversationModel,
|
|
291798
291875
|
modelReasoningPrompt,
|
|
291799
291876
|
modelSelectorOptions,
|
|
@@ -292009,6 +292086,7 @@ function AppView(props) {
|
|
|
292009
292086
|
messageQueue: queueDisplay,
|
|
292010
292087
|
onQueueEdit: handleQueueEdit,
|
|
292011
292088
|
onEscapeCancel: profileConfirmPending ? handleProfileEscapeCancel : undefined,
|
|
292089
|
+
onEscapeCommandCancel,
|
|
292012
292090
|
inputDisabled: btwState.status === "complete",
|
|
292013
292091
|
goalLoopActive: uiGoalLoopActive,
|
|
292014
292092
|
onGoalLoopExit: handleGoalLoopExit,
|
|
@@ -292022,7 +292100,8 @@ function AppView(props) {
|
|
|
292022
292100
|
statusLineText: statusLine.text || undefined,
|
|
292023
292101
|
statusLineRight: statusLine.rightText || undefined,
|
|
292024
292102
|
statusLinePrompt: statusLine.prompt,
|
|
292025
|
-
footerNotification: footerUpdateText
|
|
292103
|
+
footerNotification: footerUpdateText,
|
|
292104
|
+
showInspirationalPromptHints
|
|
292026
292105
|
}, undefined, false, undefined, this)
|
|
292027
292106
|
}, undefined, false, undefined, this),
|
|
292028
292107
|
activeOverlay === "model" && (modelReasoningPrompt ? /* @__PURE__ */ jsx_dev_runtime89.jsxDEV(ModelReasoningSelector, {
|
|
@@ -292138,6 +292217,7 @@ function AppView(props) {
|
|
|
292138
292217
|
refreshDerived,
|
|
292139
292218
|
setCommandRunning,
|
|
292140
292219
|
onCodexConnected: () => {
|
|
292220
|
+
markLocalModelsAvailable();
|
|
292141
292221
|
setModelSelectorOptions({
|
|
292142
292222
|
filterProvider: "chatgpt-plus-pro",
|
|
292143
292223
|
forceRefresh: true
|
|
@@ -292183,6 +292263,10 @@ function AppView(props) {
|
|
|
292183
292263
|
backendMode
|
|
292184
292264
|
});
|
|
292185
292265
|
},
|
|
292266
|
+
onLogin: () => {
|
|
292267
|
+
completeOverlay("resume");
|
|
292268
|
+
openOverlay("login", "/login", "Opening login...", "Login dismissed");
|
|
292269
|
+
},
|
|
292186
292270
|
onCancel: closeOverlay,
|
|
292187
292271
|
onCreateNewAgent: (name, backendMode) => {
|
|
292188
292272
|
const overlayCommand = completeOverlay("resume");
|
|
@@ -293910,6 +293994,7 @@ function useConfigurationHandlers(ctx) {
|
|
|
293910
293994
|
setConversationOverrideModelSettings,
|
|
293911
293995
|
setCurrentModelHandle,
|
|
293912
293996
|
setCurrentModelId,
|
|
293997
|
+
setHasAvailableLocalModels,
|
|
293913
293998
|
setCurrentPersonalityId,
|
|
293914
293999
|
setCurrentSystemPromptId,
|
|
293915
294000
|
setCurrentToolset,
|
|
@@ -294053,6 +294138,7 @@ function useConfigurationHandlers(ctx) {
|
|
|
294053
294138
|
settingsManager.addRecentModel(modelHandle);
|
|
294054
294139
|
resetContextHistory(contextTrackerRef.current);
|
|
294055
294140
|
setCurrentModelHandle(modelHandle);
|
|
294141
|
+
setHasAvailableLocalModels(true);
|
|
294056
294142
|
const persistedToolsetPreference = settingsManager.getToolsetPreference(agentId);
|
|
294057
294143
|
const previousToolsetSnapshot = currentToolset;
|
|
294058
294144
|
const previousToolNamesSnapshot = getToolNames();
|
|
@@ -298133,6 +298219,7 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
|
|
|
298133
298219
|
buffersRef,
|
|
298134
298220
|
commandRunner,
|
|
298135
298221
|
conversationIdRef,
|
|
298222
|
+
markLocalModelsAvailable,
|
|
298136
298223
|
refreshDerived,
|
|
298137
298224
|
setCommandRunning,
|
|
298138
298225
|
setModelSelectorOptions,
|
|
@@ -298208,6 +298295,7 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
|
|
|
298208
298295
|
refreshDerived,
|
|
298209
298296
|
setCommandRunning,
|
|
298210
298297
|
onCodexConnected: () => {
|
|
298298
|
+
markLocalModelsAvailable();
|
|
298211
298299
|
setModelSelectorOptions({
|
|
298212
298300
|
filterProvider: "chatgpt-plus-pro",
|
|
298213
298301
|
forceRefresh: true
|
|
@@ -299786,6 +299874,7 @@ function useSubmitHandler(ctx) {
|
|
|
299786
299874
|
setHasConversationModelOverride,
|
|
299787
299875
|
setLines,
|
|
299788
299876
|
setLlmConfig,
|
|
299877
|
+
markLocalModelsAvailable,
|
|
299789
299878
|
setModelSelectorOptions,
|
|
299790
299879
|
setNeedsEagerApprovalCheck,
|
|
299791
299880
|
setPinDialogLocal,
|
|
@@ -300071,6 +300160,7 @@ ${SYSTEM_REMINDER_CLOSE}` : "";
|
|
|
300071
300160
|
refreshDerived,
|
|
300072
300161
|
openOverlay,
|
|
300073
300162
|
setCommandRunning,
|
|
300163
|
+
markLocalModelsAvailable,
|
|
300074
300164
|
setModelSelectorOptions
|
|
300075
300165
|
});
|
|
300076
300166
|
if (connectionCommandResult) {
|
|
@@ -301773,6 +301863,22 @@ function buildStartupCommandHints(options3) {
|
|
|
301773
301863
|
}
|
|
301774
301864
|
return dedupedHints;
|
|
301775
301865
|
}
|
|
301866
|
+
function hasConversationContent(lines) {
|
|
301867
|
+
return lines.some((line) => {
|
|
301868
|
+
switch (line.kind) {
|
|
301869
|
+
case "user":
|
|
301870
|
+
case "assistant":
|
|
301871
|
+
case "reasoning":
|
|
301872
|
+
case "tool_call":
|
|
301873
|
+
case "error":
|
|
301874
|
+
case "command":
|
|
301875
|
+
case "bash_command":
|
|
301876
|
+
return true;
|
|
301877
|
+
default:
|
|
301878
|
+
return false;
|
|
301879
|
+
}
|
|
301880
|
+
});
|
|
301881
|
+
}
|
|
301776
301882
|
function App2({
|
|
301777
301883
|
agentId: initialAgentId,
|
|
301778
301884
|
agentState: initialAgentState,
|
|
@@ -301797,6 +301903,10 @@ function App2({
|
|
|
301797
301903
|
import_react118.useEffect(() => {
|
|
301798
301904
|
prefetchAvailableModelHandles();
|
|
301799
301905
|
}, []);
|
|
301906
|
+
const [hasAvailableLocalModels, setHasAvailableLocalModels] = import_react118.useState(startupHasAvailableLocalModels);
|
|
301907
|
+
const markLocalModelsAvailable = import_react118.useCallback(() => {
|
|
301908
|
+
setHasAvailableLocalModels(true);
|
|
301909
|
+
}, []);
|
|
301800
301910
|
const [agentId, setAgentId] = import_react118.useState(initialAgentId);
|
|
301801
301911
|
const [agentState, setAgentState] = import_react118.useState(initialAgentState);
|
|
301802
301912
|
const updateAgentName = import_react118.useCallback((name) => {
|
|
@@ -302061,8 +302171,7 @@ function App2({
|
|
|
302061
302171
|
const derivedReasoningEffort = deriveReasoningEffort(effectiveModelSettings, llmConfig);
|
|
302062
302172
|
const startupModelDisplayOverride = getStartupModelDisplayOverride({
|
|
302063
302173
|
isLocalBackend: isLocalBackendEnabled(),
|
|
302064
|
-
startupHasAvailableLocalModels
|
|
302065
|
-
agentProvenance
|
|
302174
|
+
startupHasAvailableLocalModels: hasAvailableLocalModels
|
|
302066
302175
|
});
|
|
302067
302176
|
const currentModelDisplay = import_react118.useMemo(() => {
|
|
302068
302177
|
if (startupModelDisplayOverride)
|
|
@@ -303223,7 +303332,6 @@ function App2({
|
|
|
303223
303332
|
snapshot: {
|
|
303224
303333
|
continueSession,
|
|
303225
303334
|
agentState,
|
|
303226
|
-
agentProvenance,
|
|
303227
303335
|
startupHasAvailableLocalModels,
|
|
303228
303336
|
terminalWidth: columns
|
|
303229
303337
|
}
|
|
@@ -303274,7 +303382,6 @@ function App2({
|
|
|
303274
303382
|
continueSession,
|
|
303275
303383
|
columns,
|
|
303276
303384
|
agentState,
|
|
303277
|
-
agentProvenance,
|
|
303278
303385
|
resumedExistingConversation,
|
|
303279
303386
|
releaseNotes,
|
|
303280
303387
|
startupHasCloudCredentials,
|
|
@@ -304037,6 +304144,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
304037
304144
|
setHasConversationModelOverride,
|
|
304038
304145
|
setLines,
|
|
304039
304146
|
setLlmConfig,
|
|
304147
|
+
markLocalModelsAvailable,
|
|
304040
304148
|
setModelSelectorOptions,
|
|
304041
304149
|
setNeedsEagerApprovalCheck,
|
|
304042
304150
|
setPinDialogLocal,
|
|
@@ -304157,6 +304265,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
304157
304265
|
setConversationOverrideModelSettings,
|
|
304158
304266
|
setCurrentModelHandle,
|
|
304159
304267
|
setCurrentModelId,
|
|
304268
|
+
setHasAvailableLocalModels,
|
|
304160
304269
|
setCurrentPersonalityId,
|
|
304161
304270
|
setCurrentSystemPromptId,
|
|
304162
304271
|
setCurrentToolset,
|
|
@@ -304428,7 +304537,6 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
304428
304537
|
snapshot: {
|
|
304429
304538
|
continueSession,
|
|
304430
304539
|
agentState,
|
|
304431
|
-
agentProvenance,
|
|
304432
304540
|
startupHasAvailableLocalModels,
|
|
304433
304541
|
terminalWidth: columns
|
|
304434
304542
|
}
|
|
@@ -304487,6 +304595,14 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
304487
304595
|
const trajectoryTokenDisplay = Math.max(liveTrajectoryTokenBase + runTokenDelta, trajectoryTokenDisplayRef.current);
|
|
304488
304596
|
const inputVisible = !showExitStats;
|
|
304489
304597
|
const inputEnabled = !showExitStats && pendingApprovals.length === 0 && !anySelectorOpen;
|
|
304598
|
+
const onEscapeCommandCancel = import_react118.useCallback(() => {
|
|
304599
|
+
if (isActiveConnectOperationCancellable()) {
|
|
304600
|
+
cancelActiveConnectOperation();
|
|
304601
|
+
return true;
|
|
304602
|
+
}
|
|
304603
|
+
return false;
|
|
304604
|
+
}, []);
|
|
304605
|
+
const showInspirationalPromptHints = loadingState === "ready" && !hasConversationContent(lines) && !streaming3 && queueDisplay.length === 0 && pendingApprovals.length === 0 && !anySelectorOpen;
|
|
304490
304606
|
const currentApprovalPreviewCommitted = currentApproval?.toolCallId ? eagerCommittedPreviewsRef.current.has(currentApproval.toolCallId) : false;
|
|
304491
304607
|
const showApprovalPreview = !currentApprovalShouldCommitPreview && !currentApprovalPreviewCommitted;
|
|
304492
304608
|
import_react118.useEffect(() => {
|
|
@@ -304534,6 +304650,8 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
304534
304650
|
emittedIdsRef,
|
|
304535
304651
|
feedbackPrefill,
|
|
304536
304652
|
footerUpdateText,
|
|
304653
|
+
showInspirationalPromptHints,
|
|
304654
|
+
onEscapeCommandCancel,
|
|
304537
304655
|
handleAgentSelect,
|
|
304538
304656
|
handleApproveAlways,
|
|
304539
304657
|
handleApproveCurrent,
|
|
@@ -304570,6 +304688,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
|
|
|
304570
304688
|
liveItems,
|
|
304571
304689
|
liveTrajectoryElapsedBaseMs,
|
|
304572
304690
|
loadingState,
|
|
304691
|
+
markLocalModelsAvailable,
|
|
304573
304692
|
maybeCarryOverActiveConversationModel,
|
|
304574
304693
|
modelReasoningPrompt,
|
|
304575
304694
|
modelSelectorOptions,
|
|
@@ -309442,15 +309561,67 @@ async function initTerminalTheme() {
|
|
|
309442
309561
|
|
|
309443
309562
|
// src/cli/profile-selection.tsx
|
|
309444
309563
|
init_backend2();
|
|
309445
|
-
|
|
309564
|
+
await init_build4();
|
|
309565
|
+
var import_react27 = __toESM(require_react(), 1);
|
|
309566
|
+
|
|
309567
|
+
// src/cli/helpers/recent-agent-options.ts
|
|
309568
|
+
init_client2();
|
|
309569
|
+
init_local_agent_listing();
|
|
309570
|
+
init_settings_manager();
|
|
309571
|
+
function sortRecentAgents(agents, currentAgentId) {
|
|
309572
|
+
return agents.toSorted((a2, b3) => {
|
|
309573
|
+
if (currentAgentId) {
|
|
309574
|
+
if (a2.agent.id === currentAgentId)
|
|
309575
|
+
return -1;
|
|
309576
|
+
if (b3.agent.id === currentAgentId)
|
|
309577
|
+
return 1;
|
|
309578
|
+
}
|
|
309579
|
+
const aTime = a2.agent.last_run_completion ? new Date(a2.agent.last_run_completion).getTime() : 0;
|
|
309580
|
+
const bTime = b3.agent.last_run_completion ? new Date(b3.agent.last_run_completion).getTime() : 0;
|
|
309581
|
+
return bTime - aTime;
|
|
309582
|
+
});
|
|
309583
|
+
}
|
|
309584
|
+
function shouldIncludeConstellationRecentAgents(includeConstellation, settings3) {
|
|
309585
|
+
return Boolean(includeConstellation && (settings3.refreshToken || settings3.env?.LETTA_API_KEY));
|
|
309586
|
+
}
|
|
309587
|
+
async function getRecentAgentOptions(options3) {
|
|
309588
|
+
const includeLocal = options3?.includeLocal !== false;
|
|
309589
|
+
const includeConstellation = options3?.includeConstellation !== false;
|
|
309590
|
+
const limit3 = options3?.limit ?? 5;
|
|
309591
|
+
const settings3 = includeConstellation ? await settingsManager.getSettingsWithSecureTokens() : null;
|
|
309592
|
+
const shouldIncludeConstellation = settings3 !== null ? shouldIncludeConstellationRecentAgents(includeConstellation, settings3) : false;
|
|
309593
|
+
const localAgents = includeLocal ? listLocalAgentsFromDisk().map((agent2) => ({ agent: agent2, isLocal: true })) : [];
|
|
309594
|
+
const constellationAgents = shouldIncludeConstellation ? await (async () => {
|
|
309595
|
+
try {
|
|
309596
|
+
const client = await getClient();
|
|
309597
|
+
const result = await client.agents.list({
|
|
309598
|
+
limit: limit3,
|
|
309599
|
+
include: ["agent.blocks"],
|
|
309600
|
+
order: "desc",
|
|
309601
|
+
order_by: "last_run_completion"
|
|
309602
|
+
});
|
|
309603
|
+
return result.items.map((agent2) => ({ agent: agent2, isLocal: false }));
|
|
309604
|
+
} catch {
|
|
309605
|
+
return [];
|
|
309606
|
+
}
|
|
309607
|
+
})() : [];
|
|
309608
|
+
const seen = new Set;
|
|
309609
|
+
const deduped = sortRecentAgents([...localAgents, ...constellationAgents].filter((item) => {
|
|
309610
|
+
if (seen.has(item.agent.id))
|
|
309611
|
+
return false;
|
|
309612
|
+
seen.add(item.agent.id);
|
|
309613
|
+
return true;
|
|
309614
|
+
}), options3?.currentAgentId);
|
|
309615
|
+
return deduped.slice(0, limit3);
|
|
309616
|
+
}
|
|
309617
|
+
|
|
309618
|
+
// src/cli/profile-selection.tsx
|
|
309446
309619
|
init_settings_manager();
|
|
309447
309620
|
init_colors();
|
|
309448
309621
|
await __promiseAll([
|
|
309449
|
-
init_build4(),
|
|
309450
309622
|
init_Text2(),
|
|
309451
309623
|
init_WelcomeScreen()
|
|
309452
309624
|
]);
|
|
309453
|
-
var import_react27 = __toESM(require_react(), 1);
|
|
309454
309625
|
var jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
|
|
309455
309626
|
var MAX_DISPLAY = 3;
|
|
309456
309627
|
var RECENT_FALLBACK_DISPLAY = 2;
|
|
@@ -309658,8 +309829,7 @@ function ProfileSelectionUI({
|
|
|
309658
309829
|
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(WelcomeScreen, {
|
|
309659
309830
|
loadingState: loading ? "loading_profiles" : "ready",
|
|
309660
309831
|
continueSession: false,
|
|
309661
|
-
agentState: null
|
|
309662
|
-
agentProvenance: null
|
|
309832
|
+
agentState: null
|
|
309663
309833
|
}, undefined, false, undefined, this),
|
|
309664
309834
|
/* @__PURE__ */ jsx_dev_runtime8.jsxDEV(Box_default, {
|
|
309665
309835
|
height: 1
|
|
@@ -309903,6 +310073,13 @@ function ProfileSelectionInline({
|
|
|
309903
310073
|
});
|
|
309904
310074
|
}
|
|
309905
310075
|
|
|
310076
|
+
// src/cli/startup-backend-mode.ts
|
|
310077
|
+
function inferBackendModeFromAgentId(agentId) {
|
|
310078
|
+
if (!agentId)
|
|
310079
|
+
return;
|
|
310080
|
+
return isLocalAgentId2(agentId) ? "local" : "api";
|
|
310081
|
+
}
|
|
310082
|
+
|
|
309906
310083
|
// src/cli/startup-flag-validation.ts
|
|
309907
310084
|
function validateFlagConflicts(options3) {
|
|
309908
310085
|
const { guard, checks: checks4 } = options3;
|
|
@@ -315889,6 +316066,10 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
315889
316066
|
process.exit(1);
|
|
315890
316067
|
}
|
|
315891
316068
|
const specifiedAgentName = values2.name ?? null;
|
|
316069
|
+
const inferredBackendModeFromAgentId = inferBackendModeFromAgentId(specifiedAgentId);
|
|
316070
|
+
if (!explicitBackendMode && inferredBackendModeFromAgentId) {
|
|
316071
|
+
configureBackendMode(inferredBackendModeFromAgentId);
|
|
316072
|
+
}
|
|
315892
316073
|
const specifiedModel = values2.model ?? undefined;
|
|
315893
316074
|
const systemPromptPreset = values2.system ?? undefined;
|
|
315894
316075
|
const systemCustom = values2["system-custom"] ?? undefined;
|
|
@@ -315921,10 +316102,10 @@ Note: Flags should use double dashes for full names (e.g., --yolo, not -yolo)`);
|
|
|
315921
316102
|
const isHeadless = values2.prompt || values2.run || !process.stdin.isTTY;
|
|
315922
316103
|
let apiKey = process.env.LETTA_API_KEY || settings3.env?.LETTA_API_KEY;
|
|
315923
316104
|
const baseURL = process.env.LETTA_BASE_URL || settings3.env?.LETTA_BASE_URL || LETTA_CLOUD_API_URL2;
|
|
315924
|
-
if (!explicitBackendMode && settings3.preferredBackendMode === "local" && baseURL === LETTA_CLOUD_API_URL2) {
|
|
316105
|
+
if (!explicitBackendMode && !inferredBackendModeFromAgentId && settings3.preferredBackendMode === "local" && baseURL === LETTA_CLOUD_API_URL2) {
|
|
315925
316106
|
configureBackendMode("local");
|
|
315926
316107
|
}
|
|
315927
|
-
if (!explicitBackendMode && !isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !settings3.refreshToken && !apiKey) {
|
|
316108
|
+
if (!explicitBackendMode && !inferredBackendModeFromAgentId && !isHeadless && baseURL === LETTA_CLOUD_API_URL2 && !settings3.refreshToken && !apiKey) {
|
|
315928
316109
|
configureBackendMode("local");
|
|
315929
316110
|
settingsManager2.updateSettings({ preferredBackendMode: "local" });
|
|
315930
316111
|
await settingsManager2.flush();
|
|
@@ -317079,4 +317260,4 @@ Error during initialization: ${message}`);
|
|
|
317079
317260
|
}
|
|
317080
317261
|
main();
|
|
317081
317262
|
|
|
317082
|
-
//# debugId=
|
|
317263
|
+
//# debugId=AAE13B069E013B1E64756E2164756E21
|
package/package.json
CHANGED