Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions migrations/sqlite-drizzle/0020_pin_session_name.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `agent_session` ADD `is_name_manually_edited` integer DEFAULT false NOT NULL;
7 changes: 7 additions & 0 deletions migrations/sqlite-drizzle/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@
"when": 1777636561235,
"tag": "0019_parallel_annihilus",
"breakpoints": true
},
{
"idx": 20,
"version": "6",
"when": 1778064000000,
"tag": "0020_pin_session_name",
"breakpoints": true
}
],
"version": "7"
Expand Down
4 changes: 3 additions & 1 deletion packages/shared/data/api/schemas/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ export const AGENT_MUTABLE_FIELDS = {
/** Pick-set for session mutable fields — superset of AGENT_MUTABLE_FIELDS. */
export const SESSION_MUTABLE_FIELDS = {
...AGENT_MUTABLE_FIELDS,
slashCommands: true
slashCommands: true,
isNameManuallyEdited: true
} as const

export const AgentEntitySchema = AgentBaseSchema.extend({
Expand All @@ -152,6 +153,7 @@ export const AgentSessionEntitySchema = AgentBaseSchema.extend({
agentId: z.string(),
agentType: z.enum(['claude-code']),
slashCommands: z.array(SlashCommandSchema).optional(),
isNameManuallyEdited: z.boolean().optional(),
createdAt: z.string(),
updatedAt: z.string()
})
Expand Down
1 change: 1 addition & 0 deletions src/main/data/db/schemas/agentSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const agentSessionTable = sqliteTable(
allowedTools: text({ mode: 'json' }).$type<string[]>().notNull().default(sql`'[]'`),
slashCommands: text({ mode: 'json' }).$type<SlashCommand[]>().notNull().default(sql`'[]'`),
configuration: text({ mode: 'json' }).$type<AgentConfiguration>().notNull().default(sql`'{}'`),
isNameManuallyEdited: integer({ mode: 'boolean' }).notNull().default(false),
sortOrder: integer().notNull().default(0),
...createUpdateTimestamps
},
Expand Down
1 change: 1 addition & 0 deletions src/main/data/services/AgentSessionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ function rowToSession(row: SessionRow): AgentSessionEntity {
agentType: (row.agentType === 'cherry-claw' ? 'claude-code' : row.agentType) as AgentType,
accessiblePaths: row.accessiblePaths,
configuration: parseConfiguration(row.configuration),
isNameManuallyEdited: row.isNameManuallyEdited,
createdAt: timestampToISO(row.createdAt),
updatedAt: timestampToISO(row.updatedAt)
}
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/en-us.json
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@
"move_to": "Move to",
"new": "New Topic",
"pin": "Pin Topic",
"pin_name": "Pin Name",
"prompt": {
"edit": {
"title": "Edit Topic Prompts"
Expand All @@ -1495,7 +1496,8 @@
"title": "Search"
},
"title": "Topics",
"unpin": "Unpin Topic"
"unpin": "Unpin Topic",
"unpin_name": "Unpin Name"
},
"translate": "Translate",
"user": "User",
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@
"move_to": "移动到",
"new": "开始新对话",
"pin": "固定话题",
"pin_name": "固定名称",
"prompt": {
"edit": {
"title": "编辑话题提示词"
Expand All @@ -1495,7 +1496,8 @@
"title": "搜索"
},
"title": "话题",
"unpin": "取消固定"
"unpin": "取消固定",
"unpin_name": "取消固定名称"
},
"translate": "翻译",
"user": "用户",
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@
"move_to": "移動到",
"new": "開始新對話",
"pin": "固定話題",
"pin_name": "固定名稱",
"prompt": {
"edit": {
"title": "編輯話題提示詞"
Expand All @@ -1495,7 +1496,8 @@
"title": "搜尋"
},
"title": "話題",
"unpin": "取消固定"
"unpin": "取消固定",
"unpin_name": "取消固定名稱"
},
"translate": "翻譯",
"user": "使用者",
Expand Down
27 changes: 24 additions & 3 deletions src/renderer/src/pages/agents/components/SessionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { getChannelTypeIcon } from '@renderer/utils/agentSession'
import { buildAgentSessionTopicId } from '@renderer/utils/agentSession'
import type { MenuProps } from 'antd'
import { Dropdown } from 'antd'
import { MenuIcon, Sparkles, XIcon } from 'lucide-react'
import { MenuIcon, PinIcon, PinOffIcon, Sparkles, XIcon } from 'lucide-react'
import React, { memo, startTransition, useDeferredValue, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
Expand Down Expand Up @@ -49,7 +49,7 @@ const SessionItem = ({ session, agentId, channelType, onDelete, onPress }: Sessi
const { isEditing, isSaving, startEdit, inputProps } = useInPlaceEdit({
onSave: async (value) => {
if (value !== session.name) {
await updateSession({ id: session.id, name: value })
await updateSession({ id: session.id, name: value, isNameManuallyEdited: true })
}
}
})
Expand Down Expand Up @@ -151,6 +151,14 @@ const SessionItem = ({ session, agentId, channelType, onDelete, onPress }: Sessi
}
}
},
{
label: session.isNameManuallyEdited ? t('chat.topics.unpin_name') : t('chat.topics.pin_name'),
key: 'pin-name',
icon: session.isNameManuallyEdited ? <PinOffIcon size={14} /> : <PinIcon size={14} />,
onClick: async () => {
await updateSession({ id: session.id, isNameManuallyEdited: !session.isNameManuallyEdited })
}
},
{
label: t('settings.topic.position.label'),
key: 'topic-position',
Expand Down Expand Up @@ -178,7 +186,17 @@ const SessionItem = ({ session, agentId, channelType, onDelete, onPress }: Sessi
}
}
],
[agentId, dispatch, onDelete, session.id, sessionTopicId, setTopicPosition, t, targetSession.id]
[
agentId,
dispatch,
onDelete,
session.id,
session.isNameManuallyEdited,
sessionTopicId,
setTopicPosition,
t,
targetSession.id
]
)

return (
Expand All @@ -203,6 +221,9 @@ const SessionItem = ({ session, agentId, channelType, onDelete, onPress }: Sessi
<SessionEditInput {...inputProps} style={{ opacity: isSaving ? 0.5 : 1 }} />
) : (
<>
{session.isNameManuallyEdited && (
<PinIcon size={10} color="var(--color-text-3)" style={{ minWidth: 10, flexShrink: 0 }} />
)}
<SessionName>
{channelIcon && <ChannelIconImg src={channelIcon} />}
<MarqueeText className="flex min-w-0 flex-1">
Expand Down
41 changes: 28 additions & 13 deletions src/renderer/src/pages/home/Tabs/components/Topics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ export const Topics: React.FC<Props> = ({ assistant: _assistant, activeTopic, se
}
}
},
{
label: topic.isNameManuallyEdited ? t('chat.topics.unpin_name') : t('chat.topics.pin_name'),
key: 'pin-name',
icon: topic.isNameManuallyEdited ? <PinOffIcon size={14} /> : <PinIcon size={14} />,
disabled: isRenaming(topic.id),
onClick() {
const updatedTopic = { ...topic, isNameManuallyEdited: !topic.isNameManuallyEdited }
updateTopic(updatedTopic)
}
},
{
label: t('chat.topics.prompt.label'),
key: 'topic-prompt',
Expand Down Expand Up @@ -661,19 +671,24 @@ export const Topics: React.FC<Props> = ({ assistant: _assistant, activeTopic, se
{editingTopicId === topic.id && isEditing ? (
<TopicEditInput {...inputProps} onClick={(e) => e.stopPropagation()} />
) : (
<TopicName
className={getTopicNameClassName()}
title={topicName}
onDoubleClick={
isManageMode
? undefined
: () => {
setEditingTopicId(topic.id)
startEdit(topic.name)
}
}>
{topicName}
</TopicName>
<>
{topic.isNameManuallyEdited && (
<PinIcon size={10} color="var(--color-text-3)" style={{ minWidth: 10, flexShrink: 0 }} />
)}
<TopicName
className={getTopicNameClassName()}
title={topic.isNameManuallyEdited ? `${topicName} (${t('chat.topics.pin_name')})` : topicName}
onDoubleClick={
isManageMode
? undefined
: () => {
setEditingTopicId(topic.id)
startEdit(topic.name)
}
}>
{topicName}
</TopicName>
</>
)}
{!topic.pinned && (
<Tooltip
Expand Down
20 changes: 12 additions & 8 deletions src/renderer/src/store/thunk/messageThunk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,20 +178,14 @@ export const renameAgentSessionIfNeeded = async (agentSession: AgentSessionConte
return
}

agentSessionRenameLocks.add(lockId)

try {
const { messages } = await dbFacade.fetchMessages(topicId, true)
if (!messages.length) {
return
}

const { text: summary } = await fetchMessagesSummary({ messages })
const summaryText = summary?.trim()
if (!summaryText) {
return
}

agentSessionRenameLocks.add(lockId)

let session: AgentSessionEntity
try {
session = (await dataApiService.get(
Expand All @@ -202,6 +196,16 @@ export const renameAgentSessionIfNeeded = async (agentSession: AgentSessionConte
return
}

if (session.isNameManuallyEdited) {
return
}

const { text: summary } = await fetchMessagesSummary({ messages })
const summaryText = summary?.trim()
if (!summaryText) {
return
}

const currentName = (session.name ?? '').trim()
if (currentName === summaryText) {
return
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/src/types/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export const AgentSessionEntitySchema = AgentBaseSchema.extend({
agentId: z.string(),
agentType: AgentTypeSchema,
slashCommands: z.array(SlashCommandSchema).optional(),
isNameManuallyEdited: z.boolean().optional(),
createdAt: z.iso.datetime(),
updatedAt: z.iso.datetime()
})
Expand Down Expand Up @@ -256,7 +257,7 @@ export type BaseSessionForm = AgentBase

export type CreateSessionForm = BaseSessionForm & { id?: never }

export type UpdateSessionForm = Partial<BaseSessionForm> & { id: string }
export type UpdateSessionForm = Partial<BaseSessionForm> & { id: string; isNameManuallyEdited?: boolean }

export type SessionForm = CreateSessionForm | UpdateSessionForm

Expand Down
Loading