@lobehub/lobehub 2.0.0-next.327 → 2.0.0-next.329
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/.env.example +0 -3
- package/.env.example.development +0 -3
- package/CHANGELOG.md +58 -0
- package/Dockerfile +1 -2
- package/changelog/v1.json +18 -0
- package/docs/self-hosting/advanced/auth.mdx +5 -6
- package/docs/self-hosting/advanced/auth.zh-CN.mdx +5 -6
- package/docs/self-hosting/environment-variables/auth.mdx +0 -7
- package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +0 -7
- package/locales/en-US/chat.json +6 -1
- package/locales/en-US/discover.json +1 -0
- package/locales/zh-CN/chat.json +5 -0
- package/locales/zh-CN/discover.json +1 -0
- package/package.json +1 -1
- package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +24 -0
- package/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +210 -0
- package/packages/agent-runtime/src/types/instruction.ts +46 -2
- package/packages/builtin-tool-gtd/src/const.ts +1 -0
- package/packages/builtin-tool-gtd/src/executor/index.ts +38 -21
- package/packages/builtin-tool-gtd/src/manifest.ts +15 -0
- package/packages/builtin-tool-gtd/src/systemRole.ts +33 -1
- package/packages/builtin-tool-gtd/src/types.ts +55 -33
- package/packages/builtin-tool-local-system/src/client/Inspector/ReadLocalFile/index.tsx +1 -0
- package/packages/builtin-tool-local-system/src/client/Inspector/RunCommand/index.tsx +1 -1
- package/packages/builtin-tool-local-system/src/client/Render/WriteFile/index.tsx +1 -1
- package/packages/builtin-tool-local-system/src/client/Streaming/WriteFile/index.tsx +5 -1
- package/packages/builtin-tool-notebook/src/systemRole.ts +27 -7
- package/packages/conversation-flow/src/transformation/FlatListBuilder.ts +13 -1
- package/packages/conversation-flow/src/transformation/__tests__/FlatListBuilder.test.ts +40 -0
- package/packages/database/src/models/__tests__/messages/message.thread-query.test.ts +134 -1
- package/packages/database/src/models/message.ts +8 -1
- package/packages/database/src/models/thread.ts +1 -1
- package/packages/types/src/message/ui/chat.ts +2 -0
- package/packages/types/src/topic/thread.ts +20 -0
- package/scripts/prebuild.mts +2 -2
- package/src/app/[variants]/(main)/community/(list)/agent/features/List/Item.tsx +1 -0
- package/src/components/StreamingMarkdown/index.tsx +10 -43
- package/src/envs/__tests__/app.test.ts +81 -0
- package/src/envs/app.ts +14 -2
- package/src/envs/auth.test.ts +0 -13
- package/src/envs/auth.ts +0 -41
- package/src/features/Conversation/Messages/AssistantGroup/components/MessageContent.tsx +0 -2
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/CompletedState.tsx +108 -0
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/InitializingState.tsx +66 -0
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/InstructionAccordion.tsx +63 -0
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/ProcessingState.tsx +123 -0
- package/src/features/Conversation/Messages/Task/ClientTaskDetail/index.tsx +106 -0
- package/src/features/Conversation/Messages/Task/TaskDetailPanel/index.tsx +1 -0
- package/src/features/Conversation/Messages/Task/index.tsx +11 -6
- package/src/features/Conversation/Messages/Tasks/TaskItem/TaskTitle.tsx +3 -2
- package/src/features/Conversation/Messages/Tasks/shared/InitializingState.tsx +0 -4
- package/src/features/Conversation/Messages/Tasks/shared/utils.ts +22 -1
- package/src/features/Conversation/Messages/components/ContentLoading.tsx +1 -1
- package/src/features/Conversation/components/Thinking/index.tsx +9 -30
- package/src/features/Conversation/store/slices/data/action.ts +2 -3
- package/src/features/NavPanel/components/BackButton.tsx +10 -13
- package/src/features/NavPanel/components/NavPanelDraggable.tsx +4 -0
- package/src/hooks/useAutoScroll.ts +117 -0
- package/src/libs/better-auth/auth-client.ts +0 -9
- package/src/libs/better-auth/define-config.ts +13 -12
- package/src/libs/better-auth/sso/index.ts +2 -1
- package/src/libs/better-auth/utils/config.ts +2 -2
- package/src/libs/next/proxy/define-config.ts +4 -6
- package/src/locales/default/chat.ts +6 -1
- package/src/locales/default/discover.ts +2 -0
- package/src/server/routers/lambda/__tests__/integration/topic.integration.test.ts +74 -0
- package/src/server/routers/lambda/aiAgent.ts +239 -1
- package/src/server/routers/lambda/thread.ts +2 -0
- package/src/server/routers/lambda/topic.ts +6 -0
- package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +4 -1
- package/src/server/services/agentRuntime/AgentRuntimeService.ts +2 -1
- package/src/server/services/message/__tests__/index.test.ts +37 -0
- package/src/server/services/message/index.ts +6 -1
- package/src/services/aiAgent.ts +51 -0
- package/src/services/topic/index.ts +4 -0
- package/src/store/chat/agents/createAgentExecutors.ts +714 -12
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +6 -1
- package/src/store/chat/slices/message/actions/query.ts +33 -1
- package/src/store/chat/slices/message/selectors/displayMessage.test.ts +10 -0
- package/src/store/chat/slices/message/selectors/displayMessage.ts +1 -0
- package/src/store/chat/slices/operation/types.ts +4 -0
- package/src/store/chat/slices/topic/action.test.ts +2 -1
- package/src/store/chat/slices/topic/action.ts +1 -1
package/.env.example
CHANGED
|
@@ -307,9 +307,6 @@ OPENAI_API_KEY=sk-xxxxxxxxx
|
|
|
307
307
|
# Shared between Better-Auth and Next-Auth
|
|
308
308
|
# AUTH_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
309
309
|
|
|
310
|
-
# Auth URL (accessible from browser, optional if same domain)
|
|
311
|
-
# NEXT_PUBLIC_AUTH_URL=http://localhost:3210
|
|
312
|
-
|
|
313
310
|
# Require email verification before allowing users to sign in (default: false)
|
|
314
311
|
# Set to '1' to force users to verify their email before signing in
|
|
315
312
|
# NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION=0
|
package/.env.example.development
CHANGED
|
@@ -43,9 +43,6 @@ NEXT_PUBLIC_ENABLE_BETTER_AUTH=1
|
|
|
43
43
|
# Better Auth secret for JWT signing (generate with: openssl rand -base64 32)
|
|
44
44
|
AUTH_SECRET=${UNSAFE_SECRET}
|
|
45
45
|
|
|
46
|
-
# Authentication URL
|
|
47
|
-
NEXT_PUBLIC_AUTH_URL=${APP_URL}
|
|
48
|
-
|
|
49
46
|
# SSO providers configuration - using Casdoor for development
|
|
50
47
|
AUTH_SSO_PROVIDERS=casdoor
|
|
51
48
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.329](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.328...v2.0.0-next.329)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-21**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **auth**: Remove NEXT_PUBLIC_AUTH_URL env variable.
|
|
12
|
+
|
|
13
|
+
#### 🐛 Bug Fixes
|
|
14
|
+
|
|
15
|
+
- **misc**: Sloved the old removeSessionTopics not work.
|
|
16
|
+
|
|
17
|
+
<br/>
|
|
18
|
+
|
|
19
|
+
<details>
|
|
20
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
21
|
+
|
|
22
|
+
#### Code refactoring
|
|
23
|
+
|
|
24
|
+
- **auth**: Remove NEXT_PUBLIC_AUTH_URL env variable, closes [#11658](https://github.com/lobehub/lobe-chat/issues/11658) ([c0f9875](https://github.com/lobehub/lobe-chat/commit/c0f9875))
|
|
25
|
+
|
|
26
|
+
#### What's fixed
|
|
27
|
+
|
|
28
|
+
- **misc**: Sloved the old removeSessionTopics not work, closes [#11671](https://github.com/lobehub/lobe-chat/issues/11671) ([06d41e5](https://github.com/lobehub/lobe-chat/commit/06d41e5))
|
|
29
|
+
|
|
30
|
+
</details>
|
|
31
|
+
|
|
32
|
+
<div align="right">
|
|
33
|
+
|
|
34
|
+
[](#readme-top)
|
|
35
|
+
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
## [Version 2.0.0-next.328](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.327...v2.0.0-next.328)
|
|
39
|
+
|
|
40
|
+
<sup>Released on **2026-01-20**</sup>
|
|
41
|
+
|
|
42
|
+
#### ✨ Features
|
|
43
|
+
|
|
44
|
+
- **misc**: Support client tasks mode.
|
|
45
|
+
|
|
46
|
+
<br/>
|
|
47
|
+
|
|
48
|
+
<details>
|
|
49
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
50
|
+
|
|
51
|
+
#### What's improved
|
|
52
|
+
|
|
53
|
+
- **misc**: Support client tasks mode, closes [#11666](https://github.com/lobehub/lobe-chat/issues/11666) ([98cf57b](https://github.com/lobehub/lobe-chat/commit/98cf57b))
|
|
54
|
+
|
|
55
|
+
</details>
|
|
56
|
+
|
|
57
|
+
<div align="right">
|
|
58
|
+
|
|
59
|
+
[](#readme-top)
|
|
60
|
+
|
|
61
|
+
</div>
|
|
62
|
+
|
|
5
63
|
## [Version 2.0.0-next.327](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.326...v2.0.0-next.327)
|
|
6
64
|
|
|
7
65
|
<sup>Released on **2026-01-20**</sup>
|
package/Dockerfile
CHANGED
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Sloved the old removeSessionTopics not work."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2026-01-21",
|
|
9
|
+
"version": "2.0.0-next.329"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"features": [
|
|
14
|
+
"Support client tasks mode."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2026-01-20",
|
|
18
|
+
"version": "2.0.0-next.328"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {},
|
|
4
22
|
"date": "2026-01-20",
|
|
@@ -39,12 +39,11 @@ By setting the environment variables `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CL
|
|
|
39
39
|
|
|
40
40
|
To enable Better Auth in LobeChat, set the following environment variables:
|
|
41
41
|
|
|
42
|
-
| Environment Variable | Type | Description
|
|
43
|
-
| -------------------------------- | -------- |
|
|
44
|
-
| `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | Required | Set to `1` to enable Better Auth service
|
|
45
|
-
| `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32`
|
|
46
|
-
| `
|
|
47
|
-
| `AUTH_SSO_PROVIDERS` | Optional | Comma-separated list of enabled SSO providers, e.g., `google,github,microsoft` |
|
|
42
|
+
| Environment Variable | Type | Description |
|
|
43
|
+
| -------------------------------- | -------- | ----------------------------------------------------------------------------- |
|
|
44
|
+
| `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | Required | Set to `1` to enable Better Auth service |
|
|
45
|
+
| `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32` |
|
|
46
|
+
| `AUTH_SSO_PROVIDERS` | Optional | Comma-separated list of enabled SSO providers, e.g., `google,github,microsoft`|
|
|
48
47
|
|
|
49
48
|
<Callout type={'error'}>
|
|
50
49
|
**Important**: Better Auth is currently only suitable for **fresh deployments**. If you are already using NextAuth or Clerk and have existing user data in your database, **do not switch to Better Auth yet**, otherwise existing users will not be able to log in.
|
|
@@ -37,12 +37,11 @@ LobeChat 与 Clerk 做了深度集成,能够为用户提供一个更加安全
|
|
|
37
37
|
|
|
38
38
|
要在 LobeChat 中启用 Better Auth,请设置以下环境变量:
|
|
39
39
|
|
|
40
|
-
| 环境变量 | 类型 | 描述
|
|
41
|
-
| -------------------------------- | -- |
|
|
42
|
-
| `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | 必选 | 设置为 `1` 以启用 Better Auth 服务
|
|
43
|
-
| `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32`
|
|
44
|
-
| `
|
|
45
|
-
| `AUTH_SSO_PROVIDERS` | 可选 | 启用的 SSO 提供商列表,以逗号分隔,例如 `google,github,microsoft` |
|
|
40
|
+
| 环境变量 | 类型 | 描述 |
|
|
41
|
+
| -------------------------------- | -- | ----------------------------------------------------------- |
|
|
42
|
+
| `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | 必选 | 设置为 `1` 以启用 Better Auth 服务 |
|
|
43
|
+
| `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32` |
|
|
44
|
+
| `AUTH_SSO_PROVIDERS` | 可选 | 启用的 SSO 提供商列表,以逗号分隔,例如 `google,github,microsoft` |
|
|
46
45
|
|
|
47
46
|
<Callout type={'error'}>
|
|
48
47
|
**重要提示**:Better Auth 目前仅适用于**全新部署**的场景。如果你已经使用 NextAuth 或 Clerk 并且数据库中存在用户数据,**请暂时不要切换到 Better Auth**,否则现有用户将无法登录。
|
|
@@ -34,13 +34,6 @@ LobeChat provides a complete authentication service capability when deployed. Th
|
|
|
34
34
|
- Default: `-`
|
|
35
35
|
- Example: `Tfhi2t2pelSMEA8eaV61KaqPNEndFFdMIxDaJnS1CUI=`
|
|
36
36
|
|
|
37
|
-
#### `NEXT_PUBLIC_AUTH_URL`
|
|
38
|
-
|
|
39
|
-
- Type: Optional
|
|
40
|
-
- Description: The URL accessible from the browser for Better Auth callbacks. Only set this if the default generated URL is incorrect.
|
|
41
|
-
- Default: `-`
|
|
42
|
-
- Example: `https://example.com`
|
|
43
|
-
|
|
44
37
|
#### `NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION`
|
|
45
38
|
|
|
46
39
|
- Type: Optional
|
|
@@ -32,13 +32,6 @@ LobeChat 在部署时提供了完善的身份验证服务能力,以下是相
|
|
|
32
32
|
- 默认值:`-`
|
|
33
33
|
- 示例:`Tfhi2t2pelSMEA8eaV61KaqPNEndFFdMIxDaJnS1CUI=`
|
|
34
34
|
|
|
35
|
-
#### `NEXT_PUBLIC_AUTH_URL`
|
|
36
|
-
|
|
37
|
-
- 类型:可选
|
|
38
|
-
- 描述:浏览器可访问的 Better Auth 回调 URL。仅在默认生成的 URL 不正确时设置。
|
|
39
|
-
- 默认值:`-`
|
|
40
|
-
- 示例:`https://example.com`
|
|
41
|
-
|
|
42
35
|
#### `NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION`
|
|
43
36
|
|
|
44
37
|
- 类型:可选
|
package/locales/en-US/chat.json
CHANGED
|
@@ -204,6 +204,7 @@
|
|
|
204
204
|
"noSelectedAgents": "No members selected yet",
|
|
205
205
|
"openInNewWindow": "Open in New Window",
|
|
206
206
|
"operation.execAgentRuntime": "Preparing response",
|
|
207
|
+
"operation.execClientTask": "Executing task",
|
|
207
208
|
"operation.sendMessage": "Sending message",
|
|
208
209
|
"owner": "Group owner",
|
|
209
210
|
"pageCopilot.title": "Page Agent",
|
|
@@ -322,13 +323,17 @@
|
|
|
322
323
|
"tab.profile": "Agent Profile",
|
|
323
324
|
"tab.search": "Search",
|
|
324
325
|
"task.activity.calling": "Calling Skill...",
|
|
326
|
+
"task.activity.clientExecuting": "Executing locally...",
|
|
325
327
|
"task.activity.generating": "Generating response...",
|
|
326
328
|
"task.activity.gotResult": "Tool result received",
|
|
327
329
|
"task.activity.toolCalling": "Calling {{toolName}}...",
|
|
328
330
|
"task.activity.toolResult": "{{toolName}} result received",
|
|
329
331
|
"task.batchTasks": "{{count}} Batch Subtasks",
|
|
332
|
+
"task.instruction": "Task Instruction",
|
|
333
|
+
"task.intermediateSteps": "{{count}} intermediate steps",
|
|
334
|
+
"task.metrics.duration": "(took {{duration}})",
|
|
330
335
|
"task.metrics.stepsShort": "steps",
|
|
331
|
-
"task.metrics.toolCallsShort": "
|
|
336
|
+
"task.metrics.toolCallsShort": "skill uses",
|
|
332
337
|
"task.status.cancelled": "Task Cancelled",
|
|
333
338
|
"task.status.failed": "Task Failed",
|
|
334
339
|
"task.status.initializing": "Initializing task...",
|
|
@@ -141,6 +141,7 @@
|
|
|
141
141
|
"filterBy.timePeriod.year": "Last Year",
|
|
142
142
|
"footer.desc": "Evolve with AI users worldwide. Become a creator to submit your agents and skills to the LobeHub Community.",
|
|
143
143
|
"footer.title": "Share your creation on LobeHub Community today",
|
|
144
|
+
"groupAgents.tag": "Group",
|
|
144
145
|
"home.communityAgents": "Community Agents",
|
|
145
146
|
"home.featuredAssistants": "Featured Agents",
|
|
146
147
|
"home.featuredModels": "Featured Models",
|
package/locales/zh-CN/chat.json
CHANGED
|
@@ -204,6 +204,7 @@
|
|
|
204
204
|
"noSelectedAgents": "还未选择成员",
|
|
205
205
|
"openInNewWindow": "在新窗口打开",
|
|
206
206
|
"operation.execAgentRuntime": "准备响应中",
|
|
207
|
+
"operation.execClientTask": "执行任务中",
|
|
207
208
|
"operation.sendMessage": "消息发送中",
|
|
208
209
|
"owner": "群主",
|
|
209
210
|
"pageCopilot.title": "文稿助理",
|
|
@@ -322,11 +323,15 @@
|
|
|
322
323
|
"tab.profile": "助理档案",
|
|
323
324
|
"tab.search": "搜索",
|
|
324
325
|
"task.activity.calling": "正在调用技能…",
|
|
326
|
+
"task.activity.clientExecuting": "本地执行中…",
|
|
325
327
|
"task.activity.generating": "正在生成回复…",
|
|
326
328
|
"task.activity.gotResult": "已获取技能结果",
|
|
327
329
|
"task.activity.toolCalling": "正在调用 {{toolName}}…",
|
|
328
330
|
"task.activity.toolResult": "已获取 {{toolName}} 结果",
|
|
329
331
|
"task.batchTasks": "{{count}} 个批量子任务",
|
|
332
|
+
"task.instruction": "任务说明",
|
|
333
|
+
"task.intermediateSteps": "{{count}} 个中间步骤",
|
|
334
|
+
"task.metrics.duration": "(用时 {{duration}})",
|
|
330
335
|
"task.metrics.stepsShort": "步",
|
|
331
336
|
"task.metrics.toolCallsShort": "次技能调用",
|
|
332
337
|
"task.status.cancelled": "任务已取消",
|
|
@@ -141,6 +141,7 @@
|
|
|
141
141
|
"filterBy.timePeriod.year": "近一年",
|
|
142
142
|
"footer.desc": "与全球 AI 用户共同进化。成为创作者,向 LobeHub 社区提交你的助手和技能。",
|
|
143
143
|
"footer.title": "立即在 LobeHub 社区分享你的创作",
|
|
144
|
+
"groupAgents.tag": "群组",
|
|
144
145
|
"home.communityAgents": "社区助理",
|
|
145
146
|
"home.featuredAssistants": "推荐助理",
|
|
146
147
|
"home.featuredModels": "推荐模型",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.329",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -359,6 +359,30 @@ export class GeneralChatAgent implements Agent {
|
|
|
359
359
|
type: 'exec_tasks',
|
|
360
360
|
};
|
|
361
361
|
}
|
|
362
|
+
|
|
363
|
+
// GTD client-side async task (single, desktop only)
|
|
364
|
+
if (stateType === 'execClientTask') {
|
|
365
|
+
const { parentMessageId: execParentId, task } = data.state as {
|
|
366
|
+
parentMessageId: string;
|
|
367
|
+
task: any;
|
|
368
|
+
};
|
|
369
|
+
return {
|
|
370
|
+
payload: { parentMessageId: execParentId, task },
|
|
371
|
+
type: 'exec_client_task',
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// GTD client-side async tasks (multiple, desktop only)
|
|
376
|
+
if (stateType === 'execClientTasks') {
|
|
377
|
+
const { parentMessageId: execParentId, tasks } = data.state as {
|
|
378
|
+
parentMessageId: string;
|
|
379
|
+
tasks: any[];
|
|
380
|
+
};
|
|
381
|
+
return {
|
|
382
|
+
payload: { parentMessageId: execParentId, tasks },
|
|
383
|
+
type: 'exec_client_tasks',
|
|
384
|
+
};
|
|
385
|
+
}
|
|
362
386
|
}
|
|
363
387
|
|
|
364
388
|
// Check if there are still pending tool messages waiting for approval
|
|
@@ -368,6 +368,216 @@ describe('GeneralChatAgent', () => {
|
|
|
368
368
|
});
|
|
369
369
|
|
|
370
370
|
describe('tool_result phase', () => {
|
|
371
|
+
describe('GTD async tasks', () => {
|
|
372
|
+
it('should return exec_task for single async task (execTask)', async () => {
|
|
373
|
+
const agent = new GeneralChatAgent({
|
|
374
|
+
agentConfig: { maxSteps: 100 },
|
|
375
|
+
operationId: 'test-session',
|
|
376
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
const state = createMockState();
|
|
380
|
+
const context = createMockContext('tool_result', {
|
|
381
|
+
parentMessageId: 'tool-msg-1',
|
|
382
|
+
stop: true,
|
|
383
|
+
data: {
|
|
384
|
+
state: {
|
|
385
|
+
type: 'execTask',
|
|
386
|
+
parentMessageId: 'exec-parent-msg',
|
|
387
|
+
task: { instruction: 'Do something async', timeout: 30000 },
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const result = await agent.runner(context, state);
|
|
393
|
+
|
|
394
|
+
expect(result).toEqual({
|
|
395
|
+
type: 'exec_task',
|
|
396
|
+
payload: {
|
|
397
|
+
parentMessageId: 'exec-parent-msg',
|
|
398
|
+
task: { instruction: 'Do something async', timeout: 30000 },
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('should return exec_tasks for multiple async tasks (execTasks)', async () => {
|
|
404
|
+
const agent = new GeneralChatAgent({
|
|
405
|
+
agentConfig: { maxSteps: 100 },
|
|
406
|
+
operationId: 'test-session',
|
|
407
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
const state = createMockState();
|
|
411
|
+
const tasks = [
|
|
412
|
+
{ instruction: 'Task 1', timeout: 30000 },
|
|
413
|
+
{ instruction: 'Task 2', timeout: 30000 },
|
|
414
|
+
];
|
|
415
|
+
const context = createMockContext('tool_result', {
|
|
416
|
+
parentMessageId: 'tool-msg-1',
|
|
417
|
+
stop: true,
|
|
418
|
+
data: {
|
|
419
|
+
state: {
|
|
420
|
+
type: 'execTasks',
|
|
421
|
+
parentMessageId: 'exec-parent-msg',
|
|
422
|
+
tasks,
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
const result = await agent.runner(context, state);
|
|
428
|
+
|
|
429
|
+
expect(result).toEqual({
|
|
430
|
+
type: 'exec_tasks',
|
|
431
|
+
payload: {
|
|
432
|
+
parentMessageId: 'exec-parent-msg',
|
|
433
|
+
tasks,
|
|
434
|
+
},
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it('should return exec_client_task for single client-side async task (execClientTask)', async () => {
|
|
439
|
+
const agent = new GeneralChatAgent({
|
|
440
|
+
agentConfig: { maxSteps: 100 },
|
|
441
|
+
operationId: 'test-session',
|
|
442
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
const state = createMockState();
|
|
446
|
+
const context = createMockContext('tool_result', {
|
|
447
|
+
parentMessageId: 'tool-msg-1',
|
|
448
|
+
stop: true,
|
|
449
|
+
data: {
|
|
450
|
+
state: {
|
|
451
|
+
type: 'execClientTask',
|
|
452
|
+
parentMessageId: 'exec-parent-msg',
|
|
453
|
+
task: { type: 'localFile', path: '/path/to/file' },
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const result = await agent.runner(context, state);
|
|
459
|
+
|
|
460
|
+
expect(result).toEqual({
|
|
461
|
+
type: 'exec_client_task',
|
|
462
|
+
payload: {
|
|
463
|
+
parentMessageId: 'exec-parent-msg',
|
|
464
|
+
task: { type: 'localFile', path: '/path/to/file' },
|
|
465
|
+
},
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('should return exec_client_tasks for multiple client-side async tasks (execClientTasks)', async () => {
|
|
470
|
+
const agent = new GeneralChatAgent({
|
|
471
|
+
agentConfig: { maxSteps: 100 },
|
|
472
|
+
operationId: 'test-session',
|
|
473
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
const state = createMockState();
|
|
477
|
+
const tasks = [
|
|
478
|
+
{ type: 'localFile', path: '/path/to/file1' },
|
|
479
|
+
{ type: 'localFile', path: '/path/to/file2' },
|
|
480
|
+
];
|
|
481
|
+
const context = createMockContext('tool_result', {
|
|
482
|
+
parentMessageId: 'tool-msg-1',
|
|
483
|
+
stop: true,
|
|
484
|
+
data: {
|
|
485
|
+
state: {
|
|
486
|
+
type: 'execClientTasks',
|
|
487
|
+
parentMessageId: 'exec-parent-msg',
|
|
488
|
+
tasks,
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
const result = await agent.runner(context, state);
|
|
494
|
+
|
|
495
|
+
expect(result).toEqual({
|
|
496
|
+
type: 'exec_client_tasks',
|
|
497
|
+
payload: {
|
|
498
|
+
parentMessageId: 'exec-parent-msg',
|
|
499
|
+
tasks,
|
|
500
|
+
},
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('should not trigger exec_task when stop is false', async () => {
|
|
505
|
+
const agent = new GeneralChatAgent({
|
|
506
|
+
agentConfig: { maxSteps: 100 },
|
|
507
|
+
operationId: 'test-session',
|
|
508
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
const state = createMockState({
|
|
512
|
+
messages: [
|
|
513
|
+
{ role: 'user', content: 'Hello' },
|
|
514
|
+
{ role: 'assistant', content: '' },
|
|
515
|
+
{ role: 'tool', content: 'Result', tool_call_id: 'call-1' },
|
|
516
|
+
] as any,
|
|
517
|
+
});
|
|
518
|
+
const context = createMockContext('tool_result', {
|
|
519
|
+
parentMessageId: 'tool-msg-1',
|
|
520
|
+
stop: false, // stop is false, should not trigger exec_task
|
|
521
|
+
data: {
|
|
522
|
+
state: {
|
|
523
|
+
type: 'execTask',
|
|
524
|
+
parentMessageId: 'exec-parent-msg',
|
|
525
|
+
task: { instruction: 'Do something async' },
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
const result = await agent.runner(context, state);
|
|
531
|
+
|
|
532
|
+
// Should return call_llm instead of exec_task
|
|
533
|
+
expect(result).toEqual({
|
|
534
|
+
type: 'call_llm',
|
|
535
|
+
payload: {
|
|
536
|
+
messages: state.messages,
|
|
537
|
+
model: 'gpt-4o-mini',
|
|
538
|
+
parentMessageId: 'tool-msg-1',
|
|
539
|
+
provider: 'openai',
|
|
540
|
+
tools: undefined,
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
it('should not trigger exec_task when data.state is undefined', async () => {
|
|
546
|
+
const agent = new GeneralChatAgent({
|
|
547
|
+
agentConfig: { maxSteps: 100 },
|
|
548
|
+
operationId: 'test-session',
|
|
549
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
const state = createMockState({
|
|
553
|
+
messages: [
|
|
554
|
+
{ role: 'user', content: 'Hello' },
|
|
555
|
+
{ role: 'assistant', content: '' },
|
|
556
|
+
{ role: 'tool', content: 'Result', tool_call_id: 'call-1' },
|
|
557
|
+
] as any,
|
|
558
|
+
});
|
|
559
|
+
const context = createMockContext('tool_result', {
|
|
560
|
+
parentMessageId: 'tool-msg-1',
|
|
561
|
+
stop: true,
|
|
562
|
+
data: {}, // No state property
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
const result = await agent.runner(context, state);
|
|
566
|
+
|
|
567
|
+
// Should return call_llm instead of exec_task
|
|
568
|
+
expect(result).toEqual({
|
|
569
|
+
type: 'call_llm',
|
|
570
|
+
payload: {
|
|
571
|
+
messages: state.messages,
|
|
572
|
+
model: 'gpt-4o-mini',
|
|
573
|
+
parentMessageId: 'tool-msg-1',
|
|
574
|
+
provider: 'openai',
|
|
575
|
+
tools: undefined,
|
|
576
|
+
},
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
|
|
371
581
|
it('should return call_llm when no pending tools', async () => {
|
|
372
582
|
const agent = new GeneralChatAgent({
|
|
373
583
|
agentConfig: { maxSteps: 100 },
|
|
@@ -236,12 +236,26 @@ export interface ExecTaskItem {
|
|
|
236
236
|
inheritMessages?: boolean;
|
|
237
237
|
/** Detailed instruction/prompt for the task execution */
|
|
238
238
|
instruction: string;
|
|
239
|
+
/**
|
|
240
|
+
* Whether to execute the task on the client side (desktop only).
|
|
241
|
+
* When true and running on desktop, the task will be executed locally
|
|
242
|
+
* with access to local tools (file system, shell commands, etc.).
|
|
243
|
+
*
|
|
244
|
+
* IMPORTANT: This MUST be set to true when the task requires:
|
|
245
|
+
* - Reading/writing local files via `local-system` tool
|
|
246
|
+
* - Executing shell commands
|
|
247
|
+
* - Any other desktop-only local tool operations
|
|
248
|
+
*
|
|
249
|
+
* If not specified or false, the task runs on the server (default behavior).
|
|
250
|
+
* On non-desktop platforms (web), this flag is ignored and tasks always run on server.
|
|
251
|
+
*/
|
|
252
|
+
runInClient?: boolean;
|
|
239
253
|
/** Timeout in milliseconds (optional, default 30 minutes) */
|
|
240
254
|
timeout?: number;
|
|
241
255
|
}
|
|
242
256
|
|
|
243
257
|
/**
|
|
244
|
-
* Instruction to execute a single async task
|
|
258
|
+
* Instruction to execute a single async task (server-side)
|
|
245
259
|
*/
|
|
246
260
|
export interface AgentInstructionExecTask {
|
|
247
261
|
payload: {
|
|
@@ -254,7 +268,7 @@ export interface AgentInstructionExecTask {
|
|
|
254
268
|
}
|
|
255
269
|
|
|
256
270
|
/**
|
|
257
|
-
* Instruction to execute multiple async tasks in parallel
|
|
271
|
+
* Instruction to execute multiple async tasks in parallel (server-side)
|
|
258
272
|
*/
|
|
259
273
|
export interface AgentInstructionExecTasks {
|
|
260
274
|
payload: {
|
|
@@ -266,6 +280,34 @@ export interface AgentInstructionExecTasks {
|
|
|
266
280
|
type: 'exec_tasks';
|
|
267
281
|
}
|
|
268
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Instruction to execute a single async task on the client (desktop only)
|
|
285
|
+
* Used when task requires local tools like file system or shell commands
|
|
286
|
+
*/
|
|
287
|
+
export interface AgentInstructionExecClientTask {
|
|
288
|
+
payload: {
|
|
289
|
+
/** Parent message ID (tool message that triggered the task) */
|
|
290
|
+
parentMessageId: string;
|
|
291
|
+
/** Task to execute */
|
|
292
|
+
task: ExecTaskItem;
|
|
293
|
+
};
|
|
294
|
+
type: 'exec_client_task';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Instruction to execute multiple async tasks on the client in parallel (desktop only)
|
|
299
|
+
* Used when tasks require local tools like file system or shell commands
|
|
300
|
+
*/
|
|
301
|
+
export interface AgentInstructionExecClientTasks {
|
|
302
|
+
payload: {
|
|
303
|
+
/** Parent message ID (tool message that triggered the tasks) */
|
|
304
|
+
parentMessageId: string;
|
|
305
|
+
/** Array of tasks to execute */
|
|
306
|
+
tasks: ExecTaskItem[];
|
|
307
|
+
};
|
|
308
|
+
type: 'exec_client_tasks';
|
|
309
|
+
}
|
|
310
|
+
|
|
269
311
|
/**
|
|
270
312
|
* Payload for task_result phase (single task)
|
|
271
313
|
*/
|
|
@@ -318,6 +360,8 @@ export type AgentInstruction =
|
|
|
318
360
|
| AgentInstructionCallToolsBatch
|
|
319
361
|
| AgentInstructionExecTask
|
|
320
362
|
| AgentInstructionExecTasks
|
|
363
|
+
| AgentInstructionExecClientTask
|
|
364
|
+
| AgentInstructionExecClientTasks
|
|
321
365
|
| AgentInstructionRequestHumanPrompt
|
|
322
366
|
| AgentInstructionRequestHumanSelect
|
|
323
367
|
| AgentInstructionRequestHumanApprove
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const isDesktop = process.env.NEXT_PUBLIC_IS_DESKTOP_APP === '1';
|