Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edba31e873 | ||
|
|
0804f5ccd2 | ||
|
|
29639ff516 | ||
|
|
22c80b2d94 |
@@ -625,6 +625,7 @@ GoodBuddy 是可调整窗口大小的桌面应用。响应式设计优先保证
|
|||||||
|
|
||||||
- “笔记 / 待办”属于同一工作台内的同级内容面板,使用 `PageTabs` 的 `segmented` 视觉变体,与模型设置的分段控件保持同一外观。
|
- “笔记 / 待办”属于同一工作台内的同级内容面板,使用 `PageTabs` 的 `segmented` 视觉变体,与模型设置的分段控件保持同一外观。
|
||||||
- 页签切换保留 `tablist`、`tab` 和 `tabpanel` 语义;待办状态仍使用独立的 `SegmentedControl`,不得与内容页签合并。
|
- 页签切换保留 `tablist`、`tab` 和 `tabpanel` 语义;待办状态仍使用独立的 `SegmentedControl`,不得与内容页签合并。
|
||||||
|
- 笔记编辑器保留 Quill 原生列表快捷输入:输入 `-`、`*`、`1.`、`[ ]` 或 `[x]` 后按空格,分别转换为项目符号、编号或待办清单。快捷输入只生成现有 Delta 富文本,不引入 Markdown 源码模式、第二套持久化格式或第三方 Markdown 插件;编辑区附近持续提供简短提示。
|
||||||
- 左侧“魔法笔记”入口可显示未完成待办数量。数量为 0 时隐藏徽标,超过 99 时显示 `99+`,可访问名称仍说明精确数量;勾选、取消勾选以及 Agent / MCP 对笔记清单的写入都必须刷新数量。
|
- 左侧“魔法笔记”入口可显示未完成待办数量。数量为 0 时隐藏徽标,超过 99 时显示 `99+`,可访问名称仍说明精确数量;勾选、取消勾选以及 Agent / MCP 对笔记清单的写入都必须刷新数量。
|
||||||
- 未完成待办徽标的高度不得超过主导航图标;数量从 0 变为可见或再次隐藏时,主导航项行高和相邻菜单位置必须保持不变。
|
- 未完成待办徽标的高度不得超过主导航图标;数量从 0 变为可见或再次隐藏时,主导航项行高和相邻菜单位置必须保持不变。
|
||||||
- 在待办面板勾选或取消勾选后,当前缓存中的源笔记正文必须立即同步对应清单状态,不得依赖离开工作区后重新加载。
|
- 在待办面板勾选或取消勾选后,当前缓存中的源笔记正文必须立即同步对应清单状态,不得依赖离开工作区后重新加载。
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ Windows 到 Linux x64 的既有安装、
|
|||||||
Main-only 模型桥、断线恢复、输出重放、同一 OpenCode Session 续接与终态清理已经在真实
|
Main-only 模型桥、断线恢复、输出重放、同一 OpenCode Session 续接与终态清理已经在真实
|
||||||
Host 上完成 provider-free 验证。上一轮 Linux x64 验收使用 Agent `0.11.2-e2e.12` 与
|
Host 上完成 provider-free 验证。上一轮 Linux x64 验收使用 Agent `0.11.2-e2e.12` 与
|
||||||
OpenCode Runtime `1.18.9` 完成了一次有界真实模型工具调用;加入每 helper 随机 loopback
|
OpenCode Runtime `1.18.9` 完成了一次有界真实模型工具调用;加入每 helper 随机 loopback
|
||||||
路径 capability 后,Agent `0.11.7` 已通过独立 workflow 发布 Linux x64/arm64 复合包和
|
路径 capability 后,Agent `0.11.9` 已通过独立 workflow 发布 Linux x64/arm64 复合包和
|
||||||
签名累计目录;当前源码准备 `0.11.9`,修复 Host 更新并消除重复 payload 验证。失败的
|
签名累计目录;当前桌面源码准备 `0.11.10`,修复 Host 更新并消除重复 payload 验证。失败的
|
||||||
`agent-v0.11.3` 保持不可变且未发布。
|
`agent-v0.11.3` 保持不可变且未发布。
|
||||||
|
|
||||||
## 产品语义
|
## 产品语义
|
||||||
@@ -207,6 +207,7 @@ Execute 不经过 Ask 的 bubblewrap profile:
|
|||||||
调度、跨 channel 超车、批发送或第二套拥塞控制。
|
调度、跨 channel 超车、批发送或第二套拥塞控制。
|
||||||
- Agent 在把 Main 输入交给 Runtime 前、以及把 Runtime 输出交给 Main 前,先把 ACP frame 写入本机 journal。ACK 只推进 cursor 并裁剪已确认 frame,不表示 channel 已终止。
|
- Agent 在把 Main 输入交给 Runtime 前、以及把 Runtime 输出交给 Main 前,先把 ACP frame 写入本机 journal。ACK 只推进 cursor 并裁剪已确认 frame,不表示 channel 已终止。
|
||||||
- Main 持久化 binding identity 和单调 cursor;保留中的 connection lease 即使处于 offline/reconnecting,也可以先把新 cursor 落盘。重连提交不能覆盖 resume 过程中并发落盘的更新。
|
- Main 持久化 binding identity 和单调 cursor;保留中的 connection lease 即使处于 offline/reconnecting,也可以先把新 cursor 落盘。重连提交不能覆盖 resume 过程中并发落盘的更新。
|
||||||
|
- Runtime 事件进入桌面会话后,Renderer 和 Main 将完整工具详情保存到本地 SQLite,不再对已接受的工具输入、输出、错误或摘要施加额外的会话字段长度限制。
|
||||||
- 同一 detached Agent 存活时,短暂 SSH 断线依次执行 `controller/resume`、`runtime/resumeAcpChannel` 和 `runtime/replayAcpChannel`,从 Main 已确认的 cursor 后只重放 Agent 到 Main 的已记录输出。重复 frame 会被确认但不会再次交给上层。若上一代连接只留下没有活动请求的 detached binding,完成精确 controller takeover 后会先有界停止并核对遗留 Runtime process,再用新 channel epoch 重新打开同一 binding 并恢复已有 ACP session;其他 controller、未证明 takeover 或仍有活动请求的 binding 仍被拒绝。
|
- 同一 detached Agent 存活时,短暂 SSH 断线依次执行 `controller/resume`、`runtime/resumeAcpChannel` 和 `runtime/replayAcpChannel`,从 Main 已确认的 cursor 后只重放 Agent 到 Main 的已记录输出。重复 frame 会被确认但不会再次交给上层。若上一代连接只留下没有活动请求的 detached binding,完成精确 controller takeover 后会先有界停止并核对遗留 Runtime process,再用新 channel epoch 重新打开同一 binding 并恢复已有 ACP session;其他 controller、未证明 takeover 或仍有活动请求的 binding 仍被拒绝。
|
||||||
- Main 到 Runtime 的 ACP 输入、模型请求、工具请求和 blob 不自动重放。
|
- Main 到 Runtime 的 ACP 输入、模型请求、工具请求和 blob 不自动重放。
|
||||||
- 无法确认外部 Provider 是否已处理的模型调用保持结果未知,避免重复计费或重复副作用。
|
- 无法确认外部 Provider 是否已处理的模型调用保持结果未知,避免重复计费或重复副作用。
|
||||||
@@ -245,8 +246,8 @@ Execute 不经过 Ask 的 bubblewrap profile:
|
|||||||
|
|
||||||
- 2026-08 的本地 fixture 完整验证 Linux x64 Agent `0.11.2-e2e.12`、Node `24.19.0`
|
- 2026-08 的本地 fixture 完整验证 Linux x64 Agent `0.11.2-e2e.12`、Node `24.19.0`
|
||||||
和 Agent protocol `2.0`;当时没有 arm64 fixture,因此该记录不能作为当前独立发布
|
和 Agent protocol `2.0`;当时没有 arm64 fixture,因此该记录不能作为当前独立发布
|
||||||
的双架构验收。Agent `0.11.7` 后续已由原生 workflow 发布并公开验证双架构工件;
|
的双架构验收。Agent `0.11.9` 后续已由原生 workflow 发布并公开验证双架构工件;
|
||||||
当前源码 lock 是修复候选 `0.11.9`。
|
当前源码 lock 固定为 `0.11.9`。
|
||||||
- 正常 Host 更新路径把 Linux x64 Host 的 Agent 更新为 `0.11.2-e2e.12`,并确认
|
- 正常 Host 更新路径把 Linux x64 Host 的 Agent 更新为 `0.11.2-e2e.12`,并确认
|
||||||
OpenCode Runtime 已安装版本与所需版本均为 `1.18.9`。
|
OpenCode Runtime 已安装版本与所需版本均为 `1.18.9`。
|
||||||
- 一条新的 Ask 用户操作只提交一次。OpenCode 先在 build 模型轮次请求一个原生
|
- 一条新的 Ask 用户操作只提交一次。OpenCode 先在 build 模型轮次请求一个原生
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "goodbuddy",
|
"name": "goodbuddy",
|
||||||
"version": "0.11.9",
|
"version": "0.11.11",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "goodbuddy",
|
"name": "goodbuddy",
|
||||||
"version": "0.11.9",
|
"version": "0.11.11",
|
||||||
"license": "0BSD",
|
"license": "0BSD",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@agentclientprotocol/sdk": "0.25.1",
|
"@agentclientprotocol/sdk": "0.25.1",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "goodbuddy",
|
"name": "goodbuddy",
|
||||||
"version": "0.11.9",
|
"version": "0.11.11",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Secure desktop AI workspace with controlled Agent Runtimes",
|
"description": "Secure desktop AI workspace with controlled Agent Runtimes",
|
||||||
"desktopName": "GoodBuddy",
|
"desktopName": "GoodBuddy",
|
||||||
|
|||||||
@@ -2,12 +2,36 @@
|
|||||||
"formatVersion": 1,
|
"formatVersion": 1,
|
||||||
"releases": [
|
"releases": [
|
||||||
{
|
{
|
||||||
"version": "0.11.9",
|
"version": "0.11.11",
|
||||||
|
"releasedAt": "2026-08-30",
|
||||||
|
"notes": {
|
||||||
|
"zh-CN": {
|
||||||
|
"highlights": [],
|
||||||
|
"features": [],
|
||||||
|
"fixes": [
|
||||||
|
"**远程会话完整保存。** 修复托管 SSH 远程项目的工具结果较长时,会话持久化失败并可能让已完成回复仍显示为生成中的问题。Runtime 已返回的工具输入、输出、错误和摘要现在会完整保存到本地会话,不再受额外的会话字段长度限制。",
|
||||||
|
"**魔法笔记列表快捷输入更易发现。** 编辑区现在提示输入 `-`、`1.`、`[ ]` 或 `[x]` 后按空格即可创建项目符号、编号或待办清单,并增加行为覆盖以防快捷输入回退。"
|
||||||
|
],
|
||||||
|
"notices": []
|
||||||
|
},
|
||||||
|
"en-US": {
|
||||||
|
"highlights": [],
|
||||||
|
"features": [],
|
||||||
|
"fixes": [
|
||||||
|
"**Complete remote conversation saves.** Fixed conversation persistence failing for managed SSH Remote Projects when tool results were long, which could leave a completed reply displayed as still generating. Tool input, output, errors, and summaries already returned by the Runtime are now saved completely without additional conversation-field length limits.",
|
||||||
|
"**Discoverable Magic Notes list shortcuts.** The editor now explains that typing `-`, `1.`, `[ ]`, or `[x]` followed by Space creates a bullet, numbered, or checklist item, with behavior coverage to prevent regressions."
|
||||||
|
],
|
||||||
|
"notices": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "0.11.10",
|
||||||
"releasedAt": "2026-08-29",
|
"releasedAt": "2026-08-29",
|
||||||
"notes": {
|
"notes": {
|
||||||
"zh-CN": {
|
"zh-CN": {
|
||||||
"highlights": [
|
"highlights": [
|
||||||
"GoodBuddy 0.11.9 修复正式环境中的 Host 更新失败,并显著缩短 Agent 与 OpenCode Runtime 的安装、恢复和日常启动校验。"
|
"GoodBuddy 0.11.10 修复正式环境中的 Host 更新失败,并显著缩短 Agent 与 OpenCode Runtime 的安装、恢复和日常启动校验。"
|
||||||
],
|
],
|
||||||
"features": [],
|
"features": [],
|
||||||
"fixes": [
|
"fixes": [
|
||||||
@@ -21,7 +45,7 @@
|
|||||||
},
|
},
|
||||||
"en-US": {
|
"en-US": {
|
||||||
"highlights": [
|
"highlights": [
|
||||||
"GoodBuddy 0.11.9 fixes Host updates in production and substantially reduces Agent and OpenCode Runtime verification during installation, recovery, and normal startup."
|
"GoodBuddy 0.11.10 fixes Host updates in production and substantially reduces Agent and OpenCode Runtime verification during installation, recovery, and normal startup."
|
||||||
],
|
],
|
||||||
"features": [],
|
"features": [],
|
||||||
"fixes": [
|
"fixes": [
|
||||||
|
|||||||
@@ -113,7 +113,9 @@ describe('installed Agent bundle verifier', () => {
|
|||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
writeBundle()
|
writeBundle()
|
||||||
chmodSync(join(installationDirectory, 'goodbuddy-agent'), 0o777)
|
chmodSync(join(installationDirectory, 'goodbuddy-agent'), 0o777)
|
||||||
await expect(verifyBundle()).rejects.toThrow('mode mismatch')
|
await expect(verifyBundle()).rejects.toThrow(
|
||||||
|
'entrypoint metadata changed'
|
||||||
|
)
|
||||||
resetInstallation()
|
resetInstallation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3299,6 +3299,15 @@ describe('AssistantDatabase', () => {
|
|||||||
createdAt: 1_775_000_000_001,
|
createdAt: 1_775_000_000_001,
|
||||||
state: 'complete' as const,
|
state: 'complete' as const,
|
||||||
status: '已完成',
|
status: '已完成',
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
callId: 'remote-tool-call',
|
||||||
|
name: '远程工具',
|
||||||
|
state: 'completed' as const,
|
||||||
|
summary: '完整远程工具结果',
|
||||||
|
output: '远程输出'.repeat(10_000)
|
||||||
|
}
|
||||||
|
],
|
||||||
contextCompressions: [
|
contextCompressions: [
|
||||||
{
|
{
|
||||||
state: 'completed' as const,
|
state: 'completed' as const,
|
||||||
@@ -3350,6 +3359,15 @@ describe('AssistantDatabase', () => {
|
|||||||
content: '生成完成',
|
content: '生成完成',
|
||||||
state: 'complete',
|
state: 'complete',
|
||||||
status: '已完成',
|
status: '已完成',
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
callId: 'remote-tool-call',
|
||||||
|
name: '远程工具',
|
||||||
|
state: 'completed',
|
||||||
|
summary: '完整远程工具结果',
|
||||||
|
output: '远程输出'.repeat(10_000)
|
||||||
|
}
|
||||||
|
],
|
||||||
contextCompressions: [
|
contextCompressions: [
|
||||||
{
|
{
|
||||||
state: 'completed',
|
state: 'completed',
|
||||||
|
|||||||
+10
-1
@@ -3917,7 +3917,16 @@ describe('registerIpcHandlers local conversation persistence', () => {
|
|||||||
role: 'assistant' as const,
|
role: 'assistant' as const,
|
||||||
content: '增量内容',
|
content: '增量内容',
|
||||||
createdAt: 1,
|
createdAt: 1,
|
||||||
state: 'streaming' as const
|
state: 'streaming' as const,
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
callId: 'remote-tool-call',
|
||||||
|
name: '远程工具',
|
||||||
|
state: 'completed' as const,
|
||||||
|
summary: '完整远程工具结果',
|
||||||
|
output: '远程输出'.repeat(10_000)
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||||
import { readFileSync } from 'node:fs'
|
import { readFileSync } from 'node:fs'
|
||||||
import { join } from 'node:path'
|
import { join } from 'node:path'
|
||||||
|
import Quill from 'quill'
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
import type { MagicNoteRichContent } from '../../shared/magic-notes-contracts'
|
import type { MagicNoteRichContent } from '../../shared/magic-notes-contracts'
|
||||||
import { MagicNoteEditor } from './MagicNoteEditor'
|
import { MagicNoteEditor } from './MagicNoteEditor'
|
||||||
@@ -45,6 +46,46 @@ describe('MagicNoteEditor', () => {
|
|||||||
).toBeInTheDocument()
|
).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
['-', 'bullet'],
|
||||||
|
['*', 'bullet'],
|
||||||
|
['1.', 'ordered'],
|
||||||
|
['[ ]', 'unchecked'],
|
||||||
|
['[x]', 'checked']
|
||||||
|
])(
|
||||||
|
'keeps the native Quill %s list shortcut enabled',
|
||||||
|
async (marker, expectedList) => {
|
||||||
|
const onChange = vi.fn<(content: MagicNoteRichContent) => void>()
|
||||||
|
const { container } = render(
|
||||||
|
<MagicNoteEditor
|
||||||
|
ariaLabel="笔记正文"
|
||||||
|
onChange={onChange}
|
||||||
|
onError={vi.fn()}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
const editor = container.querySelector<HTMLElement>('.ql-editor')
|
||||||
|
const quillContainer = container.querySelector<HTMLElement>(
|
||||||
|
'.magic-note-editor__content'
|
||||||
|
)
|
||||||
|
expect(editor).not.toBeNull()
|
||||||
|
expect(quillContainer).not.toBeNull()
|
||||||
|
|
||||||
|
const quill = Quill.find(quillContainer!) as Quill
|
||||||
|
quill.setText(marker, 'user')
|
||||||
|
quill.setSelection(marker.length, 0, 'silent')
|
||||||
|
fireEvent.keyDown(editor!, { key: ' ' })
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
const content = onChange.mock.calls.at(-1)?.[0]
|
||||||
|
expect(
|
||||||
|
content?.ops.some(
|
||||||
|
(operation) => operation.attributes?.list === expectedList
|
||||||
|
)
|
||||||
|
).toBe(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
it('intercepts a pasted image before Quill and inserts it once', async () => {
|
it('intercepts a pasted image before Quill and inserts it once', async () => {
|
||||||
const onChange = vi.fn<(content: MagicNoteRichContent) => void>()
|
const onChange = vi.fn<(content: MagicNoteRichContent) => void>()
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
|
|||||||
@@ -86,9 +86,10 @@ export const magicNotes = {
|
|||||||
emptySelectionDescription:
|
emptySelectionDescription:
|
||||||
'Select a note on the left, or create a note to start writing.',
|
'Select a note on the left, or create a note to start writing.',
|
||||||
newEntryLabel: 'New entry content',
|
newEntryLabel: 'New entry content',
|
||||||
composerImmediateHint: 'AI comments after you stop typing for 5 seconds',
|
composerImmediateHint:
|
||||||
|
'Type -, 1., [ ], or [x] then Space to start a list; AI comments after 5 seconds of inactivity',
|
||||||
composerRichTextHint:
|
composerRichTextHint:
|
||||||
'Supports rich text and pasting or dropping local images, videos, and attachments',
|
'Type -, 1., [ ], or [x] then Space to start a list; you can also paste or drop local files',
|
||||||
emptyEntries: 'No entries yet. Write the first entry above.',
|
emptyEntries: 'No entries yet. Write the first entry above.',
|
||||||
editEntryLabel: 'Edit entry content',
|
editEntryLabel: 'Edit entry content',
|
||||||
entryAt: '{{date}} entry'
|
entryAt: '{{date}} entry'
|
||||||
|
|||||||
@@ -80,8 +80,10 @@ export const magicNotes = {
|
|||||||
emptySelectionTitle: '还没有选择笔记',
|
emptySelectionTitle: '还没有选择笔记',
|
||||||
emptySelectionDescription: '从左侧选择笔记,或新建一篇笔记开始记录。',
|
emptySelectionDescription: '从左侧选择笔记,或新建一篇笔记开始记录。',
|
||||||
newEntryLabel: '新记录内容',
|
newEntryLabel: '新记录内容',
|
||||||
composerImmediateHint: '停止输入 5 秒后自动评论',
|
composerImmediateHint:
|
||||||
composerRichTextHint: '支持富文本,可粘贴或拖入本地图片、视频和附件',
|
'输入 -、1.、[ ] 或 [x] 后按空格可创建列表;停止输入 5 秒后自动评论',
|
||||||
|
composerRichTextHint:
|
||||||
|
'输入 -、1.、[ ] 或 [x] 后按空格可创建列表;也可粘贴或拖入本地文件',
|
||||||
emptyEntries: '还没有记录,在上方写下第一条内容。',
|
emptyEntries: '还没有记录,在上方写下第一条内容。',
|
||||||
editEntryLabel: '编辑记录内容',
|
editEntryLabel: '编辑记录内容',
|
||||||
entryAt: '{{date}} 的记录'
|
entryAt: '{{date}} 的记录'
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
conversationBranchInputSchema,
|
conversationBranchInputSchema,
|
||||||
conversationSnapshotSchema,
|
conversationSnapshotSchema,
|
||||||
isUntouchedBuiltInDefaultProject,
|
isUntouchedBuiltInDefaultProject,
|
||||||
|
localConversationSaveBatchSchema,
|
||||||
persistedProjectExecutionSpaceSchema,
|
persistedProjectExecutionSpaceSchema,
|
||||||
projectCreateSchema,
|
projectCreateSchema,
|
||||||
projectExecutionSpaceSchema,
|
projectExecutionSpaceSchema,
|
||||||
@@ -203,3 +204,42 @@ describe('conversation branch contracts', () => {
|
|||||||
).toBe(true)
|
).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('conversation persistence contracts', () => {
|
||||||
|
it('preserves complete tool details without persistence length limits', () => {
|
||||||
|
const input = 'input'.repeat(10_000)
|
||||||
|
const output = 'output'.repeat(20_000)
|
||||||
|
const error = 'error'.repeat(10_000)
|
||||||
|
const batch = [
|
||||||
|
{
|
||||||
|
header: {
|
||||||
|
id: '00000000-0000-4000-8000-000000000301',
|
||||||
|
title: '远程工具会话',
|
||||||
|
updatedAt: 1
|
||||||
|
},
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
id: '00000000-0000-4000-8000-000000000302',
|
||||||
|
role: 'assistant',
|
||||||
|
content: '',
|
||||||
|
createdAt: 1,
|
||||||
|
state: 'complete',
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
callId: 'remote-tool-call',
|
||||||
|
name: '远程工具',
|
||||||
|
state: 'completed',
|
||||||
|
summary: '完整远程工具结果',
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
error
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(localConversationSaveBatchSchema.parse(batch)).toEqual(batch)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -133,8 +133,8 @@ export type ConversationQueueItem = z.infer<
|
|||||||
|
|
||||||
export const conversationToolActivitySchema = z
|
export const conversationToolActivitySchema = z
|
||||||
.object({
|
.object({
|
||||||
callId: z.string().max(256).optional(),
|
callId: z.string().optional(),
|
||||||
name: z.string().max(200),
|
name: z.string(),
|
||||||
state: z.enum([
|
state: z.enum([
|
||||||
'pending',
|
'pending',
|
||||||
'running',
|
'running',
|
||||||
@@ -144,10 +144,10 @@ export const conversationToolActivitySchema = z
|
|||||||
'cancelled',
|
'cancelled',
|
||||||
'interrupted'
|
'interrupted'
|
||||||
]),
|
]),
|
||||||
summary: z.string().max(2_000),
|
summary: z.string(),
|
||||||
input: z.string().max(4_000).optional(),
|
input: z.string().optional(),
|
||||||
output: z.string().max(16_000).optional(),
|
output: z.string().optional(),
|
||||||
error: z.string().max(2_000).optional()
|
error: z.string().optional()
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user