style: code format
This commit is contained in:
parent
0fdc0acf91
commit
3b35493db3
@ -15,9 +15,9 @@ from langgraph.types import Command
|
|||||||
|
|
||||||
from yuxi import config as sys_config
|
from yuxi import config as sys_config
|
||||||
from yuxi.agents.context import BaseContext, resolve_agent_resource_options
|
from yuxi.agents.context import BaseContext, resolve_agent_resource_options
|
||||||
from yuxi.utils.subagent_thread_utils import make_child_thread_id
|
|
||||||
from yuxi.storage.postgres.manager import pg_manager
|
from yuxi.storage.postgres.manager import pg_manager
|
||||||
from yuxi.utils import logger
|
from yuxi.utils import logger
|
||||||
|
from yuxi.utils.subagent_thread_utils import make_child_thread_id
|
||||||
|
|
||||||
|
|
||||||
def _json_safe(value: Any) -> Any:
|
def _json_safe(value: Any) -> Any:
|
||||||
@ -79,9 +79,7 @@ def _subagent_route_for_namespace(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _collect_subagent_routes(
|
async def _collect_subagent_routes(run, parent_thread_id: str, routes: dict[tuple[str, ...], dict[str, str]]) -> None:
|
||||||
run, parent_thread_id: str, routes: dict[tuple[str, ...], dict[str, str]]
|
|
||||||
) -> None:
|
|
||||||
subagents = getattr(run, "subagents", None)
|
subagents = getattr(run, "subagents", None)
|
||||||
if subagents is None:
|
if subagents is None:
|
||||||
return
|
return
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class ChatBotContext(BaseContext):
|
|||||||
metadata={
|
metadata={
|
||||||
"name": "子智能体",
|
"name": "子智能体",
|
||||||
"options": [],
|
"options": [],
|
||||||
"description": "可选子智能体列表,只有被选中的子智能体会作为 task 工具候选。为空表示启用当前用户可见的全部子智能体。",
|
"description": "可选子智能体列表,为空表示启用当前用户可见的全部子智能体。",
|
||||||
"type": "list",
|
"type": "list",
|
||||||
"kind": "subagents",
|
"kind": "subagents",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -15,7 +15,6 @@ from yuxi.agents.middlewares.knowledge_base import KnowledgeBaseMiddleware
|
|||||||
from yuxi.agents.middlewares.skills import SkillsMiddleware
|
from yuxi.agents.middlewares.skills import SkillsMiddleware
|
||||||
from yuxi.agents.toolkits.service import resolve_configured_runtime_tools
|
from yuxi.agents.toolkits.service import resolve_configured_runtime_tools
|
||||||
|
|
||||||
|
|
||||||
_SUBAGENT_DISABLED_TOOLS = frozenset({"present_artifacts", "ask_user_question"})
|
_SUBAGENT_DISABLED_TOOLS = frozenset({"present_artifacts", "ask_user_question"})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -15,13 +15,13 @@ from langgraph.prebuilt.tool_node import ToolRuntime
|
|||||||
from langgraph.types import Command
|
from langgraph.types import Command
|
||||||
|
|
||||||
from yuxi.agents.context import build_agent_input_context
|
from yuxi.agents.context import build_agent_input_context
|
||||||
from yuxi.utils.subagent_thread_utils import make_child_thread_id
|
|
||||||
from yuxi.repositories.agent_repository import SUB_AGENT_BACKEND_ID, AgentRepository
|
from yuxi.repositories.agent_repository import SUB_AGENT_BACKEND_ID, AgentRepository
|
||||||
from yuxi.repositories.agent_run_repository import AgentRunRepository
|
from yuxi.repositories.agent_run_repository import AgentRunRepository
|
||||||
from yuxi.repositories.user_repository import UserRepository
|
from yuxi.repositories.user_repository import UserRepository
|
||||||
from yuxi.storage.postgres.manager import pg_manager
|
from yuxi.storage.postgres.manager import pg_manager
|
||||||
from yuxi.storage.postgres.models_business import Agent
|
from yuxi.storage.postgres.models_business import Agent
|
||||||
from yuxi.utils.datetime_utils import utc_isoformat
|
from yuxi.utils.datetime_utils import utc_isoformat
|
||||||
|
from yuxi.utils.subagent_thread_utils import make_child_thread_id
|
||||||
|
|
||||||
_CHILD_STATE_INHERIT_KEYS: frozenset[str] = frozenset()
|
_CHILD_STATE_INHERIT_KEYS: frozenset[str] = frozenset()
|
||||||
_TERMINAL_RUN_STATUSES = {"completed", "failed", "cancelled", "interrupted"}
|
_TERMINAL_RUN_STATUSES = {"completed", "failed", "cancelled", "interrupted"}
|
||||||
@ -195,11 +195,7 @@ def _state_for_child(
|
|||||||
skills_thread_id: str,
|
skills_thread_id: str,
|
||||||
continuing: bool = False,
|
continuing: bool = False,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
state = (
|
state = {} if continuing else {key: runtime.state[key] for key in _CHILD_STATE_INHERIT_KEYS if key in runtime.state}
|
||||||
{}
|
|
||||||
if continuing
|
|
||||||
else {key: runtime.state[key] for key in _CHILD_STATE_INHERIT_KEYS if key in runtime.state}
|
|
||||||
)
|
|
||||||
state.update(
|
state.update(
|
||||||
{
|
{
|
||||||
"parent_thread_id": parent_thread_id,
|
"parent_thread_id": parent_thread_id,
|
||||||
|
|||||||
@ -20,18 +20,19 @@ DEFAULT_SHARE_CONFIG = {"access_level": "global", "department_ids": [], "user_ui
|
|||||||
WEB_SEARCH_AGENT_SLUG = "web-search"
|
WEB_SEARCH_AGENT_SLUG = "web-search"
|
||||||
WEB_SEARCH_AGENT_NAME = "网页检索"
|
WEB_SEARCH_AGENT_NAME = "网页检索"
|
||||||
WEB_SEARCH_AGENT_DESCRIPTION = "围绕检索目标持续搜索网页,返回带引用来源的摘要资料。"
|
WEB_SEARCH_AGENT_DESCRIPTION = "围绕检索目标持续搜索网页,返回带引用来源的摘要资料。"
|
||||||
WEB_SEARCH_SYSTEM_PROMPT = """你是「网页检索」子智能体,由主智能体通过 task 工具调用,专注于面向目标的网页信息检索。
|
WEB_SEARCH_SYSTEM_PROMPT = """你是「网页检索」子智能体,专注于面向目标的网页信息检索。
|
||||||
|
|
||||||
你的职责:围绕调用方给定的检索目标,使用网页搜索工具持续检索,直到收集到足以回答目标的信息。
|
你的职责:围绕调用方给定的检索目标,使用网页搜索工具持续检索,直到收集到足以回答目标的信息。
|
||||||
|
|
||||||
工作方式:
|
工作方式:
|
||||||
1. 拆解目标,确定需要检索的关键问题与检索词。
|
1. 拆解目标,确定需要检索的关键问题与检索词。
|
||||||
2. 多轮调用网页搜索工具:依据上一轮结果调整检索词、补充遗漏角度、交叉验证关键事实,直到信息充分或确认无法获取更多有效信息。
|
2. 多轮调用搜索工具:依据上一轮结果调整检索词、补充遗漏角度、交叉验证关键事实,直到信息充分或确认无法获取更多有效信息。
|
||||||
3. 优先采信权威、时效性强且彼此印证的来源;对存在冲突的信息要说明分歧。
|
3. 优先采信权威、时效性强且彼此印证的来源;对存在冲突的信息要说明分歧。
|
||||||
|
|
||||||
输出要求:
|
输出要求:
|
||||||
- 返回一份结构化的摘要资料,按主题或要点组织。
|
- 返回一份结构化的摘要资料,按主题或要点组织。
|
||||||
- 每条关键结论后使用 <cite source="$URL" type="url">$INDEX</cite> 标注引用来源,$INDEX 从 1 开始递增。不单独成行,直接跟在结论后面。
|
- 每条关键结论后使用 <cite source="$URL" type="url">$INDEX</cite> 标注引用来源,$INDEX 从 1 开始递增。
|
||||||
|
- 引用不单独成行,直接跟在结论后面。
|
||||||
- 在结尾汇总「参考来源」列表,逐条列出标题与 URL。
|
- 在结尾汇总「参考来源」列表,逐条列出标题与 URL。
|
||||||
- 不要编造来源或链接;无法验证的信息要明确标注。"""
|
- 不要编造来源或链接;无法验证的信息要明确标注。"""
|
||||||
ACCESS_LEVELS = {"global", "department", "user"}
|
ACCESS_LEVELS = {"global", "department", "user"}
|
||||||
|
|||||||
@ -29,6 +29,7 @@ from yuxi.utils.question_utils import (
|
|||||||
normalize_questions as _normalize_interrupt_questions,
|
normalize_questions as _normalize_interrupt_questions,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _build_state_files(attachments: list[dict]) -> dict:
|
def _build_state_files(attachments: list[dict]) -> dict:
|
||||||
"""将附件列表转换为 StateBackend 格式的 files 字典
|
"""将附件列表转换为 StateBackend 格式的 files 字典
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
_CHILD_THREAD_ID_PREFIX = "subagent_"
|
_CHILD_THREAD_ID_PREFIX = "subagent_"
|
||||||
_CHILD_THREAD_ID_DIGEST_LENGTH = 64 - len(_CHILD_THREAD_ID_PREFIX)
|
_CHILD_THREAD_ID_DIGEST_LENGTH = 64 - len(_CHILD_THREAD_ID_PREFIX)
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,10 @@
|
|||||||
<div class="chat-box">
|
<div class="chat-box">
|
||||||
<template v-for="row in conversationRows" :key="row.key">
|
<template v-for="row in conversationRows" :key="row.key">
|
||||||
<div v-if="row.type === 'conversation'" class="conv-box">
|
<div v-if="row.type === 'conversation'" class="conv-box">
|
||||||
<template v-for="(displayItem, itemIndex) in row.displayItems" :key="displayItem.key">
|
<template
|
||||||
|
v-for="(displayItem, itemIndex) in row.displayItems"
|
||||||
|
:key="displayItem.key"
|
||||||
|
>
|
||||||
<AgentMessageComponent
|
<AgentMessageComponent
|
||||||
v-if="displayItem.type === 'message'"
|
v-if="displayItem.type === 'message'"
|
||||||
:message="displayItem.message"
|
:message="displayItem.message"
|
||||||
@ -547,7 +550,9 @@ const getArtifactMetaLabel = (path) => {
|
|||||||
|
|
||||||
const getSubagentRunName = (run) => {
|
const getSubagentRunName = (run) => {
|
||||||
const subagentType = run?.subagent_type ? String(run.subagent_type) : ''
|
const subagentType = run?.subagent_type ? String(run.subagent_type) : ''
|
||||||
return run?.subagent_name || currentSubagentOptionBySlug.value.get(subagentType)?.name || '子智能体'
|
return (
|
||||||
|
run?.subagent_name || currentSubagentOptionBySlug.value.get(subagentType)?.name || '子智能体'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getSubagentAgent = (run) => {
|
const getSubagentAgent = (run) => {
|
||||||
@ -824,7 +829,9 @@ const currentThreadConfigNotice = computed(() => {
|
|||||||
const shouldSuppressRefsForApproval = () =>
|
const shouldSuppressRefsForApproval = () =>
|
||||||
approvalState.showModal ||
|
approvalState.showModal ||
|
||||||
Boolean(
|
Boolean(
|
||||||
approvalState.threadId && chatState.currentThreadId === approvalState.threadId && isProcessing.value
|
approvalState.threadId &&
|
||||||
|
chatState.currentThreadId === approvalState.threadId &&
|
||||||
|
isProcessing.value
|
||||||
)
|
)
|
||||||
|
|
||||||
// 计算是否显示Refs组件的条件
|
// 计算是否显示Refs组件的条件
|
||||||
@ -911,7 +918,9 @@ const runningSubagentRunsFromStream = computed(() => {
|
|||||||
return ongoingTaskCalls.value
|
return ongoingTaskCalls.value
|
||||||
.filter((call) => activeIds.has(call.id))
|
.filter((call) => activeIds.has(call.id))
|
||||||
.map((call) => {
|
.map((call) => {
|
||||||
const option = call.subagentType ? currentSubagentOptionBySlug.value.get(call.subagentType) : null
|
const option = call.subagentType
|
||||||
|
? currentSubagentOptionBySlug.value.get(call.subagentType)
|
||||||
|
: null
|
||||||
return {
|
return {
|
||||||
id: call.id,
|
id: call.id,
|
||||||
subagent_type: call.subagentType,
|
subagent_type: call.subagentType,
|
||||||
|
|||||||
@ -569,7 +569,9 @@ const ensureArray = (key) => {
|
|||||||
if (!config[key] || !Array.isArray(config[key])) {
|
if (!config[key] || !Array.isArray(config[key])) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const validValues = new Set(getConfigOptions(configItem).map((option) => String(getOptionValue(option))))
|
const validValues = new Set(
|
||||||
|
getConfigOptions(configItem).map((option) => String(getOptionValue(option)))
|
||||||
|
)
|
||||||
if (validValues.size === 0) return config[key]
|
if (validValues.size === 0) return config[key]
|
||||||
return config[key].filter((value) => validValues.has(String(value)))
|
return config[key].filter((value) => validValues.has(String(value)))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,10 +34,15 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const conversations = computed(() => MessageProcessor.convertServerHistoryToMessages(props.messages))
|
const conversations = computed(() =>
|
||||||
|
MessageProcessor.convertServerHistoryToMessages(props.messages)
|
||||||
|
)
|
||||||
|
|
||||||
const getDisplayItems = (conv) =>
|
const getDisplayItems = (conv) =>
|
||||||
getConversationDisplayItems(conv, props.enrichToolCalls ? { enrichToolCalls: props.enrichToolCalls } : {})
|
getConversationDisplayItems(
|
||||||
|
conv,
|
||||||
|
props.enrichToolCalls ? { enrichToolCalls: props.enrichToolCalls } : {}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@ -58,10 +58,10 @@ export const isHiddenToolCall = (toolCall) => HIDDEN_TOOL_CALL_IDS.includes(getT
|
|||||||
export const isValidToolCall = (toolCall) => {
|
export const isValidToolCall = (toolCall) => {
|
||||||
return Boolean(
|
return Boolean(
|
||||||
toolCall &&
|
toolCall &&
|
||||||
(toolCall.id || toolCall.name || toolCall.function?.name) &&
|
(toolCall.id || toolCall.name || toolCall.function?.name) &&
|
||||||
(toolCall.args !== undefined ||
|
(toolCall.args !== undefined ||
|
||||||
toolCall.function?.arguments !== undefined ||
|
toolCall.function?.arguments !== undefined ||
|
||||||
toolCall.tool_call_result !== undefined)
|
toolCall.tool_call_result !== undefined)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,15 +76,21 @@ export const parseToolCallArgs = (toolCall) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enrichTaskToolCall = (toolCall, { subagentRunById, subagentRunByThreadId, subagentOptionBySlug } = {}) => {
|
export const enrichTaskToolCall = (
|
||||||
|
toolCall,
|
||||||
|
{ subagentRunById, subagentRunByThreadId, subagentOptionBySlug } = {}
|
||||||
|
) => {
|
||||||
if (getToolCallId(toolCall) !== 'task') return toolCall
|
if (getToolCallId(toolCall) !== 'task') return toolCall
|
||||||
|
|
||||||
const args = parseToolCallArgs(toolCall)
|
const args = parseToolCallArgs(toolCall)
|
||||||
const subagentRun =
|
const subagentRun =
|
||||||
(toolCall.id ? subagentRunById?.get?.(String(toolCall.id)) : null) ||
|
(toolCall.id ? subagentRunById?.get?.(String(toolCall.id)) : null) ||
|
||||||
(args.thread_id ? subagentRunByThreadId?.get?.(String(args.thread_id)) : null)
|
(args.thread_id ? subagentRunByThreadId?.get?.(String(args.thread_id)) : null)
|
||||||
const subagentOption = args.subagent_type ? subagentOptionBySlug?.get?.(String(args.subagent_type)) : null
|
const subagentOption = args.subagent_type
|
||||||
const displayLabel = subagentRun?.subagent_name || subagentOption?.name || subagentRun?.subagent_type || undefined
|
? subagentOptionBySlug?.get?.(String(args.subagent_type))
|
||||||
|
: null
|
||||||
|
const displayLabel =
|
||||||
|
subagentRun?.subagent_name || subagentOption?.name || subagentRun?.subagent_type || undefined
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...toolCall,
|
...toolCall,
|
||||||
@ -105,6 +111,8 @@ export const normalizeToolCalls = (toolCalls, { includeHidden = false, mapToolCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const enrichTaskToolCalls = (toolCalls, options = {}) =>
|
export const enrichTaskToolCalls = (toolCalls, options = {}) =>
|
||||||
normalizeToolCalls(toolCalls, { mapToolCall: (toolCall) => enrichTaskToolCall(toolCall, options) })
|
normalizeToolCalls(toolCalls, {
|
||||||
|
mapToolCall: (toolCall) => enrichTaskToolCall(toolCall, options)
|
||||||
|
})
|
||||||
|
|
||||||
export const getToolIcon = (toolId) => TOOL_ICON_MAP[toolId] || null
|
export const getToolIcon = (toolId) => TOOL_ICON_MAP[toolId] || null
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<BaseToolCall :tool-call="toolCall" :status="baseStatus" :force-show-result="Boolean(displayResult)">
|
<BaseToolCall
|
||||||
|
:tool-call="toolCall"
|
||||||
|
:status="baseStatus"
|
||||||
|
:force-show-result="Boolean(displayResult)"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="sep-header">
|
<div class="sep-header">
|
||||||
<span class="note">{{ subagentDisplayName }}</span>
|
<span class="note">{{ subagentDisplayName }}</span>
|
||||||
@ -67,9 +71,13 @@ const childThreadId = computed(
|
|||||||
(getSubagentThreadIdByToolCall ? getSubagentThreadIdByToolCall(props.toolCall.id) : '') ||
|
(getSubagentThreadIdByToolCall ? getSubagentThreadIdByToolCall(props.toolCall.id) : '') ||
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
const hasToolResult = computed(() => Boolean(props.toolCall.tool_call_result || props.toolCall.result))
|
const hasToolResult = computed(() =>
|
||||||
|
Boolean(props.toolCall.tool_call_result || props.toolCall.result)
|
||||||
|
)
|
||||||
// 是否为当前真正在执行的子智能体调用(同一子线程的多次 steer 中只有最后一个为活跃)。
|
// 是否为当前真正在执行的子智能体调用(同一子线程的多次 steer 中只有最后一个为活跃)。
|
||||||
const isActiveRun = computed(() => Boolean(activeSubagentToolCallIds?.value?.has(String(props.toolCall.id))))
|
const isActiveRun = computed(() =>
|
||||||
|
Boolean(activeSubagentToolCallIds?.value?.has(String(props.toolCall.id)))
|
||||||
|
)
|
||||||
const runStatus = computed(() => {
|
const runStatus = computed(() => {
|
||||||
if (props.toolCall.status === 'error') return 'failed'
|
if (props.toolCall.status === 'error') return 'failed'
|
||||||
// ongoing 期间工具结果不流式:有结果说明是历史/已落库,按结果展示;
|
// ongoing 期间工具结果不流式:有结果说明是历史/已落库,按结果展示;
|
||||||
@ -114,7 +122,9 @@ const shortDescription = computed(() => {
|
|||||||
const isRunning = computed(() => runStatus.value === 'running')
|
const isRunning = computed(() => runStatus.value === 'running')
|
||||||
|
|
||||||
const truncate = (text, limit = 50) => {
|
const truncate = (text, limit = 50) => {
|
||||||
const value = String(text || '').replace(/\s+/g, ' ').trim()
|
const value = String(text || '')
|
||||||
|
.replace(/\s+/g, ' ')
|
||||||
|
.trim()
|
||||||
if (!value) return ''
|
if (!value) return ''
|
||||||
return value.length > limit ? value.slice(0, limit) + '...' : value
|
return value.length > limit ? value.slice(0, limit) + '...' : value
|
||||||
}
|
}
|
||||||
@ -122,7 +132,8 @@ const truncate = (text, limit = 50) => {
|
|||||||
const formatToolCall = (toolCall) => {
|
const formatToolCall = (toolCall) => {
|
||||||
const name = toolCall?.name || toolCall?.function?.name || 'tool'
|
const name = toolCall?.name || toolCall?.function?.name || 'tool'
|
||||||
const rawArgs = toolCall?.args ?? toolCall?.function?.arguments
|
const rawArgs = toolCall?.args ?? toolCall?.function?.arguments
|
||||||
const args = rawArgs && typeof rawArgs === 'object' ? JSON.stringify(rawArgs) : String(rawArgs ?? '')
|
const args =
|
||||||
|
rawArgs && typeof rawArgs === 'object' ? JSON.stringify(rawArgs) : String(rawArgs ?? '')
|
||||||
return `Call(${name}): ${args}`
|
return `Call(${name}): ${args}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -826,7 +826,6 @@ onMounted(async () => {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info-content {
|
.user-info-content {
|
||||||
|
|||||||
@ -141,7 +141,12 @@
|
|||||||
{{ formatExtensionCardTitle(previewSkill.name) }}
|
{{ formatExtensionCardTitle(previewSkill.name) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="skill-preview-meta">
|
<div class="skill-preview-meta">
|
||||||
<span>{{ sourceTypeLabel(previewSkill.sourceType || previewSkill.source_type) }} Skill</span>
|
<span
|
||||||
|
>{{
|
||||||
|
sourceTypeLabel(previewSkill.sourceType || previewSkill.source_type)
|
||||||
|
}}
|
||||||
|
Skill</span
|
||||||
|
>
|
||||||
<span v-if="previewSkill.enabled === false" class="skill-preview-disabled-tag">
|
<span v-if="previewSkill.enabled === false" class="skill-preview-disabled-tag">
|
||||||
已禁用
|
已禁用
|
||||||
</span>
|
</span>
|
||||||
@ -525,7 +530,17 @@
|
|||||||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal } from 'ant-design-vue'
|
||||||
import { RefreshCw, Upload, Computer, BookMarked, History, Trash2, Check, Plus, Minus } from 'lucide-vue-next'
|
import {
|
||||||
|
RefreshCw,
|
||||||
|
Upload,
|
||||||
|
Computer,
|
||||||
|
BookMarked,
|
||||||
|
History,
|
||||||
|
Trash2,
|
||||||
|
Check,
|
||||||
|
Plus,
|
||||||
|
Minus
|
||||||
|
} from 'lucide-vue-next'
|
||||||
import { skillApi } from '@/apis/skill_api'
|
import { skillApi } from '@/apis/skill_api'
|
||||||
import ExtensionCardGrid from './ExtensionCardGrid.vue'
|
import ExtensionCardGrid from './ExtensionCardGrid.vue'
|
||||||
import InfoCard from '@/components/shared/InfoCard.vue'
|
import InfoCard from '@/components/shared/InfoCard.vue'
|
||||||
@ -601,7 +616,10 @@ const filteredDeletableSkills = computed(() =>
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
const canDeletePreviewSkill = computed(
|
const canDeletePreviewSkill = computed(
|
||||||
() => !!previewSkill.value && canManageSkill(previewSkill.value) && previewSkill.value.sourceType !== 'builtin'
|
() =>
|
||||||
|
!!previewSkill.value &&
|
||||||
|
canManageSkill(previewSkill.value) &&
|
||||||
|
previewSkill.value.sourceType !== 'builtin'
|
||||||
)
|
)
|
||||||
|
|
||||||
// 仓库拉取的技能列表过滤
|
// 仓库拉取的技能列表过滤
|
||||||
|
|||||||
@ -402,7 +402,9 @@ const isBuiltinInstalledSkill = computed(() => {
|
|||||||
})
|
})
|
||||||
const canManageCurrentSkill = computed(() => currentSkill.value?.can_manage !== false)
|
const canManageCurrentSkill = computed(() => currentSkill.value?.can_manage !== false)
|
||||||
const isReadOnlySkill = computed(() => isInstalledSkill.value && !canManageCurrentSkill.value)
|
const isReadOnlySkill = computed(() => isInstalledSkill.value && !canManageCurrentSkill.value)
|
||||||
const canEditSkillFiles = computed(() => canManageCurrentSkill.value && !isBuiltinInstalledSkill.value)
|
const canEditSkillFiles = computed(
|
||||||
|
() => canManageCurrentSkill.value && !isBuiltinInstalledSkill.value
|
||||||
|
)
|
||||||
const canEditSkillDependencies = computed(
|
const canEditSkillDependencies = computed(
|
||||||
() => canManageCurrentSkill.value && !isBuiltinInstalledSkill.value
|
() => canManageCurrentSkill.value && !isBuiltinInstalledSkill.value
|
||||||
)
|
)
|
||||||
|
|||||||
@ -617,7 +617,6 @@ defineExpose({
|
|||||||
min-height: 0;
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.agent-card-icon-image {
|
.agent-card-icon-image {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@ -81,7 +81,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="$slots.tags || (normalizedTags && normalizedTags.length > 0)" class="info-card-tags">
|
<div
|
||||||
|
v-if="$slots.tags || (normalizedTags && normalizedTags.length > 0)"
|
||||||
|
class="info-card-tags"
|
||||||
|
>
|
||||||
<slot name="tags">
|
<slot name="tags">
|
||||||
<span
|
<span
|
||||||
v-for="(tag, idx) in normalizedTags"
|
v-for="(tag, idx) in normalizedTags"
|
||||||
|
|||||||
@ -171,7 +171,12 @@ export function useAgentRunStream({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const finalizeRunStream = (threadId, runId, touchedThreadIds, { delay = 200, scroll = false } = {}) => {
|
const finalizeRunStream = (
|
||||||
|
threadId,
|
||||||
|
runId,
|
||||||
|
touchedThreadIds,
|
||||||
|
{ delay = 200, scroll = false } = {}
|
||||||
|
) => {
|
||||||
const ts = getThreadState(threadId)
|
const ts = getThreadState(threadId)
|
||||||
if (!ts || ts.activeRunId !== runId) return
|
if (!ts || ts.activeRunId !== runId) return
|
||||||
touchedThreadIds.forEach((id) => streamSmoother?.flushThread(id))
|
touchedThreadIds.forEach((id) => streamSmoother?.flushThread(id))
|
||||||
@ -276,7 +281,11 @@ export function useAgentRunStream({
|
|||||||
})
|
})
|
||||||
touchedThreadIds.add(routeThreadId)
|
touchedThreadIds.add(routeThreadId)
|
||||||
handleStreamChunk(
|
handleStreamChunk(
|
||||||
{ ...payload.chunk, run_id: payload.chunk.run_id || data.run_id || runId, thread_id: routeThreadId },
|
{
|
||||||
|
...payload.chunk,
|
||||||
|
run_id: payload.chunk.run_id || data.run_id || runId,
|
||||||
|
thread_id: routeThreadId
|
||||||
|
},
|
||||||
routeThreadId
|
routeThreadId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -307,7 +316,10 @@ export function useAgentRunStream({
|
|||||||
scheduleRunReconnect(threadId, runId)
|
scheduleRunReconnect(threadId, runId)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Run SSE closed before terminal event; reconnecting after status check failed:', e)
|
console.warn(
|
||||||
|
'Run SSE closed before terminal event; reconnecting after status check failed:',
|
||||||
|
e
|
||||||
|
)
|
||||||
scheduleRunReconnect(threadId, runId)
|
scheduleRunReconnect(threadId, runId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,8 +32,16 @@ const run = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
assert.throws(() => generatePixelAvatar(''), /requires an id/, 'Empty ID should be treated as invalid data')
|
assert.throws(
|
||||||
assert.throws(() => generatePixelAvatar(null), /requires an id/, 'Null ID should be treated as invalid data')
|
() => generatePixelAvatar(''),
|
||||||
|
/requires an id/,
|
||||||
|
'Empty ID should be treated as invalid data'
|
||||||
|
)
|
||||||
|
assert.throws(
|
||||||
|
() => generatePixelAvatar(null),
|
||||||
|
/requires an id/,
|
||||||
|
'Null ID should be treated as invalid data'
|
||||||
|
)
|
||||||
console.log('T5 Missing ID fails: PASS')
|
console.log('T5 Missing ID fails: PASS')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,17 +7,20 @@ const hasVisibleAssistantBody = (message) => {
|
|||||||
const { content, reasoningContent } = MessageProcessor.parseAssistantMessageBody(message)
|
const { content, reasoningContent } = MessageProcessor.parseAssistantMessageBody(message)
|
||||||
return Boolean(
|
return Boolean(
|
||||||
content ||
|
content ||
|
||||||
reasoningContent ||
|
reasoningContent ||
|
||||||
message.error_type ||
|
message.error_type ||
|
||||||
message.extra_metadata?.error_type ||
|
message.extra_metadata?.error_type ||
|
||||||
message.isStoppedByUser
|
message.isStoppedByUser
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultEnrichToolCalls = (message) => enrichTaskToolCalls(message?.tool_calls)
|
const defaultEnrichToolCalls = (message) => enrichTaskToolCalls(message?.tool_calls)
|
||||||
|
|
||||||
// 将 AI 消息拆成“正文块”和“工具块”,再跨消息合并相邻工具块。
|
// 将 AI 消息拆成“正文块”和“工具块”,再跨消息合并相邻工具块。
|
||||||
export const getConversationDisplayItems = (conv, { enrichToolCalls = defaultEnrichToolCalls } = {}) => {
|
export const getConversationDisplayItems = (
|
||||||
|
conv,
|
||||||
|
{ enrichToolCalls = defaultEnrichToolCalls } = {}
|
||||||
|
) => {
|
||||||
if (!Array.isArray(conv?.messages) || conv.messages.length === 0) return []
|
if (!Array.isArray(conv?.messages) || conv.messages.length === 0) return []
|
||||||
|
|
||||||
const items = []
|
const items = []
|
||||||
|
|||||||
@ -419,7 +419,6 @@ export class MessageProcessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MessageProcessor
|
export default MessageProcessor
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user