Workflow is almost done.

This commit is contained in:
Liu Zhicong
2023-09-01 00:39:36 -07:00
parent 27f163ddd3
commit b4990e4c57
11 changed files with 469 additions and 175 deletions
+40 -40
View File
@@ -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&lt;br&gt;@docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="5" value="Workflow&lt;br&gt;@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&lt;br&gt;ComputeNode&lt;br&gt;Run in VM" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="6" value="LLM&lt;br&gt;ComputeNode&lt;br&gt;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&lt;br&gt;Run in docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="8" value="LLM ComputeNode&lt;br&gt;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&lt;br&gt;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&lt;br&gt;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&lt;br&gt;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&lt;br&gt;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&lt;br&gt;Run in docker" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="40" value="ComputeNode&lt;br&gt;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&lt;br&gt;ComputeNode&lt;br&gt;Run on Cloud" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="42" value="LLM&lt;br&gt;ComputeNode&lt;br&gt;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"/>
+2 -2
View File
@@ -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"/>
+4 -4
View File
@@ -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字。"""
# 这里是孤立工作模式,组长只和经理沟通,也可以赋予其和其它组沟通的能力 # 这里是孤立工作模式,组长只和经理沟通,也可以赋予其和其它组沟通的能力
+20
View File
@@ -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
+10
View File
@@ -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
@@ -127,3 +129,11 @@ 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)
+2 -2
View File
@@ -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:
+7 -1
View File
@@ -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!")
@@ -36,6 +38,9 @@ class AIRole:
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
View File
@@ -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,13 +53,8 @@ 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)
if agent is None:
logger.error(f"load agent {v.agent_name} failed!")
return None return None
v.agent = agent
return the_workflow return the_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)}")
+37 -31
View File
@@ -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,6 +110,7 @@ class AIOS_Shell:
case 'history': case 'history':
num = 10 num = 10
offset = 0 offset = 0
if args is not None:
if len(args) >= 1: if len(args) >= 1:
num = args[0] num = args[0]
if len(args) >= 2: if len(args) >= 2:
@@ -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
View File
@@ -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"