wangyf10 2 天之前
父節點
當前提交
2c41b6e325

+ 1 - 1
.gitignore

@@ -170,7 +170,7 @@ cython_debug/
 #  and can be added to the global gitignore or merged into this file.  For a more nuclear
 #  option (not recommended) you can uncomment the following to ignore the entire idea folder.
 .idea/
-
+.agentscope/
 # Abstra
 # Abstra is an AI-powered process automation framework.
 # Ignore directories containing user credentials, local state, and settings.

+ 56 - 2
yusys-ai-front/src/App.vue

@@ -8,6 +8,7 @@ const { messages, running, error, send, newChat } = useAgui()
 const agents = reactive(AGENTS)
 
 const currentId = ref(agents[0]?.id || '')
+const userName = ref('admin')
 const input = ref('')
 const listEl = ref(null)
 const textareaEl = ref(null)
@@ -18,10 +19,11 @@ const agentSelectorEl = ref(null)
 const currentAgent = computed(
   () => agents.find((a) => a.id === currentId.value) || agents[0]
 )
-// 实际请求地址 = 网关地址 + 智能体 ID
+// 实际请求地址:优先用智能体自带 url,否则「网关地址 + 智能体 ID」
 const currentUrl = computed(() => {
   const a = currentAgent.value
   if (!a) return ''
+  if (a.url) return a.url
   return `${GATEWAY_URL.replace(/\/+$/, '')}/${a.id}`
 })
 
@@ -57,7 +59,7 @@ async function onSend() {
   if (!text.trim() || running.value) return
   input.value = ''
   if (textareaEl.value) textareaEl.value.style.height = 'auto'
-  await send(currentUrl.value, text)
+  await send(currentUrl.value, text, userName.value)
 }
 
 function onKeydown(e) {
@@ -100,6 +102,14 @@ watch(
           <span class="new-chat-icon">+</span> 开启新对话
         </button>
       </div>
+
+      <!-- 左下角用户信息 -->
+      <div class="sidebar-footer">
+        <div class="user-info">
+          <div class="user-avatar-sm">{{ userName.charAt(0).toUpperCase() }}</div>
+          <span class="user-name">{{ userName }}</span>
+        </div>
+      </div>
     </aside>
 
     <!-- 右侧主区 -->
@@ -326,6 +336,50 @@ watch(
   flex-shrink: 0;
 }
 
+/* 左下角用户信息 */
+.sidebar-footer {
+  flex-shrink: 0;
+  padding: 12px;
+  border-top: 1px solid #ebebec;
+}
+
+.user-info {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 8px 10px;
+  border-radius: 10px;
+  cursor: default;
+  transition: background 0.15s;
+}
+
+.user-info:hover {
+  background: #eff0f3;
+}
+
+.user-avatar-sm {
+  width: 30px;
+  height: 30px;
+  border-radius: 50%;
+  background: #4f8cff;
+  color: #fff;
+  font-size: 13px;
+  font-weight: 600;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+
+.user-name {
+  font-size: 14px;
+  font-weight: 500;
+  color: #374151;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
 /* ── 右侧主区 ── */
 .main {
   flex: 1;

+ 3 - 1
yusys-ai-front/src/config.js

@@ -5,6 +5,8 @@ export const GATEWAY_URL = 'http://127.0.0.1:9999'
 
 // 智能体列表
 // desc: 中文描述(下拉显示);id: 智能体 ID
+// url: 可选,完整请求地址;提供后优先于「网关地址 + id」
 export const AGENTS = [
-  { desc: 'Demo 智能体', id: 'DemoAgentAGUI' }
+  { desc: 'Demo 智能体', id: 'DemoAgentAGUI' },
+  { desc: 'Harness 智能体', id: 'harnessAgent', url: 'http://127.0.0.1:5555/harness' }
 ]

+ 10 - 6
yusys-ai-front/src/useAgui.js

@@ -113,7 +113,7 @@ export function useAgui() {
     return rest
   }
 
-  async function send(url, text) {
+  async function send(url, text, userId) {
     const content = (text || '').trim()
     if (!content) return
     if (!url) {
@@ -131,7 +131,7 @@ export function useAgui() {
       threadId: sessionId.value,
       runId: crypto.randomUUID(),
       state: {},
-      messages: history,
+      messages: [userMsg],
       tools: [],
       context: [],
       forwardedProps: {}
@@ -139,12 +139,16 @@ export function useAgui() {
 
     running.value = true
     try {
+      const headers = {
+        'Content-Type': 'application/json',
+        Accept: 'text/event-stream'
+      }
+      if (userId) headers['x-user-id'] = userId
+      if (sessionId.value) headers['sessionid'] = sessionId.value
+
       const res = await fetch(url, {
         method: 'POST',
-        headers: {
-          'Content-Type': 'application/json',
-          Accept: 'text/event-stream'
-        },
+        headers,
         body: JSON.stringify(body)
       })
 

+ 8 - 7
yusys-ai-plus/yusys-ai-harness/yusys-ai-harness-core/src/main/java/cn/com/yusys/ai/plus/harness/controller/HarnessAgentRest.java

@@ -1,5 +1,7 @@
 package cn.com.yusys.ai.plus.harness.controller;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import io.agentscope.core.agent.Agent;
 import io.agentscope.core.agent.RuntimeContext;
 import io.agentscope.core.agui.adapter.AguiAdapterConfig;
@@ -10,15 +12,13 @@ import io.agentscope.core.agui.model.RunAgentInput;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.http.MediaType;
 import org.springframework.http.codec.ServerSentEvent;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestHeader;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import reactor.core.publisher.Flux;
 
 import java.time.Duration;
 
 @RestController
+@CrossOrigin(originPatterns = "*", allowCredentials = "true")
 public class HarnessAgentRest {
     AguiAgentAdapter adapter;
     Agent harnessAgent;
@@ -35,11 +35,12 @@ public class HarnessAgentRest {
                 .build());
     }
 
+    private final ObjectMapper jackson2 = new ObjectMapper();
     @PostMapping(value = "/harness", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
     public Flux<ServerSentEvent<String>> run(
-            @RequestBody RunAgentInput input,
-            @RequestHeader(value = "x-user-id", required = true) String userId) {
-
+            @RequestBody String body,
+            @RequestHeader(value = "x-user-id", required = true) String userId) throws JsonProcessingException {
+        RunAgentInput input = jackson2.readValue(body, RunAgentInput.class);
         RuntimeContext ctx = RuntimeContext.builder()
                 .userId(userId)          // null 也没关系 = 匿名
                 .build();