@lobehub/lobehub 2.0.0-next.311 → 2.0.0-next.313
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/CHANGELOG.md +59 -0
- package/apps/desktop/src/main/controllers/AuthCtr.ts +75 -7
- package/changelog/v1.json +21 -0
- package/docs/usage/providers/internlm.mdx +2 -2
- package/docs/usage/providers/internlm.zh-CN.mdx +3 -3
- package/e2e/README.md +1 -1
- package/e2e/src/features/community/detail-pages.feature +2 -2
- package/e2e/src/features/community/interactions.feature +5 -5
- package/e2e/src/features/community/smoke.feature +1 -1
- package/e2e/src/steps/community/detail-pages.steps.ts +6 -4
- package/e2e/src/steps/community/interactions.steps.ts +3 -3
- package/locales/en-US/error.json +10 -1
- package/locales/en-US/subscription.json +1 -1
- package/locales/zh-CN/desktop-onboarding.json +5 -0
- package/locales/zh-CN/error.json +10 -1
- package/locales/zh-CN/subscription.json +1 -1
- package/package.json +1 -1
- package/packages/agent-runtime/src/agents/GeneralChatAgent.ts +14 -2
- package/packages/agent-runtime/src/agents/__tests__/GeneralChatAgent.test.ts +275 -1
- package/packages/builtin-tool-agent-builder/src/systemRole.ts +9 -0
- package/packages/builtin-tool-cloud-sandbox/package.json +1 -0
- package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +105 -134
- package/packages/builtin-tool-cloud-sandbox/src/executor/index.ts +254 -0
- package/packages/builtin-tool-cloud-sandbox/src/index.ts +1 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/api.ts +22 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/index.ts +4 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/params.ts +85 -0
- package/packages/builtin-tool-cloud-sandbox/src/types/service.ts +48 -0
- package/packages/builtin-tool-cloud-sandbox/src/{types.ts → types/state.ts} +0 -23
- package/packages/builtin-tool-memory/src/manifest.ts +5 -5
- package/packages/editor-runtime/src/__tests__/EditorRuntime.real.test.ts +1 -1
- package/packages/editor-runtime/src/__tests__/EditorRuntime.test.ts +1 -1
- package/packages/electron-client-ipc/src/events/index.ts +5 -1
- package/packages/electron-client-ipc/src/events/remoteServer.ts +23 -0
- package/packages/memory-user-memory/src/schemas/index.ts +0 -1
- package/packages/model-bank/src/modelProviders/internlm.ts +1 -1
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +5 -15
- package/packages/model-runtime/src/providers/internlm/index.test.ts +15 -15
- package/packages/model-runtime/src/providers/internlm/index.ts +1 -1
- package/packages/types/src/tool/intervention.ts +4 -2
- package/packages/types/src/user/preference.ts +1 -0
- package/public/favicon-32x-32-error.ico +0 -0
- package/public/favicon-32x32-done-dev.ico +0 -0
- package/public/favicon-32x32-done.ico +0 -0
- package/public/favicon-32x32-error-dev.ico +0 -0
- package/public/favicon-32x32-progress-dev.ico +0 -0
- package/public/favicon-32x32-progress.ico +0 -0
- package/public/favicon-done-dev.ico +0 -0
- package/public/favicon-done.ico +0 -0
- package/public/favicon-error-dev.ico +0 -0
- package/public/favicon-error.ico +0 -0
- package/public/favicon-progress-dev.ico +0 -0
- package/public/favicon-progress.ico +0 -0
- package/src/app/[variants]/(desktop)/desktop-onboarding/features/LoginStep.tsx +84 -26
- package/src/app/[variants]/(main)/_layout/DesktopAutoOidcOnFirstOpen.tsx +4 -0
- package/src/app/[variants]/(main)/agent/profile/features/Header/AgentPublishButton/PublishResultModal.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/_layout/Header.tsx +15 -3
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Overview/TagList.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Related/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/SystemRole/TagList.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/SystemRole/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Header.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/ActionButton/AddAgent.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/ActionButton/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Related/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/StatusPage/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserAgentCard.tsx +2 -2
- package/src/app/[variants]/(main)/community/(detail)/user/features/UserFavoriteAgents.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/(home)/index.tsx +2 -2
- package/src/app/[variants]/(main)/community/(list)/(home)/loading.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/Client.tsx +5 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/Category/index.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/Item.tsx +1 -1
- package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/MarketSourceSwitch.tsx +1 -1
- package/src/app/[variants]/(main)/community/_layout/Sidebar/Header/Nav.tsx +2 -2
- package/src/app/[variants]/(main)/home/features/CommunityAgents/List.tsx +1 -1
- package/src/app/[variants]/(main)/home/features/CommunityAgents/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/_layout/index.tsx +1 -1
- package/src/app/[variants]/(mobile)/router/mobileRouter.config.tsx +6 -6
- package/src/app/[variants]/router/desktopRouter.config.tsx +8 -8
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
- package/src/business/server/user.ts +4 -0
- package/src/features/CommandMenu/SearchResults.tsx +1 -1
- package/src/features/Conversation/Messages/Task/Actions/index.tsx +0 -2
- package/src/features/Conversation/Messages/Task/index.tsx +1 -1
- package/src/features/Conversation/Messages/Tasks/shared/ProcessingState.tsx +0 -2
- package/src/features/Electron/navigation/routeMetadata.ts +1 -1
- package/src/features/NavPanel/components/NavPanelDraggable.tsx +0 -14
- package/src/features/ResourceManager/components/Explorer/ItemDropdown/useFileItemDropdown.tsx +4 -3
- package/src/features/SharePopover/index.tsx +5 -3
- package/src/hooks/useAppOrigin.ts +16 -0
- package/src/layout/GlobalProvider/FaviconProvider.tsx +92 -0
- package/src/layout/GlobalProvider/index.tsx +15 -11
- package/src/layout/GlobalProvider/useUserStateRedirect.ts +37 -24
- package/src/libs/next/config/define-config.ts +1 -1
- package/src/libs/trusted-client/index.ts +2 -5
- package/src/locales/default/desktop-onboarding.ts +5 -0
- package/src/locales/default/error.ts +11 -0
- package/src/locales/default/subscription.ts +1 -1
- package/src/server/modules/AgentRuntime/RuntimeExecutors.ts +2 -0
- package/src/server/routers/lambda/user.ts +24 -10
- package/src/server/services/agentRuntime/AgentRuntimeService.test.ts +3 -0
- package/src/server/services/agentRuntime/AgentRuntimeService.ts +8 -5
- package/src/server/services/agentRuntime/types.ts +7 -0
- package/src/server/services/aiAgent/__tests__/execGroupSubAgentTask.test.ts +3 -0
- package/src/server/services/aiAgent/index.ts +10 -4
- package/src/server/services/market/index.ts +7 -0
- package/src/server/services/sandbox/index.ts +120 -0
- package/src/server/services/toolExecution/builtin.ts +12 -18
- package/src/server/services/toolExecution/index.ts +1 -1
- package/src/server/services/toolExecution/serverRuntimes/cloudSandbox.ts +31 -0
- package/src/server/services/toolExecution/serverRuntimes/index.ts +55 -0
- package/src/server/services/toolExecution/serverRuntimes/types.ts +14 -0
- package/src/server/services/toolExecution/serverRuntimes/webBrowsing.ts +20 -0
- package/src/server/services/toolExecution/types.ts +2 -0
- package/src/server/sitemap.test.ts +5 -5
- package/src/server/sitemap.ts +3 -3
- package/src/services/{codeInterpreter.ts → cloudSandbox.ts} +3 -3
- package/src/services/electron/remoteServer.ts +8 -0
- package/src/store/chat/agents/GroupOrchestration/__tests__/batch-exec-async-tasks.test.ts +626 -0
- package/src/store/chat/agents/GroupOrchestration/createGroupOrchestrationExecutors.ts +294 -0
- package/src/store/chat/slices/plugin/action.test.ts +0 -48
- package/src/store/chat/slices/plugin/actions/pluginTypes.ts +0 -131
- package/src/store/tool/slices/builtin/executors/index.ts +2 -0
- package/src/store/user/slices/settings/selectors/toolIntervention.test.ts +143 -0
- package/src/store/user/slices/settings/selectors/toolIntervention.ts +11 -2
- package/packages/memory-user-memory/src/schemas/jsonSchemas.ts +0 -37
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/DetailProvider.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Block.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Knowledge.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/KnowledgeItem.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/PluginItem.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/Plugins.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Capabilities/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Nav.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Overview/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/Versions/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Details/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Related/Item.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/Summary/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/TocList/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/features/Sidebar/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(detail)/{assistant → agent}/loading.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/_layout/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/_layout/style.ts +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/Category/useCategory.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/TokenTag.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/features/List/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/index.tsx +0 -0
- /package/src/app/[variants]/(main)/community/(list)/{assistant → agent}/loading.tsx +0 -0
|
@@ -911,7 +911,12 @@ describe('GeneralChatAgent', () => {
|
|
|
911
911
|
|
|
912
912
|
const context = createMockContext('task_result', {
|
|
913
913
|
parentMessageId: 'task-parent-msg',
|
|
914
|
-
result: {
|
|
914
|
+
result: {
|
|
915
|
+
success: true,
|
|
916
|
+
taskMessageId: 'task-1',
|
|
917
|
+
threadId: 'thread-1',
|
|
918
|
+
result: 'Task result',
|
|
919
|
+
},
|
|
915
920
|
});
|
|
916
921
|
|
|
917
922
|
const result = await agent.runner(context, state);
|
|
@@ -1519,4 +1524,273 @@ describe('GeneralChatAgent', () => {
|
|
|
1519
1524
|
]);
|
|
1520
1525
|
});
|
|
1521
1526
|
});
|
|
1527
|
+
|
|
1528
|
+
describe('headless mode (for async tasks)', () => {
|
|
1529
|
+
it('should execute all tools directly in headless mode including those requiring approval', async () => {
|
|
1530
|
+
const agent = new GeneralChatAgent({
|
|
1531
|
+
agentConfig: { maxSteps: 100 },
|
|
1532
|
+
operationId: 'test-session',
|
|
1533
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
const toolCall: ChatToolPayload = {
|
|
1537
|
+
id: 'call-1',
|
|
1538
|
+
identifier: 'dangerous-tool',
|
|
1539
|
+
apiName: 'delete',
|
|
1540
|
+
arguments: '{}',
|
|
1541
|
+
type: 'default',
|
|
1542
|
+
};
|
|
1543
|
+
|
|
1544
|
+
const state = createMockState({
|
|
1545
|
+
toolManifestMap: {
|
|
1546
|
+
'dangerous-tool': {
|
|
1547
|
+
identifier: 'dangerous-tool',
|
|
1548
|
+
humanIntervention: 'required', // Tool requires approval
|
|
1549
|
+
},
|
|
1550
|
+
},
|
|
1551
|
+
userInterventionConfig: {
|
|
1552
|
+
approvalMode: 'headless', // Headless mode for async tasks
|
|
1553
|
+
},
|
|
1554
|
+
});
|
|
1555
|
+
|
|
1556
|
+
const context = createMockContext('llm_result', {
|
|
1557
|
+
hasToolsCalling: true,
|
|
1558
|
+
toolsCalling: [toolCall],
|
|
1559
|
+
parentMessageId: 'msg-1',
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
const result = await agent.runner(context, state);
|
|
1563
|
+
|
|
1564
|
+
// Should execute directly in headless mode
|
|
1565
|
+
expect(result).toEqual([
|
|
1566
|
+
{
|
|
1567
|
+
type: 'call_tool',
|
|
1568
|
+
payload: {
|
|
1569
|
+
parentMessageId: 'msg-1',
|
|
1570
|
+
toolCalling: toolCall,
|
|
1571
|
+
},
|
|
1572
|
+
},
|
|
1573
|
+
]);
|
|
1574
|
+
});
|
|
1575
|
+
|
|
1576
|
+
it('should execute tools with "always" policy in headless mode', async () => {
|
|
1577
|
+
const agent = new GeneralChatAgent({
|
|
1578
|
+
agentConfig: { maxSteps: 100 },
|
|
1579
|
+
operationId: 'test-session',
|
|
1580
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
const alwaysTool: ChatToolPayload = {
|
|
1584
|
+
id: 'call-1',
|
|
1585
|
+
identifier: 'agent-builder',
|
|
1586
|
+
apiName: 'installPlugin',
|
|
1587
|
+
arguments: '{"identifier":"some-plugin","source":"market"}',
|
|
1588
|
+
type: 'builtin',
|
|
1589
|
+
};
|
|
1590
|
+
|
|
1591
|
+
const state = createMockState({
|
|
1592
|
+
toolManifestMap: {
|
|
1593
|
+
'agent-builder': {
|
|
1594
|
+
identifier: 'agent-builder',
|
|
1595
|
+
api: [
|
|
1596
|
+
{
|
|
1597
|
+
name: 'installPlugin',
|
|
1598
|
+
humanIntervention: 'always', // Always requires intervention normally
|
|
1599
|
+
},
|
|
1600
|
+
],
|
|
1601
|
+
},
|
|
1602
|
+
},
|
|
1603
|
+
userInterventionConfig: {
|
|
1604
|
+
approvalMode: 'headless', // Headless mode bypasses even 'always'
|
|
1605
|
+
},
|
|
1606
|
+
});
|
|
1607
|
+
|
|
1608
|
+
const context = createMockContext('llm_result', {
|
|
1609
|
+
hasToolsCalling: true,
|
|
1610
|
+
toolsCalling: [alwaysTool],
|
|
1611
|
+
parentMessageId: 'msg-1',
|
|
1612
|
+
});
|
|
1613
|
+
|
|
1614
|
+
const result = await agent.runner(context, state);
|
|
1615
|
+
|
|
1616
|
+
// Should execute directly in headless mode, even for 'always' policy
|
|
1617
|
+
expect(result).toEqual([
|
|
1618
|
+
{
|
|
1619
|
+
type: 'call_tool',
|
|
1620
|
+
payload: {
|
|
1621
|
+
parentMessageId: 'msg-1',
|
|
1622
|
+
toolCalling: alwaysTool,
|
|
1623
|
+
},
|
|
1624
|
+
},
|
|
1625
|
+
]);
|
|
1626
|
+
});
|
|
1627
|
+
|
|
1628
|
+
it('should skip security blacklisted tools in headless mode', async () => {
|
|
1629
|
+
const agent = new GeneralChatAgent({
|
|
1630
|
+
agentConfig: { maxSteps: 100 },
|
|
1631
|
+
operationId: 'test-session',
|
|
1632
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
1633
|
+
});
|
|
1634
|
+
|
|
1635
|
+
const blacklistedTool: ChatToolPayload = {
|
|
1636
|
+
id: 'call-1',
|
|
1637
|
+
identifier: 'bash',
|
|
1638
|
+
apiName: 'bash',
|
|
1639
|
+
arguments: '{"command":"rm -rf /"}', // Matches security blacklist
|
|
1640
|
+
type: 'builtin',
|
|
1641
|
+
};
|
|
1642
|
+
|
|
1643
|
+
const state = createMockState({
|
|
1644
|
+
toolManifestMap: {
|
|
1645
|
+
bash: {
|
|
1646
|
+
identifier: 'bash',
|
|
1647
|
+
humanIntervention: 'never',
|
|
1648
|
+
},
|
|
1649
|
+
},
|
|
1650
|
+
userInterventionConfig: {
|
|
1651
|
+
approvalMode: 'headless',
|
|
1652
|
+
},
|
|
1653
|
+
// Using default security blacklist which blocks "rm -rf /"
|
|
1654
|
+
});
|
|
1655
|
+
|
|
1656
|
+
const context = createMockContext('llm_result', {
|
|
1657
|
+
hasToolsCalling: true,
|
|
1658
|
+
toolsCalling: [blacklistedTool],
|
|
1659
|
+
parentMessageId: 'msg-1',
|
|
1660
|
+
});
|
|
1661
|
+
|
|
1662
|
+
const result = await agent.runner(context, state);
|
|
1663
|
+
|
|
1664
|
+
// Should return empty array (tool is skipped, not executed or pending)
|
|
1665
|
+
expect(result).toEqual([]);
|
|
1666
|
+
});
|
|
1667
|
+
|
|
1668
|
+
it('should handle mixed tools in headless mode - execute safe ones, skip blacklisted', async () => {
|
|
1669
|
+
const agent = new GeneralChatAgent({
|
|
1670
|
+
agentConfig: { maxSteps: 100 },
|
|
1671
|
+
operationId: 'test-session',
|
|
1672
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
1673
|
+
});
|
|
1674
|
+
|
|
1675
|
+
const safeTool: ChatToolPayload = {
|
|
1676
|
+
id: 'call-1',
|
|
1677
|
+
identifier: 'web-search',
|
|
1678
|
+
apiName: 'search',
|
|
1679
|
+
arguments: '{"query":"hello"}',
|
|
1680
|
+
type: 'default',
|
|
1681
|
+
};
|
|
1682
|
+
|
|
1683
|
+
const blacklistedTool: ChatToolPayload = {
|
|
1684
|
+
id: 'call-2',
|
|
1685
|
+
identifier: 'bash',
|
|
1686
|
+
apiName: 'bash',
|
|
1687
|
+
arguments: '{"command":"rm -rf /"}', // Matches security blacklist
|
|
1688
|
+
type: 'builtin',
|
|
1689
|
+
};
|
|
1690
|
+
|
|
1691
|
+
const alwaysTool: ChatToolPayload = {
|
|
1692
|
+
id: 'call-3',
|
|
1693
|
+
identifier: 'agent-builder',
|
|
1694
|
+
apiName: 'installPlugin',
|
|
1695
|
+
arguments: '{}',
|
|
1696
|
+
type: 'builtin',
|
|
1697
|
+
};
|
|
1698
|
+
|
|
1699
|
+
const state = createMockState({
|
|
1700
|
+
toolManifestMap: {
|
|
1701
|
+
'web-search': {
|
|
1702
|
+
identifier: 'web-search',
|
|
1703
|
+
humanIntervention: 'required',
|
|
1704
|
+
},
|
|
1705
|
+
'bash': {
|
|
1706
|
+
identifier: 'bash',
|
|
1707
|
+
},
|
|
1708
|
+
'agent-builder': {
|
|
1709
|
+
identifier: 'agent-builder',
|
|
1710
|
+
api: [
|
|
1711
|
+
{
|
|
1712
|
+
name: 'installPlugin',
|
|
1713
|
+
humanIntervention: 'always',
|
|
1714
|
+
},
|
|
1715
|
+
],
|
|
1716
|
+
},
|
|
1717
|
+
},
|
|
1718
|
+
userInterventionConfig: {
|
|
1719
|
+
approvalMode: 'headless',
|
|
1720
|
+
},
|
|
1721
|
+
});
|
|
1722
|
+
|
|
1723
|
+
const context = createMockContext('llm_result', {
|
|
1724
|
+
hasToolsCalling: true,
|
|
1725
|
+
toolsCalling: [safeTool, blacklistedTool, alwaysTool],
|
|
1726
|
+
parentMessageId: 'msg-1',
|
|
1727
|
+
});
|
|
1728
|
+
|
|
1729
|
+
const result = await agent.runner(context, state);
|
|
1730
|
+
|
|
1731
|
+
// Should execute safeTool and alwaysTool, skip blacklistedTool
|
|
1732
|
+
expect(result).toEqual([
|
|
1733
|
+
{
|
|
1734
|
+
type: 'call_tools_batch',
|
|
1735
|
+
payload: {
|
|
1736
|
+
parentMessageId: 'msg-1',
|
|
1737
|
+
toolsCalling: [safeTool, alwaysTool],
|
|
1738
|
+
},
|
|
1739
|
+
},
|
|
1740
|
+
]);
|
|
1741
|
+
});
|
|
1742
|
+
|
|
1743
|
+
it('should execute multiple tools as batch in headless mode', async () => {
|
|
1744
|
+
const agent = new GeneralChatAgent({
|
|
1745
|
+
agentConfig: { maxSteps: 100 },
|
|
1746
|
+
operationId: 'test-session',
|
|
1747
|
+
modelRuntimeConfig: mockModelRuntimeConfig,
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
const tool1: ChatToolPayload = {
|
|
1751
|
+
id: 'call-1',
|
|
1752
|
+
identifier: 'search',
|
|
1753
|
+
apiName: 'search',
|
|
1754
|
+
arguments: '{}',
|
|
1755
|
+
type: 'default',
|
|
1756
|
+
};
|
|
1757
|
+
|
|
1758
|
+
const tool2: ChatToolPayload = {
|
|
1759
|
+
id: 'call-2',
|
|
1760
|
+
identifier: 'crawl',
|
|
1761
|
+
apiName: 'crawl',
|
|
1762
|
+
arguments: '{}',
|
|
1763
|
+
type: 'default',
|
|
1764
|
+
};
|
|
1765
|
+
|
|
1766
|
+
const state = createMockState({
|
|
1767
|
+
toolManifestMap: {
|
|
1768
|
+
search: { identifier: 'search', humanIntervention: 'required' },
|
|
1769
|
+
crawl: { identifier: 'crawl', humanIntervention: 'always' },
|
|
1770
|
+
},
|
|
1771
|
+
userInterventionConfig: {
|
|
1772
|
+
approvalMode: 'headless',
|
|
1773
|
+
},
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1776
|
+
const context = createMockContext('llm_result', {
|
|
1777
|
+
hasToolsCalling: true,
|
|
1778
|
+
toolsCalling: [tool1, tool2],
|
|
1779
|
+
parentMessageId: 'msg-1',
|
|
1780
|
+
});
|
|
1781
|
+
|
|
1782
|
+
const result = await agent.runner(context, state);
|
|
1783
|
+
|
|
1784
|
+
// Should execute both tools as batch in headless mode
|
|
1785
|
+
expect(result).toEqual([
|
|
1786
|
+
{
|
|
1787
|
+
type: 'call_tools_batch',
|
|
1788
|
+
payload: {
|
|
1789
|
+
parentMessageId: 'msg-1',
|
|
1790
|
+
toolsCalling: [tool1, tool2],
|
|
1791
|
+
},
|
|
1792
|
+
},
|
|
1793
|
+
]);
|
|
1794
|
+
});
|
|
1795
|
+
});
|
|
1522
1796
|
});
|
|
@@ -86,6 +86,7 @@ Always adapt to user's language. Use natural descriptions, not raw field names.
|
|
|
86
86
|
5. **Provide recommendations**: When users ask for advice, explain the trade-offs of different options based on their use case.
|
|
87
87
|
6. **Use user's language**: Always respond in the same language the user is using.
|
|
88
88
|
7. **Keep it simple**: Focus on core settings. Don't overwhelm users with advanced options unless they ask.
|
|
89
|
+
8. **Install plugins one by one**: When multiple plugins need to be installed, install them sequentially one at a time instead of batching. This ensures better error handling, allows users to understand each plugin's purpose, and makes it easier to troubleshoot if something goes wrong.
|
|
89
90
|
</guidelines>
|
|
90
91
|
|
|
91
92
|
<configuration_knowledge>
|
|
@@ -202,6 +203,14 @@ Action: Use updateConfig with { config: { params: { temperature: 0.7 } } }
|
|
|
202
203
|
|
|
203
204
|
User: "我想调整对话配置" / "I want to configure chat settings"
|
|
204
205
|
Action: Explain the available chatConfig options and help them configure as needed.
|
|
206
|
+
|
|
207
|
+
User: "帮我安装网页浏览和图片生成这两个插件" / "Install web browsing and image generation plugins for me"
|
|
208
|
+
Action: Install plugins one by one:
|
|
209
|
+
1. First, use installPlugin to install "lobe-web-browsing", explain what it does
|
|
210
|
+
2. Wait for confirmation of success
|
|
211
|
+
3. Then, use installPlugin to install "lobe-image-generation", explain what it does
|
|
212
|
+
4. Confirm both plugins are installed successfully
|
|
213
|
+
This sequential approach ensures each plugin is properly installed and allows the user to understand each tool's purpose.
|
|
205
214
|
</examples>
|
|
206
215
|
|
|
207
216
|
<response_format>
|
|
@@ -1,125 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatEditResult,
|
|
3
|
+
formatFileContent,
|
|
4
|
+
formatFileList,
|
|
5
|
+
formatFileSearchResults,
|
|
6
|
+
formatGlobResults,
|
|
7
|
+
formatMoveResults,
|
|
8
|
+
formatRenameResult,
|
|
9
|
+
formatWriteResult,
|
|
10
|
+
} from '@lobechat/prompts';
|
|
1
11
|
import { type BuiltinServerRuntimeOutput } from '@lobechat/types';
|
|
2
12
|
|
|
3
|
-
import { codeInterpreterService } from '@/services/codeInterpreter';
|
|
4
|
-
|
|
5
13
|
import {
|
|
14
|
+
type EditLocalFileParams,
|
|
6
15
|
type EditLocalFileState,
|
|
16
|
+
type ExecuteCodeParams,
|
|
7
17
|
type ExecuteCodeState,
|
|
18
|
+
type ExportFileParams,
|
|
8
19
|
type ExportFileState,
|
|
20
|
+
type GetCommandOutputParams,
|
|
9
21
|
type GetCommandOutputState,
|
|
10
22
|
type GlobFilesState,
|
|
23
|
+
type GlobLocalFilesParams,
|
|
24
|
+
type GrepContentParams,
|
|
11
25
|
type GrepContentState,
|
|
26
|
+
type ISandboxService,
|
|
27
|
+
type KillCommandParams,
|
|
12
28
|
type KillCommandState,
|
|
29
|
+
type ListLocalFilesParams,
|
|
13
30
|
type ListLocalFilesState,
|
|
31
|
+
type MoveLocalFilesParams,
|
|
14
32
|
type MoveLocalFilesState,
|
|
33
|
+
type ReadLocalFileParams,
|
|
15
34
|
type ReadLocalFileState,
|
|
35
|
+
type RenameLocalFileParams,
|
|
16
36
|
type RenameLocalFileState,
|
|
37
|
+
type RunCommandParams,
|
|
17
38
|
type RunCommandState,
|
|
39
|
+
type SearchLocalFilesParams,
|
|
18
40
|
type SearchLocalFilesState,
|
|
41
|
+
type WriteLocalFileParams,
|
|
19
42
|
type WriteLocalFileState,
|
|
20
43
|
} from '../types';
|
|
21
44
|
|
|
22
45
|
/**
|
|
23
46
|
* Cloud Sandbox Execution Runtime
|
|
24
47
|
*
|
|
25
|
-
* This runtime executes tools via the
|
|
26
|
-
*
|
|
48
|
+
* This runtime executes tools via the injected ISandboxService.
|
|
49
|
+
* The service handles context (topicId, userId) internally - Runtime doesn't need to know about it.
|
|
27
50
|
*
|
|
28
|
-
*
|
|
29
|
-
* -
|
|
30
|
-
* -
|
|
31
|
-
* - The sessionExpiredAndRecreated flag indicates if recreation occurred
|
|
51
|
+
* Dependency Injection:
|
|
52
|
+
* - Client: Inject codeInterpreterService (uses tRPC client)
|
|
53
|
+
* - Server: Inject ServerSandboxService (uses MarketSDK directly)
|
|
32
54
|
*/
|
|
33
|
-
|
|
34
|
-
interface ExecutionContext {
|
|
35
|
-
topicId: string;
|
|
36
|
-
userId: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Types for tool parameters matching market-sdk
|
|
40
|
-
interface ListLocalFilesParams {
|
|
41
|
-
directoryPath: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
interface ReadLocalFileParams {
|
|
45
|
-
endLine?: number;
|
|
46
|
-
path: string;
|
|
47
|
-
startLine?: number;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
interface WriteLocalFileParams {
|
|
51
|
-
content: string;
|
|
52
|
-
createDirectories?: boolean;
|
|
53
|
-
path: string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface EditLocalFileParams {
|
|
57
|
-
all?: boolean;
|
|
58
|
-
path: string;
|
|
59
|
-
replace: string;
|
|
60
|
-
search: string;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
interface SearchLocalFilesParams {
|
|
64
|
-
directory: string;
|
|
65
|
-
fileType?: string;
|
|
66
|
-
keyword?: string;
|
|
67
|
-
modifiedAfter?: string;
|
|
68
|
-
modifiedBefore?: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
interface MoveLocalFilesParams {
|
|
72
|
-
operations: Array<{
|
|
73
|
-
destination: string;
|
|
74
|
-
source: string;
|
|
75
|
-
}>;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
interface RenameLocalFileParams {
|
|
79
|
-
newName: string;
|
|
80
|
-
oldPath: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
interface RunCommandParams {
|
|
84
|
-
background?: boolean;
|
|
85
|
-
command: string;
|
|
86
|
-
timeout?: number;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
interface GetCommandOutputParams {
|
|
90
|
-
commandId: string;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
interface KillCommandParams {
|
|
94
|
-
commandId: string;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
interface GrepContentParams {
|
|
98
|
-
directory: string;
|
|
99
|
-
filePattern?: string;
|
|
100
|
-
pattern: string;
|
|
101
|
-
recursive?: boolean;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
interface GlobLocalFilesParams {
|
|
105
|
-
directory?: string;
|
|
106
|
-
pattern: string;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
interface ExportFileParams {
|
|
110
|
-
path: string;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
interface ExecuteCodeParams {
|
|
114
|
-
code: string;
|
|
115
|
-
language?: 'javascript' | 'python' | 'typescript';
|
|
116
|
-
}
|
|
117
|
-
|
|
118
55
|
export class CloudSandboxExecutionRuntime {
|
|
119
|
-
private
|
|
56
|
+
private sandboxService: ISandboxService;
|
|
120
57
|
|
|
121
|
-
constructor(
|
|
122
|
-
this.
|
|
58
|
+
constructor(sandboxService: ISandboxService) {
|
|
59
|
+
this.sandboxService = sandboxService;
|
|
123
60
|
}
|
|
124
61
|
|
|
125
62
|
// ==================== File Operations ====================
|
|
@@ -128,12 +65,19 @@ export class CloudSandboxExecutionRuntime {
|
|
|
128
65
|
try {
|
|
129
66
|
const result = await this.callTool('listLocalFiles', args);
|
|
130
67
|
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
68
|
+
const files = result.result?.files || [];
|
|
69
|
+
const state: ListLocalFilesState = { files };
|
|
70
|
+
|
|
71
|
+
const content = formatFileList(
|
|
72
|
+
files.map((f: { isDirectory: boolean; name: string }) => ({
|
|
73
|
+
isDirectory: f.isDirectory,
|
|
74
|
+
name: f.name,
|
|
75
|
+
})),
|
|
76
|
+
args.directoryPath,
|
|
77
|
+
);
|
|
134
78
|
|
|
135
79
|
return {
|
|
136
|
-
content
|
|
80
|
+
content,
|
|
137
81
|
state,
|
|
138
82
|
success: true,
|
|
139
83
|
};
|
|
@@ -154,8 +98,19 @@ export class CloudSandboxExecutionRuntime {
|
|
|
154
98
|
totalLines: result.result?.totalLines,
|
|
155
99
|
};
|
|
156
100
|
|
|
101
|
+
const lineRange: [number, number] | undefined =
|
|
102
|
+
args.startLine !== undefined && args.endLine !== undefined
|
|
103
|
+
? [args.startLine, args.endLine]
|
|
104
|
+
: undefined;
|
|
105
|
+
|
|
106
|
+
const content = formatFileContent({
|
|
107
|
+
content: result.result?.content || '',
|
|
108
|
+
lineRange,
|
|
109
|
+
path: args.path,
|
|
110
|
+
});
|
|
111
|
+
|
|
157
112
|
return {
|
|
158
|
-
content
|
|
113
|
+
content,
|
|
159
114
|
state,
|
|
160
115
|
success: true,
|
|
161
116
|
};
|
|
@@ -174,11 +129,13 @@ export class CloudSandboxExecutionRuntime {
|
|
|
174
129
|
success: result.success,
|
|
175
130
|
};
|
|
176
131
|
|
|
132
|
+
const content = formatWriteResult({
|
|
133
|
+
path: args.path,
|
|
134
|
+
success: true,
|
|
135
|
+
});
|
|
136
|
+
|
|
177
137
|
return {
|
|
178
|
-
content
|
|
179
|
-
message: `Successfully wrote to ${args.path}`,
|
|
180
|
-
success: true,
|
|
181
|
-
}),
|
|
138
|
+
content,
|
|
182
139
|
state,
|
|
183
140
|
success: true,
|
|
184
141
|
};
|
|
@@ -199,13 +156,15 @@ export class CloudSandboxExecutionRuntime {
|
|
|
199
156
|
replacements: result.result?.replacements || 0,
|
|
200
157
|
};
|
|
201
158
|
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
159
|
+
const content = formatEditResult({
|
|
160
|
+
filePath: args.path,
|
|
161
|
+
linesAdded: state.linesAdded,
|
|
162
|
+
linesDeleted: state.linesDeleted,
|
|
163
|
+
replacements: state.replacements,
|
|
164
|
+
});
|
|
206
165
|
|
|
207
166
|
return {
|
|
208
|
-
content
|
|
167
|
+
content,
|
|
209
168
|
state,
|
|
210
169
|
success: true,
|
|
211
170
|
};
|
|
@@ -218,13 +177,18 @@ export class CloudSandboxExecutionRuntime {
|
|
|
218
177
|
try {
|
|
219
178
|
const result = await this.callTool('searchLocalFiles', args);
|
|
220
179
|
|
|
180
|
+
const results = result.result?.results || [];
|
|
221
181
|
const state: SearchLocalFilesState = {
|
|
222
|
-
results
|
|
182
|
+
results,
|
|
223
183
|
totalCount: result.result?.totalCount || 0,
|
|
224
184
|
};
|
|
225
185
|
|
|
186
|
+
const content = formatFileSearchResults(
|
|
187
|
+
results.map((r: { path: string }) => ({ path: r.path })),
|
|
188
|
+
);
|
|
189
|
+
|
|
226
190
|
return {
|
|
227
|
-
content
|
|
191
|
+
content,
|
|
228
192
|
state,
|
|
229
193
|
success: true,
|
|
230
194
|
};
|
|
@@ -237,17 +201,17 @@ export class CloudSandboxExecutionRuntime {
|
|
|
237
201
|
try {
|
|
238
202
|
const result = await this.callTool('moveLocalFiles', args);
|
|
239
203
|
|
|
204
|
+
const results = result.result?.results || [];
|
|
240
205
|
const state: MoveLocalFilesState = {
|
|
241
|
-
results
|
|
206
|
+
results,
|
|
242
207
|
successCount: result.result?.successCount || 0,
|
|
243
208
|
totalCount: args.operations.length,
|
|
244
209
|
};
|
|
245
210
|
|
|
211
|
+
const content = formatMoveResults(results);
|
|
212
|
+
|
|
246
213
|
return {
|
|
247
|
-
content
|
|
248
|
-
message: `Moved ${state.successCount}/${state.totalCount} items`,
|
|
249
|
-
results: state.results,
|
|
250
|
-
}),
|
|
214
|
+
content,
|
|
251
215
|
state,
|
|
252
216
|
success: true,
|
|
253
217
|
};
|
|
@@ -267,11 +231,15 @@ export class CloudSandboxExecutionRuntime {
|
|
|
267
231
|
success: result.success,
|
|
268
232
|
};
|
|
269
233
|
|
|
234
|
+
const content = formatRenameResult({
|
|
235
|
+
error: result.result?.error,
|
|
236
|
+
newName: args.newName,
|
|
237
|
+
oldPath: args.oldPath,
|
|
238
|
+
success: result.success,
|
|
239
|
+
});
|
|
240
|
+
|
|
270
241
|
return {
|
|
271
|
-
content
|
|
272
|
-
message: `Successfully renamed ${args.oldPath} to ${args.newName}`,
|
|
273
|
-
success: true,
|
|
274
|
-
}),
|
|
242
|
+
content,
|
|
275
243
|
state,
|
|
276
244
|
success: result.success,
|
|
277
245
|
};
|
|
@@ -405,14 +373,22 @@ export class CloudSandboxExecutionRuntime {
|
|
|
405
373
|
try {
|
|
406
374
|
const result = await this.callTool('globLocalFiles', args);
|
|
407
375
|
|
|
376
|
+
const files = result.result?.files || [];
|
|
377
|
+
const totalCount = result.result?.totalCount || 0;
|
|
378
|
+
|
|
408
379
|
const state: GlobFilesState = {
|
|
409
|
-
files
|
|
380
|
+
files,
|
|
410
381
|
pattern: args.pattern,
|
|
411
|
-
totalCount
|
|
382
|
+
totalCount,
|
|
412
383
|
};
|
|
413
384
|
|
|
385
|
+
const content = formatGlobResults({
|
|
386
|
+
files,
|
|
387
|
+
totalFiles: totalCount,
|
|
388
|
+
});
|
|
389
|
+
|
|
414
390
|
return {
|
|
415
|
-
content
|
|
391
|
+
content,
|
|
416
392
|
state,
|
|
417
393
|
success: true,
|
|
418
394
|
};
|
|
@@ -425,7 +401,7 @@ export class CloudSandboxExecutionRuntime {
|
|
|
425
401
|
|
|
426
402
|
/**
|
|
427
403
|
* Export a file from the sandbox to cloud storage
|
|
428
|
-
* Uses a single
|
|
404
|
+
* Uses a single call that handles:
|
|
429
405
|
* 1. Generate pre-signed upload URL
|
|
430
406
|
* 2. Call sandbox to upload file
|
|
431
407
|
* 3. Create persistent file record
|
|
@@ -437,11 +413,7 @@ export class CloudSandboxExecutionRuntime {
|
|
|
437
413
|
const filename = args.path.split('/').pop() || 'exported_file';
|
|
438
414
|
|
|
439
415
|
// Single call that handles everything: upload URL generation, sandbox upload, and file record creation
|
|
440
|
-
const result = await
|
|
441
|
-
args.path,
|
|
442
|
-
filename,
|
|
443
|
-
this.context.topicId,
|
|
444
|
-
);
|
|
416
|
+
const result = await this.sandboxService.exportAndUploadFile(args.path, filename);
|
|
445
417
|
|
|
446
418
|
const state: ExportFileState = {
|
|
447
419
|
downloadUrl: result.success && result.url ? result.url : '',
|
|
@@ -478,17 +450,16 @@ export class CloudSandboxExecutionRuntime {
|
|
|
478
450
|
// ==================== Helper Methods ====================
|
|
479
451
|
|
|
480
452
|
/**
|
|
481
|
-
* Call a tool via the
|
|
482
|
-
* Routes through: ExecutionRuntime -> codeInterpreterService -> tRPC -> codeInterpreterRouter -> MarketSDK
|
|
453
|
+
* Call a tool via the injected sandbox service
|
|
483
454
|
*/
|
|
484
455
|
private async callTool(
|
|
485
456
|
toolName: string,
|
|
486
457
|
params: Record<string, any>,
|
|
487
458
|
): Promise<{ result: any; sessionExpiredAndRecreated?: boolean; success: boolean }> {
|
|
488
|
-
const result = await
|
|
459
|
+
const result = await this.sandboxService.callTool(toolName, params);
|
|
489
460
|
|
|
490
461
|
if (!result.success) {
|
|
491
|
-
throw new Error(
|
|
462
|
+
throw new Error(result.error?.message || `Cloud Sandbox tool ${toolName} failed`);
|
|
492
463
|
}
|
|
493
464
|
|
|
494
465
|
return result;
|