diff --git a/.npmrc b/.npmrc index 4b9b305f..0730e0d0 100644 --- a/.npmrc +++ b/.npmrc @@ -4,3 +4,5 @@ save-workspace-protocol=rolling # pnpm deploy workaround https://github.com/pnpm/pnpm/issues/6437#issuecomment-1549409913 dedupe-peer-dependents=false + +link-workspace-packages=deep diff --git a/web/ui/config/routes.ts b/web/ui/config/routes.ts index a7753ac0..e28e0dbd 100644 --- a/web/ui/config/routes.ts +++ b/web/ui/config/routes.ts @@ -30,6 +30,10 @@ export default [ path: '/agent/:agentId/dev', slot: 'magent-agent-dev-slot', }, + { + path: '/agent/:agentId/flow', + slot: 'magent-agent-flow-dev-slot', + }, ], }, ]; diff --git a/web/ui/package.json b/web/ui/package.json index 4d215eab..45fc42a0 100644 --- a/web/ui/package.json +++ b/web/ui/package.json @@ -26,6 +26,7 @@ "@difizen/libro-jupyter": "^0.2.1", "@difizen/libro-lab": "^0.2.1", "@difizen/libro-markdown": "^0.2.1", + "@difizen/magent-flow": "workspace:^", "@difizen/mana-app": "^0.1.8", "@difizen/mana-react": "^0.1.8", "@rjsf/antd": "^5.18.2", diff --git a/web/ui/src/modules/app.module.ts b/web/ui/src/modules/app.module.ts index 8e58b42a..61bcbeb5 100644 --- a/web/ui/src/modules/app.module.ts +++ b/web/ui/src/modules/app.module.ts @@ -2,6 +2,7 @@ import { ManaModule } from '@difizen/mana-app'; import { AgentConfigViewModule } from '../views/agent-config/index.js'; import { AgentChatModule } from '../views/agent-dev/index.js'; +import { AgentFlowModule } from '../views/agent-flow/module.js'; import { AgentsPageModule } from '../views/agents/index.js'; import { ChatViewModule } from '../views/chat/module.js'; import { KnowledgePageModule } from '../views/knowledge/module.js'; @@ -39,6 +40,7 @@ export const AppBaseModule = new ManaModule() KnowledgePageModule, AgentConfigViewModule, PortalsModule, + AgentFlowModule, ); export default AppBaseModule; diff --git a/web/ui/src/views/agent-dev/debug-contribution.ts b/web/ui/src/views/agent-dev/debug-drawer-contribution.ts similarity index 75% rename from web/ui/src/views/agent-dev/debug-contribution.ts rename to web/ui/src/views/agent-dev/debug-drawer-contribution.ts index 8fd65538..60e2843f 100644 --- a/web/ui/src/views/agent-dev/debug-contribution.ts +++ b/web/ui/src/views/agent-dev/debug-drawer-contribution.ts @@ -3,7 +3,7 @@ import { ModalContribution, singleton } from '@difizen/mana-app'; import { DebugModal } from './debug-modal.js'; @singleton({ contrib: [ModalContribution] }) -export class DebugContribution implements ModalContribution { +export class DebugDrawerContribution implements ModalContribution { registerModal() { return DebugModal; } diff --git a/web/ui/src/views/agent-dev/module.ts b/web/ui/src/views/agent-dev/module.ts index c03a39f5..e62c2b7e 100644 --- a/web/ui/src/views/agent-dev/module.ts +++ b/web/ui/src/views/agent-dev/module.ts @@ -3,13 +3,13 @@ import { createSlotPreference, ManaModule } from '@difizen/mana-app'; import { AgentConfigViewModule } from '../agent-config/module.js'; import { AgentView, slot as ChatSlot } from './chat-view.js'; -import { DebugContribution } from './debug-contribution.js'; +import { DebugDrawerContribution } from './debug-drawer-contribution.js'; import { AgentDevView, slot as DevSlot } from './dev-view.js'; export const AgentChatModule = ManaModule.create() .register( AgentView, - DebugContribution, + DebugDrawerContribution, createSlotPreference({ slot: ChatSlot, view: AgentView, diff --git a/web/ui/src/views/agent-flow/agent-flow-view.tsx b/web/ui/src/views/agent-flow/agent-flow-view.tsx new file mode 100644 index 00000000..d0f82f66 --- /dev/null +++ b/web/ui/src/views/agent-flow/agent-flow-view.tsx @@ -0,0 +1,77 @@ +import { SaveOutlined } from '@ant-design/icons'; +import { FlowWithPanel } from '@difizen/magent-flow'; +import { + BaseView, + ViewInstance, + inject, + prop, + useInject, + view, + ViewOption, + transient, +} from '@difizen/mana-app'; +import { Flex } from 'antd'; +import { forwardRef } from 'react'; + +import { AgentManager } from '../../modules/agent/index.js'; +import type { AgentModel } from '../../modules/agent/index.js'; + +import './index.less'; + +const viewId = 'magent-agent-flow'; + +const AgentFlowComponent = forwardRef( + function AgentConfigViewComponent(props, ref) { + const instance = useInject(ViewInstance); + + return ( +
+ +
+ ); + }, +); + +export interface AgentConfigViewOption { + agentId: string; +} +@transient() +@view(viewId) +export class AgentFlowView extends BaseView { + agentId: string; + override view = AgentFlowComponent; + + @prop() agent: AgentModel; + protected agentManager: AgentManager; + constructor( + @inject(ViewOption) option: AgentConfigViewOption, + @inject(AgentManager) agentManager: AgentManager, + ) { + super(); + this.agentId = option.agentId; + this.agentManager = agentManager; + this.initAgent(option.agentId); + } + + get modelOptions() { + // TODO 大模型optios列表和对应存取值要怎么取? + return ( + this.agent?.llm?.model_name?.map((item) => { + return { + label: item, + value: item, + }; + }) || [] + ); + } + + protected initAgent = (agentId = this.agentId) => { + if (agentId) { + const agent = this.agentManager.getOrCreateAgent({ id: agentId }); + agent.fetchInfo(); + this.agent = agent; + return agent; + } + return undefined; + }; +} diff --git a/web/ui/src/views/agent-flow/flow-dev-view.tsx b/web/ui/src/views/agent-flow/flow-dev-view.tsx new file mode 100644 index 00000000..a892ac42 --- /dev/null +++ b/web/ui/src/views/agent-flow/flow-dev-view.tsx @@ -0,0 +1,72 @@ +import { ViewRender } from '@difizen/mana-app'; +import { ViewInstance, singleton, useInject, view } from '@difizen/mana-app'; +import { BoxPanel } from '@difizen/mana-react'; +import { forwardRef, useEffect } from 'react'; +import { useMatch } from 'react-router-dom'; + +import type { AgentConfigManager } from '../../modules/agent/agent-config-manager.js'; +import { AgentView } from '../agent-dev/chat-view.js'; + +import { AgentFlowView } from './agent-flow-view.js'; + +import './index.less'; + +const viewId = 'magent-agent-flow-dev'; +export const slot = `${viewId}-slot`; + +const AgentFlowDevComponent = forwardRef( + function AgentsViewComponent(props, ref) { + const instance = useInject(ViewInstance); + const match = useMatch('/agent/:agentId/flow'); + const agentId = match?.params?.agentId; + instance.agentId = agentId; + + useEffect(() => { + instance.openChat(instance.sessions?.active); + }, [instance, instance.sessions?.active]); + + return ( +
+ + {instance.agentFlow && } + {/* + {instance.agentFlow && } + + +
+

预览

+
+
+ {instance.chat && } +
+
*/} +
+
+ ); + }, +); + +@singleton() +@view(viewId) +export class AgentFlowDevView extends AgentView { + protected agentConfigManager: AgentConfigManager; + + agentFlow?: AgentFlowView; + + override view = AgentFlowDevComponent; + + protected override initialize() { + super.initialize(); + this.initAgentFlowView(); + } + + protected initAgentFlowView = async () => { + if (!this.agentId) { + return; + } + const agentFlow = await this.viewManager.getOrCreateView(AgentFlowView, { + agentId: this.agentId, + }); + this.agentFlow = agentFlow; + }; +} diff --git a/web/ui/src/views/agent-flow/index.less b/web/ui/src/views/agent-flow/index.less new file mode 100644 index 00000000..e7c505ea --- /dev/null +++ b/web/ui/src/views/agent-flow/index.less @@ -0,0 +1,131 @@ +.magent-agent-chat-layout { + height: 100%; + + &-container { + gap: 16px; + box-sizing: border-box; + padding: 12px 24px; + } + + &-history { + width: 260px; + } + + &-chat { + max-width: calc(100% - 276px); + } +} + +.magent-agent-flow-dev-layout { + height: 100%; + width: 100%; +} + +.magent-agent-dev-layout { + height: 100%; + + &-container { + gap: 16px; + box-sizing: border-box; + padding: 12px 24px; + } + + &-config { + width: 55%; + } + + &-chat-dev { + height: 100%; + min-width: 520px; + width: 520px; + background-color: var(--mana-color-bg-container); + border-radius: 8px; + + &-header { + padding: 0 24px; + height: 64px; + border-bottom: 1px solid var(--mana-color-border); + display: flex; + align-items: center; + justify-content: space-between; + + h3 { + margin: 0; + } + } + + &-content { + height: calc(100% - 64px); + } + } +} + +.magent-debug { + width: 622px; +} + +.magent-debug-header { + background-color: #f7f7fa; + border-bottom: 1px solid rgba(29, 28, 35, 8%); + padding: 16px 24px; +} + +.magent-select-container { + padding: 24px 24px 4px; + width: 100%; + + :global { + background-color: rgba(139, 139, 149, 15%); + color: rgba(75, 74, 88, 100%); + } +} + +.magent-summary-container { + padding: 16px 24px 24px; + position: relative; + width: 100%; +} + +.magent-summary-title-container { + margin-bottom: 16px; +} + +.magent-summary-title-data { + color: #1d1c23; + font-size: 14px; + font-weight: 600; + margin-right: 8px; +} + +.magent-des-item { + display: flex; + font-size: 13px; + line-height: 22px; + text-align: left; +} + +.magent-des-key { + color: rgba(29, 28, 35, 35%); + margin-right: 4px; +} + +.magent-des-value { + color: rgba(29, 28, 35, 80%); +} + +.magent-des-icon { + margin-left: 6px; + cursor: pointer; +} + +.magent-agent-flow { + height: 100%; + width: 100%; + overflow-y: auto; + display: flex; + justify-items: center; + flex-direction: column; + background-color: var(--mana-color-bg-container); + box-sizing: border-box; + border-radius: 8px; +} diff --git a/web/ui/src/views/agent-flow/index.tsx b/web/ui/src/views/agent-flow/index.tsx new file mode 100644 index 00000000..fd3c604b --- /dev/null +++ b/web/ui/src/views/agent-flow/index.tsx @@ -0,0 +1 @@ +export * from './module.js'; diff --git a/web/ui/src/views/agent-flow/module.ts b/web/ui/src/views/agent-flow/module.ts new file mode 100644 index 00000000..75d6ef56 --- /dev/null +++ b/web/ui/src/views/agent-flow/module.ts @@ -0,0 +1,17 @@ +import { createSlotPreference, ManaModule } from '@difizen/mana-app'; + +import { AgentConfigViewModule } from '../agent-config/module.js'; + +import { AgentFlowView } from './agent-flow-view.js'; +import { AgentFlowDevView, slot } from './flow-dev-view.js'; + +export const AgentFlowModule = ManaModule.create() + .register( + AgentFlowView, + AgentFlowDevView, + createSlotPreference({ + slot: slot, + view: AgentFlowDevView, + }), + ) + .dependOn(AgentConfigViewModule); diff --git a/web/ui/src/views/agent-flow/protocol.ts b/web/ui/src/views/agent-flow/protocol.ts new file mode 100644 index 00000000..d33e96b9 --- /dev/null +++ b/web/ui/src/views/agent-flow/protocol.ts @@ -0,0 +1,5 @@ +export const AgentLayoutSlots = { + history: 'magent-agent-chat-history', + config: 'magent-agent-dev-config', + chat: 'magent-agent-chat', +}; diff --git a/web/ui/src/views/agent-flow/utils.ts b/web/ui/src/views/agent-flow/utils.ts new file mode 100644 index 00000000..e05cbde8 --- /dev/null +++ b/web/ui/src/views/agent-flow/utils.ts @@ -0,0 +1,34 @@ +function copyFallback(string: string) { + function handler(event: ClipboardEvent) { + const clipboardData = event.clipboardData || (window as any).clipboardData; + clipboardData.setData('text/plain', string); + event.preventDefault(); + document.removeEventListener('copy', handler, true); + } + + document.addEventListener('copy', handler, true); + document.execCommand('copy'); +} +// 复制到剪贴板 +export const copy2clipboard = (string: string) => { + navigator.permissions + .query({ + name: 'clipboard-write' as any, + }) + .then((result) => { + if (result.state === 'granted' || result.state === 'prompt') { + if (window.navigator && window.navigator.clipboard) { + window.navigator.clipboard.writeText(string); + } else { + console.warn('navigator is not exist'); + } + } else { + console.warn('浏览器权限不允许复制'); + copyFallback(string); + } + return; + }) + .catch(() => { + // + }); +}; diff --git a/web/ui/src/views/agents/view.tsx b/web/ui/src/views/agents/view.tsx index a4220a2f..e79ce0a6 100644 --- a/web/ui/src/views/agents/view.tsx +++ b/web/ui/src/views/agents/view.tsx @@ -17,7 +17,7 @@ import './index.less'; import { AgentIcon } from '../../modules/agent/agent-icon.js'; import { AgentMarket } from '../../modules/agent/agent-market.js'; -import { AgentCreateModal, agentCreateModalId } from './modal/create.js'; +import { AgentCreateModal } from './modal/create.js'; const viewId = 'magent-agents'; export const slot = `${viewId}-slot`; @@ -65,7 +65,7 @@ const AgentsViewComponent = forwardRef( ))} - {/*
+
-
*/} +
); },