@vibe-forge/client 0.2.0-alpha.8 → 0.3.0
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/dist/assets/{arc-CybT1Fs2.js → arc-CwMXUVsq.js} +1 -1
- package/dist/assets/{blockDiagram-c4efeb88-BY5Aoa-D.js → blockDiagram-c4efeb88-CGxJV7KJ.js} +1 -1
- package/dist/assets/{c4Diagram-c83219d4-F42hTbzS.js → c4Diagram-c83219d4-BKhin7cY.js} +1 -1
- package/dist/assets/channel-jbCEHqbG.js +1 -0
- package/dist/assets/{classDiagram-beda092f-D-tIPp-3.js → classDiagram-beda092f-BASmn22R.js} +1 -1
- package/dist/assets/{classDiagram-v2-2358418a-J57aCe6u.js → classDiagram-v2-2358418a-BUk9rNBX.js} +1 -1
- package/dist/assets/clone-CCRKqS4L.js +1 -0
- package/dist/assets/{createText-1719965b-ByfEqOF-.js → createText-1719965b-2XqnWjQY.js} +1 -1
- package/dist/assets/{edges-96097737-CMEArkOa.js → edges-96097737-B7e32Jeg.js} +1 -1
- package/dist/assets/{erDiagram-0228fc6a-Cf8mX2aj.js → erDiagram-0228fc6a-CCR2or72.js} +1 -1
- package/dist/assets/{flowDb-c6c81e3f-DG6WKyo7.js → flowDb-c6c81e3f-B72HWT9x.js} +1 -1
- package/dist/assets/{flowDiagram-50d868cf-CstUxz-w.js → flowDiagram-50d868cf-WOi0KARY.js} +1 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-Baslbgn4.js +1 -0
- package/dist/assets/{flowchart-elk-definition-6af322e1--4CRoQ-H.js → flowchart-elk-definition-6af322e1-i_Yd0LCE.js} +1 -1
- package/dist/assets/{ganttDiagram-a2739b55-DYgHcKd-.js → ganttDiagram-a2739b55-CFH9zF14.js} +1 -1
- package/dist/assets/{gitGraphDiagram-82fe8481-DDSVpfsd.js → gitGraphDiagram-82fe8481-DglKfMze.js} +1 -1
- package/dist/assets/{graph-CRWF39gX.js → graph-BKbBNGPf.js} +1 -1
- package/dist/assets/{index-5325376f-W1hft795.js → index-5325376f-BK7F9nSl.js} +1 -1
- package/dist/assets/{index-PEmISxiy.css → index-B0qfCb1G.css} +1 -1
- package/dist/assets/{index-CNMzWvKV.js → index-CNo75dYr.js} +127 -127
- package/dist/assets/{infoDiagram-8eee0895-D4SHcix6.js → infoDiagram-8eee0895-BLFL77_D.js} +1 -1
- package/dist/assets/{journeyDiagram-c64418c1-MWgCkVoE.js → journeyDiagram-c64418c1-CS9XctDL.js} +1 -1
- package/dist/assets/{layout-C88ObkCf.js → layout-By3JZZGt.js} +1 -1
- package/dist/assets/{line-C7WAYMt5.js → line-9GUsXbwv.js} +1 -1
- package/dist/assets/{linear-C4msxfcU.js → linear-DzGV4E9N.js} +1 -1
- package/dist/assets/{mermaid.core-Cabag9SZ.js → mermaid.core-CG3Ib42Q.js} +4 -4
- package/dist/assets/{mindmap-definition-8da855dc-CeS8ETXx.js → mindmap-definition-8da855dc-WQ3LPKJU.js} +1 -1
- package/dist/assets/{pieDiagram-a8764435-BvjyKnq5.js → pieDiagram-a8764435-DHVIUZiN.js} +1 -1
- package/dist/assets/{quadrantDiagram-1e28029f-DzYvpbNM.js → quadrantDiagram-1e28029f-C3G9Ye8-.js} +1 -1
- package/dist/assets/{requirementDiagram-08caed73-DHIoDbyo.js → requirementDiagram-08caed73-C9ES1D5G.js} +1 -1
- package/dist/assets/{sankeyDiagram-a04cb91d-BFSGnQGs.js → sankeyDiagram-a04cb91d-B4BKXclQ.js} +1 -1
- package/dist/assets/{sequenceDiagram-c5b8d532-_LM3BJ5-.js → sequenceDiagram-c5b8d532-DrgEb25G.js} +1 -1
- package/dist/assets/{stateDiagram-1ecb1508-DwORjOzl.js → stateDiagram-1ecb1508-CF1XWARJ.js} +1 -1
- package/dist/assets/{stateDiagram-v2-c2b004d7-B4cAWWz1.js → stateDiagram-v2-c2b004d7-IO3i3yXv.js} +1 -1
- package/dist/assets/{styles-b4e223ce-D_rmV3B_.js → styles-b4e223ce-DACN9aSc.js} +1 -1
- package/dist/assets/{styles-ca3715f6-BFx4VuFc.js → styles-ca3715f6-bekm2WLP.js} +1 -1
- package/dist/assets/{styles-d45a18b0-BE3106vL.js → styles-d45a18b0-OzTDVBb8.js} +1 -1
- package/dist/assets/{svgDrawCommon-b86b1483-DwDTO1op.js → svgDrawCommon-b86b1483-BWroJerr.js} +1 -1
- package/dist/assets/{timeline-definition-faaaa080-C4b8qUQZ.js → timeline-definition-faaaa080-CCfRNigO.js} +1 -1
- package/dist/assets/{xychartDiagram-f5964ef8-BRJ9Z4u-.js → xychartDiagram-f5964ef8-C3cbfVqN.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +3 -3
- package/src/api.ts +30 -2
- package/src/components/ConfigView.tsx +6 -1
- package/src/components/chat/NewSessionGuide.scss +35 -13
- package/src/components/chat/NewSessionGuide.tsx +20 -10
- package/src/components/chat/useChatModels.tsx +19 -1
- package/src/components/chat/useChatSession.ts +1 -1
- package/src/components/config/AppSettingsPanel.tsx +33 -0
- package/src/components/knowledge-base/KnowledgeBaseView.tsx +51 -3
- package/src/components/knowledge-base/components/RuleItem.tsx +79 -0
- package/src/components/knowledge-base/components/RuleList.scss +5 -0
- package/src/components/knowledge-base/components/RuleList.tsx +70 -0
- package/src/components/knowledge-base/components/RulesTab.tsx +32 -7
- package/src/resources/locales/en.json +7 -0
- package/src/resources/locales/zh.json +7 -0
- package/src/store/index.ts +2 -0
- package/dist/assets/channel-DrWdSpqV.js +0 -1
- package/dist/assets/clone-D0cC8LLB.js +0 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-Bf_DH7dp.js +0 -1
package/dist/assets/{xychartDiagram-f5964ef8-BRJ9Z4u-.js → xychartDiagram-f5964ef8-C3cbfVqN.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{s as zt,a as Ft,v as wt,x as Nt,b as Xt,c as Yt,l as St,aH as Ht,e as $t,z as Ut,ap as ot,aJ as Ct,aL as qt,aY as jt,i as Gt}from"./mermaid.core-
|
|
1
|
+
import{s as zt,a as Ft,v as wt,x as Nt,b as Xt,c as Yt,l as St,aH as Ht,e as $t,z as Ut,ap as ot,aJ as Ct,aL as qt,aY as jt,i as Gt}from"./mermaid.core-CG3Ib42Q.js";import{a as Qt}from"./createText-1719965b-2XqnWjQY.js";import"./index-CNo75dYr.js";import{i as Kt}from"./init-Gi6I4Gst.js";import{o as Jt}from"./ordinal-Cboi1Yqb.js";import{l as ft}from"./linear-DzGV4E9N.js";import{l as pt}from"./line-9GUsXbwv.js";import"./array-BKyUJesY.js";import"./path-CbwjOpE9.js";function Zt(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s<n;)o[s]=e+s*i;return o}function st(){var e=Jt().unknown(void 0),t=e.domain,i=e.range,s=0,n=1,o,c,f=!1,d=0,R=0,_=.5;delete e.unknown;function A(){var m=t().length,T=n<s,S=T?n:s,P=T?s:n;o=(P-S)/Math.max(1,m-d+R*2),f&&(o=Math.floor(o)),S+=(P-S-o*(m-d))*_,c=o*(1-d),f&&(S=Math.round(S),c=Math.round(c));var p=Zt(m).map(function(C){return S+o*C});return i(T?p.reverse():p)}return e.domain=function(m){return arguments.length?(t(m),A()):t()},e.range=function(m){return arguments.length?([s,n]=m,s=+s,n=+n,A()):[s,n]},e.rangeRound=function(m){return[s,n]=m,s=+s,n=+n,f=!0,A()},e.bandwidth=function(){return c},e.step=function(){return o},e.round=function(m){return arguments.length?(f=!!m,A()):f},e.padding=function(m){return arguments.length?(d=Math.min(1,R=+m),A()):d},e.paddingInner=function(m){return arguments.length?(d=Math.min(1,m),A()):d},e.paddingOuter=function(m){return arguments.length?(R=+m,A()):R},e.align=function(m){return arguments.length?(_=Math.max(0,Math.min(1,m)),A()):_},e.copy=function(){return st(t(),[s,n]).round(f).paddingInner(d).paddingOuter(R).align(_)},Kt.apply(A(),arguments)}var nt=function(){var e=function(V,r,l,u){for(l=l||{},u=V.length;u--;l[V[u]]=r);return l},t=[1,10,12,14,16,18,19,21,23],i=[2,6],s=[1,3],n=[1,5],o=[1,6],c=[1,7],f=[1,5,10,12,14,16,18,19,21,23,34,35,36],d=[1,25],R=[1,26],_=[1,28],A=[1,29],m=[1,30],T=[1,31],S=[1,32],P=[1,33],p=[1,34],C=[1,35],h=[1,36],L=[1,37],z=[1,43],lt=[1,42],ct=[1,47],$=[1,50],w=[1,10,12,14,16,18,19,21,23,34,35,36],Q=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],v=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],ut=[1,64],K={trace:function(){},yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:function(r,l,u,g,b,a,F){var x=a.length-1;switch(b){case 5:g.setOrientation(a[x]);break;case 9:g.setDiagramTitle(a[x].text.trim());break;case 12:g.setLineData({text:"",type:"text"},a[x]);break;case 13:g.setLineData(a[x-1],a[x]);break;case 14:g.setBarData({text:"",type:"text"},a[x]);break;case 15:g.setBarData(a[x-1],a[x]);break;case 16:this.$=a[x].trim(),g.setAccTitle(this.$);break;case 17:case 18:this.$=a[x].trim(),g.setAccDescription(this.$);break;case 19:this.$=a[x-1];break;case 20:this.$=[Number(a[x-2]),...a[x]];break;case 21:this.$=[Number(a[x])];break;case 22:g.setXAxisTitle(a[x]);break;case 23:g.setXAxisTitle(a[x-1]);break;case 24:g.setXAxisTitle({type:"text",text:""});break;case 25:g.setXAxisBand(a[x]);break;case 26:g.setXAxisRangeData(Number(a[x-2]),Number(a[x]));break;case 27:this.$=a[x-1];break;case 28:this.$=[a[x-2],...a[x]];break;case 29:this.$=[a[x]];break;case 30:g.setYAxisTitle(a[x]);break;case 31:g.setYAxisTitle(a[x-1]);break;case 32:g.setYAxisTitle({type:"text",text:""});break;case 33:g.setYAxisRangeData(Number(a[x-2]),Number(a[x]));break;case 37:this.$={text:a[x],type:"text"};break;case 38:this.$={text:a[x],type:"text"};break;case 39:this.$={text:a[x],type:"markdown"};break;case 40:this.$=a[x];break;case 41:this.$=a[x-1]+""+a[x];break}},table:[e(t,i,{3:1,4:2,7:4,5:s,34:n,35:o,36:c}),{1:[3]},e(t,i,{4:2,7:4,3:8,5:s,34:n,35:o,36:c}),e(t,i,{4:2,7:4,6:9,3:10,5:s,8:[1,11],34:n,35:o,36:c}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},e(f,[2,34]),e(f,[2,35]),e(f,[2,36]),{1:[2,1]},e(t,i,{4:2,7:4,3:21,5:s,34:n,35:o,36:c}),{1:[2,3]},e(f,[2,5]),e(t,[2,7],{4:22,34:n,35:o,36:c}),{11:23,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:39,13:38,24:z,27:lt,29:40,30:41,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:45,15:44,27:ct,33:46,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:49,17:48,24:$,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{11:52,17:51,24:$,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},{20:[1,53]},{22:[1,54]},e(w,[2,18]),{1:[2,2]},e(w,[2,8]),e(w,[2,9]),e(Q,[2,37],{40:55,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L}),e(Q,[2,38]),e(Q,[2,39]),e(v,[2,40]),e(v,[2,42]),e(v,[2,43]),e(v,[2,44]),e(v,[2,45]),e(v,[2,46]),e(v,[2,47]),e(v,[2,48]),e(v,[2,49]),e(v,[2,50]),e(v,[2,51]),e(w,[2,10]),e(w,[2,22],{30:41,29:56,24:z,27:lt}),e(w,[2,24]),e(w,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},e(w,[2,11]),e(w,[2,30],{33:60,27:ct}),e(w,[2,32]),{31:[1,61]},e(w,[2,12]),{17:62,24:$},{25:63,27:ut},e(w,[2,14]),{17:65,24:$},e(w,[2,16]),e(w,[2,17]),e(v,[2,41]),e(w,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},e(w,[2,31]),{27:[1,69]},e(w,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},e(w,[2,15]),e(w,[2,26]),e(w,[2,27]),{11:59,32:72,37:24,38:d,39:R,40:27,41:_,42:A,43:m,44:T,45:S,46:P,47:p,48:C,49:h,50:L},e(w,[2,33]),e(w,[2,19]),{25:73,27:ut},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:function(r,l){if(l.recoverable)this.trace(r);else{var u=new Error(r);throw u.hash=l,u}},parse:function(r){var l=this,u=[0],g=[],b=[null],a=[],F=this.table,x="",U=0,gt=0,Vt=2,xt=1,Bt=a.slice.call(arguments,1),k=Object.create(this.lexer),B={yy:{}};for(var Z in this.yy)Object.prototype.hasOwnProperty.call(this.yy,Z)&&(B.yy[Z]=this.yy[Z]);k.setInput(r,B.yy),B.yy.lexer=k,B.yy.parser=this,typeof k.yylloc>"u"&&(k.yylloc={});var tt=k.yylloc;a.push(tt);var Wt=k.options&&k.options.ranges;typeof B.yy.parseError=="function"?this.parseError=B.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function Ot(){var I;return I=g.pop()||k.lex()||xt,typeof I!="number"&&(I instanceof Array&&(g=I,I=g.pop()),I=l.symbols_[I]||I),I}for(var D,W,E,it,O={},q,M,dt,j;;){if(W=u[u.length-1],this.defaultActions[W]?E=this.defaultActions[W]:((D===null||typeof D>"u")&&(D=Ot()),E=F[W]&&F[W][D]),typeof E>"u"||!E.length||!E[0]){var et="";j=[];for(q in F[W])this.terminals_[q]&&q>Vt&&j.push("'"+this.terminals_[q]+"'");k.showPosition?et="Parse error on line "+(U+1)+`:
|
|
2
2
|
`+k.showPosition()+`
|
|
3
3
|
Expecting `+j.join(", ")+", got '"+(this.terminals_[D]||D)+"'":et="Parse error on line "+(U+1)+": Unexpected "+(D==xt?"end of input":"'"+(this.terminals_[D]||D)+"'"),this.parseError(et,{text:k.match,token:this.terminals_[D]||D,line:k.yylineno,loc:tt,expected:j})}if(E[0]instanceof Array&&E.length>1)throw new Error("Parse Error: multiple actions possible at state: "+W+", token: "+D);switch(E[0]){case 1:u.push(D),b.push(k.yytext),a.push(k.yylloc),u.push(E[1]),D=null,gt=k.yyleng,x=k.yytext,U=k.yylineno,tt=k.yylloc;break;case 2:if(M=this.productions_[E[1]][1],O.$=b[b.length-M],O._$={first_line:a[a.length-(M||1)].first_line,last_line:a[a.length-1].last_line,first_column:a[a.length-(M||1)].first_column,last_column:a[a.length-1].last_column},Wt&&(O._$.range=[a[a.length-(M||1)].range[0],a[a.length-1].range[1]]),it=this.performAction.apply(O,[x,gt,U,B.yy,E[1],b,a].concat(Bt)),typeof it<"u")return it;M&&(u=u.slice(0,-1*M*2),b=b.slice(0,-1*M),a=a.slice(0,-1*M)),u.push(this.productions_[E[1]][0]),b.push(O.$),a.push(O._$),dt=F[u[u.length-2]][u[u.length-1]],u.push(dt);break;case 3:return!0}}return!0}},It=function(){var V={EOF:1,parseError:function(l,u){if(this.yy.parser)this.yy.parser.parseError(l,u);else throw new Error(l)},setInput:function(r,l){return this.yy=l||this.yy||{},this._input=r,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var r=this._input[0];this.yytext+=r,this.yyleng++,this.offset++,this.match+=r,this.matched+=r;var l=r.match(/(?:\r\n?|\n).*/g);return l?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),r},unput:function(r){var l=r.length,u=r.split(/(?:\r\n?|\n)/g);this._input=r+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-l),this.offset-=l;var g=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),u.length-1&&(this.yylineno-=u.length-1);var b=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:u?(u.length===g.length?this.yylloc.first_column:0)+g[g.length-u.length].length-u[0].length:this.yylloc.first_column-l},this.options.ranges&&(this.yylloc.range=[b[0],b[0]+this.yyleng-l]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
|
|
4
4
|
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},less:function(r){this.unput(this.match.slice(r))},pastInput:function(){var r=this.matched.substr(0,this.matched.length-this.match.length);return(r.length>20?"...":"")+r.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var r=this.match;return r.length<20&&(r+=this._input.substr(0,20-r.length)),(r.substr(0,20)+(r.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var r=this.pastInput(),l=new Array(r.length+1).join("-");return r+this.upcomingInput()+`
|
package/dist/index.html
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
type="text/css"
|
|
20
20
|
href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css"
|
|
21
21
|
/>
|
|
22
|
-
<script type="module" crossorigin src="/assets/index-
|
|
23
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
22
|
+
<script type="module" crossorigin src="/assets/index-CNo75dYr.js"></script>
|
|
23
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B0qfCb1G.css">
|
|
24
24
|
</head>
|
|
25
25
|
<body>
|
|
26
26
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibe-forge/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"imports": {
|
|
6
6
|
"#~/*": [
|
|
7
7
|
"./src/*",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"typescript": "^5.6.3",
|
|
34
34
|
"vite": "^5.4.8",
|
|
35
35
|
"vitest": "^3.2.4",
|
|
36
|
-
"@vibe-forge/core": "0.
|
|
37
|
-
"@vibe-forge/register": "^0.
|
|
36
|
+
"@vibe-forge/core": "0.3.0",
|
|
37
|
+
"@vibe-forge/register": "^0.3.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/react": "^18.3.12",
|
package/src/api.ts
CHANGED
|
@@ -21,6 +21,14 @@ export interface EntitySummary {
|
|
|
21
21
|
rules: string[]
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface RuleSummary {
|
|
25
|
+
id: string
|
|
26
|
+
name: string
|
|
27
|
+
description: string
|
|
28
|
+
always: boolean
|
|
29
|
+
globs?: string[]
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
export interface SpecDetail extends SpecSummary {
|
|
25
33
|
body: string
|
|
26
34
|
}
|
|
@@ -29,6 +37,10 @@ export interface EntityDetail extends EntitySummary {
|
|
|
29
37
|
body: string
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
export interface RuleDetail extends RuleSummary {
|
|
41
|
+
body: string
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
export interface AutomationTrigger {
|
|
33
45
|
id: string
|
|
34
46
|
type: 'interval' | 'webhook' | 'cron'
|
|
@@ -96,11 +108,15 @@ export async function listSessions(filter: 'active' | 'archived' | 'all' = 'acti
|
|
|
96
108
|
return res.json() as Promise<{ sessions: Session[] }>
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
export async function createSession(
|
|
111
|
+
export async function createSession(
|
|
112
|
+
title?: string,
|
|
113
|
+
initialMessage?: string,
|
|
114
|
+
model?: string
|
|
115
|
+
): Promise<{ session: Session }> {
|
|
100
116
|
const res = await fetch(`${SERVER_URL}/api/sessions`, {
|
|
101
117
|
method: 'POST',
|
|
102
118
|
headers: { 'Content-Type': 'application/json' },
|
|
103
|
-
body: JSON.stringify({ title, initialMessage })
|
|
119
|
+
body: JSON.stringify({ title, initialMessage, model })
|
|
104
120
|
})
|
|
105
121
|
return res.json() as Promise<{ session: Session }>
|
|
106
122
|
}
|
|
@@ -115,6 +131,11 @@ export async function listEntities(): Promise<{ entities: EntitySummary[] }> {
|
|
|
115
131
|
return res.json() as Promise<{ entities: EntitySummary[] }>
|
|
116
132
|
}
|
|
117
133
|
|
|
134
|
+
export async function listRules(): Promise<{ rules: RuleSummary[] }> {
|
|
135
|
+
const res = await fetch(`${SERVER_URL}/api/ai/rules`)
|
|
136
|
+
return res.json() as Promise<{ rules: RuleSummary[] }>
|
|
137
|
+
}
|
|
138
|
+
|
|
118
139
|
export async function getSpecDetail(path: string): Promise<{ spec: SpecDetail }> {
|
|
119
140
|
const url = new URL(`${SERVER_URL}/api/ai/specs/detail`)
|
|
120
141
|
url.searchParams.set('path', path)
|
|
@@ -129,6 +150,13 @@ export async function getEntityDetail(path: string): Promise<{ entity: EntityDet
|
|
|
129
150
|
return res.json() as Promise<{ entity: EntityDetail }>
|
|
130
151
|
}
|
|
131
152
|
|
|
153
|
+
export async function getRuleDetail(path: string): Promise<{ rule: RuleDetail }> {
|
|
154
|
+
const url = new URL(`${SERVER_URL}/api/ai/rules/detail`)
|
|
155
|
+
url.searchParams.set('path', path)
|
|
156
|
+
const res = await fetch(url.toString())
|
|
157
|
+
return res.json() as Promise<{ rule: RuleDetail }>
|
|
158
|
+
}
|
|
159
|
+
|
|
132
160
|
export async function getConfig(): Promise<ConfigResponse> {
|
|
133
161
|
const res = await fetch(`${SERVER_URL}/api/config`)
|
|
134
162
|
return res.json() as Promise<ConfigResponse>
|
|
@@ -9,6 +9,7 @@ import type { AboutInfo, ConfigResponse, ConfigSource } from '@vibe-forge/core'
|
|
|
9
9
|
|
|
10
10
|
import { getConfig, updateConfig } from '../api'
|
|
11
11
|
import { AboutSection, ConfigSectionPanel, ConfigSourceSwitch, DisplayValue } from './config'
|
|
12
|
+
import { AppSettingsPanel } from './config/AppSettingsPanel'
|
|
12
13
|
import { cloneValue, getValueByPath, isEmptyValue } from './config/configUtils'
|
|
13
14
|
|
|
14
15
|
export function ConfigView() {
|
|
@@ -75,6 +76,7 @@ export function ConfigView() {
|
|
|
75
76
|
{ key: 'mcp', icon: 'account_tree', label: t('config.sections.mcp'), value: currentSource?.mcp },
|
|
76
77
|
{ key: 'shortcuts', icon: 'keyboard', label: t('config.sections.shortcuts'), value: currentSource?.shortcuts },
|
|
77
78
|
{ key: 'group-app', type: 'group', label: t('config.groups.app') },
|
|
79
|
+
{ key: 'appearance', icon: 'tune', label: t('config.sections.appearance') },
|
|
78
80
|
{ key: 'experiments', icon: 'science', label: t('config.sections.experiments'), value: data?.meta?.experiments },
|
|
79
81
|
{ key: 'about', icon: 'info', label: t('config.sections.about'), value: data?.meta?.about }
|
|
80
82
|
], [currentSource, data?.meta?.about, data?.meta?.experiments, t])
|
|
@@ -220,7 +222,10 @@ export function ConfigView() {
|
|
|
220
222
|
{tab.key === 'about' && (
|
|
221
223
|
<AboutSection value={tab.value as AboutInfo | undefined} />
|
|
222
224
|
)}
|
|
223
|
-
{tab.key
|
|
225
|
+
{tab.key === 'appearance' && (
|
|
226
|
+
<AppSettingsPanel t={t} />
|
|
227
|
+
)}
|
|
228
|
+
{tab.key !== 'about' && tab.key !== 'appearance' && !configTabKeys.has(tab.key) && (
|
|
224
229
|
<DisplayValue value={tab.value} sectionKey={tab.key} t={t} />
|
|
225
230
|
)}
|
|
226
231
|
{configTabKeys.has(tab.key) && (
|
|
@@ -15,19 +15,47 @@
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
.new-session-guide__announcements-header {
|
|
18
|
-
display:
|
|
18
|
+
display: flex;
|
|
19
19
|
align-items: center;
|
|
20
|
-
|
|
20
|
+
justify-content: space-between;
|
|
21
|
+
gap: 12px;
|
|
21
22
|
font-size: 13px;
|
|
22
23
|
font-weight: 600;
|
|
23
24
|
color: var(--text-color);
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
.new-session-guide__announcements-title {
|
|
28
|
+
display: inline-flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 8px;
|
|
31
|
+
min-width: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
.new-session-guide__announcements-icon {
|
|
27
35
|
font-size: 18px;
|
|
28
36
|
color: var(--sub-text-color);
|
|
29
37
|
}
|
|
30
38
|
|
|
39
|
+
.new-session-guide__announcements-close {
|
|
40
|
+
border: none;
|
|
41
|
+
background: transparent;
|
|
42
|
+
padding: 0;
|
|
43
|
+
color: var(--sub-text-color);
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
line-height: 1;
|
|
46
|
+
display: inline-flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.new-session-guide__announcements-close:hover {
|
|
52
|
+
color: var(--text-color);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.new-session-guide__announcements-close .material-symbols-rounded {
|
|
56
|
+
font-size: 18px;
|
|
57
|
+
}
|
|
58
|
+
|
|
31
59
|
.new-session-guide__announcements-list {
|
|
32
60
|
display: flex;
|
|
33
61
|
flex-direction: column;
|
|
@@ -53,10 +81,6 @@
|
|
|
53
81
|
display: flex;
|
|
54
82
|
flex-direction: column;
|
|
55
83
|
gap: 12px;
|
|
56
|
-
border: 1px solid var(--border-color);
|
|
57
|
-
border-radius: 12px;
|
|
58
|
-
padding: 16px;
|
|
59
|
-
background: var(--bg-color);
|
|
60
84
|
}
|
|
61
85
|
|
|
62
86
|
.new-session-guide__header {
|
|
@@ -92,7 +116,8 @@
|
|
|
92
116
|
display: flex;
|
|
93
117
|
flex-direction: column;
|
|
94
118
|
gap: 12px;
|
|
95
|
-
|
|
119
|
+
height: 160px;
|
|
120
|
+
overflow: scroll;
|
|
96
121
|
}
|
|
97
122
|
|
|
98
123
|
.new-session-guide__list {
|
|
@@ -105,16 +130,13 @@
|
|
|
105
130
|
display: flex;
|
|
106
131
|
flex-direction: column;
|
|
107
132
|
gap: 4px;
|
|
108
|
-
padding: 10px 12px;
|
|
109
|
-
border-radius: 10px;
|
|
110
|
-
background: var(--tag-bg);
|
|
111
133
|
}
|
|
112
134
|
|
|
113
135
|
.new-session-guide__item-title {
|
|
114
136
|
display: inline-flex;
|
|
115
137
|
align-items: center;
|
|
116
138
|
gap: 6px;
|
|
117
|
-
font-size:
|
|
139
|
+
font-size: 12px;
|
|
118
140
|
font-weight: 600;
|
|
119
141
|
color: var(--text-color);
|
|
120
142
|
}
|
|
@@ -126,13 +148,13 @@
|
|
|
126
148
|
|
|
127
149
|
.new-session-guide__item-desc {
|
|
128
150
|
font-size: 12px;
|
|
129
|
-
color: var(--
|
|
151
|
+
color: var(--placeholder-color);
|
|
130
152
|
line-height: 1.4;
|
|
131
153
|
}
|
|
132
154
|
|
|
133
155
|
.new-session-guide__meta {
|
|
134
156
|
font-size: 11px;
|
|
135
|
-
color: var(--
|
|
157
|
+
color: var(--placeholder-color);
|
|
136
158
|
}
|
|
137
159
|
|
|
138
160
|
.new-session-guide__empty {
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import './NewSessionGuide.scss'
|
|
2
2
|
|
|
3
3
|
import { App, Button } from 'antd'
|
|
4
|
-
import
|
|
4
|
+
import { useAtom } from 'jotai'
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
import useSWR from 'swr'
|
|
7
7
|
|
|
8
8
|
import type { EntitySummary, SpecSummary } from '#~/api.js'
|
|
9
|
+
import { showAnnouncementsAtom } from '#~/store/index.js'
|
|
9
10
|
|
|
10
11
|
export function NewSessionGuide() {
|
|
11
12
|
const { t } = useTranslation()
|
|
12
13
|
const { message } = App.useApp()
|
|
14
|
+
const [showAnnouncements, setShowAnnouncements] = useAtom(showAnnouncementsAtom)
|
|
13
15
|
|
|
14
16
|
const { data: specsRes } = useSWR<{ specs: SpecSummary[] }>('/api/ai/specs')
|
|
15
17
|
const { data: entitiesRes } = useSWR<{ entities: EntitySummary[] }>('/api/ai/entities')
|
|
@@ -26,6 +28,7 @@ export function NewSessionGuide() {
|
|
|
26
28
|
)
|
|
27
29
|
|
|
28
30
|
const specs = specsRes?.specs ?? []
|
|
31
|
+
const alwaysSpecs = specs.filter(spec => spec.always)
|
|
29
32
|
const entities = entitiesRes?.entities ?? []
|
|
30
33
|
const isSpecsReady = specsRes != null
|
|
31
34
|
const isEntitiesReady = entitiesRes != null
|
|
@@ -47,11 +50,20 @@ export function NewSessionGuide() {
|
|
|
47
50
|
|
|
48
51
|
return (
|
|
49
52
|
<div className='new-session-guide'>
|
|
50
|
-
{announcements.length > 0 && (
|
|
53
|
+
{showAnnouncements && announcements.length > 0 && (
|
|
51
54
|
<div className='new-session-guide__announcements'>
|
|
52
55
|
<div className='new-session-guide__announcements-header'>
|
|
53
|
-
<
|
|
54
|
-
|
|
56
|
+
<div className='new-session-guide__announcements-title'>
|
|
57
|
+
<span className='material-symbols-rounded new-session-guide__announcements-icon'>campaign</span>
|
|
58
|
+
<span>{t('chat.newSessionGuide.announcements.title')}</span>
|
|
59
|
+
</div>
|
|
60
|
+
<button
|
|
61
|
+
type='button'
|
|
62
|
+
className='new-session-guide__announcements-close'
|
|
63
|
+
onClick={() => setShowAnnouncements(false)}
|
|
64
|
+
>
|
|
65
|
+
<span className='material-symbols-rounded'>close</span>
|
|
66
|
+
</button>
|
|
55
67
|
</div>
|
|
56
68
|
<div className='new-session-guide__announcements-list'>
|
|
57
69
|
{announcements.map((item, index) => (
|
|
@@ -69,18 +81,17 @@ export function NewSessionGuide() {
|
|
|
69
81
|
<span className='material-symbols-rounded new-session-guide__title-icon'>account_tree</span>
|
|
70
82
|
<span>{t('chat.newSessionGuide.specs.title')}</span>
|
|
71
83
|
</div>
|
|
72
|
-
<div className='new-session-guide__count'>{
|
|
84
|
+
<div className='new-session-guide__count'>{alwaysSpecs.length}</div>
|
|
73
85
|
</div>
|
|
74
86
|
<div className='new-session-guide__body'>
|
|
75
87
|
{!isSpecsReady && (
|
|
76
88
|
<div className='new-session-guide__loading'>{t('chat.newSessionGuide.loading')}</div>
|
|
77
89
|
)}
|
|
78
|
-
{isSpecsReady &&
|
|
90
|
+
{isSpecsReady && alwaysSpecs.length > 0 && (
|
|
79
91
|
<div className='new-session-guide__list'>
|
|
80
|
-
{
|
|
92
|
+
{alwaysSpecs.map((spec) => (
|
|
81
93
|
<div key={spec.id} className='new-session-guide__item'>
|
|
82
94
|
<div className='new-session-guide__item-title'>
|
|
83
|
-
<span className='material-symbols-rounded new-session-guide__item-icon'>route</span>
|
|
84
95
|
<span>{spec.name}</span>
|
|
85
96
|
</div>
|
|
86
97
|
<div className='new-session-guide__item-desc'>{spec.description}</div>
|
|
@@ -93,7 +104,7 @@ export function NewSessionGuide() {
|
|
|
93
104
|
))}
|
|
94
105
|
</div>
|
|
95
106
|
)}
|
|
96
|
-
{isSpecsReady &&
|
|
107
|
+
{isSpecsReady && alwaysSpecs.length === 0 && (
|
|
97
108
|
<div className='new-session-guide__empty'>
|
|
98
109
|
<div className='new-session-guide__empty-desc'>{t('chat.newSessionGuide.specs.empty')}</div>
|
|
99
110
|
<Button type='primary' size='small' onClick={handleCreateSpec}>
|
|
@@ -121,7 +132,6 @@ export function NewSessionGuide() {
|
|
|
121
132
|
{entities.map((entity) => (
|
|
122
133
|
<div key={entity.id} className='new-session-guide__item'>
|
|
123
134
|
<div className='new-session-guide__item-title'>
|
|
124
|
-
<span className='material-symbols-rounded new-session-guide__item-icon'>person</span>
|
|
125
135
|
<span>{entity.name}</span>
|
|
126
136
|
</div>
|
|
127
137
|
<div className='new-session-guide__item-desc'>{entity.description}</div>
|
|
@@ -18,7 +18,14 @@ interface ModelSelectGroup {
|
|
|
18
18
|
|
|
19
19
|
export function useChatModels() {
|
|
20
20
|
const { t } = useTranslation()
|
|
21
|
-
const [selectedModel, setSelectedModel] = useState<string | undefined>(
|
|
21
|
+
const [selectedModel, setSelectedModel] = useState<string | undefined>(() => {
|
|
22
|
+
try {
|
|
23
|
+
const raw = localStorage.getItem('vf_chat_selected_model')
|
|
24
|
+
return raw == null || raw.trim() === '' ? undefined : raw
|
|
25
|
+
} catch {
|
|
26
|
+
return undefined
|
|
27
|
+
}
|
|
28
|
+
})
|
|
22
29
|
const { data: configRes } = useSWR<ConfigResponse>('/api/config', getConfig)
|
|
23
30
|
|
|
24
31
|
const mergedModelServices = useMemo(() => {
|
|
@@ -77,6 +84,17 @@ export function useChatModels() {
|
|
|
77
84
|
})
|
|
78
85
|
}, [availableModelSet, hasAvailableModels, resolvedDefaultModel])
|
|
79
86
|
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
try {
|
|
89
|
+
if (selectedModel == null || selectedModel.trim() === '') {
|
|
90
|
+
localStorage.removeItem('vf_chat_selected_model')
|
|
91
|
+
} else {
|
|
92
|
+
localStorage.setItem('vf_chat_selected_model', selectedModel)
|
|
93
|
+
}
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
}, [selectedModel])
|
|
97
|
+
|
|
80
98
|
const modelOptions = useMemo<ModelSelectGroup[]>(() => {
|
|
81
99
|
const buildOption = (params: {
|
|
82
100
|
value: string
|
|
@@ -302,7 +302,7 @@ export function useChatSession({
|
|
|
302
302
|
if (!session?.id) {
|
|
303
303
|
setIsCreating(true)
|
|
304
304
|
try {
|
|
305
|
-
const { session: newSession } = await createSession(undefined, text.trim())
|
|
305
|
+
const { session: newSession } = await createSession(undefined, text.trim(), selectedModel)
|
|
306
306
|
|
|
307
307
|
await mutate('/api/sessions', (prev: { sessions: Session[] } | undefined) => {
|
|
308
308
|
if (!prev?.sessions) return { sessions: [newSession] }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import '../ConfigView.scss'
|
|
2
|
+
|
|
3
|
+
import { Switch } from 'antd'
|
|
4
|
+
import { useAtom } from 'jotai'
|
|
5
|
+
|
|
6
|
+
import { showAnnouncementsAtom } from '#~/store/index.js'
|
|
7
|
+
|
|
8
|
+
import { FieldRow } from './ConfigFieldRow'
|
|
9
|
+
import type { TranslationFn } from './configUtils'
|
|
10
|
+
|
|
11
|
+
export function AppSettingsPanel({ t }: { t: TranslationFn }) {
|
|
12
|
+
const [showAnnouncements, setShowAnnouncements] = useAtom(showAnnouncementsAtom)
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div className='config-view__editor-wrap'>
|
|
16
|
+
<div className='config-view__section-header'>
|
|
17
|
+
<div className='config-view__section-title'>
|
|
18
|
+
<span className='material-symbols-rounded config-view__section-icon'>tune</span>
|
|
19
|
+
<span>{t('config.sections.appearance')}</span>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
<div className='config-view__card'>
|
|
23
|
+
<FieldRow
|
|
24
|
+
title={t('config.appSettings.announcements.label')}
|
|
25
|
+
description={t('config.appSettings.announcements.desc')}
|
|
26
|
+
icon='campaign'
|
|
27
|
+
>
|
|
28
|
+
<Switch checked={showAnnouncements} onChange={setShowAnnouncements} />
|
|
29
|
+
</FieldRow>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
@@ -5,7 +5,8 @@ import React from 'react'
|
|
|
5
5
|
import { useTranslation } from 'react-i18next'
|
|
6
6
|
import useSWR from 'swr'
|
|
7
7
|
|
|
8
|
-
import type { EntitySummary, SpecSummary } from '#~/api.js'
|
|
8
|
+
import type { EntitySummary, RuleSummary, SpecSummary } from '#~/api.js'
|
|
9
|
+
import { useQueryParams } from '#~/hooks/useQueryParams.js'
|
|
9
10
|
import { EntitiesTab } from './components/EntitiesTab.js'
|
|
10
11
|
import { FlowsTab } from './components/FlowsTab.js'
|
|
11
12
|
import { KnowledgeBaseHeader } from './components/KnowledgeBaseHeader.js'
|
|
@@ -13,6 +14,10 @@ import { RulesTab } from './components/RulesTab.js'
|
|
|
13
14
|
import { SkillsTab } from './components/SkillsTab.js'
|
|
14
15
|
import { TabLabel } from './components/TabLabel.js'
|
|
15
16
|
|
|
17
|
+
interface KnowledgeQueryParams extends Record<string, string> {
|
|
18
|
+
kbTab: string
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
export function KnowledgeBaseView() {
|
|
17
22
|
const { t } = useTranslation()
|
|
18
23
|
const { message } = App.useApp()
|
|
@@ -26,14 +31,28 @@ export function KnowledgeBaseView() {
|
|
|
26
31
|
isLoading: isEntitiesLoading,
|
|
27
32
|
mutate: mutateEntities
|
|
28
33
|
} = useSWR<{ entities: EntitySummary[] }>('/api/ai/entities')
|
|
34
|
+
const {
|
|
35
|
+
data: rulesRes,
|
|
36
|
+
isLoading: isRulesLoading,
|
|
37
|
+
mutate: mutateRules
|
|
38
|
+
} = useSWR<{ rules: RuleSummary[] }>('/api/ai/rules')
|
|
29
39
|
|
|
30
40
|
const specs = specsRes?.specs ?? []
|
|
31
41
|
const entities = entitiesRes?.entities ?? []
|
|
42
|
+
const rules = rulesRes?.rules ?? []
|
|
32
43
|
|
|
33
44
|
const [specQuery, setSpecQuery] = React.useState('')
|
|
34
45
|
const [specTagFilter, setSpecTagFilter] = React.useState<string[]>([])
|
|
35
46
|
const [entityQuery, setEntityQuery] = React.useState('')
|
|
36
47
|
const [entityTagFilter, setEntityTagFilter] = React.useState<string[]>([])
|
|
48
|
+
const [ruleQuery, setRuleQuery] = React.useState('')
|
|
49
|
+
|
|
50
|
+
const { values, update } = useQueryParams<KnowledgeQueryParams>({
|
|
51
|
+
keys: ['kbTab'],
|
|
52
|
+
defaults: {
|
|
53
|
+
kbTab: 'skills'
|
|
54
|
+
}
|
|
55
|
+
})
|
|
37
56
|
|
|
38
57
|
const specTagOptions = React.useMemo(() => {
|
|
39
58
|
const tags = new Set<string>()
|
|
@@ -81,8 +100,18 @@ export function KnowledgeBaseView() {
|
|
|
81
100
|
})
|
|
82
101
|
}, [entityQuery, entityTagFilter, entities])
|
|
83
102
|
|
|
103
|
+
const filteredRules = React.useMemo(() => {
|
|
104
|
+
const query = ruleQuery.trim().toLowerCase()
|
|
105
|
+
return rules.filter(rule => {
|
|
106
|
+
if (query === '') return true
|
|
107
|
+
const globText = (rule.globs ?? []).join(' ')
|
|
108
|
+
const haystack = `${rule.name} ${rule.description} ${globText}`.toLowerCase()
|
|
109
|
+
return haystack.includes(query)
|
|
110
|
+
})
|
|
111
|
+
}, [ruleQuery, rules])
|
|
112
|
+
|
|
84
113
|
const handleRefresh = async () => {
|
|
85
|
-
await Promise.all([mutateSpecs(), mutateEntities()])
|
|
114
|
+
await Promise.all([mutateSpecs(), mutateEntities(), mutateRules()])
|
|
86
115
|
void message.success(t('knowledge.actions.refreshed'))
|
|
87
116
|
}
|
|
88
117
|
|
|
@@ -170,6 +199,11 @@ export function KnowledgeBaseView() {
|
|
|
170
199
|
label: <TabLabel icon='gavel' label={t('knowledge.tabs.rules')} />,
|
|
171
200
|
children: (
|
|
172
201
|
<RulesTab
|
|
202
|
+
rules={rules}
|
|
203
|
+
filteredRules={filteredRules}
|
|
204
|
+
isLoading={isRulesLoading}
|
|
205
|
+
query={ruleQuery}
|
|
206
|
+
onQueryChange={setRuleQuery}
|
|
173
207
|
onCreate={handleCreateRule}
|
|
174
208
|
onImport={handleImportRule}
|
|
175
209
|
/>
|
|
@@ -177,10 +211,24 @@ export function KnowledgeBaseView() {
|
|
|
177
211
|
}
|
|
178
212
|
]
|
|
179
213
|
|
|
214
|
+
const tabKeys = React.useMemo(() => tabs.map(tab => tab.key), [tabs])
|
|
215
|
+
const activeTab = tabKeys.includes(values.kbTab) ? values.kbTab : tabKeys[0]
|
|
216
|
+
|
|
217
|
+
React.useEffect(() => {
|
|
218
|
+
if (values.kbTab !== activeTab) {
|
|
219
|
+
update({ kbTab: activeTab })
|
|
220
|
+
}
|
|
221
|
+
}, [activeTab, update, values.kbTab])
|
|
222
|
+
|
|
180
223
|
return (
|
|
181
224
|
<div className='knowledge-base-view'>
|
|
182
225
|
<KnowledgeBaseHeader onRefresh={handleRefresh} />
|
|
183
|
-
<Tabs
|
|
226
|
+
<Tabs
|
|
227
|
+
className='knowledge-base-view__tabs'
|
|
228
|
+
items={tabs}
|
|
229
|
+
activeKey={activeTab}
|
|
230
|
+
onChange={(key) => update({ kbTab: key })}
|
|
231
|
+
/>
|
|
184
232
|
</div>
|
|
185
233
|
)
|
|
186
234
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Button, Empty, Tag, Tooltip } from 'antd'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import { useTranslation } from 'react-i18next'
|
|
4
|
+
import useSWR from 'swr'
|
|
5
|
+
|
|
6
|
+
import type { RuleDetail, RuleSummary } from '#~/api.js'
|
|
7
|
+
import { getRuleDetail } from '#~/api.js'
|
|
8
|
+
import { MarkdownContent } from '#~/components/chat/MarkdownContent'
|
|
9
|
+
import { LoadingState } from './LoadingState'
|
|
10
|
+
|
|
11
|
+
type RuleItemProps = {
|
|
12
|
+
rule: RuleSummary
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function RuleItem({ rule }: RuleItemProps) {
|
|
16
|
+
const { t } = useTranslation()
|
|
17
|
+
const [expanded, setExpanded] = React.useState(false)
|
|
18
|
+
const { data, isLoading } = useSWR<{ rule: RuleDetail }>(
|
|
19
|
+
expanded ? ['rule-detail', rule.id] : null,
|
|
20
|
+
() => getRuleDetail(rule.id)
|
|
21
|
+
)
|
|
22
|
+
const detail = data?.rule
|
|
23
|
+
const body = detail?.body ?? ''
|
|
24
|
+
const globList = rule.globs ?? []
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className='knowledge-base-view__item'>
|
|
28
|
+
<div className='knowledge-base-view__item-row'>
|
|
29
|
+
<div className='knowledge-base-view__item-main'>
|
|
30
|
+
<div className='knowledge-base-view__item-title'>
|
|
31
|
+
<span className='material-symbols-rounded knowledge-base-view__item-icon'>gavel</span>
|
|
32
|
+
<span>{rule.name}</span>
|
|
33
|
+
</div>
|
|
34
|
+
<div className='knowledge-base-view__item-desc'>{rule.description}</div>
|
|
35
|
+
{globList.length > 0 && (
|
|
36
|
+
<div className='knowledge-base-view__tag-list'>
|
|
37
|
+
{globList.map(glob => (
|
|
38
|
+
<Tag key={glob} className='knowledge-base-view__tag'>
|
|
39
|
+
<span className='material-symbols-rounded knowledge-base-view__tag-icon'>folder</span>
|
|
40
|
+
<span>{glob}</span>
|
|
41
|
+
</Tag>
|
|
42
|
+
))}
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
<div className='knowledge-base-view__item-meta'>
|
|
47
|
+
{rule.always && (
|
|
48
|
+
<Tag color='blue'>{t('knowledge.meta.always')}</Tag>
|
|
49
|
+
)}
|
|
50
|
+
<Tooltip title={expanded ? t('knowledge.actions.collapse') : t('knowledge.actions.expand')}>
|
|
51
|
+
<Button
|
|
52
|
+
type='text'
|
|
53
|
+
className='knowledge-base-view__icon-button'
|
|
54
|
+
onClick={() => setExpanded(prev => !prev)}
|
|
55
|
+
icon={
|
|
56
|
+
<span className='material-symbols-rounded'>
|
|
57
|
+
{expanded ? 'expand_less' : 'expand_more'}
|
|
58
|
+
</span>
|
|
59
|
+
}
|
|
60
|
+
/>
|
|
61
|
+
</Tooltip>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{expanded && (
|
|
65
|
+
<div className='knowledge-base-view__detail'>
|
|
66
|
+
{isLoading && <LoadingState />}
|
|
67
|
+
{!isLoading && body.trim() === '' && (
|
|
68
|
+
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t('knowledge.rules.empty')} />
|
|
69
|
+
)}
|
|
70
|
+
{!isLoading && body.trim() !== '' && (
|
|
71
|
+
<div className='knowledge-base-view__markdown'>
|
|
72
|
+
<MarkdownContent content={body} />
|
|
73
|
+
</div>
|
|
74
|
+
)}
|
|
75
|
+
</div>
|
|
76
|
+
)}
|
|
77
|
+
</div>
|
|
78
|
+
)
|
|
79
|
+
}
|