Refactor the Action/Function components, and refactor the basic architecture of Agent Task/Todo.

This commit is contained in:
Liu Zhicong
2023-12-17 18:23:40 -08:00
parent 3d00095650
commit 29594c0319
41 changed files with 2687 additions and 1108 deletions
+1
View File
@@ -0,0 +1 @@
disable=E0402
+61 -44
View File
@@ -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="&lt;h1&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Memory,Env,KB,Workspace的区别&lt;/font&gt;&lt;/h1&gt;&lt;p&gt;Memory是不共享的内部状态,只有 action没有function&lt;br style=&quot;border-color: var(--border-color); font-size: 11px;&quot;&gt;&lt;span style=&quot;font-size: 11px;&quot;&gt;Workspace是共享的状态,主要是action&lt;/span&gt;&lt;br style=&quot;border-color: var(--border-color); font-size: 11px;&quot;&gt;&lt;span style=&quot;font-size: 11px;&quot;&gt;Env是全局状态,主要是inner_function,有的有小部分action&lt;/span&gt;&lt;br style=&quot;border-color: var(--border-color); font-size: 11px;&quot;&gt;&lt;span style=&quot;font-size: 11px;&quot;&gt;Knowledge基本是只读的,除非专门整理Knowledge的Agent,只有function&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;" 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="&lt;h1&gt;&lt;font style=&quot;font-size: 22px;&quot;&gt;Memory,Env,KB,Workspace的区别&lt;/font&gt;&lt;/h1&gt;&lt;p&gt;Memory是不共享的内部状态,只有 action没有function&lt;br style=&quot;border-color: var(--border-color); font-size: 11px;&quot;&gt;&lt;span style=&quot;font-size: 11px;&quot;&gt;Workspace是共享的状态,主要是action&lt;/span&gt;&lt;br style=&quot;border-color: var(--border-color); font-size: 11px;&quot;&gt;&lt;span style=&quot;font-size: 11px;&quot;&gt;Env是全局状态,主要是inner_function,有的有小部分action&lt;/span&gt;&lt;br style=&quot;border-color: var(--border-color); font-size: 11px;&quot;&gt;&lt;span style=&quot;font-size: 11px;&quot;&gt;Knowledge基本是只读的,除非专门整理Knowledge的Agent,只有function&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;/p&gt;" 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&lt;br&gt;确定的执行时间(在这之前和之后都不会执行),&lt;br&gt;确定的执行人" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-2" value="确定的Task&lt;br&gt;确定的执行时间(在这之前和之后都不会执行),&lt;br&gt;确定的执行人" 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&lt;br&gt;确定的执行人&lt;br&gt;不确定的执行时间(和条件有关)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="Po7mxAQLMo4zYcBtAZ7U-7" value="半确定的Task&lt;br&gt;ASSIGNED&lt;br&gt;确定的执行人&lt;br&gt;不确定的执行时间(和条件有关)" 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="&lt;h1&gt;防止无限拆分&lt;/h1&gt;&lt;p&gt;大部分情况下,我们都鼓励使用&lt;/p&gt;&lt;p&gt;Task-Todo-Action这种3层结构来完成任务。或则再多一层Task-SubTask-Todo-Action. 今天LLM能面对的复杂度应该就是最多这4层了&lt;/p&gt;" 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="&lt;h1&gt;Workflow的核心设计&lt;/h1&gt;&lt;p&gt;1.工作流定义,工作流指导了workflow中特定的task是如何交给不同的agent完成的&lt;/p&gt;&lt;p&gt;2.agent在workflow中工作时,自己的llm_process会受到影响,有时可以使用workflow中的一些额定义的llm_process&lt;/p&gt;&lt;p&gt;3.workflow的状态是独立的,主要是指&lt;/p&gt;&lt;p&gt;1.独立的workspace&lt;/p&gt;&lt;p&gt;该workspace里支持公共的log保存&lt;/p&gt;&lt;p&gt;2.独立的env&lt;/p&gt;&lt;p&gt;3.独立的kb&lt;/p&gt;&lt;p&gt;4.Agent依旧使用自己的memory+&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;" 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
View File
@@ -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
+44 -1
View File
@@ -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
View File
@@ -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="&amp;lt;&amp;lt;input your openai API token&amp;gt;&amp;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="&amp;lt;&amp;lt;input your openai API token&amp;gt;&amp;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>
+1453 -1
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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):
+67 -2
View File
@@ -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. TODOTODO$200
2. TODOTaskPlan
3. TODO使访ActionList
4. TODO
5. TODOTODOTODO
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]
+5 -3
View File
@@ -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
View File
@@ -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()
+3 -154
View File
@@ -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
+36 -18
View File
@@ -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
+5 -4
View File
@@ -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
+310
View File
@@ -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
View File
@@ -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:
+2 -1
View File
@@ -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:
+3 -2
View File
@@ -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
View File
@@ -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
@@ -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")
@@ -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}")
@@ -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 OKspeech file store at ```{}```".format(path)
return "exec script_to_speech OKspeech 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
@@ -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):
@@ -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
+20 -7
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
# pylint:disable=E0402
import sqlite3
import json
import threading
+2
View File
@@ -2,6 +2,8 @@
Taken from: langchain
SQLAlchemy wrapper around a database.
"""
# pylint:disable=E0402
from __future__ import annotations
import os
+26 -35
View File
@@ -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))
+3 -2
View File
@@ -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,
+19
View File
@@ -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
View File
@@ -1,3 +1,4 @@
# pylint:disable=E0402
import json
import logging
import shlex
+1 -1
View File
@@ -1,4 +1,4 @@
# pylint:disable=E0402
from abc import ABC, abstractmethod
from typing import List, Optional
import datetime
+135 -55
View File
@@ -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:
+18 -17
View File
@@ -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,
+11 -19
View File
@@ -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,
+5 -3
View File
@@ -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!")