1 line
13 KiB
JavaScript
1 line
13 KiB
JavaScript
import{D as e,E as t,On as n,_ as r,b as i,bt as a,ct as o,g as s,gn as c,k as l,mt as u,o as d,qt as f,tr as p,v as m,vn as h,y as g}from"./runtime-core.esm-bundler-DkysjgTd.js";import{t as _}from"./objectSpread2-BmonrgTA.js";import{n as v}from"./objectWithoutProperties-BjoYlK0I.js";import{t as ee}from"./use-access-ObRBpYsT.js";import{t as te}from"./table-Do98iBZ3.js";import{n as y,t as b}from"./form-CZK1ilUa.js";import{t as x}from"./select-DyNDAEL2.js";import{C as ne,S as re,o as ie,r as ae}from"./console-2d_MKq1R.js";import{a as S}from"./config-provider-D1kcLCP5.js";import{t as C}from"./alert-CkUknOsQ.js";import{t as w}from"./popconfirm-BqMuKaMZ.js";import{t as T}from"./button-B2y2NpJm.js";import{t as E}from"./card-D3WO92mr.js";import{t as D}from"./tag-BFecLZmQ.js";import{r as O,t as k}from"./input-DgEff0DC.js";import{t as oe}from"./input-number-B39v8Wj_.js";import{t as se}from"./modal-Ju-U4s3Q.js";import{t as A}from"./switch-CtSw_Hgg.js";var ce={class:`p-5`},le={class:`grid grid-cols-1 gap-x-6 md:grid-cols-2`},ue={class:`flex items-center gap-3`},de={key:1,class:`text-xs text-gray-500`},fe={key:0,class:`text-xs text-gray-400`},pe={key:2,class:`text-xs text-gray-400`},me={key:0,class:`mt-3 text-xs text-gray-500`},j={class:`grid grid-cols-1 gap-x-6 md:grid-cols-2`},M={class:`mb-2 flex items-start gap-3`},N={class:`w-44 shrink-0`},P={class:`w-64 shrink-0`},F={class:`mb-2 text-xs text-gray-500`},I={class:`grid grid-cols-1 gap-x-6 md:grid-cols-2`},L=l({__name:`agents`,setup(l){let{hasAccessByCodes:L}=ee(),R=s(()=>L([`agent:write`])),z=h(!1),B=h([]),V=h(null),H=h(!1),U=h(``),W=c({mode:`single`,primary_id:``,active_ids:[]}),G=()=>({id:``,name:``,role:``,description:``,persona:``,keywords:[],rules:[],enabled:!0,priority:100}),K=c(G()),he=[{value:`guide`,label:`补充指令(告诉模型该怎么答)`},{value:`forbid`,label:`禁止措辞(回复里出现就换掉)`},{value:`reply`,label:`固定口径(命中就直接这么回)`}],ge={guide:`写一句给模型的补充要求。关键词留空 = 每一轮都注入;填了关键词 = 客户这句话命中才注入(规则多了以后靠这个控制提示词长度)。`,forbid:`关键词是**回复里**不许出现的词。命中就换成下面的兜底话术;兜底留空时客户端会用内置的那句正常人话顶上。`,reply:`关键词命中**客户这句话**时,直接发下面这句,不再问模型。口径必须一字不差的场景用它。`},_e=s(()=>B.value.filter(e=>e.enabled)),q=s(()=>_e.value.map(e=>({value:e.id,label:`${e.name}(${e.role})`})));function ve(){return J.apply(this,arguments)}function J(){return J=v(function*(){z.value=!0;try{let e=yield ie();B.value=e.agents,V.value=e.plan,Object.assign(W,{mode:e.plan.mode||`single`,primary_id:e.plan.primary_id||``,active_ids:[...e.plan.active_ids||[]]})}finally{z.value=!1}}),J.apply(this,arguments)}function ye(){U.value=``,Object.assign(K,G()),H.value=!0}function be(e){U.value=e.id,Object.assign(K,_(_({},e),{},{keywords:[...e.keywords],rules:e.rules.map(e=>_(_({},e),{},{keywords:[...e.keywords]}))})),H.value=!0}function xe(){var e;(e=K.rules)==null||e.push({label:``,type:`guide`,keywords:[],instruction:``,reply:``,enabled:!0})}function Se(e){var t;(t=K.rules)==null||t.splice(e,1)}function Ce(){var e;if(!((e=K.name)!=null&&e.trim()))return`智能体名称不能为空`;for(let[e,t]of(K.rules||[]).entries()){let n=`第 ${e+1} 条规则`;if(!t.label.trim())return`${n}没有填名称`;if(t.type===`guide`&&!t.instruction.trim())return`${n}是补充指令,必须填要告诉模型的话`;if(t.type!==`guide`&&t.keywords.length===0)return`${n}至少要有一个关键词,否则永远不会命中`;if(t.type===`reply`&&!t.reply.trim())return`${n}是固定口径,必须填要发给客户的话术`}return``}function we(){return Y.apply(this,arguments)}function Y(){return Y=v(function*(){let e=Ce();if(e){S.warning(e);return}let t=yield re(_({},K));B.value=t.agents,V.value=t.plan,H.value=!1,S.success(U.value?`已更新`:`已新增`)}),Y.apply(this,arguments)}function Te(e){return X.apply(this,arguments)}function X(){return X=v(function*(e){let t=yield ae(e.id);B.value=t.agents,V.value=t.plan,S.success(`已删除`)}),X.apply(this,arguments)}function Z(){return Q.apply(this,arguments)}function Q(){return Q=v(function*(){if(W.mode===`single`&&!W.primary_id){S.warning(`单角色模式要选一个当前生效的智能体`);return}if(W.mode===`collaborate`&&W.active_ids.length<2){S.warning(`协作模式至少要有两个在岗智能体,否则就是单角色`);return}let e=yield ne(_({},W));V.value=e.plan,S.success(`已保存为 v${e.version},客户端下次同步配置时生效`)}),Q.apply(this,arguments)}let Ee=[{title:`名称`,dataIndex:`name`,key:`name`,width:160},{title:`角色`,dataIndex:`role`,key:`role`,width:130},{title:`职责`,dataIndex:`description`,key:`description`},{title:`负责话题`,dataIndex:`keywords`,key:`keywords`},{title:`规则`,dataIndex:`rules`,key:`rules`,width:100},{title:`在岗`,key:`onduty`,width:110},{title:`状态`,dataIndex:`enabled`,key:`enabled`,width:90},{title:`操作`,key:`action`,width:130}];function $(e){return V.value?V.value.primary_id===e.id?`主答`:V.value.active_ids.includes(e.id)?`在岗`:``:``}return o(ve),(o,s)=>(u(),i(`div`,ce,[e(n(C),{class:`mb-4`,type:`info`,"show-icon":``,message:`智能体决定「用什么身份、按什么规矩说话」,模型清单决定「用哪个模型」`,description:`这两件事的变更频率差一个数量级:模型半年动一次,话术一周动三次。改这里不用动模型,也不用给客户端发版——保存后随配置下发。`}),e(n(E),{title:`启用与协作`,class:`mb-4`,loading:z.value},{default:f(()=>[s[13]||(s[13]=r(`p`,{class:`mb-3 text-xs text-gray-500`},` 单角色 = 只上一个,切换就是换这里选的那个;协作 = 多个同时在场,客户这句话 命中谁的「负责话题」就由谁主答,其余角色的禁止措辞仍然全体生效。 不论哪种模式,客户看到的永远是同一个人——不会自报角色名,也不会出现「转给同事」。 `,-1)),e(n(b),{model:W,layout:`vertical`},{default:f(()=>[r(`div`,le,[e(n(y),{label:`模式`},{default:f(()=>[e(n(x),{value:W.mode,"onUpdate:value":s[0]||(s[0]=e=>W.mode=e),disabled:!R.value,options:[{value:`single`,label:`单角色(切换到某一个)`},{value:`collaborate`,label:`协作(多个同时在场)`}]},null,8,[`value`,`disabled`])]),_:1}),e(n(y),{label:`主答智能体(没命中任何话题时由它回)`},{default:f(()=>[e(n(x),{value:W.primary_id,"onUpdate:value":s[1]||(s[1]=e=>W.primary_id=e),disabled:!R.value,options:q.value,placeholder:`选一个`},null,8,[`value`,`disabled`,`options`])]),_:1})]),W.mode===`collaborate`?(u(),m(n(y),{key:0,label:`在岗智能体(至少两个;主答会自动排在最前)`},{default:f(()=>[e(n(x),{value:W.active_ids,"onUpdate:value":s[2]||(s[2]=e=>W.active_ids=e),mode:`multiple`,disabled:!R.value,options:q.value},null,8,[`value`,`disabled`,`options`])]),_:1})):g(``,!0),r(`div`,ue,[R.value?(u(),m(n(T),{key:0,type:`primary`,onClick:Z},{default:f(()=>[...s[12]||(s[12]=[t(` 保存为新版本 `,-1)])]),_:1})):g(``,!0),V.value?(u(),i(`span`,de,[t(` 当前 v`+p(V.value.version)+` `,1),V.value.updated_at?(u(),i(d,{key:0},[t(`· `+p(V.value.updated_at),1)],64)):g(``,!0)])):g(``,!0)])]),_:1},8,[`model`])]),_:1},8,[`loading`]),e(n(E),{title:`智能体`},{extra:f(()=>[R.value?(u(),m(n(T),{key:0,type:`primary`,onClick:ye},{default:f(()=>[...s[14]||(s[14]=[t(` 新增智能体 `,-1)])]),_:1})):g(``,!0)]),default:f(()=>[e(n(te),{columns:Ee,"data-source":B.value,loading:z.value,"row-key":`id`,size:`small`,pagination:!1},{bodyCell:f(({column:r,record:o})=>[r.key===`keywords`?(u(),i(d,{key:0},[(u(!0),i(d,null,a(o.keywords,e=>(u(),m(n(D),{key:e,class:`mb-1`},{default:f(()=>[t(p(e),1)]),_:2},1024))),128)),o.keywords.length===0?(u(),i(`span`,fe,` 不认领话题 `)):g(``,!0)],64)):r.key===`rules`?(u(),i(d,{key:1},[t(p(o.rules.length)+` 条 `,1)],64)):r.key===`onduty`?(u(),i(d,{key:2},[$(o)===`主答`?(u(),m(n(D),{key:0,color:`green`},{default:f(()=>[...s[15]||(s[15]=[t(`主答`,-1)])]),_:1})):$(o)===`在岗`?(u(),m(n(D),{key:1,color:`blue`},{default:f(()=>[...s[16]||(s[16]=[t(`在岗`,-1)])]),_:1})):(u(),i(`span`,pe,`未上岗`))],64)):r.key===`enabled`?(u(),m(n(D),{key:3,color:o.enabled?`green`:`default`},{default:f(()=>[t(p(o.enabled?`已启用`:`已停用`),1)]),_:2},1032,[`color`])):r.key===`action`?(u(),i(d,{key:4},[e(n(T),{type:`link`,size:`small`,disabled:!R.value,onClick:e=>be(o)},{default:f(()=>[...s[17]||(s[17]=[t(` 编辑 `,-1)])]),_:1},8,[`disabled`,`onClick`]),e(n(w),{title:`确定删除这个智能体?`,onConfirm:e=>Te(o)},{default:f(()=>[e(n(T),{type:`link`,size:`small`,danger:``,disabled:!R.value},{default:f(()=>[...s[18]||(s[18]=[t(` 删除 `,-1)])]),_:1},8,[`disabled`])]),_:1},8,[`onConfirm`])],64)):g(``,!0)]),_:1},8,[`data-source`,`loading`]),B.value.length===0&&!z.value?(u(),i(`p`,me,` 还没有智能体——客户端会沿用内置人设,行为和没有这套东西时一样。 `)):g(``,!0)]),_:1}),e(n(se),{open:H.value,"onUpdate:open":s[11]||(s[11]=e=>H.value=e),title:U.value?`编辑智能体:${K.name}`:`新增智能体`,width:`760px`,onOk:we},{default:f(()=>[e(n(b),{model:K,layout:`vertical`,class:`pt-2`},{default:f(()=>[r(`div`,j,[e(n(y),{label:`名称`},{default:f(()=>[e(n(k),{value:K.name,"onUpdate:value":s[3]||(s[3]=e=>K.name=e),placeholder:`客户经理`},null,8,[`value`])]),_:1}),e(n(y),{label:`角色标签(留空同名称)`},{default:f(()=>[e(n(k),{value:K.role,"onUpdate:value":s[4]||(s[4]=e=>K.role=e),placeholder:`客户经理 / 糖尿病专科医生`},null,8,[`value`])]),_:1})]),e(n(y),{label:`ID(留空自动生成,之后不可改)`},{default:f(()=>[e(n(k),{value:K.id,"onUpdate:value":s[5]||(s[5]=e=>K.id=e),disabled:!!U.value,placeholder:`customer-manager`},null,8,[`value`,`disabled`])]),_:1}),e(n(y),{label:`职责(一句话,写给人看的)`},{default:f(()=>[e(n(k),{value:K.description,"onUpdate:value":s[6]||(s[6]=e=>K.description=e),placeholder:`挂号预约、面诊链接、订单物流、投诉退款`},null,8,[`value`])]),_:1}),e(n(y),{label:`负责话题(协作时按它认领本轮;留空 = 不主动认领)`},{default:f(()=>[e(n(x),{value:K.keywords,"onUpdate:value":s[7]||(s[7]=e=>K.keywords=e),mode:`tags`,placeholder:`输入后回车,可以加多个`,style:{width:`100%`}},null,8,[`value`])]),_:1}),e(n(y),{label:`人设(这个角色怎么说话、管哪一摊事)`},{default:f(()=>[e(n(O),{value:K.persona,"onUpdate:value":s[8]||(s[8]=e=>K.persona=e),rows:5,placeholder:`你负责流程类事情:挂号预约、面诊安排、订单物流、投诉退款……`},null,8,[`value`]),s[19]||(s[19]=r(`p`,{class:`mt-1 text-xs text-gray-500`},` 追加在内置人设后面,压过默认的表达习惯。不用重复写「像真人一样说话」 这种通用要求,内置人设里已经有了——这里只写这个角色特有的部分。 `,-1))]),_:1}),e(n(y),{label:`规则`},{default:f(()=>[(u(!0),i(d,null,a(K.rules,(a,o)=>(u(),i(`div`,{key:o,class:`mb-3 rounded border border-dashed p-3`},[r(`div`,M,[r(`div`,N,[e(n(k),{value:a.label,"onUpdate:value":e=>a.label=e,placeholder:`规则名称`},null,8,[`value`,`onUpdate:value`])]),r(`div`,P,[e(n(x),{value:a.type,"onUpdate:value":e=>a.type=e,options:he,style:{width:`100%`}},null,8,[`value`,`onUpdate:value`])]),e(n(A),{checked:a.enabled,"onUpdate:checked":e=>a.enabled=e,class:`mt-1 shrink-0`},null,8,[`checked`,`onUpdate:checked`]),e(n(T),{danger:``,type:`link`,size:`small`,class:`shrink-0`,onClick:e=>Se(o)},{default:f(()=>[...s[20]||(s[20]=[t(` 删除 `,-1)])]),_:1},8,[`onClick`])]),r(`p`,F,p(ge[a.type]),1),e(n(x),{value:a.keywords,"onUpdate:value":e=>a.keywords=e,mode:`tags`,class:`mb-2`,placeholder:a.type===`forbid`?`回复里不许出现的词,回车分隔`:`触发关键词,回车分隔`,style:{width:`100%`}},null,8,[`value`,`onUpdate:value`,`placeholder`]),a.type===`guide`?(u(),m(n(O),{key:0,value:a.instruction,"onUpdate:value":e=>a.instruction=e,rows:2,placeholder:`要告诉模型的话,例如:客户只发数字时按血糖值理解,严禁说这是系统编码。`},null,8,[`value`,`onUpdate:value`])):(u(),m(n(O),{key:1,value:a.reply,"onUpdate:value":e=>a.reply=e,rows:2,placeholder:a.type===`reply`?`命中后直接发给客户的话术`:`命中禁止措辞后的兜底话术(留空则用客户端内置的那句)`},null,8,[`value`,`onUpdate:value`,`placeholder`]))]))),128)),e(n(T),{size:`small`,onClick:xe},{default:f(()=>[...s[21]||(s[21]=[t(`+ 新增规则`,-1)])]),_:1})]),_:1}),r(`div`,I,[e(n(y),{label:`优先级(数字越小越靠前)`},{default:f(()=>[e(n(oe),{value:K.priority,"onUpdate:value":s[9]||(s[9]=e=>K.priority=e),min:1,max:999},null,8,[`value`])]),_:1}),e(n(y),{label:`启用`},{default:f(()=>[e(n(A),{checked:K.enabled,"onUpdate:checked":s[10]||(s[10]=e=>K.enabled=e)},null,8,[`checked`])]),_:1})])]),_:1},8,[`model`])]),_:1},8,[`open`,`title`])]))}});export{L as default}; |