Workflow is almost done.
This commit is contained in:
@@ -1,132 +1,132 @@
|
|||||||
<mxfile host="65bd71144e">
|
<mxfile host="65bd71144e">
|
||||||
<diagram id="EAoW1hfBXHFT-SqL8OPS" name="Page-1">
|
<diagram id="EAoW1hfBXHFT-SqL8OPS" name="Page-1">
|
||||||
<mxGraphModel dx="1563" dy="697" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
|
<mxGraphModel dx="1568" dy="699" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0"/>
|
<mxCell id="0"/>
|
||||||
<mxCell id="1" parent="0"/>
|
<mxCell id="1" parent="0"/>
|
||||||
<mxCell id="33" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="2" target="3">
|
<mxCell id="33" value="" style="edgeStyle=none;html=1;" parent="1" source="2" target="3" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="34" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="2" target="4">
|
<mxCell id="34" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="2" target="4" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="2" value="User Msg" style="ellipse;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="2" value="User Msg" style="ellipse;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="20" y="230" width="90" height="60" as="geometry"/>
|
<mxGeometry x="20" y="230" width="90" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="36" value="event/msg" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="3" target="5">
|
<mxCell id="36" value="event/msg" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="3" target="5" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="3" value="Gateway" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="3" value="Gateway" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="180" y="235" width="100" height="50" as="geometry"/>
|
<mxGeometry x="180" y="235" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="35" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="4" target="3">
|
<mxCell id="35" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="4" target="3" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="4" value="telegram roboter" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="4" value="telegram roboter" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="180" y="340" width="100" height="50" as="geometry"/>
|
<mxGeometry x="180" y="340" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="37" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="5" target="7">
|
<mxCell id="37" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="5" target="7" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<Array as="points">
|
<Array as="points">
|
||||||
<mxPoint x="520" y="350"/>
|
<mxPoint x="520" y="350"/>
|
||||||
</Array>
|
</Array>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="5" value="Workflow<br>@docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="5" value="Workflow<br>@docker" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="390" y="230" width="100" height="60" as="geometry"/>
|
<mxGeometry x="390" y="230" width="100" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="6" value="LLM<br>ComputeNode<br>Run in VM" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="6" value="LLM<br>ComputeNode<br>Run in VM" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="485" y="40" width="100" height="50" as="geometry"/>
|
<mxGeometry x="485" y="40" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="7" value="Agent@docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="7" value="Agent@docker" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="560" y="330" width="100" height="70" as="geometry"/>
|
<mxGeometry x="560" y="330" width="100" height="70" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="8" value="LLM ComputeNode<br>Run in docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="8" value="LLM ComputeNode<br>Run in docker" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="355" y="40" width="100" height="50" as="geometry"/>
|
<mxGeometry x="355" y="40" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="10" value="Node Client" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
|
<mxCell id="10" value="Node Client" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="405" y="200" width="70" height="30" as="geometry"/>
|
<mxGeometry x="405" y="200" width="70" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="11" value="Node Client" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" vertex="1" parent="1">
|
<mxCell id="11" value="Node Client" style="shape=process;whiteSpace=wrap;html=1;backgroundOutline=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="575" y="300" width="70" height="30" as="geometry"/>
|
<mxGeometry x="575" y="300" width="70" height="30" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="13" value="FileSystem" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
|
<mxCell id="13" value="FileSystem" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
<mxGeometry x="195" y="700" width="120" height="80" as="geometry"/>
|
<mxGeometry x="195" y="700" width="120" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="14" value="Object Store" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
|
<mxCell id="14" value="Object Store" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
<mxGeometry x="345" y="700" width="120" height="80" as="geometry"/>
|
<mxGeometry x="345" y="700" width="120" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="15" value="RDB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
|
<mxCell id="15" value="RDB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
<mxGeometry x="495" y="700" width="120" height="80" as="geometry"/>
|
<mxGeometry x="495" y="700" width="120" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="16" value="VDB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" vertex="1" parent="1">
|
<mxCell id="16" value="VDB" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=15;" parent="1" vertex="1">
|
||||||
<mxGeometry x="645" y="700" width="120" height="80" as="geometry"/>
|
<mxGeometry x="645" y="700" width="120" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="17" value="Zone States:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
<mxCell id="17" value="Zone States:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||||
<mxGeometry x="110" y="710" width="70" height="80" as="geometry"/>
|
<mxGeometry x="110" y="710" width="70" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="32" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="18" target="3">
|
<mxCell id="32" value="" style="edgeStyle=none;html=1;" parent="1" source="18" target="3" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="18" value="Environment" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" vertex="1" parent="1">
|
<mxCell id="18" value="Environment" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="167.5" y="80" width="125" height="60" as="geometry"/>
|
<mxGeometry x="167.5" y="80" width="125" height="60" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="41" value="" style="edgeStyle=none;html=1;" edge="1" parent="1" source="20" target="40">
|
<mxCell id="41" value="" style="edgeStyle=none;html=1;" parent="1" source="20" target="40" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="20" value="Functions" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="20" value="Functions" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="575" y="400" width="70" height="40" as="geometry"/>
|
<mxGeometry x="575" y="400" width="70" height="40" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="21" value="Functions" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="21" value="Functions" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="405" y="290" width="70" height="40" as="geometry"/>
|
<mxGeometry x="405" y="290" width="70" height="40" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="23" value="email-spieder" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="23" value="email-spieder" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="220" y="600" width="100" height="50" as="geometry"/>
|
<mxGeometry x="220" y="600" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="25" value="embading pipline" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="25" value="embading pipline" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="357.5" y="600" width="155" height="50" as="geometry"/>
|
<mxGeometry x="357.5" y="600" width="155" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="27" value="Workflow,Agent,Env这3个概念都是主机无关的,只要能访问到其状态,任意Zone主机运行都可以" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
<mxCell id="27" value="Workflow,Agent,Env这3个概念都是主机无关的,只要能访问到其状态,任意Zone主机运行都可以" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||||
<mxGeometry x="558" y="180" width="212" height="50" as="geometry"/>
|
<mxGeometry x="558" y="180" width="212" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="38" value="Workflow's<br>state" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;size=21;" vertex="1" parent="1">
|
<mxCell id="38" value="Workflow's<br>state" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;size=21;" parent="1" vertex="1">
|
||||||
<mxGeometry x="415" y="345" width="60" height="80" as="geometry"/>
|
<mxGeometry x="415" y="345" width="60" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="39" value="Agent's<br>state" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;size=21;" vertex="1" parent="1">
|
<mxCell id="39" value="Agent's<br>state" style="shape=note;whiteSpace=wrap;html=1;backgroundOutline=1;darkOpacity=0.05;size=21;" parent="1" vertex="1">
|
||||||
<mxGeometry x="585" y="450" width="60" height="80" as="geometry"/>
|
<mxGeometry x="585" y="450" width="60" height="80" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="40" value="ComputeNode<br>Run in docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="40" value="ComputeNode<br>Run in docker" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="740" y="395" width="100" height="50" as="geometry"/>
|
<mxGeometry x="740" y="395" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="42" value="LLM<br>ComputeNode<br>Run on Cloud" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="42" value="LLM<br>ComputeNode<br>Run on Cloud" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="615" y="40" width="100" height="50" as="geometry"/>
|
<mxGeometry x="615" y="40" width="100" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="46" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="43" target="18">
|
<mxCell id="46" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" parent="1" source="43" target="18" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="43" value="Device" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
|
<mxCell id="43" value="Device" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="1" vertex="1">
|
||||||
<mxGeometry x="70" y="70" width="50" height="50" as="geometry"/>
|
<mxGeometry x="70" y="70" width="50" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="45" style="edgeStyle=none;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="44" target="18">
|
<mxCell id="45" style="edgeStyle=none;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0.25;entryY=0;entryDx=0;entryDy=0;" parent="1" source="44" target="18" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry"/>
|
<mxGeometry relative="1" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="44" value="Device" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
|
<mxCell id="44" value="Device" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="1" vertex="1">
|
||||||
<mxGeometry x="125" y="10" width="50" height="50" as="geometry"/>
|
<mxGeometry x="125" y="10" width="50" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="47" value="Device" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
|
<mxCell id="47" value="Device" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" parent="1" vertex="1">
|
||||||
<mxGeometry x="295" y="140" width="50" height="50" as="geometry"/>
|
<mxGeometry x="295" y="140" width="50" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="48" value="Driver Sync Service" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="48" value="Driver Sync Service" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="545" y="600" width="90" height="50" as="geometry"/>
|
<mxGeometry x="545" y="600" width="90" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="49" value="Zone backup service" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="49" value="Zone backup service" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="665" y="600" width="90" height="50" as="geometry"/>
|
<mxGeometry x="665" y="600" width="90" height="50" as="geometry"/>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
</root>
|
</root>
|
||||||
</mxGraphModel>
|
</mxGraphModel>
|
||||||
</diagram>
|
</diagram>
|
||||||
<diagram id="gXHOratDfWrfJ3-cl-bj" name="Page-2">
|
<diagram id="gXHOratDfWrfJ3-cl-bj" name="Page-2">
|
||||||
<mxGraphModel dx="2266" dy="1010" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
|
<mxGraphModel dx="1881" dy="676" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="850" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0"/>
|
<mxCell id="0"/>
|
||||||
<mxCell id="1" parent="0"/>
|
<mxCell id="1" parent="0"/>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<mxfile host="65bd71144e" pages="3">
|
<mxfile host="65bd71144e" pages="3">
|
||||||
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
||||||
<mxGraphModel dx="1800" dy="877" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
<mxGraphModel dx="1881" dy="676" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0"/>
|
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0"/>
|
||||||
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0"/>
|
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0"/>
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
</mxGraphModel>
|
</mxGraphModel>
|
||||||
</diagram>
|
</diagram>
|
||||||
<diagram id="7NYJTgo0U9cdVshLy85U" name="Page-3">
|
<diagram id="7NYJTgo0U9cdVshLy85U" name="Page-3">
|
||||||
<mxGraphModel dx="1800" dy="877" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
<mxGraphModel dx="1881" dy="676" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0"/>
|
<mxCell id="0"/>
|
||||||
<mxCell id="1" parent="0"/>
|
<mxCell id="1" parent="0"/>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ content="""你是一个活动策划公司的经理,与客户对接并向团队
|
|||||||
1. 收到客户的明确的指令后,基于客户的已有信息和客户商量活动方案,和活动策划公司无关的业务你会回答‘与我无关’。当和客户完成活动方案的确认后,你会将拆解后的任务分配给各个小组
|
1. 收到客户的明确的指令后,基于客户的已有信息和客户商量活动方案,和活动策划公司无关的业务你会回答‘与我无关’。当和客户完成活动方案的确认后,你会将拆解后的任务分配给各个小组
|
||||||
2. 根据目前已经确认的活动方案,你要根据时间适时的检查不同小组的工作情况。当收到小组的工作情况反馈后,你会站在全局的角度判断是否需要调整活动方案,如果需要调整,你会和客户商量重新确定方案,然后再将调整后的方案分配给各个小组。
|
2. 根据目前已经确认的活动方案,你要根据时间适时的检查不同小组的工作情况。当收到小组的工作情况反馈后,你会站在全局的角度判断是否需要调整活动方案,如果需要调整,你会和客户商量重新确定方案,然后再将调整后的方案分配给各个小组。
|
||||||
3. 有时工作小组会主动与你沟通,反馈一些问题。你会站在全局的角度给与指导,适当的调整工作小组的工作目标。如果反馈的问题需要你和客户沟通,你会和客户沟通后重新确定方案。再将调整后的方案分配给受到影响各个小组。
|
3. 有时工作小组会主动与你沟通,反馈一些问题。你会站在全局的角度给与指导,适当的调整工作小组的工作目标。如果反馈的问题需要你和客户沟通,你会和客户沟通后重新确定方案。再将调整后的方案分配给受到影响各个小组。
|
||||||
4. 当你决定要和工作小组通信时,请使用`sendmsg({小组名称},{内容}`)的形式。"""
|
4. 当你决定要和工作小组通信时,请使用 sendmsg(小组名称,内容) 的形式。"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ agent="email_reader"
|
|||||||
role="system"
|
role="system"
|
||||||
content="""你是一家活动策划公司的嘉宾对接组的组长,你的工作是基于已知信息,当前活动信息、公司经理的指令与嘉宾沟通,收集嘉宾的信息,然后将信息反馈给经理。在你看来,参加活动的多少有成员都是嘉宾,你可以通过你知道的信息给不同的成员进行分级。你的基本工作模式是:
|
content="""你是一家活动策划公司的嘉宾对接组的组长,你的工作是基于已知信息,当前活动信息、公司经理的指令与嘉宾沟通,收集嘉宾的信息,然后将信息反馈给经理。在你看来,参加活动的多少有成员都是嘉宾,你可以通过你知道的信息给不同的成员进行分级。你的基本工作模式是:
|
||||||
1. 处理收到的邮件,如果邮件来自嘉宾,你会尝试从邮件的表态和内容中分享嘉宾的需要,并结合你对当前活动方案的理解判断是否需要和经理沟通,如果需要和经理沟通,你会将嘉宾的需求总结和告诉经理。不需要沟通的事项可以直接回复嘉宾。
|
1. 处理收到的邮件,如果邮件来自嘉宾,你会尝试从邮件的表态和内容中分享嘉宾的需要,并结合你对当前活动方案的理解判断是否需要和经理沟通,如果需要和经理沟通,你会将嘉宾的需求总结和告诉经理。不需要沟通的事项可以直接回复嘉宾。
|
||||||
2. 你总是通过`call_function(get_env,'parent.topic'`的形式查询当前的活动方案。等待函数返回后,你会根据函数的返回结果继续处理上一个对话。
|
2. 你总是通过 call_function(get_env,'parent.topic')的形式查询当前的活动方案。等待函数返回后,你会根据函数的返回结果继续处理上一个对话。
|
||||||
3. 当你决定要和经理通信时,请使用`send_msg(manager,{内容}`)的形式,内容的长度不超过200字。
|
3. 当你决定要和经理通信时,请使用 sendmsg(manager,内容)的形式,内容的长度不超过200字。
|
||||||
4. 当你决定要回复嘉宾时,请使用`call_function(sendmail,{嘉宾邮件地址},{标题},{内容})的形式,内容的长度不超过500字。"""
|
4. 当你决定要回复嘉宾时,请使用 call(sendmail,嘉宾邮件地址,邮件标题,内容) 的形式,内容的长度不超过500字。"""
|
||||||
# 这里是孤立工作模式,组长只和经理沟通,也可以赋予其和其它组沟通的能力
|
# 这里是孤立工作模式,组长只和经理沟通,也可以赋予其和其它组沟通的能力
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
import uuid
|
import uuid
|
||||||
import time
|
import time
|
||||||
|
import re
|
||||||
|
|
||||||
class AgentMsgState(Enum):
|
class AgentMsgState(Enum):
|
||||||
RESPONSED = 0
|
RESPONSED = 0
|
||||||
@@ -37,3 +38,22 @@ class AgentMsg:
|
|||||||
|
|
||||||
def get_target(self) -> str:
|
def get_target(self) -> str:
|
||||||
return self.target
|
return self.target
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse_function_call(cls,func_string:str):
|
||||||
|
match = re.search(r'\s*(\w+)\s*\(\s*(.*)\s*\)\s*', func_string)
|
||||||
|
if not match:
|
||||||
|
return None
|
||||||
|
|
||||||
|
func_name = match.group(1)
|
||||||
|
if func_name is None:
|
||||||
|
return None
|
||||||
|
if len(func_name) < 2:
|
||||||
|
return None
|
||||||
|
|
||||||
|
params_string = match.group(2).strip()
|
||||||
|
params = re.split(r'\s*,\s*(?=(?:[^"]*"[^"]*")*[^"]*$)', params_string)
|
||||||
|
params = [param.strip('"') for param in params]
|
||||||
|
|
||||||
|
return func_name, params
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -34,6 +34,7 @@ class AIBus:
|
|||||||
self.unhandle_handler = None
|
self.unhandle_handler = None
|
||||||
|
|
||||||
async def post_message(self,target_id,msg:AgentMsg,use_unhandle=True) -> bool:
|
async def post_message(self,target_id,msg:AgentMsg,use_unhandle=True) -> bool:
|
||||||
|
target_id = target_id.split(".")[0]
|
||||||
handler = self.handlers.get(target_id)
|
handler = self.handlers.get(target_id)
|
||||||
if handler:
|
if handler:
|
||||||
handler.queue.put_nowait(msg)
|
handler.queue.put_nowait(msg)
|
||||||
@@ -62,6 +63,7 @@ class AIBus:
|
|||||||
return handler.results.get(msg_id)
|
return handler.results.get(msg_id)
|
||||||
|
|
||||||
async def send_message(self,target_id:str,msg:AgentMsg) -> AgentMsg:
|
async def send_message(self,target_id:str,msg:AgentMsg) -> AgentMsg:
|
||||||
|
target_id = target_id.split(".")[0]
|
||||||
post_result = await self.post_message(target_id,msg)
|
post_result = await self.post_message(target_id,msg)
|
||||||
if post_result is False:
|
if post_result is False:
|
||||||
return None
|
return None
|
||||||
@@ -126,4 +128,12 @@ class AIBus:
|
|||||||
|
|
||||||
handler.working_task = asyncio.create_task(self.process_queue(handler))
|
handler.working_task = asyncio.create_task(self.process_queue(handler))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#send message to target logic:
|
||||||
|
# find target handler:
|
||||||
|
# process_message(msg):
|
||||||
|
# session = get_session(msg.sender,msg.target)
|
||||||
|
|
||||||
|
|
||||||
|
# history: open(sender,target,topic)
|
||||||
@@ -237,13 +237,13 @@ class AIChatSession:
|
|||||||
|
|
||||||
def append_post(self,msg:AgentMsg) -> None:
|
def append_post(self,msg:AgentMsg) -> None:
|
||||||
"""append msg to session, msg is post from session (owner => msg.target)"""
|
"""append msg to session, msg is post from session (owner => msg.target)"""
|
||||||
assert msg.sender == self.owner_id,"post message means msg.sender == self.owner_id"
|
#assert msg.sender == self.owner_id,"post message means msg.sender == self.owner_id"
|
||||||
self.append(msg)
|
self.append(msg)
|
||||||
|
|
||||||
|
|
||||||
def append_recv(self,msg:AgentMsg) -> None:
|
def append_recv(self,msg:AgentMsg) -> None:
|
||||||
"""append msg to session, msg is recv from msg'sender (msg.sender => owner)"""
|
"""append msg to session, msg is recv from msg'sender (msg.sender => owner)"""
|
||||||
assert msg.target == self.owner_id,"recv message means msg.target == self.owner_id"
|
#assert msg.target == self.owner_id,"recv message means msg.target == self.owner_id"
|
||||||
self.append(msg)
|
self.append(msg)
|
||||||
|
|
||||||
#def attach_event_handler(self,handler) -> None:
|
#def attach_event_handler(self,handler) -> None:
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ class AIRole:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.agent_instance_id : str = None
|
self.agent_instance_id : str = None
|
||||||
self.role_name : str = None
|
self.role_name : str = None
|
||||||
|
self.role_id :str = None # $workflow_id.$sub_workflow_id.$role_name
|
||||||
self.fullname : str = None
|
self.fullname : str = None
|
||||||
self.agent_name : str = None
|
self.agent_name : str = None
|
||||||
self.prompt : AgentPrompt = None
|
self.prompt : AgentPrompt = None
|
||||||
@@ -19,6 +20,7 @@ class AIRole:
|
|||||||
return False
|
return False
|
||||||
self.role_name = name_node
|
self.role_name = name_node
|
||||||
|
|
||||||
|
|
||||||
agent_id_node = config.get("agent")
|
agent_id_node = config.get("agent")
|
||||||
if agent_id_node is None:
|
if agent_id_node is None:
|
||||||
logging.error("agent id is not found!")
|
logging.error("agent id is not found!")
|
||||||
@@ -35,7 +37,10 @@ class AIRole:
|
|||||||
intro_node = config.get("intro")
|
intro_node = config.get("intro")
|
||||||
if intro_node is not None:
|
if intro_node is not None:
|
||||||
self.introduce = intro_node
|
self.introduce = intro_node
|
||||||
|
|
||||||
|
def get_role_id(self) -> str:
|
||||||
|
return self.role_id
|
||||||
|
|
||||||
def get_intro(self) -> str:
|
def get_intro(self) -> str:
|
||||||
return self.introduce
|
return self.introduce
|
||||||
|
|
||||||
@@ -48,6 +53,7 @@ class AIRole:
|
|||||||
class AIRoleGroup:
|
class AIRoleGroup:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.roles : dict[str,AIRole] = {}
|
self.roles : dict[str,AIRole] = {}
|
||||||
|
self.owner_name : str = None
|
||||||
|
|
||||||
def load_from_config(self,config:dict) -> bool:
|
def load_from_config(self,config:dict) -> bool:
|
||||||
for k,v in config.items():
|
for k,v in config.items():
|
||||||
@@ -55,7 +61,7 @@ class AIRoleGroup:
|
|||||||
if role.load_from_config(v) is False:
|
if role.load_from_config(v) is False:
|
||||||
logging.error(f"load role {k} failed!")
|
logging.error(f"load role {k} failed!")
|
||||||
return False
|
return False
|
||||||
|
role.role_id = self.owner_name + "." + k
|
||||||
self.roles[k] = role
|
self.roles[k] = role
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|||||||
+241
-68
@@ -33,9 +33,20 @@ class MessageFilter:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class LLMResult:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.state : str = "ignore"
|
||||||
|
self.resp : str = ""
|
||||||
|
self.post_msgs = []
|
||||||
|
self.send_msgs = []
|
||||||
|
self.calls = []
|
||||||
|
self.post_calls = []
|
||||||
|
|
||||||
|
|
||||||
class Workflow:
|
class Workflow:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.workflow_name : str = None
|
self.workflow_name : str = None
|
||||||
|
self.workflow_id : str = None
|
||||||
self.rule_prompt : AgentPrompt = None
|
self.rule_prompt : AgentPrompt = None
|
||||||
self.workflow_config = None
|
self.workflow_config = None
|
||||||
self.role_group : dict = None
|
self.role_group : dict = None
|
||||||
@@ -62,6 +73,11 @@ class Workflow:
|
|||||||
logger.error("workflow config must have name")
|
logger.error("workflow config must have name")
|
||||||
return False
|
return False
|
||||||
self.workflow_name = config.get("name")
|
self.workflow_name = config.get("name")
|
||||||
|
if self.owner_workflow is None:
|
||||||
|
self.workflow_id = self.workflow_name
|
||||||
|
else:
|
||||||
|
self.workflow_id = self.owner_workflow.workflow_id + "." + self.workflow_name
|
||||||
|
self.db_file = self.owner_workflow.db_file
|
||||||
|
|
||||||
#if config.get("rule_prompt") is None:
|
#if config.get("rule_prompt") is None:
|
||||||
# logger.error("workflow config must have rule_prompt")
|
# logger.error("workflow config must have rule_prompt")
|
||||||
@@ -74,13 +90,14 @@ class Workflow:
|
|||||||
logger.error("workflow config must have roles")
|
logger.error("workflow config must have roles")
|
||||||
return False
|
return False
|
||||||
self.role_group = AIRoleGroup()
|
self.role_group = AIRoleGroup()
|
||||||
|
self.role_group.owner_name = self.workflow_id
|
||||||
if self.role_group.load_from_config(config.get("roles")) is False:
|
if self.role_group.load_from_config(config.get("roles")) is False:
|
||||||
logger.error("Workflow load role_group failed")
|
logger.error("Workflow load role_group failed")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if config.get("input_filter") is not None:
|
if config.get("filter") is not None:
|
||||||
self.input_filter = MessageFilter()
|
self.input_filter = MessageFilter()
|
||||||
if self.input_filter.load_from_config(config.get("input_filter")) is False:
|
if self.input_filter.load_from_config(config.get("filter")) is False:
|
||||||
logger.error("Workflow load input_filter failed")
|
logger.error("Workflow load input_filter failed")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@@ -98,15 +115,52 @@ class Workflow:
|
|||||||
for k,v in config.items():
|
for k,v in config.items():
|
||||||
sub_workflow = Workflow()
|
sub_workflow = Workflow()
|
||||||
sub_workflow.set_owner(self)
|
sub_workflow.set_owner(self)
|
||||||
|
|
||||||
if sub_workflow.load_from_config(v) is False:
|
if sub_workflow.load_from_config(v) is False:
|
||||||
logger.error(f"load sub workflow {k} failed!")
|
logger.error(f"load sub workflow {k} failed!")
|
||||||
return False
|
return False
|
||||||
self.sub_workflows[k] = sub_workflow
|
self.sub_workflows[k] = sub_workflow
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _parse_msg_target(self,s:str)->list[str]:
|
||||||
|
return s.split(".")
|
||||||
|
|
||||||
|
async def _forword_msg(self,inner_obj_id,msg):
|
||||||
|
i : int = 1
|
||||||
|
current_workflow = self
|
||||||
|
while i < len(inner_obj_id):
|
||||||
|
if i == len(inner_obj_id) - 1:
|
||||||
|
the_role : AIRole = current_workflow.role_group.get(inner_obj_id[i])
|
||||||
|
if the_role is not None:
|
||||||
|
return await current_workflow.role_process_msg(msg,the_role)
|
||||||
|
sub_workflow = current_workflow.sub_workflows.get(inner_obj_id[i])
|
||||||
|
if sub_workflow is not None:
|
||||||
|
return await sub_workflow.process_msg(msg)
|
||||||
|
logger.error(f"{msg.target} not found! forword message failed!")
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
current_workflow = current_workflow.sub_workflows.get(inner_obj_id[i])
|
||||||
|
if current_workflow is None:
|
||||||
|
logger.error(f"sub workflow {inner_obj_id[i]} not found!")
|
||||||
|
return None
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
logger.error(f"{msg.target} not found! forword message failed!")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _process_msg(self,msg:AgentMsg):
|
async def _process_msg(self,msg:AgentMsg):
|
||||||
|
# workflow can be a message handler, but never be a message sender
|
||||||
|
# all message forword to roles or sub workflow
|
||||||
|
# workflow no chatsession record, but role have
|
||||||
|
|
||||||
final_result = None
|
final_result = None
|
||||||
chatsession = None
|
|
||||||
|
targets = self._parse_msg_target(msg.target)
|
||||||
|
if len(targets) > 1:
|
||||||
|
return await self._forword_msg(targets,msg)
|
||||||
|
|
||||||
if self.input_filter is not None:
|
if self.input_filter is not None:
|
||||||
select_role_id = self.input_filter.select(msg)
|
select_role_id = self.input_filter.select(msg)
|
||||||
if select_role_id is not None:
|
if select_role_id is not None:
|
||||||
@@ -115,35 +169,206 @@ class Workflow:
|
|||||||
logger.error(f"input_filter return invalid role id:{select_role_id}, role not found in role_group")
|
logger.error(f"input_filter return invalid role id:{select_role_id}, role not found in role_group")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
result = await self._role_process_msg(msg,select_role)
|
result = await self.role_process_msg(msg,select_role)
|
||||||
if result is None:
|
if result is None:
|
||||||
logger.error(f"_process_msg return None for :{msg}")
|
logger.error(f"_process_msg return None for :{msg}")
|
||||||
return
|
return
|
||||||
if chatsession is not None:
|
|
||||||
chatsession.append_post(result)
|
|
||||||
final_result = result
|
final_result = result
|
||||||
else:
|
else:
|
||||||
logger.error(f"input_filter return None for :{msg}")
|
logger.error(f"input_filter return None for :{msg}")
|
||||||
return
|
return
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
# no input filter, we would process all message, slowly,not suggest to use
|
||||||
results = {}
|
results = {}
|
||||||
|
final_result:AgentMsg = None
|
||||||
for this_role in self.role_group.roles.values():
|
for this_role in self.role_group.roles.values():
|
||||||
# TODO : we would do this in parallel
|
# TODO : we would do this in parallel
|
||||||
a_result = await self._role_process_msg(msg,this_role)
|
a_result = await self.role_process_msg(msg,this_role)
|
||||||
results[this_role.get_name()] = a_result
|
results[this_role.get_name()] = a_result
|
||||||
|
final_result = a_result
|
||||||
# merge result from all roles
|
|
||||||
# TODO: one input msg can have multiple result msg, at this while ,we only support one result msg
|
|
||||||
final_result:AgentMsg = self._merge_msg_result(results)
|
|
||||||
if chatsession is not None:
|
|
||||||
chatsession.append_post(final_result)
|
|
||||||
|
|
||||||
return final_result
|
return final_result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prase_llm_result(cls,llm_result_str:str)->LLMResult:
|
||||||
|
r = LLMResult()
|
||||||
|
if llm_result_str is None:
|
||||||
|
r.state = "ignore"
|
||||||
|
return r
|
||||||
|
if llm_result_str == "ignore":
|
||||||
|
r.state = "ignore"
|
||||||
|
return r
|
||||||
|
|
||||||
|
lines = llm_result_str.splitlines()
|
||||||
|
is_need_wait = False
|
||||||
|
for line in lines:
|
||||||
|
func_call = AgentMsg.parse_function_call(line)
|
||||||
|
if func_call:
|
||||||
|
func_args = func_call[1]
|
||||||
|
match func_call[0]:
|
||||||
|
case "sendmsg":# sendmsg($target_id,$msg_content)
|
||||||
|
if len(func_args) != 2:
|
||||||
|
logger.error(f"parse sendmsg failed! {func_call}")
|
||||||
|
continue
|
||||||
|
new_msg = AgentMsg()
|
||||||
|
target_id = func_args[0]
|
||||||
|
msg_content = func_args[1]
|
||||||
|
new_msg.set("_",target_id,msg_content)
|
||||||
|
|
||||||
|
r.send_msgs.append(new_msg)
|
||||||
|
is_need_wait = True
|
||||||
|
continue
|
||||||
|
case "postmsg":# postmsg($target_id,$msg_content)
|
||||||
|
if len(func_args) != 2:
|
||||||
|
logger.error(f"parse postmsg failed! {func_call}")
|
||||||
|
continue
|
||||||
|
new_msg = AgentMsg()
|
||||||
|
target_id = func_args[1]
|
||||||
|
msg_content = func_args[2]
|
||||||
|
new_msg.set("_",target_id,msg_content)
|
||||||
|
r.post_msgs.append(new_msg)
|
||||||
|
continue
|
||||||
|
case "call":# call($func_name,$args_str)
|
||||||
|
r.calls.append(func_call)
|
||||||
|
is_need_wait = True
|
||||||
|
continue
|
||||||
|
case "post_call": # post_call($func_name,$args_str)
|
||||||
|
r.post_calls.append(func_call)
|
||||||
|
continue
|
||||||
|
|
||||||
|
r.resp += line + "\n"
|
||||||
|
else:
|
||||||
|
r.resp += line + "\n"
|
||||||
|
|
||||||
|
if is_need_wait:
|
||||||
|
r.state = "waiting"
|
||||||
|
else:
|
||||||
|
r.state = "reponsed"
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
async def role_post_msg(self,msg:AgentMsg,the_role:AIRole):
|
||||||
|
msg.sender = the_role.get_role_id()
|
||||||
|
|
||||||
|
target_role = self.role_group.get(msg.target)
|
||||||
|
if target_role:
|
||||||
|
msg.target = target_role.get_role_id()
|
||||||
|
logger.info(f"{msg.sender} post message {msg.id} to inner role: {msg.target}")
|
||||||
|
asyncio.create_task(self.role_process_msg(msg,target_role))
|
||||||
|
return
|
||||||
|
|
||||||
|
target_workflow = self.sub_workflows.get(msg.target)
|
||||||
|
if target_workflow:
|
||||||
|
msg.target = target_workflow.workflow_id
|
||||||
|
logger.info(f"{msg.sender} post message {msg.id} to sub workflow: {msg.target}")
|
||||||
|
asyncio.create_task(target_workflow._process_msg(msg))
|
||||||
|
|
||||||
|
logger.info(f"{msg.sender} post message {msg.id} to AIBus: {msg.target}")
|
||||||
|
await self.get_bus().post_message(msg.target,msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
async def role_send_msg(self,msg:AgentMsg,the_role:AIRole):
|
||||||
|
msg.sender = the_role.get_role_id()
|
||||||
|
target_role = self.role_group.get(msg.target)
|
||||||
|
if target_role:
|
||||||
|
# msg.target = target_role.get_role_id()
|
||||||
|
logger.info(f"{msg.sender} send message {msg.id} to inner role: {msg.target}")
|
||||||
|
return await self.role_process_msg(msg,target_role)
|
||||||
|
|
||||||
|
|
||||||
|
target_workflow = self.sub_workflows.get(msg.target)
|
||||||
|
if target_workflow:
|
||||||
|
# msg.target = target_workflow.workflow_id
|
||||||
|
logger.info(f"{msg.sender} send message {msg.id} to sub workflow: {msg.target}")
|
||||||
|
return await target_workflow._process_msg(msg)
|
||||||
|
|
||||||
|
logger.info(f"{msg.sender} post message {msg.id} to AIBus: {msg.target}")
|
||||||
|
return await self.get_bus().send_message(msg.target,msg)
|
||||||
|
|
||||||
|
async def role_call(self,call:tuple,the_role:AIRole):
|
||||||
|
logger.info(f"{the_role.role_id} call {call[0]} with args {call[1]}")
|
||||||
|
return """{result:"timeout"}"""
|
||||||
|
|
||||||
|
async def role_post_call(self,call:tuple,the_role:AIRole):
|
||||||
|
logger.info(f"{the_role.role_id} post call {call[0]} with args {call[1]}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
async def role_process_msg(self,msg:AgentMsg,the_role:AIRole):
|
||||||
|
session_topic = f"{msg.sender}#{msg.topic}"
|
||||||
|
session_owner = the_role.get_role_id()
|
||||||
|
chatsession : AIChatSession = AIChatSession.get_session(session_owner,session_topic,self.db_file)
|
||||||
|
if chatsession is None:
|
||||||
|
logger.error(f"get session {session_topic}@{session_owner} failed!")
|
||||||
|
return None
|
||||||
|
|
||||||
|
prompt = AgentPrompt()
|
||||||
|
prompt.append(the_role.agent.prompt)
|
||||||
|
prompt.append(the_role.get_prompt())
|
||||||
|
|
||||||
|
# prompt.append(self.get_workflow_rule_prompt())
|
||||||
|
# prompt.append(self._get_function_prompt(the_role.get_name()))
|
||||||
|
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
||||||
|
prompt.append(await self._get_prompt_from_session(chatsession))
|
||||||
|
|
||||||
|
msg_prompt = AgentPrompt()
|
||||||
|
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
||||||
|
prompt.append(msg_prompt)
|
||||||
|
|
||||||
|
|
||||||
|
async def _do_process_msg():
|
||||||
|
#TODO: send msg to agent might be better?
|
||||||
|
result_str = await ComputeKernel().do_llm_completion(prompt,the_role.agent.get_llm_model_name(),the_role.agent.get_max_token_size())
|
||||||
|
result = Workflow.prase_llm_result(result_str)
|
||||||
|
|
||||||
|
|
||||||
|
for postmsg in result.post_msgs:
|
||||||
|
postmsg.topic = msg.topic
|
||||||
|
await self.role_post_msg(the_role,postmsg)
|
||||||
|
|
||||||
|
for post_call in result.post_calls:
|
||||||
|
await self.role_post_call(post_call,the_role)
|
||||||
|
|
||||||
|
|
||||||
|
result_prompt_str = ""
|
||||||
|
match result.state:
|
||||||
|
case "ignore":
|
||||||
|
return None
|
||||||
|
case "reponsed":
|
||||||
|
resp_msg = AgentMsg()
|
||||||
|
resp_msg.topic = msg.topic
|
||||||
|
resp_msg.set(session_owner,msg.sender,result.resp)
|
||||||
|
|
||||||
|
chatsession.append_recv(msg)
|
||||||
|
chatsession.append_post(resp_msg)
|
||||||
|
return resp_msg
|
||||||
|
case "waiting":
|
||||||
|
# TODO: Use role:"function" would be better
|
||||||
|
for sendmsg in result.send_msgs:
|
||||||
|
target = sendmsg.target
|
||||||
|
sendmsg.topic = msg.topic
|
||||||
|
send_resp = await self.role_send_msg(sendmsg,the_role)
|
||||||
|
if send_resp is not None:
|
||||||
|
result_prompt_str += f"\n{target} response is :{send_resp.body}"
|
||||||
|
|
||||||
|
for call in result.calls:
|
||||||
|
call_result = await self.role_call(call,the_role)
|
||||||
|
if call_result is not None:
|
||||||
|
result_prompt_str += f"\ncall {call[0]} result is :{call_result}"
|
||||||
|
|
||||||
|
result_prompt = AgentPrompt()
|
||||||
|
result_prompt.messages = [{"role":"user","content":result_prompt_str}]
|
||||||
|
prompt.append(result_prompt)
|
||||||
|
r = await _do_process_msg()
|
||||||
|
return r
|
||||||
|
|
||||||
|
return await _do_process_msg()
|
||||||
|
|
||||||
|
|
||||||
|
#obsolete
|
||||||
async def _role_process_msg(self,msg:AgentMsg,the_role:AIRole) -> None:
|
async def _role_process_msg(self,msg:AgentMsg,the_role:AIRole) -> None:
|
||||||
# TODO : we just record role's chatsession, but in future, we would record workflow's chatsession(like a groupo chat)
|
# TODO : we just record role's chatsession, but in future, we would record workflow's chatsession(like a groupo chat)
|
||||||
session_topic = f"{the_role.get_name()}#{msg.sender}#{msg.topic}"
|
session_topic = f"{the_role.get_name()}#{msg.sender}#{msg.topic}"
|
||||||
@@ -162,7 +387,6 @@ class Workflow:
|
|||||||
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
||||||
|
|
||||||
prompt.append(await self._get_prompt_from_session(chatsession))
|
prompt.append(await self._get_prompt_from_session(chatsession))
|
||||||
#prompt.append(await self._get_prompt_from_session(chatsession,the_role.get_name())) # chat context
|
|
||||||
|
|
||||||
msg_prompt = AgentPrompt()
|
msg_prompt = AgentPrompt()
|
||||||
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
||||||
@@ -180,7 +404,7 @@ class Workflow:
|
|||||||
resp = await callchain.exec()
|
resp = await callchain.exec()
|
||||||
if callchain.have_result():
|
if callchain.have_result():
|
||||||
# generator proc resp prompt with WAITING state
|
# generator proc resp prompt with WAITING state
|
||||||
#proc_resp_prompt:AgentPrompt = self._get_resp_prompt(resp,msg,the_role,prompt,chatsession)
|
proc_resp_prompt:AgentPrompt = self._get_resp_prompt(resp,msg,the_role,prompt,chatsession)
|
||||||
final_result = await ComputeKernel().do_llm_completion(proc_resp_prompt,the_role.agent.get_llm_model_name(),the_role.agent.get_max_token_size())
|
final_result = await ComputeKernel().do_llm_completion(proc_resp_prompt,the_role.agent.get_llm_model_name(),the_role.agent.get_max_token_size())
|
||||||
return final_result
|
return final_result
|
||||||
|
|
||||||
@@ -218,31 +442,18 @@ class Workflow:
|
|||||||
chatsession.append_post(resp_msg)
|
chatsession.append_post(resp_msg)
|
||||||
return resp_msg
|
return resp_msg
|
||||||
|
|
||||||
async def _pop_msg(self) -> AgentMsg:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _get_chat_session_for_msg(self,msg:AgentMsg) -> AIChatSession:
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def _get_prompt_from_session(self,chatsession:AIChatSession) -> AgentPrompt:
|
async def _get_prompt_from_session(self,chatsession:AIChatSession) -> AgentPrompt:
|
||||||
messages = chatsession.read_history() # read last 10 message
|
messages = chatsession.read_history() # read last 10 message
|
||||||
result_prompt = AgentPrompt()
|
result_prompt = AgentPrompt()
|
||||||
for msg in reversed(messages):
|
for msg in reversed(messages):
|
||||||
if msg.target == chatsession.owner_id:
|
|
||||||
result_prompt.messages.append({"role":"user","content":f"{msg.sender}:{msg.body}"})
|
|
||||||
if msg.sender == chatsession.owner_id:
|
if msg.sender == chatsession.owner_id:
|
||||||
result_prompt.messages.append({"role":"assistant","content":msg.body})
|
result_prompt.messages.append({"role":"assistant","content":msg.body})
|
||||||
|
else:
|
||||||
|
result_prompt.messages.append({"role":"user","content":f"{msg.body}"})
|
||||||
|
|
||||||
return result_prompt
|
return result_prompt
|
||||||
|
|
||||||
def _get_msg_queue(self,session_id:str):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _merge_msg_result(self,results:dict) -> AgentMsg:
|
|
||||||
# TODO: one input msg can have multiple result msg, at this while ,we only support one result msg
|
|
||||||
for k,v in results.items():
|
|
||||||
if v is not None:
|
|
||||||
return v
|
|
||||||
|
|
||||||
def _get_function_prompt(self,role_name:str) -> AgentPrompt:
|
def _get_function_prompt(self,role_name:str) -> AgentPrompt:
|
||||||
pass
|
pass
|
||||||
@@ -250,48 +461,10 @@ class Workflow:
|
|||||||
def _get_knowlege_prompt(self,role_name:str) -> AgentPrompt:
|
def _get_knowlege_prompt(self,role_name:str) -> AgentPrompt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _get_resp_prompt(self,resp:str,msg:AgentMsg,role:AIRole,prompt:AgentPrompt) -> AgentPrompt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_workflow_rule_prompt(self) -> AgentPrompt:
|
def get_workflow_rule_prompt(self) -> AgentPrompt:
|
||||||
return self.rule_prompt
|
return self.rule_prompt
|
||||||
|
|
||||||
def _get_llm_result_type(self,llm_resp_str:str) -> str:
|
|
||||||
if llm_resp_str == "ignore":
|
|
||||||
return "ignore"
|
|
||||||
|
|
||||||
if llm_resp_str.find("sendmsg(") != -1:
|
|
||||||
return "send_message"
|
|
||||||
|
|
||||||
if llm_resp_str.find("postmsg(") != -1:
|
|
||||||
return "post_message"
|
|
||||||
|
|
||||||
if llm_resp_str.find("call(") != -1:
|
|
||||||
return "function"
|
|
||||||
|
|
||||||
return "text"
|
|
||||||
|
|
||||||
def _parse_function_call_chain(self,llm_resp_str) -> CallChain:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _parse_to_msg(self,llm_resp_str) -> AgentMsg:
|
|
||||||
lines = llm_resp_str.splitlines()
|
|
||||||
for line in lines:
|
|
||||||
if line.startswith("sendmsg("):
|
|
||||||
line = line[8:]
|
|
||||||
_index = line.find(",")
|
|
||||||
msg = AgentMsg()
|
|
||||||
msg.set("",line[:_index],line[_index+1:])
|
|
||||||
return msg
|
|
||||||
|
|
||||||
if line.startswith("postmsg("):
|
|
||||||
line = line[8:]
|
|
||||||
_index = line.find(",")
|
|
||||||
msg = AgentMsg()
|
|
||||||
msg.set("",line[:_index],line[_index+1:])
|
|
||||||
return msg
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_workflow(self,workflow_name:str):
|
def get_workflow(self,workflow_name:str):
|
||||||
"""get workflow from known workflow list or sub workflow list"""
|
"""get workflow from known workflow list or sub workflow list"""
|
||||||
|
|||||||
@@ -25,6 +25,20 @@ class WorkflowManager:
|
|||||||
async def get_agent_default_workflow(self,agent_id:str) -> Workflow:
|
async def get_agent_default_workflow(self,agent_id:str) -> Workflow:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def _load_workflow_agents(self,workflow:Workflow) -> bool:
|
||||||
|
for v in workflow.role_group.roles.values():
|
||||||
|
agent = await AgentManager().get(v.agent_name)
|
||||||
|
if agent is None:
|
||||||
|
logger.error(f"load agent {v.agent_name} failed!")
|
||||||
|
return False
|
||||||
|
v.agent = agent
|
||||||
|
|
||||||
|
for sub_workflow in workflow.sub_workflows.values():
|
||||||
|
if await self._load_workflow_agents(sub_workflow) is False:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def get_workflow(self,workflow_id:str) -> Workflow:
|
async def get_workflow(self,workflow_id:str) -> Workflow:
|
||||||
the_workflow : Workflow = self.loaded_workflow.get(workflow_id)
|
the_workflow : Workflow = self.loaded_workflow.get(workflow_id)
|
||||||
if the_workflow:
|
if the_workflow:
|
||||||
@@ -39,14 +53,9 @@ class WorkflowManager:
|
|||||||
if the_workflow is None:
|
if the_workflow is None:
|
||||||
logger.warn(f"load workflow {workflow_id} from media failed!")
|
logger.warn(f"load workflow {workflow_id} from media failed!")
|
||||||
|
|
||||||
for v in the_workflow.role_group.roles.values():
|
if await self._load_workflow_agents(the_workflow) is False:
|
||||||
agent = await AgentManager().get(v.agent_name)
|
return None
|
||||||
if agent is None:
|
|
||||||
logger.error(f"load agent {v.agent_name} failed!")
|
|
||||||
return None
|
|
||||||
v.agent = agent
|
|
||||||
|
|
||||||
|
|
||||||
return the_workflow
|
return the_workflow
|
||||||
|
|
||||||
async def _load_workflow_from_media(self,workflow_media:PackageMediaInfo) -> Workflow:
|
async def _load_workflow_from_media(self,workflow_media:PackageMediaInfo) -> Workflow:
|
||||||
@@ -64,10 +73,12 @@ class WorkflowManager:
|
|||||||
config_data = await config_file.read()
|
config_data = await config_file.read()
|
||||||
config = toml.loads(config_data)
|
config = toml.loads(config_data)
|
||||||
result_workflow = Workflow()
|
result_workflow = Workflow()
|
||||||
|
result_workflow.db_file = self.db_file
|
||||||
|
|
||||||
if result_workflow.load_from_config(config) is False:
|
if result_workflow.load_from_config(config) is False:
|
||||||
logger.error(f"load workflow from {workflow_media} failed!")
|
logger.error(f"load workflow from {workflow_media} failed!")
|
||||||
return None
|
return None
|
||||||
result_workflow.db_file = self.db_file
|
|
||||||
return result_workflow
|
return result_workflow
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"read workflow.toml cfg from {workflow_media} failed! unexpected error occurred: {str(e)}")
|
logger.error(f"read workflow.toml cfg from {workflow_media} failed! unexpected error occurred: {str(e)}")
|
||||||
|
|||||||
@@ -41,16 +41,15 @@ class AIOS_Shell:
|
|||||||
self.current_topic = "default"
|
self.current_topic = "default"
|
||||||
|
|
||||||
async def _handle_no_target_msg(self,bus:AIBus,msg:AgentMsg) -> bool:
|
async def _handle_no_target_msg(self,bus:AIBus,msg:AgentMsg) -> bool:
|
||||||
agent : AIAgent = await AgentManager().get(msg.target)
|
target_id = msg.target.split(".")[0]
|
||||||
|
agent : AIAgent = await AgentManager().get(target_id)
|
||||||
if agent is not None:
|
if agent is not None:
|
||||||
bus.register_message_handler(msg.target,agent._process_msg)
|
bus.register_message_handler(target_id,agent._process_msg)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
a_workflow = await WorkflowManager().get_workflow(msg.target)
|
a_workflow = await WorkflowManager().get_workflow(target_id)
|
||||||
if a_workflow is not None:
|
if a_workflow is not None:
|
||||||
bus.register_message_handler(msg.target,a_workflow._process_msg)
|
bus.register_message_handler(target_id,a_workflow._process_msg)
|
||||||
for subflow in a_workflow.sub_workflows.values():
|
|
||||||
bus.register_message_handler(subflow.workflow_name,subflow._process_msg)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@@ -79,7 +78,7 @@ class AIOS_Shell:
|
|||||||
agent_msg = AgentMsg()
|
agent_msg = AgentMsg()
|
||||||
agent_msg.set(sender,target_id,msg)
|
agent_msg.set(sender,target_id,msg)
|
||||||
agent_msg.topic = topic
|
agent_msg.topic = topic
|
||||||
resp = await AIBus().get_default_bus().send_message(target_id,agent_msg)
|
resp = await AIBus.get_default_bus().send_message(target_id,agent_msg)
|
||||||
if resp is not None:
|
if resp is not None:
|
||||||
return resp.body
|
return resp.body
|
||||||
else:
|
else:
|
||||||
@@ -111,10 +110,11 @@ class AIOS_Shell:
|
|||||||
case 'history':
|
case 'history':
|
||||||
num = 10
|
num = 10
|
||||||
offset = 0
|
offset = 0
|
||||||
if len(args) >= 1:
|
if args is not None:
|
||||||
num = args[0]
|
if len(args) >= 1:
|
||||||
if len(args) >= 2:
|
num = args[0]
|
||||||
offset = args[1]
|
if len(args) >= 2:
|
||||||
|
offset = args[1]
|
||||||
|
|
||||||
db_path = ""
|
db_path = ""
|
||||||
if await self.is_agent(self.current_target):
|
if await self.is_agent(self.current_target):
|
||||||
@@ -140,37 +140,43 @@ class AIOS_Shell:
|
|||||||
history = FileHistory('history.txt')
|
history = FileHistory('history.txt')
|
||||||
session = PromptSession(history=history)
|
session = PromptSession(history=history)
|
||||||
|
|
||||||
def parse_function_call(s):
|
def parse_function_call(func_string):
|
||||||
match = re.match(r'(\w+)\((.*)\)$', s)
|
match = re.search(r'\s*(\w+)\s*\(\s*(.*)\s*\)\s*', func_string)
|
||||||
if match:
|
if not match:
|
||||||
func_name = match.group(1)
|
|
||||||
args_str = match.group(2)
|
|
||||||
|
|
||||||
args = []
|
|
||||||
buffer = ''
|
|
||||||
quote_count = 0 # Count of single or double quotes
|
|
||||||
for char in args_str:
|
|
||||||
|
|
||||||
if char in ['"', "'"]:
|
|
||||||
quote_count += 1
|
|
||||||
if char == ',' and quote_count % 2 == 0: # ',' is outside of quotes
|
|
||||||
args.append(buffer.strip())
|
|
||||||
buffer = ''
|
|
||||||
else:
|
|
||||||
buffer += char
|
|
||||||
if buffer:
|
|
||||||
args.append(buffer.strip())
|
|
||||||
|
|
||||||
return func_name, args
|
|
||||||
else:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
func_name = match.group(1)
|
||||||
|
params_string = match.group(2).strip()
|
||||||
|
params = re.split(r'\s*,\s*(?=(?:[^"]*"[^"]*")*[^"]*$)', params_string)
|
||||||
|
params = [param.strip('"') for param in params]
|
||||||
|
if len(params[0]) == 0:
|
||||||
|
params = None
|
||||||
|
|
||||||
|
return func_name, params
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
print("aios shell prepareing...")
|
print("aios shell prepareing...")
|
||||||
logging.basicConfig(filename="aios_shell.log",filemode="w",level=logging.INFO,format='[%(asctime)s]%(name)s[%(levelname)s]: %(message)s')
|
logging.basicConfig(filename="aios_shell.log",filemode="w",encoding='utf-8',
|
||||||
|
level=logging.INFO,
|
||||||
|
format='[%(asctime)s]%(name)s[%(levelname)s]: %(message)s')
|
||||||
shell = AIOS_Shell("user")
|
shell = AIOS_Shell("user")
|
||||||
await shell.initial()
|
await shell.initial()
|
||||||
|
|
||||||
|
s = """了解。首先,我们需要进行方案讨论,定出一致的活动策略。我将任务分解如下:
|
||||||
|
财务组: 分析可见的预算,提供一份合理并被执行的财务方案。
|
||||||
|
行程预订组: 硅谷自然迷人的地方众多,寻找适合11人秋游的地点,以及一个可行的周末日期。策划一个一天或两天的安排,包括选择有南瓜园的地方,采摘苹果,参观当地的酗酒作坊等秋游活动。
|
||||||
|
嘉宾对接组: 把个人的食品饮料或过敏食物的需求事先了解并计入行程内。
|
||||||
|
酒店预订组:根据行程预订组的日期安排,活动时间在1天还是2天,在这个之内找一个合适的住宿,试着保持让住宿在预算边界以内。
|
||||||
|
活动摄像组: 准备活动拍摄与剪辑方案。\n\n然后,我将把这些拆分后的任务发来小组。
|
||||||
|
sendmsg(财务组,分析预算并提供一份财务方案.)
|
||||||
|
sendmsg(行程预订组,找出适合秋游的地方和日期.)
|
||||||
|
sendmsg(嘉宾对接组,了解个人的饮食需求.)
|
||||||
|
sendmsg(酒店预订组,查询并预订住宿.)
|
||||||
|
sendmsg(活动摄像组,提供活动拍摄方案.)
|
||||||
|
经过一两天的准备,一切就绪之后,我将向工作人员发送最后的行程计划,
|
||||||
|
"""
|
||||||
|
r = Workflow.prase_llm_result(s)
|
||||||
print(f"aios shell {shell.get_version()} ready.")
|
print(f"aios shell {shell.get_version()} ready.")
|
||||||
|
|
||||||
completer = WordCompleter(['send($target,$msg,$topic)',
|
completer = WordCompleter(['send($target,$msg,$topic)',
|
||||||
|
|||||||
+80
-12
@@ -1,15 +1,83 @@
|
|||||||
|
# workflow实例场景
|
||||||
|
# 能展示sub workflow
|
||||||
|
# 能展示env的整合
|
||||||
|
# 能展示filter的使用
|
||||||
|
# 能展示function的调用
|
||||||
|
# 能展示基于工作目标/KPI的sub workflow迭代流程
|
||||||
|
# 多人场景安排
|
||||||
|
|
||||||
[authors]
|
# 例子:举办一个团队活动
|
||||||
"buckyos.org" = {public="aaaa",name="BuckyOS Core Dev Team"}
|
# 方案讨论(通过交互引导的方式收集主人的需求)与确定
|
||||||
[authors."cyfs.com"]
|
|
||||||
public="bbbb"
|
|
||||||
name="CYFS Core Dev Team"
|
|
||||||
|
|
||||||
[env]
|
# 活动前:
|
||||||
is_strict = false
|
# 通讯员,对接管理参加活动的人的情况 (email spider)
|
||||||
prefixs = ["default","../m/s","abc"]
|
# 酒店预订 简单:搜索(酒店评价) 处理异常
|
||||||
obj2 = {k1="bb",k2=300}
|
# 行程(票务)预订 :搜索,处理异常
|
||||||
[env.obj]
|
# 餐饮预订:给出方案,确定细节,预订
|
||||||
k1="aa"
|
|
||||||
k2=200
|
# 活动中:
|
||||||
|
# 进行统计和分析,调整设备
|
||||||
|
# 安保,空调,音乐,拍照,录像
|
||||||
|
# 响应紧急情况
|
||||||
|
|
||||||
|
# 活动结束后:
|
||||||
|
# 整理照片,视频,进行必要的二次创作,发送给相关人员
|
||||||
|
# 对活动进行总结,提出改件意见(指导下一次活动)
|
||||||
|
|
||||||
|
# 1. 人员
|
||||||
|
# 主管,负责和客户沟通,并对每个环境的结果进行总结
|
||||||
|
# 嘉宾对接
|
||||||
|
# 酒店组
|
||||||
|
# 行程组
|
||||||
|
# 财务组
|
||||||
|
# 多媒体组
|
||||||
|
|
||||||
|
|
||||||
|
[filter]
|
||||||
|
"*" = "manager"
|
||||||
|
|
||||||
|
[roles.manager]
|
||||||
|
fullname = "经理"
|
||||||
|
agent="manager"
|
||||||
|
[[roles.manager.prompt]]
|
||||||
|
role="system"
|
||||||
|
content="""你是一个活动策划公司的经理,与客户对接并向团队下达指令。你的团队分为下面几个小组:嘉宾对接组,酒店预定组,行程预订组,财务组,活动摄像组。活动策划分为四个阶段:方案讨论,活动前,活动中,活动后。你会根据客户的需求,对团队进行分工,分别完成各个阶段的工作。你的基本工作模式是:\
|
||||||
|
1. 收到客户的明确的指令后,基于客户的已有信息和客户商量活动方案,和活动策划公司无关的业务你会回答‘与我无关’。当和客户完成活动方案的确认后,你会将拆解后的任务分配给各个小组 \
|
||||||
|
2. 根据目前已经确认的活动方案,你要根据时间适时的检查不同小组的工作情况。当收到小组的工作情况反馈后,你会站在全局的角度判断是否需要调整活动方案,如果需要调整,你会和客户商量重新确定方案,然后再将调整后的方案分配给各个小组。\
|
||||||
|
3. 有时工作小组会主动与你沟通,反馈一些问题。你会站在全局的角度给与指导,适当的调整工作小组的工作目标。如果反馈的问题需要你和客户沟通,你会和客户沟通后重新确定方案。再将调整后的方案分配给受到影响各个小组。\
|
||||||
|
4. 当你决定要和工作小组通信时,请使用`send_message({小组名称},{内容}`)的形式。"""}]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[sub_workflows]
|
||||||
|
[sub_workflows."嘉宾对接组"]
|
||||||
|
# 展现读取email和发送email与嘉宾沟通的能力
|
||||||
|
[sub_workflows."嘉宾对接组".environments.email]
|
||||||
|
new_mail = "收到来自{event.data.from},标题为{event.data.subject}的邮件,内容为{event.data.content}的电子邮件" # 这里将new_mail事件转换为了一个来自环境的message
|
||||||
|
|
||||||
|
[sub_workflows."嘉宾对接组".roles.leader]
|
||||||
|
name = "嘉宾对接组组长"
|
||||||
|
[[sub_workflows."嘉宾对接组".roles.leader.prompt]]
|
||||||
|
role="system"
|
||||||
|
content="""你是一家活动策划公司的嘉宾对接组的组长,你的工作是基于已知信息,当前活动信息、公司经理的指令与嘉宾沟通,收集嘉宾的信息,然后将信息反馈给经理。在你看来,参加活动的多少有成员都是嘉宾,你可以通过你知道的信息给不同的成员进行分级。你的基本工作模式是:\
|
||||||
|
1. 处理收到的邮件,如果邮件来自嘉宾,你会尝试从邮件的表态和内容中分享嘉宾的需要,并结合你对当前活动方案的理解判断是否需要和经理沟通,如果需要和经理沟通,你会将嘉宾的需求总结和告诉经理。不需要沟通的事项可以直接回复嘉宾。\
|
||||||
|
2. 你总是通过`call_function(get_env,'parent.topic'`的形式查询当前的活动方案。等待函数返回后,你会根据函数的返回结果继续处理上一个对话。\
|
||||||
|
3. 当你决定要和经理通信时,请使用`send_message(manager,{内容}`)的形式,内容的长度不超过200字。\
|
||||||
|
4. 当你决定要回复嘉宾时,请使用`call_function(sendmail,{嘉宾邮件地址},{标题},{内容})的形式,内容的长度不超过500字。"""
|
||||||
|
# 这里是孤立工作模式,组长只和经理沟通,也可以赋予其和其它组沟通的能力
|
||||||
|
|
||||||
|
[sub_workflows."酒店预定组"]
|
||||||
|
# 展现使用搜索引擎,并调用预订酒店的能力
|
||||||
|
[sub_workflows."酒店预定组".environments.email]
|
||||||
|
|
||||||
|
[sub_workflows."酒店预定组".roles.leader]
|
||||||
|
name="酒店预定组组长"
|
||||||
|
prompt = [{role="xxx",content="yyy"}]
|
||||||
|
|
||||||
|
[sub_workflows."酒店预定组".roles.research]
|
||||||
|
name="酒店搜索专家"
|
||||||
|
|
||||||
|
[sub_workflows."行程预订组"]
|
||||||
|
# 展现处理冲突并反推
|
||||||
|
nam3="3"
|
||||||
|
|||||||
Reference in New Issue
Block a user