Refactor the Action/Function components, and refactor the basic architecture of Agent Task/Todo.
This commit is contained in:
+61
-44
@@ -1,4 +1,4 @@
|
||||
<mxfile host="Electron" modified="2023-12-09T10:05:21.341Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="NcEmel1aD_FGfbcRcY7b" version="22.1.2" type="device" pages="5">
|
||||
<mxfile host="Electron" modified="2023-12-16T07:48:34.853Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="Jb4FnfYeMwslMLOmSp3i" version="22.1.2" type="device" pages="6">
|
||||
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
||||
<mxGraphModel dx="780" dy="596" 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>
|
||||
@@ -122,8 +122,8 @@
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="kWxfmPxtNxOAf0a73TCG" name="Page-2">
|
||||
<mxGraphModel dx="780" dy="596" 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">
|
||||
<diagram id="kWxfmPxtNxOAf0a73TCG" name="Workflow">
|
||||
<mxGraphModel dx="2046" dy="1168" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
@@ -220,7 +220,7 @@
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="7NYJTgo0U9cdVshLy85U" name="Page-3">
|
||||
<mxGraphModel dx="780" dy="596" 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="2046" dy="1168" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
@@ -366,7 +366,7 @@
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="3kOHILldrhYu_NusAgTt" name="LLM Process">
|
||||
<mxGraphModel dx="2060" dy="1183" 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="1421" dy="816" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
@@ -507,96 +507,96 @@
|
||||
<mxCell id="mAWNT_NJkWkCqDQJkoOU-14" value="Prepare过程可以是固定的计算组合,也可以是LLM参与的" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="380" y="270" width="165" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="f2v0L3gmEFmQxlVvJ0Yg-1" value="<h1><font style="font-size: 22px;">Memory,Env,KB,Workspace的区别</font></h1><p>Memory是不共享的内部状态,只有 action没有function<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">Workspace是共享的状态,主要是action</span><br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">Env是全局状态,主要是inner_function,有的有小部分action</span><br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">Knowledge基本是只读的,除非专门整理Knowledge的Agent,只有function</span><br><br></p>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="f2v0L3gmEFmQxlVvJ0Yg-1" value="<h1><font style="font-size: 22px;">Memory,Env,KB,Workspace的区别</font></h1><p>Memory是不共享的内部状态,只有 action没有function<br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">Workspace是共享的状态,主要是action</span><br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">Env是全局状态,主要是inner_function,有的有小部分action</span><br style="border-color: var(--border-color); font-size: 11px;"><span style="font-size: 11px;">Knowledge基本是只读的,除非专门整理Knowledge的Agent,只有function</span><br><br></p>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="449.97" y="530" width="390" height="230" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="CqH4P1G_RAjWfIoYkaMU" name="Task/Todo">
|
||||
<mxGraphModel dx="1717" dy="986" 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="2060" dy="1183" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-1" target="Po7mxAQLMo4zYcBtAZ7U-5">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-1" target="Po7mxAQLMo4zYcBtAZ7U-5" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-1" value="未开始的Task" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-1" value="未开始的Task" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="380" y="40" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-2" target="Po7mxAQLMo4zYcBtAZ7U-8">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-2" target="Po7mxAQLMo4zYcBtAZ7U-8" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-2" value="确定的Task:<br>确定的执行时间(在这之前和之后都不会执行),<br>确定的执行人" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-2" value="确定的Task:<br>确定的执行时间(在这之前和之后都不会执行),<br>确定的执行人" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="250" width="120" height="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-5" target="Po7mxAQLMo4zYcBtAZ7U-7">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-5" target="Po7mxAQLMo4zYcBtAZ7U-7" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-5" target="Po7mxAQLMo4zYcBtAZ7U-2">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-5" target="Po7mxAQLMo4zYcBtAZ7U-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-5" target="Po7mxAQLMo4zYcBtAZ7U-31">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-5" target="Po7mxAQLMo4zYcBtAZ7U-31" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-5" value="Task Review" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-5" value="Task Review" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="380" y="140" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-6" target="Po7mxAQLMo4zYcBtAZ7U-2">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-6" target="Po7mxAQLMo4zYcBtAZ7U-2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-6" value="Quick Review" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-6" value="Quick Review" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="380" y="290" width="130" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-7" target="Po7mxAQLMo4zYcBtAZ7U-6">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-7" target="Po7mxAQLMo4zYcBtAZ7U-6" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-7" value="半确定的Task:<br>确定的执行人<br>不确定的执行时间(和条件有关)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-7" value="半确定的Task:<br>ASSIGNED<br>确定的执行人<br>不确定的执行时间(和条件有关)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="210" y="250" width="120" height="140" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-8" target="Po7mxAQLMo4zYcBtAZ7U-9">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-8" target="Po7mxAQLMo4zYcBtAZ7U-9" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-8" value="Task Review" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-8" value="Task Review" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="430" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-9" target="Po7mxAQLMo4zYcBtAZ7U-10">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-9" target="Po7mxAQLMo4zYcBtAZ7U-10" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-9" value="未执行Todo" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-9" value="未执行Todo" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="530" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-10" target="Po7mxAQLMo4zYcBtAZ7U-11">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-10" target="Po7mxAQLMo4zYcBtAZ7U-11" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-10" value="Do Todo" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-10" value="Do Todo" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="640" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-11" target="Po7mxAQLMo4zYcBtAZ7U-12">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-11" target="Po7mxAQLMo4zYcBtAZ7U-12" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-11" value="已执行Todo" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-11" value="已执行Todo" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="760" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-12" target="Po7mxAQLMo4zYcBtAZ7U-24">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-12" target="Po7mxAQLMo4zYcBtAZ7U-24" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-12" value="Check Todo" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-12" value="Check Todo" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="860" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-24" target="Po7mxAQLMo4zYcBtAZ7U-26">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-27" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-24" target="Po7mxAQLMo4zYcBtAZ7U-26" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-24" value="已完成TODO" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-24" value="已完成TODO" style="shape=parallelogram;perimeter=parallelogramPerimeter;whiteSpace=wrap;html=1;fixedSize=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="570" y="960" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-26" target="Po7mxAQLMo4zYcBtAZ7U-28">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-26" target="Po7mxAQLMo4zYcBtAZ7U-28" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-26" value="Check Task" style="rounded=1;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-26" value="Check Task" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="360" y="960" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-43" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-28" target="Po7mxAQLMo4zYcBtAZ7U-5">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-43" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="Po7mxAQLMo4zYcBtAZ7U-28" target="Po7mxAQLMo4zYcBtAZ7U-5" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="90" y="990" />
|
||||
@@ -604,36 +604,53 @@
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-28" value="已完成的Task" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-28" value="已完成的Task" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="180" y="960" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-31" value="未开始的SubTask(通常是半确定的)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-31" value="未开始的SubTask(通常是半确定的)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="560" y="140" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-35" value="Plan" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-35" value="Plan" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="470" y="130" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-36" value="Plan" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-36" value="Plan" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="660" y="420" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-37" value="将Task拆解成一系列TODO" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-37" value="将Task拆解成一系列TODO" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="640" y="490" width="155" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-38" value="Check" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-38" value="Check" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="470" y="280" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-40" value="Check" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-40" value="Check" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="650" y="850" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-41" value="Check" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-41" value="Check" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="950" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-42" value="Do" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-42" value="Do" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;" parent="1" vertex="1">
|
||||
<mxGeometry x="660" y="630" width="50" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-44" value="失败的有机会重新开始" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-44" value="失败的有机会重新开始" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="110" y="950" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="JyX1mhbkDWa9bGLsmIIT-1" value="创建" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="500" y="170" width="60" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="dTeZOjKiqq0ditQk53ut-1" value="<h1>防止无限拆分</h1><p>大部分情况下,我们都鼓励使用</p><p>Task-Todo-Action这种3层结构来完成任务。或则再多一层Task-SubTask-Todo-Action. 今天LLM能面对的复杂度应该就是最多这4层了</p>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="190" y="470" width="190" height="240" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="1AT3sDmhgRXqQU36RNgs" name="New Workflow">
|
||||
<mxGraphModel dx="650" dy="497" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="h0utY9AjMI-hVYMkH-L3-1" value="<h1>Workflow的核心设计</h1><p>1.工作流定义,工作流指导了workflow中特定的task是如何交给不同的agent完成的</p><p>2.agent在workflow中工作时,自己的llm_process会受到影响,有时可以使用workflow中的一些额定义的llm_process</p><p>3.workflow的状态是独立的,主要是指</p><p>1.独立的workspace</p><p>该workspace里支持公共的log保存</p><p>2.独立的env</p><p>3.独立的kb</p><p>4.Agent依旧使用自己的memory+</p><p><br></p>" style="text;html=1;strokeColor=none;fillColor=none;spacing=5;spacingTop=-20;whiteSpace=wrap;overflow=hidden;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="70" y="50" width="300" height="330" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
|
||||
+45
-1
@@ -2,4 +2,48 @@
|
||||
目标是结合 角色定义,手头的工具,已知知识 完成一个确定的任务。
|
||||
完成任务时应使用ReAct的方法:应在给出执行动作前,先自言自语的输出一个计划,然后在动作(这个自言自语会变成TODO Logs)
|
||||
|
||||
|
||||
## 提示词思路
|
||||
TODO从Task拆分而来,因此不应该再次拆分。请尽全力完成。如果判断缺乏完成TODO的能力,请标记为取消。如果是缺乏完成任务的前置条件,请标记为执行失败。
|
||||
|
||||
执行一个新的TODO:
|
||||
```
|
||||
YOUR ROLE:
|
||||
你是主人的超级个人助理。你的主要工作是安排主人的日程。
|
||||
|
||||
PROCESS RULE:
|
||||
1. 你的任务是结合自己的角色定义,手头的工具,已知信息、完成一个确定的TODO。完成该TODO后你会得到$200的小费。
|
||||
2. 输入的TODO是来自你自己对一个Task的Plan结果。
|
||||
3. 完成TODO的过程中你应该先思考再执行。执行的过程中可以使用工具,访问前置步骤的结果。执行的结果通常是按顺序执行的ActionList。
|
||||
4. 你必须独立的,一次性完成该TODO,你无法得到来自任何他人的协助。
|
||||
5. 对确认超出任务范围的TODO,你可以取消该TODO。对执行任务条件不满足的TODO,你可以标记为失败,但要说明失败原因
|
||||
7. TODO的完成结果如有需要应保存成数字文档
|
||||
|
||||
CONTEXT:
|
||||
ActionList:PostMsg,WriteFile,UpdateFile,RemoveFile,Rename,
|
||||
现在时间,主人所在位置,以及天气。主人目前正在做什么。
|
||||
|
||||
REPLY FORMAT:
|
||||
The Response must be directly parsed by `python json.loads`. Here is an example:
|
||||
{
|
||||
think:'我的思考.'
|
||||
tags: ['tag1', 'tag2'], #Optional,If the TODO involves important things and people, you can mark by 1-3 tags.
|
||||
actions: [{
|
||||
name: '$action1_name',
|
||||
$param_name: '$parm' #Optional, fill in only if the action has parameters.
|
||||
}, ...
|
||||
]
|
||||
}
|
||||
|
||||
KNOWN_INFO:
|
||||
1.TODO所在的Task信息,重点是Task的整个Plan计划
|
||||
2.该TODO之前的执行失败记录 (如有)
|
||||
|
||||
|
||||
Tools_tips:(重要!)
|
||||
inner_function:GetTodoResult, ReadFile
|
||||
使用GetAllSupportAction进一步获得所有可用的Action
|
||||
|
||||
|
||||
```
|
||||
(注意Workspace和AgentMemory都有Worklog,但视角不同。)
|
||||
执行一个有失败记录的TODO:
|
||||
|
||||
@@ -16,7 +16,50 @@ LLM 结果动作:
|
||||
- 判断可以立刻执行任务(将任务当成TODO工作),通过Action进入下一个LLMProcess
|
||||
- 判断任务超出Agent能力范围,宣告失败
|
||||
|
||||
Example:
|
||||
|
||||
ExampleA:(Task不支持分拆,Agent必须通过Task-Todo两级结构完成任务)
|
||||
```
|
||||
YOUR ROLE:
|
||||
你是主人的超级个人助理。你的主要工作是安排主人的日程。
|
||||
|
||||
PROCESS RULE:
|
||||
你得到的输入来自你自己之前记录在TaskList系统里的一个Task。现在你并不需要完成该Task,而是结合已知信息对Task进行一次Review.Review的过程是你独立完成的,你在形成结论的过程中可以使用工具,但不能和其它人交流。
|
||||
1. 理性的思考如何一步一步的高效的,在潜在的截止时间前完成该Task。明确拒绝超出自己能力范围的Task。
|
||||
2. 尝试对Task进行确认操作。确认操作的关键在于任务有了明确的执行时间。
|
||||
3. 对于需要多个步骤才能完成的Task,对Task进行TODO Plan。尤其注意与相关人员确认的步骤
|
||||
4. 对于不需要拆分TODO,且可立刻执行的任务。直接执行该任务。
|
||||
|
||||
CONTEXT:
|
||||
ActionList:cancel,confirm,execute
|
||||
现在时间,主人所在位置,以及天气。主人目前正在做什么?
|
||||
|
||||
REPLY FORMAT:
|
||||
The Response must be directly parsed by `python json.loads`. Here is an example:
|
||||
{
|
||||
think:'$think step-by-step to be sure you have the right answer.'
|
||||
plans:[ #Optional
|
||||
{"todo":"$todo_name","detail":"$todo_detail,"category":"$todo_category"}
|
||||
...
|
||||
],
|
||||
tags: ['tag1', 'tag2'], #Optional,If the task involves important things and people, you can mark by 1-3 tags.
|
||||
actions: [{
|
||||
name: '$action_name',
|
||||
$param_name: '$parm' #Optional, fill in only if the action has parameters.
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
KNOWN_INFO:
|
||||
1.已有Task
|
||||
|
||||
Tools_tips:
|
||||
2.可以给与Readonly的日历API,进一步查询某个人的已知日程安排)
|
||||
|
||||
```
|
||||
问题:拆分TODO时是否需要知道有哪些Agent可以用,这样的话在布置任务的时候也会充分考虑其人员能力边界
|
||||
|
||||
|
||||
Example OLD:
|
||||
```markdown
|
||||
I think hard and try my best to complete TODOs. The types of TODO I can handle include:
|
||||
- Scheduling, where I will try to contact the relevant personnel of the plan and confirm the details of the schedule with them.
|
||||
|
||||
+17
-14
@@ -1,13 +1,13 @@
|
||||
<mxfile host="Electron" modified="2023-11-22T04:04:28.746Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.0.2 Chrome/114.0.5735.289 Electron/25.8.4 Safari/537.36" etag="sDA3Z7V6Md16IKaqwf9n" version="22.0.2" type="device" pages="8">
|
||||
<mxfile host="Electron" modified="2023-12-13T22:01:24.775Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.1.2 Chrome/114.0.5735.289 Electron/25.9.4 Safari/537.36" etag="E51kKpuxtuq7HP7WJjo-" version="22.1.2" type="device" pages="8">
|
||||
<diagram name="Init" id="eZ0Fsh2vPRb0vo3J8o-a">
|
||||
<mxGraphModel dx="1421" dy="816" 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="2046" dy="1168" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="IzO59fDZ9m1edTcSyALi-20" value="" style="verticalLabelPosition=bottom;verticalAlign=top;html=1;shape=mxgraph.basic.rect;fillColor2=none;strokeWidth=1;size=20;indent=5;" parent="1" vertex="1">
|
||||
<mxGeometry x="195" y="90" width="565" height="420" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-11" value="" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-11" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="300" y="120" width="330" height="380" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="IzO59fDZ9m1edTcSyALi-11" value="" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
@@ -52,38 +52,38 @@
|
||||
<mxCell id="l8k4_rfZMrNWla8Lv80Y-1" value="AI Store" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="40" y="240" width="155" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-1" value="OpenAI" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.forms.comboBox;strokeColor=#999999;fillColor=#ddeeff;align=left;fillColor2=#aaddff;mainText=;fontColor=#666666;fontSize=17;spacingLeft=3;" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-1" value="OpenAI" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.forms.comboBox;strokeColor=#999999;fillColor=#ddeeff;align=left;fillColor2=#aaddff;mainText=;fontColor=#666666;fontSize=17;spacingLeft=3;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="144.5" width="150" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-2" value="OpenAI API Token:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-2" value="OpenAI API Token:" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="180" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-3" value="&lt;&lt;input your openai API token&gt;&gt;" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-3" value="&lt;&lt;input your openai API token&gt;&gt;" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="214" width="280" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-4" value="My Name:" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-4" value="My Name:" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="270" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-5" value="" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-5" value="" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="300" width="280" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-7" value="My Email:" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-7" value="My Email:" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="320" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-8" value="" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-8" value="" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="350" width="280" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-9" value="My Telegram Username:" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-9" value="My Telegram Username:" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="370" width="150" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-10" value="(Optional)" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" vertex="1" parent="1">
|
||||
<mxCell id="KPRGaicIhTDQW55mVU-i-10" value="(Optional)" style="strokeWidth=1;shadow=0;dashed=0;align=center;html=1;shape=mxgraph.mockup.text.textBox;fontColor=#666666;align=left;fontSize=17;spacingLeft=4;spacingTop=-3;whiteSpace=wrap;strokeColor=#666666;mainText=" parent="1" vertex="1">
|
||||
<mxGeometry x="320" y="400" width="280" height="20" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="BYP5jSDgWWDytgGHs8je" name="Page-7">
|
||||
<mxGraphModel dx="2060" dy="1183" 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="2046" dy="1168" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
@@ -91,7 +91,7 @@
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
<diagram id="EX4l-TP_pYMqB1o-9Pjg" name="MainPage">
|
||||
<mxGraphModel dx="2060" dy="1183" 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="1410" dy="805" 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>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
@@ -152,6 +152,9 @@
|
||||
<mxCell id="38aqMLvnZxr78S6UhFXi-6" value="Logs/Command Line" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="117.5" y="570" width="122.5" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="0Z58B_YgUAABuKnZxCUR-1" value="考虑手机上也能很好的排版" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
|
||||
<mxGeometry x="120" y="10" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
|
||||
Generated
+1453
-1
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
from typing import Optional
|
||||
|
||||
from aios.environment.environment import Environment
|
||||
from aios.environment.sql_database_function import GetTableInfosFunction, ExecuteSqlFunction
|
||||
from aios.ai_functions.sql_database_function import GetTableInfosFunction, ExecuteSqlFunction
|
||||
|
||||
|
||||
class DBQuerierEnvironment(Environment):
|
||||
|
||||
@@ -45,11 +45,76 @@ known_info_tips = """
|
||||
tools_tips = """
|
||||
"""
|
||||
|
||||
[behavior.review_task]
|
||||
type="ReviewTaskProcess"
|
||||
process_description="""
|
||||
你得到的输入来自你自己之前记录在TaskList系统里的一个Task。现在你并不需要完成该Task,而是结合已知信息对Task进行一次Review.Review的过程是你独立完成的,你在形成结论的过程中可以使用工具,但不能和其它人交流。
|
||||
1. 理性的思考如何一步一步的高效的,在潜在的截止时间前完成该Task。明确拒绝超出自己能力范围的Task。
|
||||
2. 尝试对Task进行确认操作。确认操作的关键在于任务有了明确的执行时间。
|
||||
3. 对于需要多个步骤才能完成的Task,对Task进行TODO Plan。尤其注意与相关人员确认的步骤
|
||||
4. 对于不需要拆分TODO,且可立刻执行的任务。直接执行该任务。
|
||||
"""
|
||||
|
||||
reply_format = """
|
||||
The Response must be directly parsed by `python json.loads`. Here is an example:
|
||||
{
|
||||
think:'$think step-by-step to be sure you have the right answer.'
|
||||
plans:[ #Optional
|
||||
{"todo":"$todo_name","detail":"$todo_detail,"category":"$todo_category"}
|
||||
...
|
||||
],
|
||||
tags: ['tag1', 'tag2'], #Optional,If the task involves important things and people, you can mark by 1-3 tags.
|
||||
actions: [{
|
||||
name: '$action_name',
|
||||
$param_name: '$parm' #Optional, fill in only if the action has parameters.
|
||||
}]
|
||||
}
|
||||
"""
|
||||
# action_list: ['cancle','confirm', 'execute']
|
||||
LLMContext.action_list = ['cancle','confirm', 'execute']
|
||||
|
||||
context="Your master now in {location}, time: {now}, weather: {weather}."
|
||||
|
||||
known_info_tips = """
|
||||
"""
|
||||
|
||||
tools_tips = """
|
||||
|
||||
"""
|
||||
[llm_context.actions]
|
||||
enable = ["agent.memory.append_chatlog"]
|
||||
|
||||
[llm_context.functions]
|
||||
enable = []
|
||||
|
||||
[behavior.do] # do TODO
|
||||
type="DoTodoProcess"
|
||||
process_description="""
|
||||
1. 你的任务是结合自己的角色定义,手头的工具,已知信息、完成一个确定的TODO。完成该TODO后你会得到$200的小费。
|
||||
2. 输入的TODO是来自你自己对一个Task的Plan结果。
|
||||
3. 完成TODO的过程中你应该先思考再执行。执行的过程中可以使用工具,访问前置步骤的结果。执行的结果通常是按顺序执行的ActionList。
|
||||
4. 你必须独立的,一次性完成该TODO,你无法得到来自任何他人的协助。
|
||||
5. 对确认超出任务范围的TODO,你可以取消该TODO。对执行任务条件不满足的TODO,你可以标记为失败,但要说明失败原因
|
||||
7. TODO的完成结果如有需要应保存成数字文档
|
||||
"""
|
||||
|
||||
|
||||
reply_format = """
|
||||
The Response must be directly parsed by `python json.loads`. Here is an example:
|
||||
{
|
||||
think:'我的思考.'
|
||||
tags: ['tag1', 'tag2'], #Optional,If the TODO involves important things and people, you can mark by 1-3 tags.
|
||||
actions: [{
|
||||
name: '$action1_name',
|
||||
$param_name: '$parm' #Optional, fill in only if the action has parameters.
|
||||
}, ...
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
#[behavior.self_thinking]
|
||||
|
||||
#[behavior.review_task]
|
||||
|
||||
#[behavior.do]
|
||||
|
||||
#[behavior.check]
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ from .agent.chatsession import AIChatSession
|
||||
from .agent.agent import AIAgent,AIAgentTemplete, BaseAIAgent
|
||||
from .agent.role import AIRole,AIRoleGroup
|
||||
from .agent.workflow import Workflow
|
||||
from .agent.agent_memory import AgentMemory
|
||||
from .agent.llm_context import LLMProcessContext,GlobaToolsLibrary,SimpleLLMContext
|
||||
|
||||
from .frame.compute_kernel import ComputeKernel,ComputeTask,ComputeTaskResult,ComputeTaskState,ComputeTaskType
|
||||
from .frame.compute_node import ComputeNode,LocalComputeNode
|
||||
@@ -19,8 +21,8 @@ from .frame.queue_compute_node import Queue_ComputeNode
|
||||
|
||||
from .environment.environment import BaseEnvironment,SimpleEnvironment,CompositeEnvironment
|
||||
# from .environment.workflow_env import WorkflowEnvironment,CalenderEnvironment,CalenderEvent,PaintEnvironment
|
||||
from .environment.text_to_speech_function import TextToSpeechFunction
|
||||
from .environment.image_2_text_function import Image2TextFunction
|
||||
from .ai_functions.text_to_speech_function import TextToSpeechFunction
|
||||
from .ai_functions.image_2_text_function import Image2TextFunction
|
||||
from .environment.workspace_env import WorkspaceEnvironment
|
||||
|
||||
from .storage.storage import ResourceLocation,AIStorage,UserConfig,UserConfigItem
|
||||
@@ -31,4 +33,4 @@ from .package_manager import *
|
||||
from .utils import *
|
||||
|
||||
|
||||
AIOS_Version = "0.5.2, build 2023-11-30"
|
||||
AIOS_Version = "0.5.2, build 2023-12-15"
|
||||
|
||||
+5
-459
@@ -36,37 +36,6 @@ from ..proto.compute_task import ComputeTaskResult,ComputeTaskResultCode
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# DEFAULT_AGENT_READ_REPORT_PROMPT = """
|
||||
# """
|
||||
|
||||
# DEFAULT_AGENT_DO_PROMPT = """
|
||||
# You are a helpful AI assistant.
|
||||
# Solve tasks using your coding and language skills.
|
||||
# In the following cases, suggest python code (in a python coding block) for the user to execute.
|
||||
# 1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.
|
||||
# 2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.
|
||||
# Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.
|
||||
# When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.
|
||||
# If you want the user to save the code in a file before executing it, put # filename: <filename> inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.
|
||||
# If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.
|
||||
# When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible.
|
||||
# Reply "TERMINATE" in the end when everything is done.
|
||||
# """
|
||||
|
||||
# DEFAULT_AGENT_SELF_CHECK_PROMPT = """
|
||||
|
||||
# """
|
||||
|
||||
# DEFAULT_AGENT_GOAL_TO_TODO_PROMPT = """
|
||||
# 我会给你一个目标,你需要结合自己的角色思考如何将其拆解成多个TODO。请直接返回json来表达这些TODO
|
||||
# """
|
||||
|
||||
# DEFAULT_AGENT_LEARN_LONG_CONENT_PROMPT = """
|
||||
# 我给你一段内容,尝试为期建立目录。目录的标题不能超过16个字,
|
||||
# 目录要指向正文的位置(用字符偏移即可),整个目录的文本长度不能超过256个字节。并用json表达这个目录
|
||||
# """
|
||||
|
||||
|
||||
class AIAgentTemplete:
|
||||
def __init__(self) -> None:
|
||||
self.llm_model_name:str = "gpt-4-0613"
|
||||
@@ -120,7 +89,7 @@ class AIAgent(BaseAIAgent):
|
||||
todo_prompts = {}
|
||||
todo_prompts[TodoListType.TO_WORK] = {
|
||||
"do": None,
|
||||
"check": None,
|
||||
"check": None,
|
||||
"review": None,
|
||||
}
|
||||
todo_prompts[TodoListType.TO_LEARN] = {
|
||||
@@ -133,10 +102,10 @@ class AIAgent(BaseAIAgent):
|
||||
self.chat_db = None
|
||||
self.unread_msg = Queue() # msg from other agent
|
||||
self.owenr_bus = None
|
||||
self.enable_function_list = None
|
||||
|
||||
self.memory : AgentMemory = None
|
||||
self.prviate_workspace : AgentWorkspace = None
|
||||
|
||||
self.behaviors:Dict[str,BaseLLMProcess] = {}
|
||||
|
||||
|
||||
@@ -161,7 +130,6 @@ class AIAgent(BaseAIAgent):
|
||||
logger.error("agent instance_id is None!")
|
||||
return False
|
||||
self.agent_id = config["instance_id"]
|
||||
self.agent_workspace = config["workspace"]
|
||||
|
||||
if config.get("fullname") is None:
|
||||
logger.error(f"agent {self.agent_id} fullname is None!")
|
||||
@@ -171,43 +139,6 @@ class AIAgent(BaseAIAgent):
|
||||
if config.get("enable_thread") is not None:
|
||||
self.enable_thread = bool(config["enable_thread"])
|
||||
|
||||
if config.get("prompt") is not None:
|
||||
self.agent_prompt = LLMPrompt()
|
||||
self.agent_prompt.load_from_config(config["prompt"])
|
||||
|
||||
if config.get("think_prompt") is not None:
|
||||
self.agent_think_prompt = LLMPrompt()
|
||||
self.agent_think_prompt.load_from_config(config["think_prompt"])
|
||||
|
||||
def load_todo_config(todo_type:str) -> bool:
|
||||
todo_config = config.get(todo_type)
|
||||
if todo_config is not None:
|
||||
if todo_config.get("do") is not None:
|
||||
prompt = LLMPrompt()
|
||||
prompt.load_from_config(todo_config["do"])
|
||||
self.todo_prompts[todo_type]["do"] = prompt
|
||||
if todo_config.get("check") is not None:
|
||||
prompt = LLMPrompt()
|
||||
prompt.load_from_config(todo_config["check"])
|
||||
self.todo_prompts[todo_type]["check"] = prompt
|
||||
if todo_config.get("review_prompt") is not None:
|
||||
prompt = LLMPrompt()
|
||||
prompt.load_from_config(todo_config["review_prompt"])
|
||||
self.todo_prompts[todo_type]["review"] = prompt
|
||||
|
||||
load_todo_config(TodoListType.TO_WORK)
|
||||
load_todo_config(TodoListType.TO_LEARN)
|
||||
|
||||
if config.get("guest_prompt") is not None:
|
||||
self.guest_prompt_str = config["guest_prompt"]
|
||||
|
||||
if config.get("owner_prompt") is not None:
|
||||
self.owner_promp_str = config["owner_prompt"]
|
||||
|
||||
if config.get("contact_prompt") is not None:
|
||||
self.contact_prompt_str = config["contact_prompt"]
|
||||
|
||||
|
||||
if config.get("powerby") is not None:
|
||||
self.powerby = config["powerby"]
|
||||
if config.get("template_id") is not None:
|
||||
@@ -265,62 +196,11 @@ class AIAgent(BaseAIAgent):
|
||||
def get_agent_role_prompt(self) -> LLMPrompt:
|
||||
return self.role_prompt
|
||||
|
||||
def _get_remote_user_prompt(self,remote_user:str) -> LLMPrompt:
|
||||
cm = ContactManager.get_instance()
|
||||
contact = cm.find_contact_by_name(remote_user)
|
||||
if contact is None:
|
||||
#create guest prompt
|
||||
if self.guest_prompt_str is not None:
|
||||
prompt = LLMPrompt()
|
||||
prompt.system_message = {"role":"system","content":self.guest_prompt_str}
|
||||
return prompt
|
||||
return None
|
||||
else:
|
||||
if contact.is_family_member:
|
||||
if self.owner_promp_str is not None:
|
||||
real_str = self.owner_promp_str.format_map(contact.to_dict())
|
||||
prompt = LLMPrompt()
|
||||
prompt.system_message = {"role":"system","content":real_str}
|
||||
return prompt
|
||||
else:
|
||||
if self.contact_prompt_str is not None:
|
||||
real_str = self.contact_prompt_str.format_map(contact.to_dict())
|
||||
prompt = LLMPrompt()
|
||||
prompt.system_message = {"role":"system","content":real_str}
|
||||
return prompt
|
||||
|
||||
return None
|
||||
|
||||
def get_agent_prompt(self) -> LLMPrompt:
|
||||
return self.agent_prompt
|
||||
|
||||
async def _get_agent_think_prompt(self) -> LLMPrompt:
|
||||
return self.agent_think_prompt
|
||||
|
||||
def _format_msg_by_env_value(self,prompt:LLMPrompt):
|
||||
for msg in prompt.messages:
|
||||
old_content = msg.get("content")
|
||||
msg["content"] = old_content.format_map(self.agent_workspace)
|
||||
|
||||
async def _handle_event(self,event):
|
||||
if event.type == "AgentThink":
|
||||
return await self.do_self_think()
|
||||
|
||||
def get_workspace_by_msg(self,msg:AgentMsg) -> WorkspaceEnvironment:
|
||||
return self.agent_workspace
|
||||
|
||||
def need_session_summmary(self,msg:AgentMsg,session:AIChatSession) -> bool:
|
||||
return False
|
||||
|
||||
async def _create_openai_thread(self) -> str:
|
||||
return None
|
||||
|
||||
def check_and_to_base64(self, image_path: str) -> str:
|
||||
if image_utils.is_file(image_path):
|
||||
return image_utils.to_base64(image_path, (1024, 1024))
|
||||
else:
|
||||
return image_path
|
||||
|
||||
async def llm_process_msg(self,msg:AgentMsg) -> AgentMsg:
|
||||
need_process:bool = True
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
@@ -349,7 +229,7 @@ class AIAgent(BaseAIAgent):
|
||||
elif llm_result.state == LLMResultStates.IGNORE:
|
||||
return None
|
||||
else: # OK
|
||||
resp_msg = llm_result.raw_result.get("resp_msg")
|
||||
resp_msg = llm_result.raw_result.get("_resp_msg")
|
||||
return resp_msg
|
||||
|
||||
async def _process_msg(self,msg:AgentMsg,workspace = None) -> AgentMsg:
|
||||
@@ -358,271 +238,8 @@ class AIAgent(BaseAIAgent):
|
||||
msg.context_info["now"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
msg.context_info["weather"] = "Partly Cloudy, 60°F"
|
||||
return await self.llm_process_msg(msg)
|
||||
msg_prompt = LLMPrompt()
|
||||
need_process = True
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
need_process = False
|
||||
|
||||
session_topic = msg.target + "#" + msg.topic
|
||||
chatsession = AIChatSession.get_session(self.agent_id,session_topic,self.chat_db)
|
||||
|
||||
if msg.mentions is not None:
|
||||
if self.agent_id in msg.mentions:
|
||||
need_process = True
|
||||
logger.info(f"agent {self.agent_id} recv a group chat message from {msg.sender},but is not mentioned,ignore!")
|
||||
else:
|
||||
if msg.is_image_msg():
|
||||
image_prompt, images = msg.get_image_body()
|
||||
if image_prompt is None:
|
||||
msg_prompt.messages = [{"role": "user", "content": [{"type": "image_url", "image_url": {"url": self.check_and_to_base64(image)}} for image in images]}]
|
||||
else:
|
||||
content = [{"type": "text", "text": image_prompt}]
|
||||
content.extend([{"type": "image_url", "image_url": {"url": self.check_and_to_base64(image)}} for image in images])
|
||||
msg_prompt.messages = [{"role": "user", "content": content}]
|
||||
elif msg.is_video_msg():
|
||||
video_prompt, video = msg.get_video_body()
|
||||
frames = video_utils.extract_frames(video, (1024, 1024))
|
||||
if video_prompt is None:
|
||||
msg_prompt.messages = [{"role": "user", "content": [{"type": "image_url", "image_url": {"url": frame}} for frame in frames]}]
|
||||
else:
|
||||
content = [{"type": "text", "text": video_prompt}]
|
||||
content.extend([{"type": "image_url", "image_url": {"url": frame}} for frame in frames])
|
||||
msg_prompt.messages = [{"role": "user", "content": content}]
|
||||
elif msg.is_audio_msg():
|
||||
audio_file = msg.body
|
||||
resp = await (ComputeKernel.get_instance().do_speech_to_text(audio_file, None, prompt=None, response_format="text"))
|
||||
if resp.result_code != ComputeTaskResultCode.OK:
|
||||
error_resp = msg.create_error_resp(resp.error_str)
|
||||
return error_resp
|
||||
else:
|
||||
msg.body = resp.result_str
|
||||
msg_prompt.messages = [{"role":"user","content":resp.result_str}]
|
||||
else:
|
||||
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
||||
session_topic = msg.get_sender() + "#" + msg.topic
|
||||
chatsession = AIChatSession.get_session(self.agent_id,session_topic,self.chat_db)
|
||||
if self.enable_thread:
|
||||
need_create_thread = False
|
||||
if chatsession.openai_thread_id is not None:
|
||||
if len(chatsession.openai_thread_id) < 1:
|
||||
need_create_thread = True
|
||||
else:
|
||||
need_create_thread = True
|
||||
|
||||
if need_create_thread:
|
||||
openai_thread_id = await self._create_openai_thread()
|
||||
if openai_thread_id is not None:
|
||||
chatsession.update_openai_thread_id(openai_thread_id)
|
||||
|
||||
|
||||
workspace = self.get_workspace_by_msg(msg)
|
||||
|
||||
prompt = LLMPrompt()
|
||||
if workspace:
|
||||
prompt.append(workspace.get_prompt())
|
||||
prompt.append(workspace.get_role_prompt(self.agent_id))
|
||||
|
||||
prompt.append(self.get_agent_prompt())
|
||||
prompt.append(self._get_remote_user_prompt(msg.sender))
|
||||
self._format_msg_by_env_value(prompt)
|
||||
|
||||
if self.need_session_summmary(msg,chatsession):
|
||||
# get relate session(todos) summary
|
||||
summary = self.llm_select_session_summary(msg,chatsession)
|
||||
prompt.append(LLMPrompt(summary))
|
||||
|
||||
known_info_str = "# Known information\n"
|
||||
have_known_info = False
|
||||
todos_str,todo_count = await workspace.todo_list[TodoListType.TO_WORK].get_todo_tree()
|
||||
if todo_count > 0:
|
||||
have_known_info = True
|
||||
known_info_str += f"## todo\n{todos_str}\n"
|
||||
inner_functions,function_token_len = BaseAIAgent.get_inner_functions(self.agent_workspace)
|
||||
system_prompt_len = ComputeKernel.llm_num_tokens(prompt)
|
||||
input_len = len(msg.body)
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
history_str,history_token_len = await self._get_prompt_from_session_for_groupchat(chatsession,system_prompt_len + function_token_len,input_len)
|
||||
else:
|
||||
history_str,history_token_len = await self.get_prompt_from_session(chatsession,system_prompt_len + function_token_len,input_len)
|
||||
if history_str:
|
||||
have_known_info = True
|
||||
known_info_str += history_str
|
||||
|
||||
if have_known_info:
|
||||
known_info_prompt = LLMPrompt(known_info_str)
|
||||
prompt.append(known_info_prompt) # chat context
|
||||
|
||||
prompt.append(msg_prompt)
|
||||
|
||||
|
||||
logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
|
||||
task_result = await self.do_llm_complection(prompt,msg, inner_functions=inner_functions)
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
error_resp = msg.create_error_resp(task_result.error_str)
|
||||
return error_resp
|
||||
|
||||
final_result = task_result.result_str
|
||||
if final_result is not None:
|
||||
llm_result : LLMResult = LLMResult.from_str(final_result)
|
||||
else:
|
||||
llm_result = LLMResult()
|
||||
llm_result.state = "ignore"
|
||||
|
||||
if llm_result.resp is None:
|
||||
if llm_result.raw_resp:
|
||||
final_result = json.dumps(llm_result.raw_resp)
|
||||
else:
|
||||
final_result = llm_result.resp
|
||||
|
||||
|
||||
await workspace.exec_op_list(llm_result.action_list,self.agent_id)
|
||||
|
||||
is_ignore = False
|
||||
result_prompt_str = ""
|
||||
match llm_result.state:
|
||||
case "ignore":
|
||||
is_ignore = True
|
||||
case "waiting": # like inner call
|
||||
for sendmsg in llm_result.send_msgs:
|
||||
sendmsg.sender = self.agent_id
|
||||
target = sendmsg.target
|
||||
sendmsg.topic = msg.topic
|
||||
sendmsg.prev_msg_id = msg.get_msg_id()
|
||||
send_resp = await AIBus.get_default_bus().send_message(sendmsg)
|
||||
if send_resp is not None:
|
||||
result_prompt_str += f"\n{target} response is :{send_resp.body}"
|
||||
agent_sesion = AIChatSession.get_session(self.agent_id,f"{sendmsg.target}#{sendmsg.topic}",self.chat_db)
|
||||
agent_sesion.append(sendmsg)
|
||||
agent_sesion.append(send_resp)
|
||||
|
||||
final_result = llm_result.resp + result_prompt_str
|
||||
|
||||
if is_ignore is not True:
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
resp_msg = msg.create_group_resp_msg(self.agent_id,final_result)
|
||||
else:
|
||||
resp_msg = msg.create_resp_msg(final_result)
|
||||
chatsession.append(msg)
|
||||
chatsession.append(resp_msg)
|
||||
|
||||
return resp_msg
|
||||
|
||||
return None
|
||||
|
||||
|
||||
async def _get_history_prompt_for_think(self,chatsession:AIChatSession,summary:str,system_token_len:int,pos:int)->(LLMPrompt,int):
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len
|
||||
|
||||
messages = chatsession.read_history(self.history_len,pos,"natural") # read
|
||||
result_token_len = 0
|
||||
result_prompt = LLMPrompt()
|
||||
have_summary = False
|
||||
if summary is not None:
|
||||
if len(summary) > 1:
|
||||
have_summary = True
|
||||
|
||||
if have_summary:
|
||||
result_prompt.messages.append({"role":"user","content":summary})
|
||||
result_token_len -= len(summary)
|
||||
else:
|
||||
result_prompt.messages.append({"role":"user","content":"There is no summary yet."})
|
||||
result_token_len -= 6
|
||||
|
||||
read_history_msg = 0
|
||||
history_str : str = ""
|
||||
for msg in messages:
|
||||
read_history_msg += 1
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
history_str = history_str + record_str
|
||||
|
||||
history_len -= len(msg.body)
|
||||
result_token_len += len(msg.body)
|
||||
if history_len < 0:
|
||||
logger.warning(f"_get_prompt_from_session reach limit of token,just read {read_history_msg} history message.")
|
||||
break
|
||||
|
||||
result_prompt.messages.append({"role":"user","content":history_str})
|
||||
return result_prompt,pos+read_history_msg
|
||||
|
||||
async def _get_prompt_from_session_for_groupchat(self,chatsession:AIChatSession,system_token_len,input_token_len,is_groupchat=False):
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len - input_token_len
|
||||
messages = chatsession.read_history(self.history_len) # read
|
||||
result_token_len = 0
|
||||
result_prompt = LLMPrompt()
|
||||
read_history_msg = 0
|
||||
for msg in reversed(messages):
|
||||
read_history_msg += 1
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
|
||||
if msg.sender == self.agent_id:
|
||||
if self.enable_timestamp:
|
||||
result_prompt.messages.append({"role":"assistant","content":f"(create on {formatted_time}) {msg.body} "})
|
||||
else:
|
||||
result_prompt.messages.append({"role":"assistant","content":msg.body})
|
||||
|
||||
else:
|
||||
if self.enable_timestamp:
|
||||
result_prompt.messages.append({"role":"user","content":f"(create on {formatted_time}) {msg.body} "})
|
||||
else:
|
||||
result_prompt.messages.append({"role":"user","content":f"{msg.sender}:{msg.body}"})
|
||||
|
||||
history_len -= len(msg.body)
|
||||
result_token_len += len(msg.body)
|
||||
if history_len < 0:
|
||||
logger.warning(f"_get_prompt_from_session reach limit of token,just read {read_history_msg} history message.")
|
||||
break
|
||||
|
||||
return result_prompt,result_token_len
|
||||
|
||||
|
||||
|
||||
async def _llm_summary_work(self,workspace:WorkspaceEnvironment):
|
||||
# read report ,and update work summary of
|
||||
# build todo list from work summary and goals
|
||||
#
|
||||
report_list = self.get_unread_reports()
|
||||
|
||||
for report in report_list:
|
||||
if self.agent_energy <= 0:
|
||||
break
|
||||
# merge report to work summary
|
||||
await self._llm_read_report(report,workspace)
|
||||
self.agent_energy -= 1
|
||||
|
||||
if workspace.is_mgr(self.agent_id):
|
||||
# manager can do more work
|
||||
await self._llm_review_team(workspace)
|
||||
self.agent_energy -= 5
|
||||
await self._llm_review_unassigned_todos(workspace)
|
||||
self.agent_energy -= 5
|
||||
|
||||
|
||||
async def _llm_review_team(self,workspace:WorkspaceEnvironment):
|
||||
pass
|
||||
|
||||
async def _llm_review_unassigned_todos(self,workspace:WorkspaceEnvironment):
|
||||
pass
|
||||
|
||||
async def _llm_read_report(self,report,worksapce:WorkspaceEnvironment):
|
||||
work_summary = worksapce.get_work_summary(self.agent_id)
|
||||
prompt : LLMPrompt = LLMPrompt()
|
||||
prompt.append(self.agent_prompt)
|
||||
prompt.append(worksapce.get_role_prompt(self.agent_id))
|
||||
prompt.append(self.read_report_prompt)
|
||||
# report is a message from other agent(human) about work
|
||||
prompt.append(LLMPrompt(work_summary))
|
||||
prompt.append(LLMPrompt(report.content))
|
||||
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt)
|
||||
|
||||
if task_result.error_str is not None:
|
||||
logger.error(f"_llm_read_report compute error:{task_result.error_str}")
|
||||
return
|
||||
|
||||
worksapce.set_work_summary(self.agent_id,task_result.result_str)
|
||||
|
||||
async def _llm_run_todo_list(self, todo_list_type: TodoListType):
|
||||
workspace : WorkspaceEnvironment = self.get_workspace_by_msg(None)
|
||||
@@ -872,82 +489,11 @@ class AIAgent(BaseAIAgent):
|
||||
async def think_todo_log(self,todo_log:AgentWorkLog):
|
||||
pass
|
||||
|
||||
async def think_chatsession(self,session_id):
|
||||
if self.agent_think_prompt is None:
|
||||
return
|
||||
logger.info(f"agent {self.agent_id} think session {session_id}")
|
||||
chatsession = AIChatSession.get_session_by_id(session_id,self.chat_db)
|
||||
|
||||
while True:
|
||||
cur_pos = chatsession.summarize_pos
|
||||
summary = chatsession.summary
|
||||
prompt:LLMPrompt = LLMPrompt()
|
||||
#prompt.append(self._get_agent_prompt())
|
||||
prompt.append(await self._get_agent_think_prompt())
|
||||
system_prompt_len = ComputeKernel.llm_num_tokens(prompt)
|
||||
#think env?
|
||||
history_prompt,next_pos = await self._get_history_prompt_for_think(chatsession,summary,system_prompt_len,cur_pos)
|
||||
prompt.append(history_prompt)
|
||||
is_finish = next_pos - cur_pos < 2
|
||||
if is_finish:
|
||||
logger.info(f"agent {self.agent_id} think session {session_id} is finished!,no more history")
|
||||
break
|
||||
#3) llm summarize chat history
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt)
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
logger.error(f"think_chatsession llm compute error:{task_result.error_str}")
|
||||
break
|
||||
else:
|
||||
new_summary= task_result.result_str
|
||||
logger.info(f"agent {self.agent_id} think session {session_id} from {cur_pos} to {next_pos} summary:{new_summary}")
|
||||
chatsession.update_think_progress(next_pos,new_summary)
|
||||
return
|
||||
|
||||
async def get_prompt_from_session(self,chatsession:AIChatSession,system_token_len,input_token_len) -> LLMPrompt:
|
||||
# TODO: get prompt from group chat is different from single chat
|
||||
if self.enable_thread:
|
||||
return None
|
||||
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len - input_token_len
|
||||
messages = chatsession.read_history(self.history_len) # read
|
||||
result_token_len = 0
|
||||
|
||||
read_history_msg = 0
|
||||
have_known_info = False
|
||||
|
||||
known_info = ""
|
||||
if chatsession.summary is not None:
|
||||
if len(chatsession.summary) > 1:
|
||||
known_info += f"## Recent conversation summary \n {chatsession.summary}\n"
|
||||
result_token_len -= len(chatsession.summary)
|
||||
have_known_info = True
|
||||
|
||||
histroy_str = ""
|
||||
for msg in reversed(messages):
|
||||
read_history_msg += 1
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
have_known_info = True
|
||||
histroy_str = histroy_str + record_str
|
||||
|
||||
history_len -= len(msg.body)
|
||||
result_token_len += len(msg.body)
|
||||
if history_len < 0:
|
||||
logger.warning(f"_get_prompt_from_session reach limit of token,just read {read_history_msg} history message.")
|
||||
break
|
||||
|
||||
known_info += f"## Recent conversation history \n {histroy_str}\n"
|
||||
|
||||
if have_known_info:
|
||||
return known_info,result_token_len
|
||||
return None,0
|
||||
|
||||
|
||||
def need_self_think(self) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def wake_up(self) -> None:
|
||||
if self.agent_task is None:
|
||||
self.agent_task = asyncio.create_task(self._on_timer())
|
||||
@@ -971,9 +517,9 @@ class AIAgent(BaseAIAgent):
|
||||
continue
|
||||
|
||||
# complete & check todo
|
||||
await self._llm_run_todo_list(TodoListType.TO_WORK)
|
||||
#await self._llm_run_todo_list(TodoListType.TO_WORK)
|
||||
|
||||
await self._llm_run_todo_list(TodoListType.TO_LEARN)
|
||||
##await self._llm_run_todo_list(TodoListType.TO_LEARN)
|
||||
|
||||
if self.need_self_think():
|
||||
await self.do_self_think()
|
||||
|
||||
@@ -1,27 +1,9 @@
|
||||
# pylint:disable=E0402
|
||||
|
||||
import abc
|
||||
import copy
|
||||
from abc import abstractmethod
|
||||
from datetime import datetime, timedelta
|
||||
import logging
|
||||
from enum import Enum
|
||||
import uuid
|
||||
import time
|
||||
import re
|
||||
import shlex
|
||||
import json
|
||||
from typing import List, Tuple
|
||||
|
||||
from ..proto.ai_function import *
|
||||
from ..proto.agent_msg import *
|
||||
from ..proto.compute_task import *
|
||||
from ..environment.environment import *
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
|
||||
from ..proto.agent_msg import AgentMsg
|
||||
|
||||
class BaseAIAgent(abc.ABC):
|
||||
@abstractmethod
|
||||
@@ -40,139 +22,6 @@ class BaseAIAgent(abc.ABC):
|
||||
async def _process_msg(self,msg:AgentMsg,workspace = None) -> AgentMsg:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_inner_functions(cls, env:BaseEnvironment) -> (dict,int):
|
||||
if env is None:
|
||||
return None,0
|
||||
|
||||
all_inner_function = env.get_all_ai_functions()
|
||||
if all_inner_function is None:
|
||||
return None,0
|
||||
|
||||
result_func = []
|
||||
result_len = 0
|
||||
for inner_func in all_inner_function:
|
||||
func_name = inner_func.get_name()
|
||||
this_func = {}
|
||||
this_func["name"] = func_name
|
||||
this_func["description"] = inner_func.get_description()
|
||||
this_func["parameters"] = inner_func.get_parameters()
|
||||
result_len += len(json.dumps(this_func)) / 4
|
||||
result_func.append(this_func)
|
||||
|
||||
return result_func,result_len
|
||||
|
||||
async def do_llm_complection(
|
||||
self,
|
||||
prompt:LLMPrompt,
|
||||
org_msg:AgentMsg=None,
|
||||
env:BaseEnvironment=None,
|
||||
inner_functions=None,
|
||||
is_json_resp=False,
|
||||
) -> ComputeTaskResult:
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
|
||||
#logger.debug(f"Agent {self.agent_id} do llm token static system:{system_prompt_len},function:{function_token_len},history:{history_token_len},input:{input_len}, totoal prompt:{system_prompt_len + function_token_len + history_token_len} ")
|
||||
if inner_functions is None and env is not None:
|
||||
inner_functions,_ = BaseAIAgent.get_inner_functions(env)
|
||||
|
||||
model_name = self.get_llm_model_name()
|
||||
if org_msg.is_video_msg() or org_msg.is_image_msg():
|
||||
if model_name.startswith("gpt-4"):
|
||||
model_name = "gpt-4-vision-preview"
|
||||
if is_json_resp:
|
||||
task_result: ComputeTaskResult = await (ComputeKernel.get_instance()
|
||||
.do_llm_completion(
|
||||
prompt,
|
||||
resp_mode="json",
|
||||
mode_name=model_name,
|
||||
max_token=self.get_max_token_size(),
|
||||
inner_functions=inner_functions,
|
||||
timeout=None))
|
||||
else:
|
||||
task_result: ComputeTaskResult = await (ComputeKernel.get_instance()
|
||||
.do_llm_completion(
|
||||
prompt,
|
||||
resp_mode="text",
|
||||
mode_name=model_name,
|
||||
max_token=self.get_max_token_size(),
|
||||
inner_functions=inner_functions,
|
||||
timeout=None))
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
logger.error(f"_do_llm_complection llm compute error:{task_result.error_str}")
|
||||
#error_resp = msg.create_error_resp(task_result.error_str)
|
||||
return task_result
|
||||
|
||||
result_message = task_result.result.get("message")
|
||||
inner_func_call_node = None
|
||||
if result_message:
|
||||
inner_func_call_node = result_message.get("function_call")
|
||||
|
||||
if inner_func_call_node:
|
||||
call_prompt : LLMPrompt = copy.deepcopy(prompt)
|
||||
func_msg = copy.deepcopy(result_message)
|
||||
del func_msg["tool_calls"]
|
||||
call_prompt.messages.append(func_msg)
|
||||
task_result = await self._execute_func(env,inner_func_call_node,call_prompt,inner_functions,org_msg)
|
||||
|
||||
return task_result
|
||||
|
||||
async def _execute_func(
|
||||
self,
|
||||
env: BaseEnvironment,
|
||||
inner_func_call_node: dict,
|
||||
prompt: LLMPrompt,
|
||||
inner_functions: dict,
|
||||
org_msg:AgentMsg,
|
||||
stack_limit = 5
|
||||
) -> ComputeTaskResult:
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
arguments = None
|
||||
try:
|
||||
func_name = inner_func_call_node.get("name")
|
||||
arguments = json.loads(inner_func_call_node.get("arguments"))
|
||||
logger.info(f"llm execute inner func:{func_name} ({json.dumps(arguments)})")
|
||||
|
||||
func_node : AIFunction = env.get_ai_function(func_name)
|
||||
if func_node is None:
|
||||
result_str = f"execute {func_name} error,function not found"
|
||||
else:
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
except Exception as e:
|
||||
result_str = f"execute {func_name} error:{str(e)}"
|
||||
logger.error(f"llm execute inner func:{func_name} error:{e}")
|
||||
|
||||
|
||||
logger.info("llm execute inner func result:" + result_str)
|
||||
|
||||
prompt.messages.append({"role":"function","content":result_str,"name":func_name})
|
||||
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,mode_name=self.get_llm_model_name(),max_token=self.get_max_token_size(),inner_functions=inner_functions)
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
logger.error(f"llm compute error:{task_result.error_str}")
|
||||
return task_result
|
||||
|
||||
if org_msg:
|
||||
internal_call_record = AgentMsg.create_internal_call_msg(func_name,arguments,org_msg.get_msg_id(),org_msg.target)
|
||||
internal_call_record.result_str = task_result.result_str
|
||||
internal_call_record.done_time = time.time()
|
||||
org_msg.inner_call_chain.append(internal_call_record)
|
||||
|
||||
inner_func_call_node = None
|
||||
if stack_limit > 0:
|
||||
result_message : dict = task_result.result.get("message")
|
||||
if result_message:
|
||||
inner_func_call_node = result_message.get("function_call")
|
||||
if inner_func_call_node:
|
||||
func_msg = copy.deepcopy(result_message)
|
||||
del func_msg["tool_calls"]
|
||||
prompt.messages.append(func_msg)
|
||||
|
||||
if inner_func_call_node:
|
||||
return await self._execute_func(env,inner_func_call_node,prompt,inner_functions,org_msg,stack_limit-1)
|
||||
else:
|
||||
return task_result
|
||||
|
||||
|
||||
class CustomAIAgent(BaseAIAgent):
|
||||
def __init__(self, agent_id: str, llm_model_name: str, max_token_size: int) -> None:
|
||||
self.agent_id = agent_id
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
from ast import Dict
|
||||
from datetime import timedelta
|
||||
from typing import List
|
||||
# pylint:disable=E0402
|
||||
from datetime import datetime,timedelta
|
||||
from typing import Dict
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..proto.ai_function import SimpleAIOperation
|
||||
from ..proto.ai_function import SimpleAIAction
|
||||
from ..proto.agent_msg import AgentMsg, AgentMsgType
|
||||
|
||||
from .chatsession import *
|
||||
from .llm_context import GlobaToolsLibrary
|
||||
from .chatsession import AIChatSession
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AgentMemory:
|
||||
def __init__(self,agent_id:str,db_path:str) -> None:
|
||||
@@ -14,12 +20,16 @@ class AgentMemory:
|
||||
self.model_name:str = "gp4-1106-preview"
|
||||
self.threshold_hours = 72
|
||||
|
||||
self.actions = {}
|
||||
self.init_actions()
|
||||
|
||||
def init_actions(self) -> Dict:
|
||||
chatlog_append_op = SimpleAIOperation("chatlog_append","Append request & reply message to chatlog. No params",self.action_chatlog_append)
|
||||
self.actions[chatlog_append_op.get_name()] = chatlog_append_op
|
||||
@classmethod
|
||||
def register_actions(cls):
|
||||
async def action_chatlog_append(parms:Dict):
|
||||
memory = parms.get("_memory")
|
||||
if memory:
|
||||
return await memory.action_chatlog_append(parms)
|
||||
|
||||
chatlog_append_action = SimpleAIAction("chatlog_append","Append request & reply message to chatlog. No params",action_chatlog_append)
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(chatlog_append_action,"agent.memory.chatlog.append")
|
||||
|
||||
|
||||
def get_session_from_msg(self,msg:AgentMsg) -> AIChatSession:
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
@@ -32,8 +42,8 @@ class AgentMemory:
|
||||
|
||||
async def load_chatlogs(self,msg:AgentMsg,n:int=6,m:int=64,token_limit=800)->str:
|
||||
chatsession = self.get_session_from_msg(msg)
|
||||
# 必定加载n条(n>=2),期望加载m条
|
||||
# m条里的信息逐步添加,知道距离现在的时间未72小时以上,且消耗了足够的Token
|
||||
# Must load n (n> = 2), and hope to load the M
|
||||
# The information in the # M is gradually added, knowing that it is less than 72 hours from the current time, and consumes enough tokens
|
||||
|
||||
messages_n = chatsession.read_history(n) # read
|
||||
if len(messages_n) >= n:
|
||||
@@ -44,7 +54,7 @@ class AgentMemory:
|
||||
histroy_str = ""
|
||||
read_count = 0
|
||||
for msg in messages_n:
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
dt = datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
token_limit -= ComputeKernel.llm_num_tokens_from_text(record_str,self.model_name)
|
||||
@@ -57,9 +67,9 @@ class AgentMemory:
|
||||
if read_count < 3:
|
||||
logging.warning(f"read history {read_count} < 3, will not load more")
|
||||
|
||||
now = datetime.datetime.now()
|
||||
now = datetime.now()
|
||||
for msg in messages_m:
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
dt = datetime.fromtimestamp(float(msg.create_time))
|
||||
time_diff = now - dt
|
||||
if time_diff > timedelta(hours=self.threshold_hours):
|
||||
break
|
||||
@@ -95,10 +105,18 @@ class AgentMemory:
|
||||
return "lzc is your master. Male, 40 years old, Mother tongue is Chinese, senior software engineer."
|
||||
return None
|
||||
|
||||
def get_actions(self) -> Dict:
|
||||
return self.actions
|
||||
async def update_contact_summary(self,contact_id:str,summary:str) -> str:
|
||||
return "OK"
|
||||
|
||||
async def get_sth_summary(self,sth_id:str) -> str:
|
||||
return None
|
||||
|
||||
async def update_sth_summary(self,sth_id:str,summary:str) -> str:
|
||||
return None
|
||||
|
||||
async def get_log_summary(self,msg:AgentMsg) -> str:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
# pylint:disable=E0402
|
||||
import sqlite3 # Because sqlite3 IO operation is small, so we can use sqlite3 directly.(so we don't need to use async sqlite3 now)
|
||||
from sqlite3 import Error
|
||||
import logging
|
||||
@@ -38,9 +38,10 @@ class ChatSessionDB:
|
||||
return conn
|
||||
|
||||
def close(self):
|
||||
if not hasattr(self.local, 'conn'):
|
||||
local = threading.local()
|
||||
if not hasattr(local, 'conn'):
|
||||
return
|
||||
self.local.conn.close()
|
||||
local.conn.close()
|
||||
|
||||
def _create_table(self, conn):
|
||||
""" create table """
|
||||
@@ -119,7 +120,7 @@ class ChatSessionDB:
|
||||
match msg.msg_type:
|
||||
case AgentMsgType.TYPE_MSG:
|
||||
pass
|
||||
case AgentMsgType.TYPE_ACTION:
|
||||
case AgentMsgType.TYPE_ACTION:# THIS Action is not AIAction
|
||||
action_name = msg.func_name
|
||||
action_params = json.dumps(msg.args)
|
||||
action_result = msg.result_str
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
# pylint:disable=E0402
|
||||
from abc import ABC, abstractmethod
|
||||
import json
|
||||
import logging
|
||||
from typing import Optional,Set,List,Dict,Callable
|
||||
|
||||
from ..proto.ai_function import AIFunction,AIAction,SimpleAIAction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class LLMProcessContext:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@staticmethod
|
||||
def function2action(ai_func:AIFunction) -> AIAction:
|
||||
async def exec_func(params:Dict) -> str:
|
||||
return await ai_func.execute(params)
|
||||
return SimpleAIAction(ai_func.get_name(),ai_func.get_detail_description(),exec_func)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def aifunction_to_inner_function(self,all_inner_function:List[AIFunction]) -> List[Dict]:
|
||||
result_func = []
|
||||
result_len = 0
|
||||
for inner_func in all_inner_function:
|
||||
func_name = inner_func.get_name()
|
||||
this_func = {}
|
||||
this_func["name"] = func_name
|
||||
this_func["description"] = inner_func.get_description()
|
||||
this_func["parameters"] = inner_func.get_openai_parameters()
|
||||
result_len += len(json.dumps(this_func)) / 4
|
||||
result_func.append(this_func)
|
||||
return result_func
|
||||
|
||||
@abstractmethod
|
||||
def get_ai_function(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
def get_all_ai_functions(self) -> List[AIFunction]:
|
||||
return self.get_function_set(None)
|
||||
|
||||
@abstractmethod
|
||||
def get_function_set(self,set_name:str = None) -> List[AIFunction]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_ai_action(self,op_name:str) -> AIAction:
|
||||
pass
|
||||
|
||||
def get_all_ai_action(self) -> List[AIAction]:
|
||||
return self.get_action_set(None)
|
||||
|
||||
@abstractmethod
|
||||
def get_action_set(self,set_name:str = None) -> List[AIFunction]:
|
||||
pass
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.get_value(key)
|
||||
|
||||
@abstractmethod
|
||||
def get_value(self,key:str) -> Optional[str]:
|
||||
pass
|
||||
|
||||
def list_actions(self,path:str) -> List[AIAction]:
|
||||
return "No more actions!"
|
||||
|
||||
def list_functions(self,path:str) -> List[AIFunction]:
|
||||
return "No more tool functions!"
|
||||
|
||||
class GlobaToolsLibrary:
|
||||
@classmethod
|
||||
def get_instance(cls) -> 'GlobaToolsLibrary':
|
||||
if cls._instance is None:
|
||||
cls._instance = GlobaToolsLibrary()
|
||||
return cls._instance
|
||||
|
||||
def __init__(self,global_env_name:str = None) -> None:
|
||||
self.all_preset_context = {}
|
||||
self.all_tool_functions : Dict[str,AIFunction] = {}
|
||||
self.all_action_sets : Dict[str,Set[str]] = {}
|
||||
self.all_function_sets : Dict[str,Set[str]] = {}
|
||||
|
||||
def register_prset_context(self,preset_id:str,context) -> None:
|
||||
self.all_preset_context[preset_id] = context
|
||||
|
||||
def get_preset_context(self,preset_id:str):
|
||||
return self.all_preset_context.get(preset_id)
|
||||
|
||||
def register_tool_function(self,function:AIFunction) -> None:
|
||||
if self.all_tool_functions.get(function.get_name()):
|
||||
logger.warning(f"Tool function {function.get_name()} already exists! will be replaced!")
|
||||
|
||||
self.all_tool_functions[function.get_name()] = function
|
||||
|
||||
def get_tool_function(self,function_name:str) -> AIFunction:
|
||||
return self.all_tool_functions.get(function_name)
|
||||
|
||||
def register_function_set(self,set_name:str,function_set:Set[str]) -> None:
|
||||
self.all_function_sets[set_name] = function_set
|
||||
|
||||
def get_function_set(self,set_name:str) -> Set[str]:
|
||||
return self.all_function_sets.get(set_name)
|
||||
|
||||
class SimpleLLMContext(LLMProcessContext):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.parent = None
|
||||
self.values : Dict[str,str] = {}
|
||||
self.values_callback = {}
|
||||
|
||||
self.functions: Dict[str,AIFunction] = {}
|
||||
self.func_sets : Dict[str,Dict[str,AIFunction]] = {}
|
||||
self.actions: Dict[str,AIAction] = {}
|
||||
self.action_sets : Dict[str,Dict[str,AIAction]] = {}
|
||||
|
||||
def load_action_set_from_config(self,preset,config:Dict[str,str]) -> bool:
|
||||
if preset is None:
|
||||
result = {}
|
||||
else:
|
||||
result = preset
|
||||
|
||||
enable_actions = config.get("enable")
|
||||
if enable_actions:
|
||||
for action_id in enable_actions:
|
||||
ai_func = GlobaToolsLibrary.get_instance().get_tool_function(action_id)
|
||||
if ai_func:
|
||||
result[action_id] = LLMProcessContext.function2action(ai_func)
|
||||
else:
|
||||
func_set = GlobaToolsLibrary.get_instance().get_function_set(action_id)
|
||||
if func_set:
|
||||
for _func_id in func_set:
|
||||
ai_func = GlobaToolsLibrary.get_instance().get_tool_function(_func_id)
|
||||
if ai_func:
|
||||
result[_func_id] = LLMProcessContext.function2action(ai_func)
|
||||
else:
|
||||
logger.error(f"load_action_set_from_config failed! enable action id {action_id} not found!")
|
||||
return None
|
||||
|
||||
disable_actions = config.get("disable")
|
||||
for disable_action in disable_actions:
|
||||
if result.get(disable_action):
|
||||
result.pop(disable_action)
|
||||
else:
|
||||
func_set = GlobaToolsLibrary.get_instance().get_function_set(action_id)
|
||||
if func_set:
|
||||
for _func_id in func_set:
|
||||
if result.get(_func_id):
|
||||
result.pop(_func_id)
|
||||
else:
|
||||
logger.error(f"load_action_set_from_config failed! disable action id {action_id} not found!")
|
||||
return None
|
||||
|
||||
return result
|
||||
|
||||
def load_function_set_from_config(self,preset,config:Dict) -> Dict[str,AIFunction]:
|
||||
if preset is None:
|
||||
result = {}
|
||||
else:
|
||||
result = preset
|
||||
|
||||
enable_functions = config.get("enable")
|
||||
if enable_functions:
|
||||
for func_id in enable_functions:
|
||||
ai_func = GlobaToolsLibrary.get_instance().get_tool_function(func_id)
|
||||
if ai_func:
|
||||
result[func_id] = ai_func
|
||||
else:
|
||||
func_set = GlobaToolsLibrary.get_instance().get_function_set(func_id)
|
||||
if func_set:
|
||||
for func_id in func_set:
|
||||
ai_func = GlobaToolsLibrary.get_instance().get_tool_function(func_id)
|
||||
if ai_func:
|
||||
result[func_id] = ai_func
|
||||
else:
|
||||
logger.error(f"load_function_set_from_config failed! enable function id {func_id} not found!")
|
||||
return None
|
||||
else:
|
||||
logger.error(f"load_function_set_from_config failed! enable function id {func_id} not found!")
|
||||
return None
|
||||
|
||||
|
||||
disable_functions = config.get("disable")
|
||||
for disable_function in disable_functions:
|
||||
if result.get(disable_function):
|
||||
result.pop(disable_function)
|
||||
else:
|
||||
func_set = GlobaToolsLibrary.get_instance().get_function_set(func_id)
|
||||
if func_set:
|
||||
for func_id in func_set:
|
||||
if result.get(func_id):
|
||||
result.pop(func_id)
|
||||
else:
|
||||
logger.error(f"load_function_set_from_config failed! disable function id {disable_function} not found!")
|
||||
return None
|
||||
|
||||
return result
|
||||
|
||||
def load_from_config(self,config:Dict[str,str]) -> bool:
|
||||
preset = config.get("preset")
|
||||
if preset:
|
||||
self.parent:SimpleLLMContext = GlobaToolsLibrary.get_instance().get_preset_context(preset)
|
||||
if self.parent is None:
|
||||
logger.error(f"preset context {preset} not found!")
|
||||
return False
|
||||
|
||||
self.values = self.parent.values
|
||||
self.values_callback = self.parent.values_callback
|
||||
self.actions = self.parent.actions
|
||||
self.functions = self.parent.functions
|
||||
self.action_sets = self.parent.action_sets
|
||||
self.func_sets = self.parent.func_sets
|
||||
|
||||
action_def:Dict= config.get("actions")
|
||||
if action_def is None:
|
||||
logger.error(f"load_from_config failed! actions not found!")
|
||||
return False
|
||||
self.actions = self.load_action_set_from_config(self.actions,action_def)
|
||||
if self.actions is None:
|
||||
logger.error(f"load_from_config failed! load_action_set_from_config failed!")
|
||||
return False
|
||||
|
||||
for set_name in action_def.keys():
|
||||
if set_name == "enable":
|
||||
continue
|
||||
if set_name == "disable":
|
||||
continue
|
||||
|
||||
sub_set = config.get(set_name)
|
||||
self.action_sets[set_name] = self.load_action_set_from_config(None,sub_set)
|
||||
if self.action_sets[set_name] is None:
|
||||
logger.error(f"load_from_config failed! load_action_set_from_config failed!")
|
||||
return False
|
||||
|
||||
function_def:Dict = config.get("functions")
|
||||
self.functions = self.load_function_set_from_config(self.functions,function_def)
|
||||
if self.functions is None:
|
||||
logger.error(f"load_from_config failed! load_function_set_from_config failed!")
|
||||
return False
|
||||
|
||||
for set_name in function_def.keys():
|
||||
if set_name == "enable":
|
||||
continue
|
||||
if set_name == "disable":
|
||||
continue
|
||||
|
||||
sub_set = config.get(set_name)
|
||||
self.func_sets[set_name] = self.load_function_set_from_config(None,sub_set)
|
||||
if self.func_sets[set_name] is None:
|
||||
logger.error(f"load_from_config failed! load_function_set_from_config failed!")
|
||||
return False
|
||||
|
||||
#values_def = config.get("values")
|
||||
#if values_def:
|
||||
# for key,value in values_def.items():
|
||||
# self.values[key] = value
|
||||
|
||||
def get_value(self,key:str) -> Optional[str]:
|
||||
callback = self.values_callback.get(key)
|
||||
if callback:
|
||||
return callback()
|
||||
return self.values.get(key)
|
||||
|
||||
def set_value_callback(self,key:str,callback:Callable[[],str]) -> None:
|
||||
self.values_callback[key] = callback
|
||||
|
||||
def set_value(self,key:str,value:str):
|
||||
self.values[key] = value
|
||||
|
||||
#def get_ai_function(self,func_name:str) -> AIFunction:
|
||||
# func = self.functions.get(func_name)
|
||||
# if func is not None:
|
||||
# return func
|
||||
|
||||
# for set_name in self.func_sets.keys():
|
||||
# func = self.func_sets[set_name].get(func_name)
|
||||
# if func is not None:
|
||||
# return func
|
||||
|
||||
def get_function_set(self,set_name:str = None) -> List[AIFunction]:
|
||||
if set_name is None:
|
||||
return self.functions.values()
|
||||
else:
|
||||
func_set = self.func_sets.get(set_name)
|
||||
if func_set:
|
||||
return func_set.values()
|
||||
return None
|
||||
|
||||
|
||||
# def get_ai_action(self,op_name:str) -> AIOperation:
|
||||
# op = self.actions.get(op_name)
|
||||
# if op is not None:
|
||||
# return op
|
||||
# for set_name in self.action_sets.keys():
|
||||
# op = self.action_sets[set_name].get(op_name)
|
||||
# if op is not None:
|
||||
# return op
|
||||
# return None
|
||||
|
||||
def get_action_set(self,set_name:str = None) -> List[AIFunction]:
|
||||
if set_name is None:
|
||||
return self.actions.values()
|
||||
else:
|
||||
action_set = self.action_sets.get(set_name)
|
||||
if action_set:
|
||||
return action_set.values()
|
||||
return None
|
||||
|
||||
|
||||
+230
-108
@@ -1,34 +1,31 @@
|
||||
# Old name is behavior, I belive new name "llm_process" is better
|
||||
# pylint:disable=E0402
|
||||
from ..utils import video_utils,image_utils
|
||||
|
||||
from ..proto.compute_task import LLMPrompt,LLMResult,ComputeTaskResult,ComputeTaskResultCode
|
||||
from ..proto.ai_function import AIFunction,AIAction,ActionNode
|
||||
from ..proto.agent_msg import AgentMsg,AgentMsgType
|
||||
|
||||
from .agent_memory import AgentMemory
|
||||
from .workspace import AgentWorkspace
|
||||
from .llm_context import LLMProcessContext,GlobaToolsLibrary, SimpleLLMContext
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
|
||||
from abc import ABC,abstractmethod
|
||||
import copy
|
||||
import json
|
||||
import shlex
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
from typing import Any, Callable, Coroutine, Optional,Dict,Awaitable,List
|
||||
from enum import Enum
|
||||
|
||||
from aios.agent.chatsession import AIChatSession
|
||||
|
||||
from ..utils import video_utils
|
||||
|
||||
from ..proto.compute_task import *
|
||||
from ..proto.ai_function import *
|
||||
|
||||
from .agent_base import *
|
||||
from .agent_memory import *
|
||||
from .workspace import *
|
||||
|
||||
from ..frame.compute_kernel import *
|
||||
from ..environment.environment import *
|
||||
from ..environment.workspace_env import *
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
MIN_PREDICT_TOKEN_LEN = 32
|
||||
|
||||
class LLMProcessContext:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class BaseLLMProcess(ABC):
|
||||
def __init__(self) -> None:
|
||||
@@ -38,37 +35,23 @@ class BaseLLMProcess(ABC):
|
||||
self.result_example:str = None #llm_result样例
|
||||
|
||||
self.enable_json_resp = False
|
||||
self.model_name = "gpt-4"
|
||||
#None means system default,
|
||||
# TODO: support abcstract model name like: local-hight,local-low,local-medium,remote-hight,remote-low,remote-medium
|
||||
self.model_name = None
|
||||
self.max_token = 1000 # result_token
|
||||
self.max_prompt_token = 1000 # not include input prompt
|
||||
self.timeout = 1800 # 30 min
|
||||
|
||||
self.envs : Dict[str,BaseEnvironment] = []
|
||||
self.env : CompositeEnvironment = None
|
||||
|
||||
def aifunction_to_inner_function(self,all_inner_function:List[AIFunction]) -> List[Dict]:
|
||||
result_func = []
|
||||
result_len = 0
|
||||
for inner_func in all_inner_function:
|
||||
func_name = inner_func.get_name()
|
||||
this_func = {}
|
||||
this_func["name"] = func_name
|
||||
this_func["description"] = inner_func.get_description()
|
||||
this_func["parameters"] = inner_func.get_parameters()
|
||||
result_len += len(json.dumps(this_func)) / 4
|
||||
result_func.append(this_func)
|
||||
return result_func
|
||||
|
||||
@abstractmethod
|
||||
async def prepare_prompt(self,input:Dict) -> LLMPrompt:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
return GlobaToolsLibrary.get_instance().get_tool_function(func_name)
|
||||
|
||||
@abstractmethod
|
||||
async def post_llm_process(self,actions:List[ActionItem],input:Dict,llm_result:LLMResult) -> bool:
|
||||
async def post_llm_process(self,actions:List[ActionNode],input:Dict,llm_result:LLMResult) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
@@ -93,15 +76,11 @@ class BaseLLMProcess(ABC):
|
||||
@abstractmethod
|
||||
async def initial(self,params:Dict = None) -> bool:
|
||||
pass
|
||||
|
||||
def append_envs(self,envs:Dict[str,BaseEnvironment]):
|
||||
self.envs.update(envs)
|
||||
self.env = CompositeEnvironment(self.envs)
|
||||
|
||||
def _format_content_by_env_value(self,content:str,env)->str:
|
||||
return content.format_map(env)
|
||||
|
||||
async def _execute_inner_func(self,inner_func_call_node,prompt: LLMPrompt,stack_limit = 1) -> ComputeTaskResult:
|
||||
async def _execute_inner_func(self,inner_func_call_node:Dict,prompt: LLMPrompt,stack_limit = 1) -> ComputeTaskResult:
|
||||
arguments = None
|
||||
stack_limit = stack_limit - 1
|
||||
try:
|
||||
@@ -109,7 +88,7 @@ class BaseLLMProcess(ABC):
|
||||
arguments = json.loads(inner_func_call_node.get("arguments"))
|
||||
logger.info(f"LLMProcess execute inner func:{func_name} :\n\t {json.dumps(arguments)}")
|
||||
|
||||
func_node : AIFunction = await self.get_inner_function(func_name)
|
||||
func_node : AIFunction = await self.get_inner_function_for_exec(func_name)
|
||||
if func_node is None:
|
||||
result_str:str = f"execute {func_name} error,function not found"
|
||||
else:
|
||||
@@ -172,6 +151,7 @@ class BaseLLMProcess(ABC):
|
||||
else:
|
||||
resp_mode = "text"
|
||||
|
||||
# Action define in prompt, will be execute after llm compute
|
||||
prompt = await self.prepare_prompt(input)
|
||||
max_result_token = self.max_token - ComputeKernel.llm_num_tokens(prompt,self.model_name)
|
||||
if max_result_token < MIN_PREDICT_TOKEN_LEN:
|
||||
@@ -209,11 +189,61 @@ class BaseLLMProcess(ABC):
|
||||
llm_result = LLMResult.from_str(task_result.result_str)
|
||||
|
||||
# use action to save history?
|
||||
if llm_result.action_list or len(llm_result.action_list) > 0:
|
||||
await self.post_llm_process(llm_result.action_list,input,llm_result)
|
||||
await self.post_llm_process(llm_result.action_list,input,llm_result)
|
||||
|
||||
return llm_result
|
||||
|
||||
class LLMAgentBaseProcess(BaseLLMProcess):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.role_description:str = None
|
||||
self.process_description:str = None
|
||||
self.reply_format:str = None
|
||||
self.context : str = None
|
||||
|
||||
self.known_info_tips :str = None
|
||||
self.tools_tips:str = None
|
||||
|
||||
self.workspace : AgentWorkspace = None # If Workspace is not none , enable Agent Tasklist
|
||||
self.memory : AgentMemory = None
|
||||
self.kb = None
|
||||
|
||||
async def load_default_config(self) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
async def load_from_config(self, config: dict,is_load_default=True) -> Coroutine[Any, Any, bool]:
|
||||
if is_load_default:
|
||||
await self.load_default_config()
|
||||
|
||||
if await super().load_from_config(config) is False:
|
||||
return False
|
||||
|
||||
self.role_description = config.get("role_desc")
|
||||
if self.role_description is None:
|
||||
logger.error(f"role_description not found in config")
|
||||
return False
|
||||
|
||||
if config.get("process_description"):
|
||||
self.process_description = config.get("process_description")
|
||||
|
||||
if config.get("reply_format"):
|
||||
self.reply_format = config.get("reply_format")
|
||||
|
||||
if config.get("context"):
|
||||
self.context = config.get("context")
|
||||
|
||||
if config.get("known_info_tips"):
|
||||
self.known_info_tips = config.get("known_info_tips")
|
||||
|
||||
if config.get("tools_tips"):
|
||||
self.tools_tips = config.get("tools_tips")
|
||||
|
||||
if config.get("knowledge_base"):
|
||||
self.kb = config.get("knowledge_base")
|
||||
|
||||
|
||||
class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
@@ -226,27 +256,13 @@ class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
self.known_info_tips :str = None
|
||||
self.tools_tips:str = None
|
||||
|
||||
self.enable_inner_functions : Dict[str,bool] = None
|
||||
self.enable_actions : Dict[str,AIOperation] = None
|
||||
self.actions_desc : Dict[str,Dict] = None
|
||||
self.workspace : AgentWorkspace = None
|
||||
|
||||
self.workspace : AgentWorkspace = None # If Workspace is not none , enable Agent Tasklist
|
||||
self.memory : AgentMemory = None
|
||||
self.enable_kb = False
|
||||
self.kb = None
|
||||
|
||||
def init_actions(self):
|
||||
self.enable_actions = {}
|
||||
self.actions_desc = {}
|
||||
self.enable_actions.update(self.memory.get_actions())
|
||||
if self.workspace:
|
||||
self.enable_actions.update(self.workspace.get_actions())
|
||||
if self.enable_kb:
|
||||
self.enable_actions.update(self.kb.get_actions())
|
||||
self.llm_context : LLMProcessContext = None
|
||||
|
||||
for name,op in self.enable_actions.items():
|
||||
self.actions_desc[name] = op.get_description()
|
||||
|
||||
async def initial(self,params:Dict = None) -> bool:
|
||||
self.memory = params.get("memory")
|
||||
if self.memory is None:
|
||||
@@ -254,7 +270,7 @@ class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
return False
|
||||
self.workspace = params.get("workspace")
|
||||
|
||||
self.init_actions()
|
||||
|
||||
return True
|
||||
|
||||
async def load_default_config(self) -> bool:
|
||||
@@ -290,14 +306,18 @@ class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
|
||||
if config.get("enable_kb"):
|
||||
self.enable_kb = config.get("enable_kb") == "true"
|
||||
|
||||
if config.get("enable_function"):
|
||||
self.enable_inner_functions = config.get("enable_function")
|
||||
|
||||
if config.get("enable_actions"):
|
||||
self.enable_actions = config.get("enable_actions")
|
||||
|
||||
self.llm_context = SimpleLLMContext()
|
||||
if config.get("llm_context"):
|
||||
self.llm_context.load_from_config(config.get("llm_context"))
|
||||
|
||||
|
||||
|
||||
def check_and_to_base64(self, image_path: str) -> str:
|
||||
if image_utils.is_file(image_path):
|
||||
return image_utils.to_base64(image_path, (1024, 1024))
|
||||
else:
|
||||
return image_path
|
||||
|
||||
|
||||
async def get_prompt_from_msg(self,msg:AgentMsg) -> LLMPrompt:
|
||||
msg_prompt = LLMPrompt()
|
||||
@@ -334,8 +354,9 @@ class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
|
||||
async def get_action_desc(self) -> Dict:
|
||||
result = {}
|
||||
for name,op in self.enable_actions.items():
|
||||
result[name] = op.get_description()
|
||||
actions_list = self.llm_context.get_all_ai_action()
|
||||
for action in actions_list:
|
||||
result[action.get_name()] = action.get_description()
|
||||
return result
|
||||
|
||||
async def sender_info(self,msg:AgentMsg)->str:
|
||||
@@ -420,14 +441,16 @@ class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
if self.tools_tips:
|
||||
system_prompt_dict["tools_tips"] = self.tools_tips
|
||||
#prompt.append_system_message(self.tools_tips)
|
||||
prompt.inner_functions.extend(self.get_inner_function_desc_from_env())
|
||||
#self.llm_context.
|
||||
|
||||
if self.workspace:
|
||||
prompt.inner_functions.extend(self.aifunction_to_inner_function(self.workspace.get_inner_function_desc()))
|
||||
#TODO eanble workspace functions?
|
||||
logger.info(f"workspace is not none,enable workspace functions")
|
||||
|
||||
## 给予查询KB的权限
|
||||
if self.enable_kb:
|
||||
prompt.inner_functions.extend(self.get_inner_function_desc_from_kb())
|
||||
logger.info(f"enable kb")
|
||||
|
||||
|
||||
prompt.append_system_message(json.dumps(system_prompt_dict))
|
||||
## 扩展已知信息 (这可能是一个LLM过程)
|
||||
@@ -436,35 +459,41 @@ class LLMAgentMessageProcess(BaseLLMProcess):
|
||||
return prompt
|
||||
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
return self.workspace.inner_functions.get(func_name)
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
return self.llm_context.get_ai_function(func_name)
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem],input:Dict,llm_result:LLMResult) -> bool:
|
||||
msg = input.get("msg")
|
||||
async def post_llm_process(self,actions:List[ActionNode],input:Dict,llm_result:LLMResult) -> bool:
|
||||
msg:AgentMsg = input.get("msg")
|
||||
if msg.msg_type == AgentMsgType.TYPE_GROUPMSG:
|
||||
resp_msg = msg.create_group_resp_msg(self.memory.agent_id,llm_result.resp)
|
||||
else:
|
||||
resp_msg = msg.create_resp_msg(llm_result.resp)
|
||||
|
||||
llm_result.raw_result["resp_msg"] = resp_msg
|
||||
llm_result.raw_result["_resp_msg"] = resp_msg
|
||||
|
||||
for action_item in actions:
|
||||
op : AIOperation = self.enable_actions.get(action_item.name)
|
||||
op : AIAction = self.llm_context.get_ai_action(action_item.name)
|
||||
if op:
|
||||
if action_item.parms is None:
|
||||
action_item.parms = {}
|
||||
|
||||
action_item.parms["input"] = input
|
||||
action_item.parms["resp_msg"] = resp_msg
|
||||
action_item.parms["llm_result"] = llm_result
|
||||
action_item.parms["start_at"] = datetime.now()
|
||||
action_item.parms["creator"] = self.memory.agent_id
|
||||
action_item.parms["result"] = await op.execute(action_item.parms)
|
||||
action_item.parms["end_at"] = datetime.now()
|
||||
action_item.parms["_input"] = input
|
||||
action_item.parms["_memory"] = self.memory
|
||||
action_item.parms["_workspace"] = self.workspace
|
||||
action_item.parms["_resp_msg"] = resp_msg
|
||||
action_item.parms["_llm_result"] = llm_result
|
||||
action_item.parms["_start_at"] = datetime.now()
|
||||
action_item.parms["_agentid"] = self.memory.agent_id
|
||||
|
||||
action_item.parms["_result"] = await op.execute(action_item.parms)
|
||||
action_item.parms["_end_at"] = datetime.now()
|
||||
else:
|
||||
logger.warn(f"action {action_item.name} not found")
|
||||
return False
|
||||
|
||||
|
||||
chatsession = self.memory.get_session_from_msg(msg)
|
||||
chatsession.append(msg)
|
||||
chatsession.append(resp_msg)
|
||||
return True
|
||||
|
||||
|
||||
@@ -473,25 +502,50 @@ class ReviewTaskProcess(BaseLLMProcess):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
async def load_from_config(self, config: dict) -> Coroutine[Any, Any, bool]:
|
||||
self.role_description:str = None
|
||||
self.process_description:str = None
|
||||
self.reply_format = None
|
||||
|
||||
# 虽然在架构上LLM Process可以很容易的去Call另一个Process,但实际应用中还是应该慎重的保持LLM Process的简单性
|
||||
#self.do_task_llm_process : BaseLLMProcess = None
|
||||
|
||||
async def initial(self,params:Dict = None) -> bool:
|
||||
self.memory = params.get("memory")
|
||||
if self.memory is None:
|
||||
logger.error(f"LLMAgeMessageProcess initial failed! memory not found")
|
||||
return False
|
||||
self.workspace = params.get("workspace")
|
||||
|
||||
|
||||
return True
|
||||
async def load_from_config(self, config: dict):
|
||||
if await super().load_from_config(config) is False:
|
||||
return False
|
||||
|
||||
async def prepare_prompt(self) -> LLMPrompt:
|
||||
prompt = LLMPrompt()
|
||||
pass
|
||||
system_prompt_dict = {}
|
||||
system_prompt_dict["role_description"] = self.role_description
|
||||
system_prompt_dict["process_rule"] = self.process_description
|
||||
system_prompt_dict["reply_format"] = self.reply_format
|
||||
|
||||
return prompt
|
||||
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
async def get_review_task_actions(self) -> Dict[str,Dict]:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem]) -> bool:
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionNode]) -> bool:
|
||||
pass
|
||||
|
||||
class QuickReviewTaskProcess(BaseLLMProcess):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
async def load_from_config(self, config: dict) -> Coroutine[Any, Any, bool]:
|
||||
async def load_from_config(self, config: dict):
|
||||
if await super().load_from_config(config) is False:
|
||||
return False
|
||||
|
||||
@@ -499,17 +553,17 @@ class QuickReviewTaskProcess(BaseLLMProcess):
|
||||
prompt = LLMPrompt()
|
||||
pass
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem]) -> bool:
|
||||
async def post_llm_process(self,actions:List[ActionNode]) -> bool:
|
||||
pass
|
||||
|
||||
class DoTodoProcess(BaseLLMProcess):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
async def load_from_config(self, config: dict) -> Coroutine[Any, Any, bool]:
|
||||
async def load_from_config(self, config: dict):
|
||||
if await super().load_from_config(config) is False:
|
||||
return False
|
||||
|
||||
@@ -517,10 +571,10 @@ class DoTodoProcess(BaseLLMProcess):
|
||||
prompt = LLMPrompt()
|
||||
pass
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem]) -> bool:
|
||||
async def post_llm_process(self,actions:List[ActionNode]) -> bool:
|
||||
pass
|
||||
|
||||
|
||||
@@ -536,10 +590,10 @@ class CheckTodoProcess(BaseLLMProcess):
|
||||
prompt = LLMPrompt()
|
||||
pass
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem]) -> bool:
|
||||
async def post_llm_process(self,actions:List[ActionNode]) -> bool:
|
||||
pass
|
||||
|
||||
class SelfLearningProcess(BaseLLMProcess):
|
||||
@@ -554,10 +608,10 @@ class SelfLearningProcess(BaseLLMProcess):
|
||||
prompt = LLMPrompt()
|
||||
pass
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem]) -> bool:
|
||||
async def post_llm_process(self,actions:List[ActionNode]) -> bool:
|
||||
pass
|
||||
|
||||
class SelfThinkingProcess(BaseLLMProcess):
|
||||
@@ -568,14 +622,82 @@ class SelfThinkingProcess(BaseLLMProcess):
|
||||
if await super().load_from_config(config) is False:
|
||||
return False
|
||||
|
||||
|
||||
async def _get_history_prompt_for_think(self,chatsession,summary:str,system_token_len:int,pos:int)->(LLMPrompt,int):
|
||||
history_len = (self.max_token_size * 0.7) - system_token_len
|
||||
|
||||
messages = chatsession.read_history(self.history_len,pos,"natural") # read
|
||||
result_token_len = 0
|
||||
result_prompt = LLMPrompt()
|
||||
have_summary = False
|
||||
if summary is not None:
|
||||
if len(summary) > 1:
|
||||
have_summary = True
|
||||
|
||||
if have_summary:
|
||||
result_prompt.messages.append({"role":"user","content":summary})
|
||||
result_token_len -= len(summary)
|
||||
else:
|
||||
result_prompt.messages.append({"role":"user","content":"There is no summary yet."})
|
||||
result_token_len -= 6
|
||||
|
||||
read_history_msg = 0
|
||||
history_str : str = ""
|
||||
for msg in messages:
|
||||
read_history_msg += 1
|
||||
dt = datetime.datetime.fromtimestamp(float(msg.create_time))
|
||||
formatted_time = dt.strftime('%y-%m-%d %H:%M:%S')
|
||||
record_str = f"{msg.sender},[{formatted_time}]\n{msg.body}\n"
|
||||
history_str = history_str + record_str
|
||||
|
||||
history_len -= len(msg.body)
|
||||
result_token_len += len(msg.body)
|
||||
if history_len < 0:
|
||||
logger.warning(f"_get_prompt_from_session reach limit of token,just read {read_history_msg} history message.")
|
||||
break
|
||||
|
||||
result_prompt.messages.append({"role":"user","content":history_str})
|
||||
return result_prompt,pos+read_history_msg
|
||||
|
||||
async def _think_chatsession(self,session_id):
|
||||
if self.agent_think_prompt is None:
|
||||
return
|
||||
logger.info(f"agent {self.agent_id} think session {session_id}")
|
||||
chatsession = AIChatSession.get_session_by_id(session_id,self.chat_db)
|
||||
|
||||
while True:
|
||||
cur_pos = chatsession.summarize_pos
|
||||
summary = chatsession.summary
|
||||
prompt:LLMPrompt = LLMPrompt()
|
||||
#prompt.append(self._get_agent_prompt())
|
||||
prompt.append(await self._get_agent_think_prompt())
|
||||
system_prompt_len = ComputeKernel.llm_num_tokens(prompt)
|
||||
#think env?
|
||||
history_prompt,next_pos = await self._get_history_prompt_for_think(chatsession,summary,system_prompt_len,cur_pos)
|
||||
prompt.append(history_prompt)
|
||||
is_finish = next_pos - cur_pos < 2
|
||||
if is_finish:
|
||||
logger.info(f"agent {self.agent_id} think session {session_id} is finished!,no more history")
|
||||
break
|
||||
#3) llm summarize chat history
|
||||
task_result:ComputeTaskResult = await self.do_llm_complection(prompt)
|
||||
if task_result.result_code != ComputeTaskResultCode.OK:
|
||||
logger.error(f"think_chatsession llm compute error:{task_result.error_str}")
|
||||
break
|
||||
else:
|
||||
new_summary= task_result.result_str
|
||||
logger.info(f"agent {self.agent_id} think session {session_id} from {cur_pos} to {next_pos} summary:{new_summary}")
|
||||
chatsession.update_think_progress(next_pos,new_summary)
|
||||
return
|
||||
|
||||
async def prepare_prompt(self) -> LLMPrompt:
|
||||
prompt = LLMPrompt()
|
||||
pass
|
||||
|
||||
async def get_inner_function(self,func_name:str) -> AIFunction:
|
||||
async def get_inner_function_for_exec(self,func_name:str) -> AIFunction:
|
||||
pass
|
||||
|
||||
async def post_llm_process(self,actions:List[ActionItem]) -> bool:
|
||||
async def post_llm_process(self,actions:List[ActionNode]) -> bool:
|
||||
pass
|
||||
|
||||
class LLMProcessLoader:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# pylint:disable=E0402
|
||||
import logging
|
||||
|
||||
from .agent_base import LLMPrompt
|
||||
from ..proto.compute_task import LLMPrompt
|
||||
|
||||
class AIRole:
|
||||
def __init__(self) -> None:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# pylint:disable=E0402
|
||||
import logging
|
||||
import asyncio
|
||||
import json
|
||||
@@ -279,7 +280,7 @@ class Workflow:
|
||||
logger.info(f"{msg.sender} post message {msg.msg_id} to AIBus: {msg.target}")
|
||||
return await self.get_bus().send_message(msg)
|
||||
|
||||
async def role_call(self,func_item:ActionItem,the_role:AIRole):
|
||||
async def role_call(self,func_item:ActionNode,the_role:AIRole):
|
||||
logger.info(f"{the_role.role_id} call {func_item.name} ")
|
||||
arguments = func_item.args
|
||||
|
||||
@@ -290,7 +291,7 @@ class Workflow:
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
return result_str
|
||||
|
||||
async def role_post_call(self,func_item:ActionItem,the_role:AIRole):
|
||||
async def role_post_call(self,func_item:ActionNode,the_role:AIRole):
|
||||
logger.info(f"{the_role.role_id} post call {func_item.name} ")
|
||||
return await self.role_call(func_item,the_role)
|
||||
|
||||
|
||||
+41
-13
@@ -1,14 +1,17 @@
|
||||
# pylint:disable=E0402
|
||||
from ast import Dict
|
||||
import json
|
||||
import sqlite3
|
||||
import os
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
import aiofiles
|
||||
|
||||
from ..proto.ai_function import *
|
||||
from ..proto.agent_task import *
|
||||
from ..storage.storage import *
|
||||
from ..proto.ai_function import AIFunction,SimpleAIFunction,ActionNode,SimpleAIAction
|
||||
from ..proto.agent_task import AgentTask,AgentTodoTask,AgentWorkLog,AgentTaskManager
|
||||
from ..storage.storage import AIStorage
|
||||
from .llm_context import GlobaToolsLibrary
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -313,26 +316,48 @@ class AgentWorkspace:
|
||||
def __init__(self,owner_agent_id:str) -> None:
|
||||
self.agent_id : str = owner_agent_id
|
||||
self.task_mgr : AgentTaskManager = LocalAgentTaskManger(owner_agent_id)
|
||||
self.actions : Dict[str,ActionItem] = {}
|
||||
self.actions : Dict[str,ActionNode] = {}
|
||||
self.inner_functions : Dict[str,AIFunction] = {}
|
||||
|
||||
self.init_actions()
|
||||
self.init_inner_functions()
|
||||
#self.init_actions()
|
||||
#self.init_inner_functions()
|
||||
|
||||
|
||||
def init_actions(self):
|
||||
@staticmethod
|
||||
def register_actions():
|
||||
async def create_task(params):
|
||||
_self = params.get("_workspace")
|
||||
if _self is None:
|
||||
return "self not found"
|
||||
|
||||
taskObj = AgentTask.create_by_dict(params)
|
||||
parent_id = params.get("parent")
|
||||
return await self.task_mgr.create_task(taskObj,parent_id)
|
||||
return await _self.task_mgr.create_task(taskObj,parent_id)
|
||||
|
||||
create_task_action = SimpleAIOperation(
|
||||
"create_task",
|
||||
create_task_action = SimpleAIAction(
|
||||
"agent.workspace.create_task",
|
||||
"Create a task in the task system, the supported parameters are: title, detail (simple task can not be filled), tags,due_date",
|
||||
create_task,
|
||||
)
|
||||
|
||||
self.actions[create_task_action.get_name()] = create_task_action
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(create_task_action)
|
||||
|
||||
async def cancel_task(parameters):
|
||||
_self = parameters.get("_workspace")
|
||||
if _self is None:
|
||||
return "self not found"
|
||||
task_id = parameters.get("task_id")
|
||||
task = await _self.task_mgr.get_task(task_id)
|
||||
if task is None:
|
||||
return f"task {task_id} not found"
|
||||
task.state = "cancel"
|
||||
return await _self.task_mgr.update_task(task)
|
||||
cancel_task_action = SimpleAIAction(
|
||||
"agent.workspace.cancel_task",
|
||||
"Cancel this task",
|
||||
cancel_task,
|
||||
)
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(create_task_action)
|
||||
|
||||
|
||||
def get_actions(self) -> Dict:
|
||||
return self.actions
|
||||
@@ -354,4 +379,7 @@ class AgentWorkspace:
|
||||
def get_inner_function_desc(self) -> List[AIFunction]:
|
||||
func_list = []
|
||||
func_list.extend(self.inner_functions.values())
|
||||
return func_list
|
||||
return func_list
|
||||
|
||||
def get_actions_for_task_review(self) -> Dict:
|
||||
return self.actions
|
||||
@@ -1,16 +1,26 @@
|
||||
# pylint:disable=E0402
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..proto.ai_function import *
|
||||
from ..agent.llm_context import GlobaToolsLibrary
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AsrFunction(AIFunction):
|
||||
def __init__(self):
|
||||
self.func_id = "speech_to_text"
|
||||
self.description = "语音识别,将语音转换为文字"
|
||||
self.func_id = "aigc.speech_to_text"
|
||||
self.description = "Voice recognition, convert the voice into text"
|
||||
self.parameters = ParameterDefine.create_parameters({
|
||||
"audio_file": {"type": "string", "description": "Audio file path"},
|
||||
"model": {"type": "string", "description": "Recognition model", "enum": ["openai-whisper"]},
|
||||
"prompt": {"type": "string", "description": "Prompt statement, can be None"},
|
||||
"response_format": {"type": "string", "description": "Return format", "enum": ["text", "json", "srt", "verbose_json", "vtt"]},
|
||||
})
|
||||
|
||||
def register_function(self):
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(self)
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.func_id
|
||||
@@ -19,15 +29,7 @@ class AsrFunction(AIFunction):
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"audio_file": {"type": "string", "description": "音频文件路径"},
|
||||
"model": {"type": "string", "description": "识别模型", "enum": ["openai-whisper"]},
|
||||
"prompt": {"type": "string", "description": "提示语句,可以为None"},
|
||||
"response_format": {"type": "string", "description": "返回格式", "enum": ["text", "json", "srt", "verbose_json", "vtt"]},
|
||||
}
|
||||
}
|
||||
return self.parameters
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
logger.info(f"execute asr function: {kwargs}")
|
||||
@@ -1,3 +1,4 @@
|
||||
# pylint:disable=E0402
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
@@ -424,3 +425,36 @@ def execute_code(
|
||||
# return the exit code, logs and image
|
||||
return exit_code, logs
|
||||
|
||||
class CodeInterpreterFunction(AIFunction):
|
||||
def __init__(self):
|
||||
self.func_id = "system.code_interpreter"
|
||||
self.description = "execute python code"
|
||||
self.parameters = ParameterDefine.create_parameters({
|
||||
"code": {"type": "string", "description": "python code"}
|
||||
})
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.func_id
|
||||
|
||||
def get_description(self) -> str:
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return self.parameters
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
code = kwargs.get("code")
|
||||
ret_code, result = execute_code(code=code)
|
||||
if ret_code == 0:
|
||||
return result.strip()
|
||||
else:
|
||||
return result.strip()
|
||||
|
||||
def is_local(self) -> bool:
|
||||
return True
|
||||
|
||||
def is_in_zone(self) -> bool:
|
||||
return True
|
||||
|
||||
def is_ready_only(self) -> bool:
|
||||
return False
|
||||
+9
-5
@@ -1,7 +1,9 @@
|
||||
# pylint:disable=E0402
|
||||
import json
|
||||
from typing import Dict
|
||||
|
||||
from ..proto.ai_function import *
|
||||
from ..agent.llm_context import GlobaToolsLibrary
|
||||
from duckduckgo_search import AsyncDDGS
|
||||
|
||||
|
||||
@@ -13,6 +15,12 @@ class DuckDuckGoTextSearchFunction(AIFunction):
|
||||
self.safesearch = "moderate"
|
||||
self.time = "y"
|
||||
self.max_results = 5
|
||||
self.parameters = ParameterDefine.create_parameters({
|
||||
"query": {"type": "string", "description": "The query to search for."}
|
||||
})
|
||||
|
||||
def register_function(self):
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(self)
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.name
|
||||
@@ -21,11 +29,7 @@ class DuckDuckGoTextSearchFunction(AIFunction):
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return {"type": "object",
|
||||
"properties": {
|
||||
"query": {"type": "string", "description": "The query to search for."}
|
||||
}
|
||||
}
|
||||
return self.parameters
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
query = kwargs.get("query")
|
||||
+11
-3
@@ -1,17 +1,26 @@
|
||||
# pylint:disable=E0402
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
from ..proto.ai_function import *
|
||||
from ..agent.llm_context import GlobaToolsLibrary
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Image2TextFunction(AIFunction):
|
||||
|
||||
def __init__(self):
|
||||
self.func_id = "image_2_text"
|
||||
self.func_id = "aigc.image_2_text"
|
||||
self.description = "According to the input image file address, return the description of the image content"
|
||||
self.parameters = ParameterDefine.create_parameters({
|
||||
"image_path": {"type": "string", "description": "image file path"}
|
||||
})
|
||||
logger.info(f"init Image2TextFunction")
|
||||
|
||||
def register_function(self):
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(self)
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.func_id
|
||||
|
||||
@@ -19,8 +28,7 @@ class Image2TextFunction(AIFunction):
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return {
|
||||
}
|
||||
return self.parameters
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
logger.info(f"execute image_2_text function: {kwargs}")
|
||||
+31
-30
@@ -1,3 +1,5 @@
|
||||
# pylint:disable=E0402
|
||||
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
@@ -17,9 +19,30 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class ScriptToSpeechFunction(AIFunction):
|
||||
def __init__(self):
|
||||
self.func_id = "script_to_speech"
|
||||
self.description = "根据输入的剧本生成音频文件,成功时会返回音频文件路径"
|
||||
self.func_id = "aigc.script_to_speech"
|
||||
self.description = "Generate audio files according to the input script, and the audio file path will be returned when successful"
|
||||
self.speech_path = os.path.join(AIStorage.get_instance().get_myai_dir(), "tts")
|
||||
self.parameters = ParameterDefine.create_parameters({
|
||||
"language": {"type": "string", "description": "Actual language", "enum": ["zh", "en"]},
|
||||
"model": {"type": "string", "description": "Studio", "enum": ["tts-1", "tts-1-hd"]},
|
||||
"roles": {"type": "array", "items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "Character name"},
|
||||
"gender": {"type": "string", "description": "Gender", "enum": ["man", "female"]},
|
||||
"age": {"type": "string", "description": "age", "enum": ["child", "adult"]},
|
||||
}}},
|
||||
"lines": {"type": "array", "items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "Character name"},
|
||||
"tone": {"type": "string", "description": "Sovereign emotions",
|
||||
"enum": ["happy", "sad", "angry", "fear", "disgust", "surprise", "neutral"]},
|
||||
"text": {"type": "string", "description": "Line"},
|
||||
}
|
||||
}}
|
||||
})
|
||||
|
||||
Path(self.speech_path).mkdir(exist_ok=True)
|
||||
|
||||
def get_name(self) -> str:
|
||||
@@ -28,33 +51,11 @@ class ScriptToSpeechFunction(AIFunction):
|
||||
def get_description(self) -> str:
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"language": {"type": "string", "description": "演播语言", "enum": ["zh", "en"]},
|
||||
"model": {"type": "string", "description": "演播模型", "enum": ["tts-1", "tts-1-hd"]},
|
||||
"roles": {"type": "array", "items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "角色名字"},
|
||||
"gender": {"type": "string", "description": "角色性别", "enum": ["man", "female"]},
|
||||
"age": {"type": "string", "description": "年龄", "enum": ["child", "adult"]},
|
||||
}}},
|
||||
"lines": {"type": "array", "items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "description": "角色名字"},
|
||||
"tone": {"type": "string", "description": "演播情感",
|
||||
"enum": ["happy", "sad", "angry", "fear", "disgust", "surprise", "neutral"]},
|
||||
"text": {"type": "string", "description": "台词"},
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
def get_parameters(self):
|
||||
return self.parameters
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
logger.info(f"execute text_to_speech function: {kwargs}")
|
||||
logger.info(f"execute aigc.script_to_speech function: {kwargs}")
|
||||
|
||||
language = kwargs.get("language")
|
||||
if language is None:
|
||||
@@ -86,16 +87,16 @@ class ScriptToSpeechFunction(AIFunction):
|
||||
audio = audio + AudioSegment.from_mp3(io.BytesIO(data))
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"do_text_to_speech failed: {e}")
|
||||
logger.error(f"script_to_speech failed: {e}")
|
||||
i += 1
|
||||
continue
|
||||
|
||||
if audio is not None:
|
||||
path = os.path.join(self.speech_path, "{}.mp3".format(''.join(random.sample('zyxwvutsrqponmlkjihgfedcba', 10))))
|
||||
audio.export(path, format="mp3")
|
||||
return "exec text_to_speech OK,speech file store at ```{}```".format(path)
|
||||
return "exec script_to_speech OK,speech file store at ```{}```".format(path)
|
||||
else:
|
||||
return "exec text_to_speech failed"
|
||||
return "exec script_to_speech failed"
|
||||
|
||||
def is_local(self) -> bool:
|
||||
return True
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
# pylint:disable=E0402
|
||||
from datetime import timedelta, datetime
|
||||
from typing import Dict
|
||||
|
||||
from cachetools import TLRUCache, cached
|
||||
|
||||
from ..proto.ai_function import *
|
||||
from .sql_database import SQLDatabase, get_from_env
|
||||
from ..environment.sql_database import SQLDatabase, get_from_env
|
||||
|
||||
|
||||
def _my_ttu(_key, _value, now):
|
||||
+9
-11
@@ -17,9 +17,14 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
class TextToSpeechFunction(AIFunction):
|
||||
def __init__(self):
|
||||
self.func_id = "text_to_speech"
|
||||
self.description = "根据输入的文本生成音频文件,成功时会返回音频文件路径"
|
||||
self.func_id = "aigc.text_to_speech"
|
||||
self.description = "To generate audio files according to the input text, the audio file path will be returned when successful"
|
||||
self.speech_path = os.path.join(AIStorage.get_instance().get_myai_dir(), "tts")
|
||||
self.parameters = ParameterDefine.create_parameters({
|
||||
"language": {"type": "string", "description": "Actual language", "enum": ["zh", "en"]},
|
||||
"model": {"type": "string", "description": "Studio", "enum": ["tts-1", "tts-1-hd"]},
|
||||
"text": {"type": "string", "description": "text"}
|
||||
})
|
||||
Path(self.speech_path).mkdir(exist_ok=True)
|
||||
|
||||
def get_name(self) -> str:
|
||||
@@ -29,17 +34,10 @@ class TextToSpeechFunction(AIFunction):
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"language": {"type": "string", "description": "演播语言", "enum": ["zh", "en"]},
|
||||
"model": {"type": "string", "description": "演播模型", "enum": ["tts-1", "tts-1-hd"]},
|
||||
"text": {"type": "string", "description": "文本内容"}
|
||||
}
|
||||
}
|
||||
return self.parameters
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
logger.info(f"execute text_to_speech function: {kwargs}")
|
||||
logger.info(f"execute aigc.text_to_speech function: {kwargs}")
|
||||
|
||||
language = kwargs.get("language")
|
||||
if language is None:
|
||||
@@ -1,41 +0,0 @@
|
||||
from typing import Dict
|
||||
|
||||
from ..proto.ai_function import *
|
||||
from .code_interpreter import execute_code
|
||||
|
||||
|
||||
class CodeInterpreterFunction(AIFunction):
|
||||
def __init__(self):
|
||||
self.func_id = "code_interpreter"
|
||||
self.description = "execute python code"
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.func_id
|
||||
|
||||
def get_description(self) -> str:
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {"type": "string", "description": "python code"}
|
||||
}
|
||||
}
|
||||
|
||||
async def execute(self, **kwargs) -> str:
|
||||
code = kwargs.get("code")
|
||||
ret_code, result = execute_code(code=code)
|
||||
if ret_code == 0:
|
||||
return result.strip()
|
||||
else:
|
||||
return result.strip()
|
||||
|
||||
def is_local(self) -> bool:
|
||||
return True
|
||||
|
||||
def is_in_zone(self) -> bool:
|
||||
return True
|
||||
|
||||
def is_ready_only(self) -> bool:
|
||||
return False
|
||||
@@ -1,6 +1,6 @@
|
||||
# basic environment class
|
||||
# we have some built-in environment: Calender(include timer),Home(connect to IoT device in your home), ,KnwoledgeBase,FileSystem,
|
||||
|
||||
# pylint:disable=E0402
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Callable, Optional,Dict,Awaitable,List
|
||||
import logging
|
||||
@@ -11,6 +11,19 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseEnvironment:
|
||||
@classmethod
|
||||
def get_env_by_id(cls,env_id:str)->'BaseEnvironment':
|
||||
if cls.all_env is None:
|
||||
cls.all_env = {}
|
||||
return cls.all_env.get(env_id)
|
||||
|
||||
@classmethod
|
||||
def register_env(cls,env_id:str,env:'BaseEnvironment')->None:
|
||||
if cls.all_env is None:
|
||||
cls.all_env = {}
|
||||
cls.all_env[env_id] = env
|
||||
|
||||
|
||||
def __init__(self, workspace: str) -> None:
|
||||
pass
|
||||
|
||||
@@ -29,11 +42,11 @@ class BaseEnvironment:
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def get_ai_operation(self,op_name:str) -> AIOperation:
|
||||
def get_ai_operation(self,op_name:str) -> AIAction:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_all_ai_operations(self) -> List[AIOperation]:
|
||||
def get_all_ai_operations(self) -> List[AIAction]:
|
||||
pass
|
||||
|
||||
def __getitem__(self, key):
|
||||
@@ -57,7 +70,7 @@ class SimpleEnvironment(BaseEnvironment):
|
||||
def __init__(self, workspace: str) -> None:
|
||||
super().__init__(workspace)
|
||||
self.functions: Dict[str,AIFunction] = {}
|
||||
self.operations: Dict[str,AIOperation] = {}
|
||||
self.operations: Dict[str,AIAction] = {}
|
||||
|
||||
def add_ai_function(self,func:AIFunction) -> None:
|
||||
self.functions[func.get_name()] = func
|
||||
@@ -73,16 +86,16 @@ class SimpleEnvironment(BaseEnvironment):
|
||||
func_list.extend(self.functions.values())
|
||||
return func_list
|
||||
|
||||
def add_ai_operation(self,op:AIOperation) -> None:
|
||||
def add_ai_operation(self,op:AIAction) -> None:
|
||||
self.operations[op.get_name()] = op
|
||||
|
||||
def get_ai_operation(self,op_name:str) -> AIOperation:
|
||||
def get_ai_operation(self,op_name:str) -> AIAction:
|
||||
op = self.operations.get(op_name)
|
||||
if op is not None:
|
||||
return op
|
||||
return None
|
||||
|
||||
def get_all_ai_operations(self) -> List[AIOperation]:
|
||||
def get_all_ai_operations(self) -> List[AIAction]:
|
||||
op_list = []
|
||||
op_list.extend(self.operations.values())
|
||||
return op_list
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
# pylint:disable=E0402
|
||||
import sqlite3
|
||||
import json
|
||||
import threading
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
Taken from: langchain
|
||||
SQLAlchemy wrapper around a database.
|
||||
"""
|
||||
# pylint:disable=E0402
|
||||
|
||||
from __future__ import annotations
|
||||
import os
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
# pylint:disable=E0402
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
import json
|
||||
@@ -9,6 +9,7 @@ import logging
|
||||
from typing import Optional
|
||||
import aiosqlite
|
||||
|
||||
from ..agent.llm_context import GlobaToolsLibrary
|
||||
from ..proto.compute_task import *
|
||||
from ..proto.ai_function import *
|
||||
from ..frame.compute_kernel import ComputeKernel
|
||||
@@ -16,8 +17,8 @@ from ..frame.contact_manager import ContactManager,Contact,FamilyMember
|
||||
from ..storage.storage import AIStorage
|
||||
|
||||
from .environment import SimpleEnvironment, CompositeEnvironment
|
||||
from .script_to_speech_function import ScriptToSpeechFunction
|
||||
from .image_2_text_function import Image2TextFunction
|
||||
from ..ai_functions.script_to_speech_function import ScriptToSpeechFunction
|
||||
from ..ai_functions.image_2_text_function import Image2TextFunction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -36,38 +37,40 @@ class CalenderEnvironment(SimpleEnvironment):
|
||||
super().__init__(env_id)
|
||||
self.db_file = AIStorage.get_instance().get_myai_dir() / "calender.db"
|
||||
self.is_run = False
|
||||
gl = GlobaToolsLibrary.get_instance()
|
||||
|
||||
self.add_ai_function(SimpleAIFunction("get_time",
|
||||
gl.register_tool_function(SimpleAIFunction("system.now",
|
||||
"get current time",
|
||||
self._get_now))
|
||||
get_param = {
|
||||
|
||||
get_param = ParameterDefine.create_parameters({
|
||||
"start_time": "start time (UTC) of event",
|
||||
"end_time": "end time (UTC) of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("get_events",
|
||||
})
|
||||
gl.register_tool_function(SimpleAIFunction("system.calender.get_events",
|
||||
"get events in calender by time range",
|
||||
self._get_events_by_time_range,get_param))
|
||||
|
||||
add_param = {
|
||||
add_param = ParameterDefine.create_parameters({
|
||||
"title": "title of event",
|
||||
"start_time": "start time (UTC) of event",
|
||||
"end_time": "end time (UTC) of event",
|
||||
"participants": "participants of event",
|
||||
"location": "location of event",
|
||||
"details": "details of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("add_event",
|
||||
})
|
||||
gl.register_tool_function(SimpleAIFunction("system.calender.add_event",
|
||||
"add event to calender",
|
||||
self._add_event,add_param))
|
||||
|
||||
delete_param = {
|
||||
delete_param = ParameterDefine.create_parameters({
|
||||
"event_id": "id of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("delete_event",
|
||||
})
|
||||
gl.register_tool_function(SimpleAIFunction("system.calender.delete_event",
|
||||
"delete event from calender",
|
||||
self._delete_event,delete_param))
|
||||
|
||||
update_param = {
|
||||
update_param = ParameterDefine.create_parameters({
|
||||
"event_id": "id of event",
|
||||
"new_title": "new title of event",
|
||||
"new_participants": "new participants of event",
|
||||
@@ -75,27 +78,12 @@ class CalenderEnvironment(SimpleEnvironment):
|
||||
"new_details": "new details of event",
|
||||
"start_time": "new start time (UTC) of event",
|
||||
"end_time": "new end time (UTC) of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("update_event",
|
||||
})
|
||||
gl.register_tool_function(SimpleAIFunction("system.calender.update_event",
|
||||
"update event in calender",
|
||||
self._update_event,update_param))
|
||||
|
||||
|
||||
self.add_ai_function(SimpleAIFunction("get_contact",
|
||||
"get contact info",
|
||||
self._get_contact,{"name":"name of contact"}))
|
||||
|
||||
self.add_ai_function(SimpleAIFunction("set_contact",
|
||||
"set contact info",
|
||||
self._set_contact,{"name":"name of contact","contact_info":"A json to descrpit contact"}))
|
||||
|
||||
|
||||
|
||||
|
||||
#self.add_ai_function(SimpleAIFunction("user_confirm",
|
||||
# "user confirm",
|
||||
# self._user_confirm))
|
||||
|
||||
async def init_db(self):
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
await db.execute("""
|
||||
@@ -305,12 +293,15 @@ class CalenderEnvironment(SimpleEnvironment):
|
||||
class PaintEnvironment(SimpleEnvironment):
|
||||
def __init__(self, env_id: str) -> None:
|
||||
super().__init__(env_id)
|
||||
self.is_run = False
|
||||
|
||||
paint_param = {
|
||||
|
||||
|
||||
|
||||
def register_functions(self):
|
||||
paint_param = ParameterDefine.create_parameters({
|
||||
"prompt": "Description of the content of the painting",
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("paint",
|
||||
})
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(SimpleAIFunction("aigc.text_2_image",
|
||||
"Draw a picture according to the description",
|
||||
self._paint,paint_param))
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# pylint:disable=E0402
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@@ -51,7 +52,7 @@ class TodoListEnvironment(SimpleEnvironment):
|
||||
parent_id = params.get("parent")
|
||||
return await self.create_todo(parent_id,todoObj)
|
||||
|
||||
self.add_ai_operation(SimpleAIOperation(
|
||||
self.add_ai_operation(SimpleAIAction(
|
||||
op="create_todo",
|
||||
description="create todo",
|
||||
func_handler=create_todo,
|
||||
@@ -63,7 +64,7 @@ class TodoListEnvironment(SimpleEnvironment):
|
||||
new_stat = params["state"]
|
||||
return await self.update_todo(todo_id,new_stat)
|
||||
|
||||
self.add_ai_operation(SimpleAIOperation(
|
||||
self.add_ai_operation(SimpleAIAction(
|
||||
op="update_todo",
|
||||
description="update todo",
|
||||
func_handler=update_todo,
|
||||
|
||||
@@ -5,6 +5,8 @@ import logging
|
||||
|
||||
from datetime import datetime
|
||||
from ..proto.agent_msg import AgentMsg
|
||||
from ..proto.ai_function import ParameterDefine, SimpleAIFunction
|
||||
from ..agent.llm_context import GlobaToolsLibrary
|
||||
from .tunnel import AgentTunnel
|
||||
from .contact import Contact,FamilyMember
|
||||
|
||||
@@ -19,6 +21,23 @@ class ContactManager:
|
||||
if cls._instance is None:
|
||||
cls._instance = ContactManager(str(filename))
|
||||
return cls._instance
|
||||
|
||||
def register_global_functions(self):
|
||||
gl = GlobaToolsLibrary.get_instance()
|
||||
|
||||
get_parameters = ParameterDefine.create_parameters({"name":"name"})
|
||||
gl.register_tool_function(SimpleAIFunction("system.contacts.get",
|
||||
"get contact info",
|
||||
self._get_contact,get_parameters))
|
||||
|
||||
update_parameters = ParameterDefine.create_parameters({"name":"name","contact_info":"A json to descrpit contact"})
|
||||
gl.register_tool_function(SimpleAIFunction("system.contacts.set",
|
||||
"set contact info",
|
||||
self._set_contact,update_parameters))
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
def __init__(self, filename="contacts.toml"):
|
||||
self.filename = filename
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# pylint:disable=E0402
|
||||
import json
|
||||
import logging
|
||||
import shlex
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
# pylint:disable=E0402
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Optional
|
||||
import datetime
|
||||
|
||||
+135
-55
@@ -1,11 +1,23 @@
|
||||
# pylint:disable=E0402
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict,Coroutine,Callable,List
|
||||
|
||||
class ParameterDefine:
|
||||
def __init__(self) -> None:
|
||||
self.name = None
|
||||
self.type = None
|
||||
self.description = None
|
||||
def __init__(self,name:str,desc:str) -> None:
|
||||
self.name:str = name
|
||||
self.type:str = "string"
|
||||
self.enum:List[str] = None
|
||||
self.description = desc
|
||||
self.is_required = False
|
||||
|
||||
@classmethod
|
||||
def create_parameters(cls,json_obj:dict) -> Dict[str,'ParameterDefine']:
|
||||
result = {}
|
||||
for k,v in json_obj.items():
|
||||
param = ParameterDefine(k,v)
|
||||
result[k] = param
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class AIFunction:
|
||||
@@ -23,32 +35,125 @@ class AIFunction:
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_detail_description(self) -> str:
|
||||
"""
|
||||
return a detailed description of what the function does
|
||||
"""
|
||||
parameters = self.get_parameters()
|
||||
parameters_str = ""
|
||||
for k,v in parameters.items():
|
||||
if len(v.description) <= 0:
|
||||
parameters_str +=f"{k},"
|
||||
else:
|
||||
if v.description == k:
|
||||
parameters_str += f"{k},"
|
||||
else:
|
||||
if v.is_required:
|
||||
parameters_str += f"{k}: {v.description},"
|
||||
else:
|
||||
parameters_str += f"{k} (Optional): {v.description},"
|
||||
if len(parameters_str) > 0:
|
||||
return f"{self.get_description} Parameters: {parameters_str}"
|
||||
return f"f{self.get_description()}, no parameters"
|
||||
|
||||
@abstractmethod
|
||||
def get_parameters(self) -> Dict:
|
||||
def get_parameters(self) -> Dict[str,ParameterDefine]:
|
||||
pass
|
||||
|
||||
def get_openai_parameters(self) -> Dict:
|
||||
"""
|
||||
Return the list of parameters to execute this function in the form of
|
||||
JSON schema as specified in the OpenAI documentation:
|
||||
https://platform.openai.com/docs/api-reference/chat/create#chat/create-parameters
|
||||
|
||||
str = run_code(code:str)
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"code": {
|
||||
"type": "string",
|
||||
"description": "Python code which needs to be executed"
|
||||
tools = [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_current_weather",
|
||||
"description": "Get the current weather",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "The city and state, e.g. San Francisco, CA",
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["celsius", "fahrenheit"],
|
||||
"description": "The temperature unit to use. Infer this from the users location.",
|
||||
},
|
||||
},
|
||||
"required": ["location", "format"],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_n_day_weather_forecast",
|
||||
"description": "Get an N-day weather forecast",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "The city and state, e.g. San Francisco, CA",
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["celsius", "fahrenheit"],
|
||||
"description": "The temperature unit to use. Infer this from the users location.",
|
||||
},
|
||||
"num_days": {
|
||||
"type": "integer",
|
||||
"description": "The number of days to forecast",
|
||||
}
|
||||
},
|
||||
"required": ["location", "format", "num_days"]
|
||||
},
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
"""
|
||||
pass
|
||||
parameters = self.get_parameters()
|
||||
if parameters is not None:
|
||||
result = {}
|
||||
result["type"] = "object"
|
||||
required = []
|
||||
parm_defines = {}
|
||||
for parm_name,parm in parameters.items():
|
||||
parm_item = {}
|
||||
parm_item["type"] = parm.type
|
||||
parm_item["description"] = parm.description
|
||||
if parm.enum is not None:
|
||||
parm_item["enum"] = parm.enum
|
||||
parm_defines[parm_name] = parm_item
|
||||
if parm.is_required:
|
||||
required.append(parm_name)
|
||||
result["properties"] = parm_defines
|
||||
result["required"] = required
|
||||
return result
|
||||
|
||||
return {"type": "object", "properties": {}}
|
||||
|
||||
@abstractmethod
|
||||
async def execute(self, **kwargs) -> str:
|
||||
"""
|
||||
Execute the function and return a JSON serializable dict.
|
||||
Execute the function and return a JSON serializable dict by LLM
|
||||
The parameters are passed in the form of kwargs
|
||||
|
||||
[{'id': 'call_fLsKR5vGllhbWxvpqsDT3jBj',
|
||||
'type': 'function',
|
||||
'function': {'name': 'get_n_day_weather_forecast',
|
||||
'arguments': '{"location": "San Francisco, CA", "format": "celsius", "num_days": 4}'}},
|
||||
{'id': 'call_CchlsGE8OE03QmeyFbg7pkDz',
|
||||
'type': 'function',
|
||||
'function': {'name': 'get_n_day_weather_forecast',
|
||||
'arguments': '{"location": "Glasgow", "format": "celsius", "num_days": 4}'}}
|
||||
]
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -70,10 +175,8 @@ class AIFunction:
|
||||
def is_ready_only(self) -> bool:
|
||||
pass
|
||||
|
||||
#def load_from_config(self,config:dict) -> bool:
|
||||
# pass
|
||||
|
||||
class ActionItem:
|
||||
#TODO need to be upgrade
|
||||
class ActionNode:
|
||||
def __init__(self,name:str,args:List[str]) -> None:
|
||||
self.name:str= name
|
||||
self.args:List[str]= args
|
||||
@@ -90,9 +193,9 @@ class ActionItem:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def from_json(cls,json_obj:dict) -> 'ActionItem':
|
||||
def from_json(cls,json_obj:dict) -> 'ActionNode':
|
||||
args = json_obj.get("args",[])
|
||||
r = ActionItem(json_obj["name"],args)
|
||||
r = ActionNode(json_obj["name"],args)
|
||||
if json_obj.get("body"):
|
||||
r.body = json_obj["body"]
|
||||
r.parms = json_obj
|
||||
@@ -100,23 +203,12 @@ class ActionItem:
|
||||
return r
|
||||
|
||||
|
||||
# call chain is a combination of ai_function,group of ai_function.
|
||||
class CallChain:
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
pass
|
||||
|
||||
async def execute(self):
|
||||
pass
|
||||
|
||||
class SimpleAIFunction(AIFunction):
|
||||
def __init__(self,func_id:str,description:str,func_handler:Coroutine,parameters:Dict = None) -> None:
|
||||
def __init__(self,func_id:str,description:str,func_handler:Coroutine,parameters:Dict[str,ParameterDefine] = None) -> None:
|
||||
self.func_id = func_id
|
||||
self.description = description
|
||||
self.func_handler = func_handler
|
||||
self.parameters = parameters
|
||||
self.parameters:Dict[str,ParameterDefine] = parameters
|
||||
|
||||
def get_name(self) -> str:
|
||||
return self.func_id
|
||||
@@ -124,24 +216,12 @@ class SimpleAIFunction(AIFunction):
|
||||
def get_description(self) -> str:
|
||||
return self.description
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
if self.parameters is not None:
|
||||
result = {}
|
||||
result["type"] = "object"
|
||||
parm_defines = {}
|
||||
for parm,desc in self.parameters.items():
|
||||
parm_item = {}
|
||||
parm_item["type"] = "string"
|
||||
parm_item["description"] = desc
|
||||
parm_defines[parm] = parm_item
|
||||
result["properties"] = parm_defines
|
||||
return result
|
||||
return {"type": "object", "properties": {}}
|
||||
|
||||
|
||||
def get_parameters(self) -> Dict[str,ParameterDefine]:
|
||||
return self.parameters
|
||||
|
||||
async def execute(self,**kwargs) -> str:
|
||||
if self.func_handler is None:
|
||||
return "error: function not implemented"
|
||||
return f"error: function {self.func_id} not implemented"
|
||||
|
||||
return await self.func_handler(**kwargs)
|
||||
|
||||
@@ -154,7 +234,7 @@ class SimpleAIFunction(AIFunction):
|
||||
def is_ready_only(self) -> bool:
|
||||
return False
|
||||
|
||||
class AIOperation:
|
||||
class AIAction:
|
||||
@abstractmethod
|
||||
def get_name(self) -> str:
|
||||
"""
|
||||
@@ -178,7 +258,7 @@ class AIOperation:
|
||||
"""
|
||||
pass
|
||||
|
||||
class SimpleAIOperation(AIOperation):
|
||||
class SimpleAIAction(AIAction):
|
||||
def __init__(self,op:str,description:str,func_handler:Coroutine) -> None:
|
||||
self.op = op
|
||||
self.description = description
|
||||
@@ -197,7 +277,7 @@ class SimpleAIOperation(AIOperation):
|
||||
return await self.func_handler(params)
|
||||
|
||||
|
||||
class AIFunctionOperation(AIOperation):
|
||||
class AIFunction2Action(AIAction):
|
||||
def __init__(self, func: AIFunction) -> None:
|
||||
self.func = func
|
||||
super().__init__()
|
||||
@@ -208,7 +288,7 @@ class AIFunctionOperation(AIOperation):
|
||||
|
||||
@abstractmethod
|
||||
def get_description(self) -> str:
|
||||
return self.func.get_description()
|
||||
return self.func.get_detail_description()
|
||||
|
||||
@abstractmethod
|
||||
async def execute(self, params: dict) -> str:
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
# pylint:disable=E0402
|
||||
import copy
|
||||
from enum import Enum
|
||||
import json
|
||||
import shlex
|
||||
import uuid
|
||||
import time
|
||||
from typing import List, Union
|
||||
from .ai_function import *
|
||||
from .agent_msg import *
|
||||
from typing import List, Union,Dict
|
||||
from .ai_function import AIFunction,ActionNode
|
||||
from .agent_msg import AgentMsg
|
||||
from ..knowledge import ObjectID
|
||||
from ..storage.storage import AIStorage
|
||||
|
||||
@@ -33,13 +33,15 @@ class ComputeTaskState(Enum):
|
||||
class ComputeTaskType(Enum):
|
||||
NONE = "None"
|
||||
LLM_COMPLETION = "llm_completion"
|
||||
TEXT_EMBEDDING ="text_embedding"
|
||||
IMAGE_EMBEDDING ="image_embedding"
|
||||
|
||||
TEXT_2_IMAGE = "text_2_image"
|
||||
IMAGE_2_TEXT = "image_2_text"
|
||||
IMAGE_2_IMAGE = "image_2_image"
|
||||
VOICE_2_TEXT = "voice_2_text"
|
||||
TEXT_2_VOICE = "text_2_voice"
|
||||
TEXT_EMBEDDING ="text_embedding"
|
||||
IMAGE_EMBEDDING ="image_embedding"
|
||||
|
||||
|
||||
# class Function(TypedDict, total=False):
|
||||
# name: Required[str]
|
||||
@@ -155,11 +157,8 @@ class LLMResult:
|
||||
self.compute_error_str = None
|
||||
self.resp : str = "" # llm say:
|
||||
self.raw_result = None # raw result from compute kernel
|
||||
self.inner_functions : List[AIFunction] = []
|
||||
self.action_list : List[ActionItem] = [] # op_list is a optimize design for saving token
|
||||
|
||||
#self.post_msgs : List[AgentMsg] = [] # move to op_list
|
||||
# self.send_msgs : List[AgentMsg] = [] # move to op_list
|
||||
#self.inner_functions : List[AIFunction] = []
|
||||
self.action_list : List[ActionNode] = [] # op_list is a optimize design for saving token
|
||||
|
||||
|
||||
@classmethod
|
||||
@@ -185,9 +184,11 @@ class LLMResult:
|
||||
r.resp = llm_json.get("resp")
|
||||
r.raw_result = llm_json
|
||||
action_list = llm_json.get("actions")
|
||||
for action in action_list:
|
||||
action_item = ActionItem.from_json(action)
|
||||
r.action_list.append(action_item)
|
||||
if action_list:
|
||||
for action in action_list:
|
||||
action_item = ActionNode.from_json(action)
|
||||
if action_item:
|
||||
r.action_list.append(action_item)
|
||||
|
||||
return r
|
||||
|
||||
@@ -215,7 +216,7 @@ class LLMResult:
|
||||
lines = llm_result_str.splitlines()
|
||||
is_need_wait = False
|
||||
|
||||
def check_args(action_item:ActionItem):
|
||||
def check_args(action_item:ActionNode):
|
||||
match action_item.name:
|
||||
case "post_msg":# /post_msg $target_id
|
||||
if len(action_item.args) != 1:
|
||||
@@ -232,7 +233,7 @@ class LLMResult:
|
||||
return False
|
||||
|
||||
|
||||
current_action : ActionItem = None
|
||||
current_action : ActionNode = None
|
||||
for line in lines:
|
||||
if line.startswith("##/"):
|
||||
if current_action:
|
||||
@@ -242,7 +243,7 @@ class LLMResult:
|
||||
r.action_list.append(current_action)
|
||||
|
||||
action_name,action_args = LLMResult.parse_action(line[3:])
|
||||
current_action = ActionItem(action_name,action_args)
|
||||
current_action = ActionNode(action_name,action_args)
|
||||
else:
|
||||
if current_action:
|
||||
current_action.append_body(line + "\n")
|
||||
|
||||
@@ -28,7 +28,6 @@ class AgentManager:
|
||||
self.agent_templete_env : PackageEnv = None
|
||||
self.agent_env : PackageEnv = None
|
||||
self.db_path : str = None
|
||||
self.environments: dict = {}
|
||||
self.loaded_agent_instance : Dict[str,BaseAIAgent] = None
|
||||
|
||||
async def initial(self) -> None:
|
||||
@@ -50,16 +49,6 @@ class AgentManager:
|
||||
async def scan_all_agent(self)->None:
|
||||
pass
|
||||
|
||||
def register_environment(self, env_id: str, init_env) -> None:
|
||||
self.environments[env_id] = init_env
|
||||
|
||||
def init_environment(self, env_id: str, workspace: str):
|
||||
if env_id not in self.environments:
|
||||
logger.error(f"env {env_id} not found!")
|
||||
return
|
||||
|
||||
return self.environments[env_id](workspace)
|
||||
|
||||
async def is_exist(self,agent_id:str) -> bool:
|
||||
the_aget = await self.get(agent_id)
|
||||
if the_aget:
|
||||
@@ -123,28 +112,6 @@ class AgentManager:
|
||||
config_data = await config_file.read()
|
||||
config = toml.loads(config_data)
|
||||
result_agent = AIAgent()
|
||||
|
||||
workspace = config.get("workspace", config.get("instance_id"))
|
||||
workspace = WorkspaceEnvironment(workspace)
|
||||
config["workspace"] = workspace
|
||||
|
||||
if "owner_env" in config:
|
||||
owner_env = config["owner_env"]
|
||||
|
||||
def init_env(env_config: str):
|
||||
_, ext = os.path.splitext(env_config)
|
||||
if ext == ".py":
|
||||
env_path = os.path.join(agent_media.full_path, env_config)
|
||||
env = runpy.run_path(env_path)["init"](None, workspace.root_path)
|
||||
else:
|
||||
env = self.init_environment(env_config, workspace.root_path)
|
||||
workspace.add_env(env)
|
||||
|
||||
if isinstance(owner_env, list):
|
||||
for env in owner_env:
|
||||
init_env(env)
|
||||
else:
|
||||
init_env(owner_env)
|
||||
|
||||
if await result_agent.load_from_config(config) is False:
|
||||
logger.error(f"load agent from {agent_media} failed!")
|
||||
|
||||
@@ -279,7 +279,7 @@ class LocalKnowledgeBase(CompositeEnvironment):
|
||||
meta = self.learning_cache.get(full_path)
|
||||
meta.update(op)
|
||||
|
||||
self.add_ai_operation(SimpleAIOperation(
|
||||
self.add_ai_operation(SimpleAIAction(
|
||||
op="learn",
|
||||
description="update knowledge llm summary",
|
||||
func_handler=learn,
|
||||
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
import aiofiles
|
||||
from typing import Any,List,Dict
|
||||
import chardet
|
||||
from aios import SimpleAIOperation
|
||||
from aios import SimpleAIAction
|
||||
from aios import SimpleEnvironment
|
||||
|
||||
class FilesystemEnvironment(SimpleEnvironment):
|
||||
@@ -19,7 +19,7 @@ class FilesystemEnvironment(SimpleEnvironment):
|
||||
if is_append is None:
|
||||
is_append = False
|
||||
return await self.write(op["path"],op["content"],is_append)
|
||||
self.add_ai_operation(SimpleAIOperation(
|
||||
self.add_ai_operation(SimpleAIAction(
|
||||
op="write",
|
||||
description="write file",
|
||||
func_handler=write,
|
||||
@@ -27,7 +27,7 @@ class FilesystemEnvironment(SimpleEnvironment):
|
||||
|
||||
async def delete(op):
|
||||
return await self.delete(op["path"])
|
||||
self.add_ai_operation(SimpleAIOperation(
|
||||
self.add_ai_operation(SimpleAIAction(
|
||||
op="delete",
|
||||
description="delete path",
|
||||
func_handler=delete,
|
||||
@@ -35,7 +35,7 @@ class FilesystemEnvironment(SimpleEnvironment):
|
||||
|
||||
async def rename(op):
|
||||
return await self.move(op["path"],op["new_name"])
|
||||
self.add_ai_operation(SimpleAIOperation(
|
||||
self.add_ai_operation(SimpleAIAction(
|
||||
op="rename",
|
||||
description="rename path",
|
||||
func_handler=rename,
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
import os
|
||||
from typing import Any,List,Dict
|
||||
from aios import AgentMsg,AgentTodo,LLMPrompt
|
||||
from aios import SimpleAIFunction, SimpleAIOperation
|
||||
from aios import SimpleAIFunction
|
||||
from aios import SimpleEnvironment
|
||||
from aios import GlobaToolsLibrary,ParameterDefine
|
||||
|
||||
class ShellEnvironment(SimpleEnvironment):
|
||||
def __init__(self, workspace: str) -> None:
|
||||
super().__init__(workspace)
|
||||
def __init__(self) -> None:
|
||||
super().__init__("shell")
|
||||
|
||||
operator_param = {
|
||||
"command": "command will execute",
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("shell_exec",
|
||||
@classmethod
|
||||
def register_global_functions(cls):
|
||||
operator_param = ParameterDefine.create_parameters({"command":"command will execute"})
|
||||
GlobaToolsLibrary.get_instance().register_tool_function(SimpleAIFunction("system.shell.exec",
|
||||
"execute shell command in linux bash",
|
||||
self.shell_exec,operator_param))
|
||||
|
||||
#run_code_param = {
|
||||
# "pycode": "python code will execute",
|
||||
#}
|
||||
#self.add_ai_function(SimpleAIFunction("run_code",
|
||||
# "execute python code",
|
||||
# self.run_code,run_code_param))
|
||||
|
||||
|
||||
async def shell_exec(self,command:str) -> str:
|
||||
ShellEnvironment.shell_exec,operator_param))
|
||||
@staticmethod
|
||||
async def shell_exec(command:str) -> str:
|
||||
import asyncio.subprocess
|
||||
process = await asyncio.create_subprocess_shell(
|
||||
command,
|
||||
|
||||
@@ -95,6 +95,8 @@ class AIOS_Shell:
|
||||
|
||||
#Stability_ComputeNode.declare_user_config()
|
||||
|
||||
def init_global_action_lib(self):
|
||||
AgentMemory.register_actions()
|
||||
|
||||
|
||||
async def _handle_no_target_msg(self,bus:AIBus,target_id:str) -> bool:
|
||||
@@ -144,9 +146,9 @@ class AIOS_Shell:
|
||||
# paint_env = PaintEnvironment("paint")
|
||||
# Environment.set_env_by_id("paint",paint_env)
|
||||
|
||||
AgentManager.get_instance().register_environment("bash", ShellEnvironment)
|
||||
AgentManager.get_instance().register_environment("fs", FilesystemEnvironment)
|
||||
AgentManager.get_instance().register_environment("knowledge", LocalKnowledgeBase)
|
||||
#AgentManager.get_instance().register_environment("bash", ShellEnvironment)
|
||||
#AgentManager.get_instance().register_environment("fs", FilesystemEnvironment)
|
||||
#AgentManager.get_instance().register_environment("knowledge", LocalKnowledgeBase)
|
||||
|
||||
if await AgentManager.get_instance().initial() is not True:
|
||||
logger.error("agent manager initial failed!")
|
||||
|
||||
Reference in New Issue
Block a user