DevLog:2026年1月6日

1、继续测试使用Flutter重写的ChatWith for Mac,还有很多问题需要修改,先修改这几处:

1.把右上角的搜索按钮挪到最左侧,放在“对话”上面

2.明确对话列表、收藏列表的显示规则,对话列表中,标题是用户提出的最后一个问题,下面小字显示最后一次回答的内容,只显示一行,收藏列表中,标题是收藏的回答对应的问题,下面小字显示收藏的回答内容,只显示一行

3.对话列表和收藏列表的宽度都固定为300,且不需要拖动调整

4.应用最顶部标题栏的chatwith改成ChatWith

2、上述问题1、2、3均已修改,问题4仍未修改,而且还存在如下问题,继续修改

1.顶部居中显示的ChatWith没有用,可以去掉

2.每次打开应用时窗口大小都会回到初始值,没有保存上次打开时对窗口大小的调整,还需要手动调整一下

3.简化一下设置界面,第三列即设置详情的顶部,需要去掉AI模型管理、外观设置、数据统计、回收站这些标题

4.添加和修改模型时,底部的高级设置展开后显示不全,并且有一条多余的分割线,可以去掉

3、继续修改一些界面上的小问题,之后重点测试对话流程,比如切换模型对话、联网搜索功能等等

1、左上角搜索按钮,鼠标划过时不需要显示提示,并且划过时的背景大小要和下面的对话、收藏、设置按钮背景大小一致,在搜索按钮下方增加“搜索”二字,与其他三个按钮样式保持一致

2.去掉对话列表顶部的“新建对话”按钮,去掉收藏列表顶部的“新建收藏”按钮

3.About chatwith界面的应用名是哪里规定的?可否改成ChatWith?

4.每条AI回答内容的底部除现有的收藏、复制按钮外,增加一个删除按钮

4、Cursor修改之后,上面2、3、4都已经OK,但是1鼠标在划过时显示成了方形的背景,而非划过对话、收藏、设置按钮时的圆角矩形按钮,继续修改,并且给最左侧导航栏顶部添加了8像素的间距,不再紧贴顶部

5、收藏界面打开一条收藏后,列表顶部的分割线和收藏详情顶部的分割线没有对齐,让Cursor把收藏详情顶部的“编辑”和“复制”按钮改成和对话详情顶部的“新建对话”按钮一致的样式,虽然仍然没有完全对齐,但相比之前已经美观很多了

6、继续修改对话和收藏页,首次打开应用时对话界面虽然有空状态提示,但没有新建对话按钮,还需要把刚才删掉的对话列表顶部的“新建对话”按钮加回来,同时右侧详情页顶部的模型切换按钮、新建对话按钮,即使未打开任何对话,也要一直显示;针对收藏页,收藏列表顶部的“新建收藏”按钮也加回来,如果没有打开任何一条收藏,右侧详情页顶部就只显示一个“新建收藏”按钮,如果打开了任何一条收藏,右侧详情页顶部就显示“编辑”和“复制”按钮,这样修改之后对话和收藏页面的列表、详情页分割线就对齐了

7、接下来给收藏详情页底部增加一行信息栏,打开一条收藏后,可显示该条收藏的添加时间、修改时间(最后一次修改的时间)、字数统计三个信息;然后在对话详情页,需要给每条消息增加时间信息,显示在消息下方,Cursor先使用了比较复杂的相对时间(近期)+完整日期时间(较早的日期)的方式,今天的时间只显示时分,昨天的时间显示为昨天+时分,一周内的时间显示为几天前,更早的显示为完整日期时间,貌似这也是苹果设备上的应用比较常用的时间显示方式

8、然后把回收站的收藏和对话换个顺序,左边是已删除的对话,右边是已删除的收藏,到此,对于应用界面的首轮修改就差不多了,备份了之前使用Swift写的ChatWith for Mac,然后清理了对应的文件、刷新了README.md文档

9、接下来开始对各项功能进行测试和完善,在对话过程中发现如下问题,先集中修改一波:

1.新建对话时,有时会出现这样的问题:新对话在列表里会显示和上一个对话一样的标题和副标题,再次新建对话才会以“新对话”为标题

2.启用联网搜索功能后,联网搜索结果的显示需要优化,我只需要看到标题-网站名和来源链接,不需要从中摘取的内容,并且这些链接我需要可以点击,点击后直接用默认浏览器打开

3.对话列表的置顶功能有问题,比如我将对话A和B都置顶,再取消对话A的置顶,这时应该只有对话B置顶,但实际使用时却是对话A置顶,对话B被取消了置顶,并且置顶的对话应该有个区别于非置顶对话的底色,可以对比下收藏列表的置顶功能,收藏列表的置顶功能正常

4.对话列表和收藏列表,都应当支持用户修改标题(点击标题后面的三个圆点,菜单里需要有置顶/取消置顶、修改、删除三个功能,在在现在的基础上增加“修改”功能),如果用户修改了标题,就一直用用户修改的标题,如果没有修改,就沿用之前的标题获取逻辑

10、修改后测试,构建失败,问题:The sandbox is not in sync with the Podfile.lock. Run ‘pod install’ or update your CocoaPods installation.原因在于刚刚为了实现参考链接可点击的功能,添加了url_launcher依赖,需要重新安装Pods以包含新的macOS插件(url_launcher_macos),否则就会出现Podfile.lock与实际的Pods目录不同步的问题,修改之后解决

11、再次测试,其他问题基本都已修正,还需要继续进行一些优化:对话列表可能存在刷新机制的问题,对标题进行修改、置顶/取消置顶、新建对话等操作后,列表有时不会立即刷新;联网搜索功能参考的链接需要增加到10个,5个链接可能参考性不足;AI回答内容背景的灰色太深了,需要浅一些

12、再次测试,发现对话列表的刷新机制还是有点问题,比如AI正在回答时,对话列表就会频繁刷新,其实不需要,让Cursor改成了回答结束后刷新对话列表,但发现在联网搜索过程中和回答过程中还是在频繁刷新,于是和Cursor明确:在联网搜索过程中也不要频繁刷新,只有回答结束后、置顶/取消置顶后、修改标题后、创建新对话后 这几种情况下才触发对话列表的刷新操作,再次修改后对话列表仍然会在AI回答过程中频繁刷新,这个问题后面再开一个新对话再修改

13、继续测试应用的功能,接下来是收藏模块,首先收藏的内容比较长时,收藏详情底部会出现“BOTTOM OVERFLOWED BY XXX PIXELS”这种提示,并且无法滚动查看,只有在点击编辑后才能滚动查看,修改过程中将非编辑模式下的MarkdownBody包裹在SingleChildScrollView中,使内容可滚动,问题已解决

14、发现新问题,有些回答内容中就会带一些文字形式的链接,但只显示为蓝色文字,无法打开,我需要让这些链接也像Tavily提供的参考链接那样可以直接点开,在回答内容、收藏内容都是如此,都要点击可以直接点开,为实现这一需求,针对AI回答内容中的链接,Cursor给MarkdownBody添加了onTapLink回调,点击链接时使用url_launcher在默认浏览器中打开,并且添加了链接样式,针对收藏内容中的链接,Cursor导入了url_launcher包,并为MarkdownBody添加了onTapLink回调,实测问题已解决

15、对话和收藏删除之后,回收站里第一条内容和分割线之间没有任何间距,需要稍微增加一点间距(可以用第一条和第二条之间的间距),视觉上更好一些,针对这一问题,Cursor给第一条删除的内容和TabBar分割线之间增加了8像素的间距,与列表项之间的间距一致,视觉上更统一了

16、还有,数据统计界面的收藏、对话、模型三个图标颜色有些突兀,需要改一下,针对这种比较模糊的需求,Cursor将Colors.red、Colors.blue和Colors.purple改成了Colors.pink.shade300、Colors.blue.shade300和Colors.grey.shade300,认为这些颜色比较柔和,与界面更协调,再次构建看效果,的确比之前要好些了

17、AI模型管理界面,每个模型卡片的整体高度需要稍微缩减一下,稍微紧凑一点点,现在每个卡片的高度都比较高,默认窗口大小的情况下只能显示两三个模型,Cursor同步修改了卡片内边距、标题字体大小、垂直间距、文字大小、按钮尺寸等等,显示效果好多了

18、然后调整数据统计界面的卡片间距,之前间距过大,要求统一成8,但视觉上还是很大,可能每个卡片上下各有8的间距?另外还需要增加已删除的对话、已删除的收藏 两个数据统计卡片,图标颜色用灰色,整体顺序用:AI模型数量、对话数量、已删除对话数量、收藏数量、已删除收藏数量,再次构建测试,需求已达成,今天到此结束

DevLog:2025年11月4日

补充一条,时间线有点乱了,但还是要记录一下。

1、继续试用ChatWith,发现目前的应用在使用支持深度思考的模型时,思考内容好像限制了显示高度,一旦达到高度限制,就不会随着思考的内容继续自动滚动,Cursor表示思考内容的显示高度的确固定在了400点,且超出之后会出现滚动条,但超过400点后就不会再自动滚动,在修改过程中发现了另一个问题,好像在对话中切换了另一个模型,再提出新问题时应用就会卡死

2、Cursor分析了可能导致应用卡死的几个问题:Core Data并发冲突、通知监听器生命周期、状态读取时序、缺少状态同步,特别是Core Data并发冲突,由于直接在主线程修改Core Data managedobject,如果此时用户立即发送消息,可能造成并发访问冲突,updateAISession可能触发Core Data save操作,与其他操作冲突,明天继续修改这个问题

3、添加其他模型来测试Base URL的填写方法,之前已经要求Cursor将其改为用户手动填写AI服务的跟地址,应用会自动补全路径,比如api.openai.com、openrouter.ai/api,然后针对火山引擎的“应用”(bots)做了特别优化,需要填写完整地址https://ark.cn-beijing.volces.com/api/v3/bots/,测试发现百度云千帆的Base URL填写仍然有问题,比如我填写官网提供的https://qianfan.baidubce.com/v2/chat/completions就会连接失败,删掉v2往后的内容也不行,只填写https://qianfan.baidubce.com也不行,与其设定各种复杂的自动补全规则,倒不如直接要求用户填写完整的Base URL,或者应用内置一些常用的Base URL来的简单

附上常用的几个AI的Base URL:

OpenAI

https://api.openai.com/v1/chat/completions

DeepSeek

https://api.deepseek.com/v1/chat/completions

OpenRouter

https://openrouter.ai/api/v1/chat/completions

硅基流动

https://api.siliconflow.cn/v1/chat/completions

火山方舟

https://ark.cn-beijing.volces.com/api/v3/chat/completions

https://ark.cn-beijing.volces.com/api/v3/bots/chat/completions

百度云千帆

https://qianfan.baidubce.com/v2/chat/completions

阿里云百炼

https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions

4、询问Cursor目前应用在Base URL补全方面的规则是怎样的,根据回答内容,规则包括:

1.如果没有http://或https://,就自动添加https://

2.如果URL末尾有斜杠,就自动移除

3.如果已经包含完整路径,就不做任何修改

4.如果包含部分路径,就自动补全,比如补全v1,补全/chat/completions

5.如果只有基础URL,就自动补全/v1/chat/completions

按照这套规则,我填写了完整的百度云千帆的Base URL,应该能正常使用才对,但填写完整地址之后测试仍然提示404

5、问题可能出现在自动补全v1上,也就是在“包含/chat/completions但不包含v1时,会自动添加v1前缀,包含/api/、/bots/、/v3/、/v2/,且不含/chat/时,则添加chat/completions”这里,根据Cursor给出的示例,可能会出现/v1出现在/chat/completions之后的情况

6、目前的规则的确有些复杂,可能用户在填写过程中也会不知道该填写完整的地址还是部分地址,倒不如直接在应用里内置几个常用的、完整的Base URL,由用户自行选择,要求:目前的规则有些复杂,我希望能在添加和编辑AI模型界面,预置几个常用的API平台的完整Base URL,用户只需要填写备注、模型名称、选择模型提供商、填写API Key、填写Tavily API Key即可使用模型

7、Cursor在修改过程中创建了APIProvider枚举,包含10个常用平台(OpenAI、DeepSeek、Anthropic Claude、OpenRouter、Google Gemini、智谱GLM、月之暗面Kimi、百度文心一言、阿里通义千问、腾讯混元、自定义),这样就不再需要配置路径补全规则,用起来也更方便了,先添加几个模型试试,再决定要不要增加或删减APIProvider

8、在修正因为使用中文引号导致构建失败的错误之后,百度云千帆和火山方舟的API都可成功连接,当API提供商选择自定义时,需在“高级设置”的Base URL中填写完整地址,即带有/chat/completions的地址

9、APIProvider需要增加硅基流动、火山方舟、百度云千帆、阿里云百炼,这四个都放在“自定义”前面,另外我发现在选择某个APIProvider之后,模型名称部分也会出现预置的模型名称,但我不需要,改成由用户手动填写模型名称,修改之后测试了几个不同的模型,都可以成功连接了

DevLog:2025年12月15日

1、继续测试深度思考功能是否正常,换不同的问题问一下支持深度思考的模型,以及对话的置顶/修改/删除功能(已有按钮,和之前使用Swift的ChatWith操作方式一致,但按钮的样式变了,可能是安卓原生的按钮?)

2、测试发现未能显示深度思考内容,且即使在问题中增加了“最新”这样的提示词,也未能联网获取最新信息,对话的三个操作按钮中,置顶/取消置顶功能正常,修改标题后在列表中仍然显示原标题,删除后可正常进入回收站,也能从回收站中恢复到对话列表,且在回收站里的对话会显示为修改后的标题

3、除了要修正上面的问题外,还需要补充的功能包括触发联网搜索、显示联网搜索的参考链接、测试模型是否可用,继续对Cursor提出需求如下:

1.只要是与支持深度思考的模型对话,就在对话最上方显示思考内容,默认展开,可在回答结束后折叠

2.只要我在模型设置中填写了Tavily Key,在回答时就调用Tavily的联网搜索能力,并且在回答内容下方显示参考链接,样式需要与回答内容有所区别

3.在添加/编辑模型页底部增加测试按钮,点击测试模型是否可正常使用,如果不能正常使用需要给出错误信息

4.在对话上左滑修改对话标题后,对话列表里仍然显示为原标题,但在回收站里的对话会显示为修改后的标题

5.对话列表里,只能看到最后一个问题,看不到最后一次回答,我需要在每个对话的标题下方显示一行最后一次回答的内容

4、修改完成后测试上述功能,发现:

1.与支持深度思考的模型对话时,仍然未能看到思考内容,又添加了另一个支持深度思考的模型(DeepSeek官方的deepseek-reasoner),也看不到思考内容,但是回答的速度还是挺快的

2.联网搜索功能已实现,点击参考链接不会直接打开,而是可以看到完整链接,并且可以选中、复制,可能改成点击直接跳转至默认浏览器打开链接会比较合适

3.模型测试功能已实现

4.已实现需求,对话列表里可以看到修改后的标题,但不是我最后一次提出的问题

5.创建新的对话,已经可以在列表里看到最后一次回答的内容,可能已经改好了?

5、基于上述测试结果,继续提出修改需求:

1.对于联网搜索的参考链接,我需要点击后直接在默认浏览器中打开

2.在对话列表中,我需要对话的标题默认显示我提出的最后一个问题,如果我修改了标题,则一直显示为修改后的标题

3.AI回答的内容下方,除了收藏按钮之外,还需要增加一个复制按钮,点击可将回答内容(不含参考链接)复制到剪贴板,并且在点击收藏和复制按钮时,要分别有收藏成功、复制成功的toast提示

6、修改过程中,对于上述第一个需求,出现了/Users/jinlei.wu/Documents/GitHub/ChatWith/chatwith_flutter/ios/Runner/GeneratedPluginRegistrant.m:24:9 Module ‘url_launcher_ios’ not found的错误提示,无法构建,Cursor认为这是在添加url_launcher后,iOS项目需要更新CocoaPods依赖,修改之后可以正常构建并在模拟器中运行应用,并且上述三个需求均已实现

7、仍有如下需求未能实现,后面在Cursor中开启新对话时再看能否实现:

对话页、收藏页、设置页三个页面的标题仍然是居中显示(第二次修改无效),看不到支持深度思考的模型的思考内容(第三次修改无效)

8、还需要处理一下目前Xcode中出现的警告信息:/Users/jinlei.wu/.pub-cache/hosted/pub.dev/url_launcher_ios-6.3.6/ios/url_launcher_ios/Sources/url_launcher_ios/URLLauncherPlugin.swift:22:26 ‘keyWindow’ was deprecated in iOS 13.0: Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes,看样子还是刚刚添加的url_launcher导致的问题

DevLog:2025年12月11日

1、需要给应用增加多模型管理和切换、联网搜索(通过Tavily,在模型界面增加Tavily Key字段)、回收站(可删除和恢复AI对话、收藏内容)、深度思考(在使用支持深度思考的模型时,可在对话过程中看到思考过程,并且样式和回答内容要有区别)、流式输出(可能现在已经有了?)、Markdown渲染(可能现在已经有了?)等功能

2、决定先增加联网搜索、回收站、深度思考功能,Cursor规划了7步:实现联网搜索功能(Tavily):添加Tavily Key字段到设置页面和存储、创建Tavily服务,实现联网搜索API调用、在聊天中集成联网搜索功能、实现回收站功能:修改数据库添加is_deleted字段、修改删除逻辑为软删除,创建回收站页面、实现深度思考功能:修改OpenAI服务解析思考内容、修改消息显示组件,区分显示思考过程和回答内容

3、Cursor只用了几分钟就完成了如下修改:

1. 联网搜索功能(Tavily):在设置页面的API配置部分添加了Tavily Key输入字段;创建了TavilyService处理联网搜索API调用;在聊天中集成:配置Tavily Key后,发送消息时会自动进行联网搜索,并将搜索结果作为上下文发送给 AI

2. 回收站功能:数据库更新:为conversations和messages表添加了is_deleted和deleted_at字段;软删除:删除操作改为软删除,数据不会真正删除;回收站页面:在设置页面的“数据管理”部分可进入回收站;可查看已删除的AI对话和收藏内容;可恢复已删除的内容;永久删除(不可恢复)

3. 深度思考功能:OpenAI服务更新:支持解析深度思考模型的thinking字段;消息显示更新:区分显示思考过程和回答内容;思考过程:灰色背景、斜体、带边框,顶部有“思考过程”标签;回答内容:正常样式显示

4、按照目前已有的功能,应该已经可以实现从添加模型到对话到删除的完整流程了,测试一下,先让Cursor解决两个问题,以及一个新需求:

1.在模拟器中打开应用时,对话页面出现了错误提示:LocaleDataException: Locale data has not been initialized, call initializedDataFormatting(<locale>).

2.在填写API Key、Base URL、模型名、Tavily Key后,填写的信息无法保存,退出设置界面后再回来看填写的信息就消失了

3.我需要把数据统计和回收站都放到设置-数据管理里

5、第一个问题,可能是因为中文日期的问题?第二个问题,为所有输入框添加了onEditComplete回调,在失去焦点时自动保存,第三个问题,将数据统计和回收站合并到了“数据管理”卡片中,继续测试,1和3已经解决,二仍然未能保存,决定直接动个大手术,添加多模型管理和切换功能,并在其中增加模型信息保存机制,需求包括:

1.在设置界面增加“模型管理”卡片,将现有的API配置整合到“模型管理”卡片中

2.可以在“模型管理”界面查看我添加的所有模型,可以在这里新建、修改、删除模型,并且可以将我添加的任何一个模型设置为默认模型,在开启新对话时,直接使用默认模型

3.添加和修改模型的界面,需要有取消和确认按钮,点确认按钮确认添加/修改,点取消按钮可取消添加/修改,点击确认或取消后可以返回“模型管理”界面

4.在添加和修改模型的界面,增加“备注”字段,可自行填写,并在对话窗口右上角的模型切换按钮上显示备注名和模型名

5.开启新对话时,直接使用默认模型

6.在对话中允许用户切换模型,模型切换按钮放在对话窗口右上角

6、修改过程中,Cursor将操作分为如下步骤:更新AIModel模型,添加备注字段和默认模型标记;创建模型数据库表和DAO;创建模型管理的Respository和Provider、创建模型管理界面、创建添加/编辑模型界面、修改设置界面,整合API配置到模型管理、修改对话页面,添加模型切换功能、修改聊天provider使用当前模型,大概耗时5分钟

7、在测试之前先记录一个关于Flutter开发的知识点:关于这几天在修改过程中频繁出现的DAO、Repository和Provider。

1.DAO(Data Access Object,数据访问对象)专注于数据存储层的读写,是直接与底层数据源交互的抽象层,封装所有数据访问细节,对外提供统一的GRUD(增删改查)接口,简单说就是DAO只负责“怎么从数据库/网络/本地文件拿数据/存数据”,不关心业务逻辑

2.Repository(业务数据仓库)是“业务层与数据层的中间层”,聚合多个DAO/数据源,封装业务逻辑,为上层(UI/Provider)提供统一的业务数据接口,简单说就是Repository负责“什么时候/从哪里/拿什么数据”,是数据的“调度中心”

3.Provider(状态管理工具)是“UI层与业务层的桥梁”,管理应用的状态(如用户信息、页面数据、加载状态),并将状态分发给UI组件,实现“状态变化——UI自动刷新”,简单说就是Provider负责“管理UI需要的状态,让UI能拿到最新数据”。

4.这几个概念之间的关系是:UI依赖Provider,Provider依赖Repository,Repository依赖DAO,分层设计本质是为了降低耦合,提升代码的可维护性

8、后续再测试今天新增的功能:多模型管理和切换、联网搜索、回收站、深度思考,测试正常后,还需要补充的细节包括流式输出、回答和收藏内容的Markdown渲染、模型测试、消息时间显示等等

DevLog:2025年10月13日

1、在上周给对话界面增加联网搜索开关功能之后,出现了点击发送问题应用便会卡死的问题,且看不到Cursor增加的搜索状态提示,在Cursor中开启新对话,排查一下问题出在哪里

2、Cursor在排查之后指出可能是TavilySearchService在执行网络请求时使用了await MainActor.run,导致网络请求在主线程上等待响应,但网络请求通常需要数秒时间,在主线程上等待会导致UI完全卡死,于是修改了TavilySearchService、AIService和AIViewModel三个文件,再次测试发现问题已经解决,可以看到搜索状态和思考状态提示,思考内容、回答内容、参考链接的展示也都正常,回答结束后状态提示也会消失

3、接下来解决之前用户反馈的其它问题,包括:

1.当前搜索页面缺少返回按钮,实际上搜索功能目前还不全,搜完能看到关键词所在的对话/收藏,但点击不会跳转到对应条目,还得再完善下

2.问题太长时,对话界面上方的标题可能会断行,需要限制一下字数

4、先解决第二个问题,让Cursor限制一下对话界面顶部标题的显示字数,这里涉及到了AIChatView,目前直接显示了完整的用户问题内容,没有长度限制,改成了完整显示前20个字符,之后则用省略号

5、然后完善搜索功能,搜索界面需要增加返回按钮,另外在输入关键词、呈现搜索结果后,点击搜索结果就应该跳转到对应的对话内容所在位置或对应的收藏内容,已要求Cursor修改,包括添加返回按钮、实现搜索结果跳转功能、UI的改进等,但未实际测试

6、还有一些需要优化的地方,比如将系统更新到macOS Tahoe 26.0.1之后,AI对话的提问和回答都没有边框了,可能是因为系统更新之后一些UI有了变化导致的,但不清楚Cursor是否了解最新的开发规范,后面再试

DevLog:2025年10月11日

1、节前发现的遗留问题如下,今天开始逐步修改:

1.当前搜索页面缺少返回按钮,实际上搜索功能目前还不全,搜完能看到关键词所在的对话/收藏,但点击不会跳转到对应条目,还得再完善下

2.联网搜索的触发词有点少,比如“今年”就无法触发搜索,需要进一步扩充,或者增加一个联网搜索按钮,点亮后开启联网搜索,或者改一下逻辑,在添加模型时只要填了Tavily Key,就开启联网搜索,并且在选择模型界面显示是否填写了Tavily Key,如果填写了就显示“联网搜索已开启”

3.问题太长时,对话界面上方的标题可能会断行,需要限制一下字数

2、首先修改上面的问题2,决定先用第三种方案,来解决部分AI模型因为训练数据比较老导致回答内容易出现错误的问题,要求Cursor修改一下联网搜索功能的逻辑,不再通过关键词判定是否开启联网搜索,而是在添加模型时只要填了Tavily Key,就会一直开启联网搜索,并且在选择AI模型界面显示“联网搜索已开启”,未填写Tavily Key的AI模型,则显示“联网搜索未开启”

3、但在这次修改后只要点击发送问题应用就会卡死,结合DEBUG信息,Cursor认为这是因为每次发送消息都会进行联网搜索会阻塞主线程,导致应用卡主,并且会消耗大量API配额、增加不必要的延迟,于是又给我改回了之前的方案1

4、可能方案2会比较合适?尝试让Cursor在发送按钮旁边增加一个“联网搜索已开启/已关闭” 的按钮,需要用户手动开启/关闭,默认是关闭状态,不用关键词来判定是否开启联网搜索,但在发送问题后仍然会让应用卡住,Cursor分析表示虽然代码本身是异步的,但可能存在网络请求没有超时控制(Tavily搜索请求可能长时间等待)、缺少用户反馈(用户不知道搜索正在进行)等问题,于是给TavilySearchService添加了超时控制、给AIService添加了搜索状态反馈,改进了AIViewModel和AIChatView的UI状态显示,但依然没有解决问题,甚至现在即使不打开联网搜索开关,点击发送按钮时应用也会卡死,而且也没有看到Cursor给AIService添加的调试信息

5、近期Cursor频繁更新,先更新一下再重新开启对话来修正这个问题,另外在将电脑系统更新到最新的macOS  Tahoe 26之后,由于整个系统的界面都有变化,ChatWith的一些UI也发生了变化,比如对话界面有些消息的边框看不到了,输入框的边框也看不到了,后面也需要调整下

DevLog:2025年9月30日

1、首先跟Cursor明确了模型切换界面AIModelSelectorView底部的确认和取消按钮的功能,切换模型时,点“确认”确认我对模型的切换,点“取消”则不切换模型,仍然保持打开模型切换界面前的选择,为实现这一功能,Cursor在这个文件里增加了临时选择机制,界面会高亮显示临时选择的模型,只有点确认时才会更新模型选择并关闭界面,在打开界面时,临时选择状态会设置为当前已选择的模型

2、昨天发现Xcode更新了,并且支持了Coding Intelligence功能,可以使用内建的Claude in Xcode(需要登录Claude账号),也可以自己添加模型或调用本地模型,还没有测试,感觉这个功能可能会和Cursor之类的AI IDE比较像,当然了更专注于苹果的应用

3、接下来可以试试用Icon Composer或者Asset Catalog给ChatWith for Mac创建一套图标

4、遗留问题如下,节后再修改:

1.当前搜索页面缺少返回按钮,实际上搜索功能目前还不全,搜完能看到关键词所在的对话/收藏,但点击不会跳转到对应条目,还得再完善下

2.联网搜索的触发词有点少,比如“今年”就无法触发搜索,需要进一步扩充,或者增加一个联网搜索按钮,点亮后开启联网搜索,或者改一下逻辑,在添加模型时只要填了Tavily Key,就开启联网搜索,并且在选择模型界面显示是否填写了Tavily Key,如果填写了就显示“联网搜索已开启”

3.问题太长时,对话界面上方的标题可能会断行,需要限制一下字数

DevLog:2025年9月26日

1、询问Cursor如何将当前的应用打包,没想到Cursor竟然直接用Archive命令给我完成了打包,并且创建了ExportOptions.plist配置文件,并使用macOS Developer证书签名,生成了通用的双架构二进制文件,并输出为.app应用程序包,放到了ChatWith_Distribution文件夹下,另有一个名为ChatWith_v1.0_macOS的分发包,应用大小3.5MB(毕竟应用的功能还很简单)

2、找到了第一个用户,直接发了分发包,解压放到Mac的“应用程序”文件夹,但打开时会提示:Apple无法验证ChatWith是否包含可能危害Mac安全或泄露隐私的恶意软件,需要在设置中允许一下,可能是没有签名吧,这个以后再说

3、发现了如下bug:

1.对话界面切换模型按钮无法直达添加模型界面,新用户首次打开应用可能会有点困惑

2.联网搜索的触发词有点少,比如“今年”就无法触发搜索,需要进一步扩充,或者增加一个联网搜索按钮,点亮后开启联网搜索,或者改一下逻辑,在添加模型时只要填了Tavily Key,就开启联网搜索,并且在选择模型界面显示是否填写了Tavily Key,如果填写了就显示联网搜索已开启

3.问题太长时,对话界面上方的标题可能会断行,需要限制一下字数

DevLog:2025年9月17日

1、昨天已经基本实现了模型添加、AI对话的基础功能,今天继续完善,首先是添加多个模型并在对话时切换模型,首先在添加两个模型之后,发现设置-可用模型的模型列表里,两个模型之间有两条分割线,而且创建新模型时,无法保存我填写的新API密钥和基础URL,而是沿用了我添加的第一个模型的API密钥和基础URL

2、首先更新了AIModel结构体,添加了apiKey和baseURL字段,移除了isDefault字段,修复了ModelEditView的保存逻辑,更新了模型测试逻辑和对话配置逻辑,使用模型自己的API配置进行对话,而不是使用全局的API配置(早就应该这样了),然后移除了modelRow函数中的Divider():,去掉了多余的分割线,再次测试,两个问题成功解决

3、但AI对话窗口里又出现了回答在上、问题在下的情况,另外切换模型的弹窗显示也有问题,先修复切换模型的弹窗的显示效果,同时修复一下AI对话列表的选中状态,目前根本看不出来选中了哪个对话,修改后仍然不能在对话列表中标示出当前选中的对话,还需要再修改

4、先用硅基流动的DeepSeek R1 API测试了一个需要联网获取最新信息的问题,发现目前思考过程没有展示、AI回答内容没有经Markdown渲染、看不到Tavily提供的资料链接,决定让Cursor同时修复这些问题,并明确要求使用MarkdownUI来进行Markdown渲染,其实之前已经有了一部分支持这些功能的代码,但功能不完整,Cursor列出了Todo,一步步修改,稍后一并给Cursor反馈问题

5、Cursor一次修改了思考过程展示/折叠和展开、Markdown渲染、Tavily资料链接显示等功能,其中在Markdown渲染上,先创建了一个新的文件MarkdownView,但没有添加到项目里,提示构建失败,于是又重新启用现有的MarkdownRenderer,并且引入了MarkdownUI,同时还保留了自定义AttributedString实现作为备选方案,原因貌似是MarkdownUI只支持14.0以上的macOS,我觉得没有必要保留备选方案,之前修改NoteWith时已经验证了MarkdownUI的渲染效果,于是要求Cursor去掉了自定义实现相关代码,使用MarkdownUI作为唯一的渲染方案,MarkdownRenderer代码更加简洁了

6、接下来测试一下思考过程、Markdown渲染、Tavily链接的显示效果,先把AI对话内容的显示顺序搞定,然后处理了一下点击AI对话右上角无法切换模型的问题(原因是ChatView的模型选择回调中代码被注释掉了,没有实际实现模型切换功能,而且每个对话都显示第一个可用模型,而不是用户选择的模型,模型切换没有保存到对话中,我需要为每个对话独立保存选择的模型),Cursor自称目前已经实现如下目标:新对话默认使用第一个可用模型、点击右上角的模型名称选择其它模型、选择的模型立即保存到该对话中、每个对话都有自己独立的模型选择、重启应用后每个对话仍然使用之前选择的模型

7、模型可以正常切换了,但试了几个问题,发现无法触发应用通过Tavily获取最新信息,Cursor分析发现虽然Tavily密钥已经存储在模型中,但实际的消息发送逻辑中没有使用Tavily服务,需要实现Tavily集成,创建了一个新的Tavily服务类TavilyService,并修改了OpenAIService,表示当提问时应用会自动通过Tavily获取最新信息

8、测试发现即使是不支持深度思考的模型,回答内容里也会出现思考过程区域,而且回答内容没有经过Markdown渲染,也看不到Tavily的资料链接,在用MarkdownUI来实现Markdown渲染效果的过程中,Cursor多次创建和删除Package文件(因为一直没有真正引入MarkdownUI),多次用命令行修改MarkdownRenderer,多次尝试不使用MarkdownUI,而是换用SwiftUI的原生功能来实现基本的Markdown渲染,不知道为啥今天反复出现这种“退步”的操作,我多次打断,反复强调要用MarkdownUI来渲染

9、已经有部分文字可以呈现渲染后的效果,但表格还是无法正常显示,参考NoteWith,可能要对表格和代码块的显示进行单独的优化,猜测上面重复同样的操作可能是因为这个对话的上下文太长了导致的,后面在Cursor里开一个新对话再修改这些内容

10、又遇到了刚刚进行的问答没有被保存到对话里的问题,在修改ChatWith,将用户消息和AI消息更新后都调用onUpdate将其保存到Core Data后,问题解决

11、在修改MarkdownRenderer以支持对表格和代码块的渲染优化时,Cursor反复检查MarkdownUI的版本、添加MarkdownUI默认的表格和代码块渲染样式、添加自定义的表格和代码块渲染样式,然后删除这些内容,多次操作后相当于没有做任何的修改

12、决定试试让Cursor创建单独的文件来处理表格和代码块的渲染,并且使用MarkdownUI,Cursor创建了TableRenderer和CodeBlockRenderer,并将新文件添加到项目,但多次尝试后,即使已经将这两个新文件集成到AssistantMessageView之后,仍然未能实现对表格的正常渲染

13、由于目前的ChatWith是由iOS应用修改而来,且在修改过程中对代码和架构进行了大量的调整,怀疑目前有部分文件功能是重复的,让Cursor列举结构和分工后发现ChatWrapper是多余的、ChatView过于庞大、且组件职责不清晰,比如ChatMessageListSection和ChatMessageListView功能重复、ChatInputSection和ChatInputView功能重复,Cursor建议简化架构、删除冗余文件、重新组织文件结构,决定让Cursor实施这些优化

14、修改完成后架构更清晰(每个文件职责单一,易于维护,减少了不必要的中间层),代码更简洁(ChatView从436行减少到约280行,移除了重复的组件子定义),维护性更好(组件独立,便于单独测试和修改,文件结构更符合SwiftUI最佳实践),当然每次Cursor在修改完后都会这么说,还是要实际测试一下修改成果

15、继续测试具体的功能,首先发现在与支持深度思考的DeepSeek R1模型对话时,思考内容和回答内容混在了一起,未能像之前规划的那样分成两块,并且思考内容要可以折叠,可以展开,Cursor在分析后修改了OpenAIService中的seperateThinkAndAnswer函数,以正确解析思考内容,但仍然没有解决问题

16、我现在觉得可能将iOS版的ChatWith修改成Mac版,再逐个测试、恢复功能,可能是做了大量的重复工作,既然之前NoteWith for Mac已经基本可用了,那其实可以对它进行简化,实现我对ChatWith for Mac的一系列需求,于是复制了一份NoteWith for Mac的源文件,并要求Cursor将应用的名字改成ChatWith,这一过程包括将应用名称由NoteWith改为ChatWith、更新XCode项目文件中的名称引用、更新Swift文件中的名称引用、更新Info.plist文件、重命名相关文件夹和文件等

17、Cursor很快完成了修改,并且按照我的反馈替换掉了一些漏网之鱼,接下来就是去掉待办事项模块、测试功能了,后面可能还要把备忘录替换为收藏,去掉待办事项模块及相关功能包括了分析待办事项模块的组件和依赖、移除待办事项相关的数据模型、移除待办事项相关的视图、移除待办事项相关的视图模型、从DataManager中移除待办事项相关代码、从导航中移除待办事项相关项目、从项目文件中移除待办事项相关文件等步骤,并且根据我的反馈删掉了两处遗留的待办事项相关功能

18、构建成功后,整理了文件结构,特别是Views文件夹下既有AIChat和Notes两个文件夹来存放AI对话和备忘录相关的视图文件,又有大量视图文件散落在Views文件夹下,ViewModels文件夹也有类似问题,移动文件并更新project.pbxproj中的路径后,问题解决,结构清晰了一些

DevLog:2025年9月16日

1、今天首先解决昨天的遗留问题,统一一下应用的布局,改成三栏布局,最左边是应用的名字,以及对话、收藏、设置 三个按钮,中间栏是对话列表、收藏列表和设置大项,第三栏是对应的详情,Cursor延续了昨天的NavigationSplitView,并且创建了AppSidebar和MiddleSideBar组件(都在ContentView里,后面可能也要拆分这个文件了),然后修改了多个文件来匹配三栏布局

2、最左侧导航栏的颜色、图标、文字大小等样式都还可以,但目前对话界面缺少了创建对话按钮,设置界面的详情显示也都比较局促,需要继续调整布局和功能,比如:

1.模型设置界面需要有多模型管理功能,可以添加、删除、测试模型,并且增加Tavily联网搜索能力的支持,Base URL需要具备自动补全能力

2.增加回收站功能,可以管理已删除的对话和收藏,并且按钮放在数据统计和外观设置之间

3.外观设置的样式也需要改一下,现在这种横向三个按钮切换显得很局促

3、接下来一步步修改,先从模型的添加、修改、删除、测试功能开始,第一次修改后效果不佳,我发现DetailView好像包含了对话、收藏、设置三个模块的最右侧区域,于是让Cursor将其拆分为单独的文件,ConversationDetailView、FavoriteDetailView、SettingsDetailView,拆分后DetailView由596行代码缩减成了42行,并且新创建的三个文件每个文件都专注于特定功能,代码结构清晰了一些

4、现在添加模型的弹窗显示不正常,可填写信息的窗口只有很小一块,存在大片空白,无法正常使用,让Cursor修复,同时删除可用模型列表顶部的API配置按钮,我不需要在列表里配置API Key和BASE URL

5、然后调整弹窗的功能,包括给弹窗增加Tavily密钥字段,放在API配置的最后,弹窗底部增加取消和保存两个按钮,去掉“默认模型”相关的设置等等,现在弹窗信息可以完整显示,并且效果还可以,然后删除了部分按钮的边框线,去掉了“默认”标识,但Cursor标识在删除当前使用的模型时会自动切换到第一个可用的模型,看样子还是有类似默认模型、当前模型的设置,还是要清理掉

6、开始添加模型,测试后决定,删掉应用预置的默认模型配置,所有的模型都由用户来自行设置,另外在点击测试时,无需通过弹窗提示测试结果,直接在列表里模型名称的下方显示测试结果,比如错误信息、响应时间等,然后修正部分问题,比如在添加模型后重启应用模型信息会消失,创建新模型时可以看到之前填写的API KEY和Base URL

7、发现SettingsView里目前还有一些AI模型相关设置,但刚刚这些修改都不涉及SettingsView,怀疑可能有部分代码未被使用,询问后发现整个文件都未被使用,并且SidebarView里也有部分过时代码,一并进行了清理

7、看起来暂时没有引发新的问题,目前已经添加了第一个模型,继续测试AI对话功能,首先就是对话界面缺少了创建新对话按钮,把这个按钮加在对话界面右上角,测试发现即使是经过测试提示连接成功的模型,也无法正常对话,Cursor表示目前没有实现真正的模型测试功能,没有真正调用API,怪不得每次测试连接时间都是1.2s,并且ChatView使用的是全局的AppStorage值,而不是用户选择的模型配置,在修改过程中Cursor添加了一些调试信息,发现可能是因为currentModelID为空字符串,导致无法找到匹配的模型,系统回退到默认配置gpt-3.5-turbo,而不是我自己配置的模型

8、这就是上面说的“当前模型”的设置,要求Cursor去掉这个增加了应用复杂性的功能,在开启对话时,直接用可用模型列表里的第一个模型

9、测试了几次对话,但发送消息后会报错400,结合Cursor添加的调试信息,多次反馈后定位了问题,然后修正了AI对话内容无法保存的问题,可能是未能将新对话和更新的对话保存到Core Data,至此已经基本实现了添加模型、AI对话的基础操作

10、修改了AI对话消息的显示顺序,改成问题在上、回答在下,明天再继续完善功能,比如添加多个模型、测试模型的切换效果,完善AI对话列表的选中状态提示、更新时间、置顶/取消置顶等右键菜单操作