diff --git a/package-lock.json b/package-lock.json
index 2d07a0b..d0d3a0a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@letta-ai/letta-code",
- "version": "0.19.4",
+ "version": "0.19.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@letta-ai/letta-code",
- "version": "0.19.4",
+ "version": "0.19.5",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
diff --git a/package.json b/package.json
index f4b04a3..dffbe95 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@letta-ai/letta-code",
- "version": "0.19.4",
+ "version": "0.19.5",
"description": "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
"type": "module",
"bin": {
@@ -68,7 +68,7 @@
"fix": "bunx --bun @biomejs/biome@2.2.5 check --write src",
"typecheck": "tsc --noEmit",
"check": "bun run scripts/check.js",
- "dev": "LETTA_DEBUG=1 bun --loader:.md=text --loader:.mdx=text --loader:.txt=text run src/index.ts",
+ "dev": "LETTA_DEBUG=${LETTA_DEBUG:-1} bun --loader:.md=text --loader:.mdx=text --loader:.txt=text run src/index.ts",
"build": "node scripts/postinstall-patches.js && bun run build.js",
"test:update-chain:manual": "bun run src/tests/update-chain-smoke.ts --mode manual",
"test:update-chain:startup": "bun run src/tests/update-chain-smoke.ts --mode startup",
diff --git a/src/cli/App.tsx b/src/cli/App.tsx
index ca49d3e..23f0776 100644
--- a/src/cli/App.tsx
+++ b/src/cli/App.tsx
@@ -8130,10 +8130,14 @@ export default function App({
}
// Special handling for /new command - start new conversation
- if (msg.trim() === "/new") {
+ const newMatch = msg.trim().match(/^\/new(?:\s+(.+))?$/);
+ if (newMatch) {
+ const conversationName = newMatch[1]?.trim();
const cmd = commandRunner.start(
msg.trim(),
- "Starting new conversation...",
+ conversationName
+ ? `Starting new conversation: ${conversationName}...`
+ : "Starting new conversation...",
);
// New conversations should not inherit pending reasoning-tier debounce.
@@ -8150,8 +8154,14 @@ export default function App({
const conversation = await client.conversations.create({
agent_id: agentId,
isolated_block_labels: [...ISOLATED_BLOCK_LABELS],
+ ...(conversationName && { summary: conversationName }),
});
+ // If we created the conversation with an explicit summary, mark it as set
+ // to prevent auto-summary from first user message overwriting it
+ if (conversationName) {
+ hasSetConversationSummaryRef.current = true;
+ }
await maybeCarryOverActiveConversationModel(conversation.id);
// Update conversationId state
@@ -13939,6 +13949,11 @@ If using apply_patch, use this exact relative patch path: ${applyPatchRelativePa
messageHistory: resumeData.messageHistory,
};
+ // If the conversation already has a summary, prevent auto-summary from overwriting it
+ if (selectorContext?.summary) {
+ hasSetConversationSummaryRef.current = true;
+ }
+
settingsManager.setLocalLastSession(
{ agentId, conversationId: convId },
process.cwd(),
diff --git a/src/cli/components/ConversationSelector.tsx b/src/cli/components/ConversationSelector.tsx
index 6a5fab7..3f92e1e 100644
--- a/src/cli/components/ConversationSelector.tsx
+++ b/src/cli/components/ConversationSelector.tsx
@@ -441,20 +441,6 @@ export function ConversationSelector({
const bracket = {"⎿ "};
const indent = " "; // Same width as "⎿ " for alignment
- // Priority 1: Summary
- if (conv.summary) {
- return (
-
- {bracket}
-
- {conv.summary.length > 57
- ? `${conv.summary.slice(0, 54)}...`
- : conv.summary}
-
-
- );
- }
-
// Priority 2: Preview lines with emoji prefixes
if (previewLines.length > 0) {
return (
@@ -516,9 +502,15 @@ export function ConversationSelector({
bold={isSelected}
color={isSelected ? colors.selector.itemHighlighted : undefined}
>
- {isDefault ? "default" : conv.id}
+ {conv.summary
+ ? `${conv.summary.length > 40 ? `${conv.summary.slice(0, 37)}...` : conv.summary} (${conv.id})`
+ : isDefault
+ ? "default"
+ : conv.id}
- {isDefault && (agent's default conversation)}
+ {!conv.summary && isDefault && (
+ (agent's default conversation)
+ )}
{isCurrent && (
(current)
)}
diff --git a/src/cli/components/MessageSearch.tsx b/src/cli/components/MessageSearch.tsx
index cb0405c..acc720c 100644
--- a/src/cli/components/MessageSearch.tsx
+++ b/src/cli/components/MessageSearch.tsx
@@ -116,7 +116,7 @@ export function MessageSearch({
const [searchInput, setSearchInput] = useState(initialQuery ?? "");
const [activeQuery, setActiveQuery] = useState(initialQuery ?? "");
const [searchMode, setSearchMode] = useState("hybrid");
- const [searchRange, setSearchRange] = useState("all");
+ const [searchRange, setSearchRange] = useState("agent");
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
diff --git a/src/models.json b/src/models.json
index c39a1d5..9de2ad9 100644
--- a/src/models.json
+++ b/src/models.json
@@ -1468,12 +1468,24 @@
"parallel_tool_calls": true
}
},
+ {
+ "id": "minimax-m2.7",
+ "handle": "minimax/MiniMax-M2.7",
+ "label": "MiniMax 2.7",
+ "description": "MiniMax's latest coding model",
+ "isFeatured": true,
+ "free": true,
+ "updateArgs": {
+ "context_window": 160000,
+ "max_output_tokens": 64000,
+ "parallel_tool_calls": true
+ }
+ },
{
"id": "minimax-m2.5",
"handle": "minimax/MiniMax-M2.5",
"label": "MiniMax 2.5",
- "description": "MiniMax's latest coding model",
- "isFeatured": true,
+ "description": "MiniMax's latest coding model (legacy)",
"free": true,
"updateArgs": {
"context_window": 160000,
diff --git a/src/tests/agent/model-preset-refresh.wiring.test.ts b/src/tests/agent/model-preset-refresh.wiring.test.ts
index 6d5d011..58c4459 100644
--- a/src/tests/agent/model-preset-refresh.wiring.test.ts
+++ b/src/tests/agent/model-preset-refresh.wiring.test.ts
@@ -153,8 +153,9 @@ describe("model preset refresh wiring", () => {
) ?? [];
expect(carryOverCalls.length).toBeGreaterThanOrEqual(3);
- const newCmdAnchor = source.indexOf('if (msg.trim() === "/new")');
- expect(newCmdAnchor).toBeGreaterThanOrEqual(0);
+ const newCmdAnchor = source.indexOf(
+ "const newMatch = msg.trim().match(/^\\/new(?:\\s+(.+))?$/);",
+ );
const newCmdWindow = source.slice(newCmdAnchor, newCmdAnchor + 1800);
expect(newCmdWindow).toContain(
"await maybeCarryOverActiveConversationModel(conversation.id);",
diff --git a/src/tests/cli/bootstrap-reminders-reset-wiring.test.ts b/src/tests/cli/bootstrap-reminders-reset-wiring.test.ts
index 3f79bdd..2f8ef3c 100644
--- a/src/tests/cli/bootstrap-reminders-reset-wiring.test.ts
+++ b/src/tests/cli/bootstrap-reminders-reset-wiring.test.ts
@@ -29,7 +29,7 @@ describe("bootstrap reminder reset wiring", () => {
const anchors = [
'origin: "agent-switch"',
'const inputCmd = "/new";', // new-agent creation flow
- 'if (msg.trim() === "/new")',
+ "const newMatch = msg.trim().match(/^\\/new(?:\\s+(.+))?$/);",
'if (msg.trim() === "/clear")',
'origin: "resume-direct"',
'if (action.type === "switch_conversation")', // queued conversation switch flow