@brandon_9527/tcode 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/python-src/.autodev/skills/teams/scripts/README.md +29 -0
  2. package/dist/python-src/.autodev/skills/teams/scripts/cursor_dispatch.sh +88 -0
  3. package/dist/python-src/.autodev/skills/teams/scripts/dispatch.sh +112 -0
  4. package/dist/python-src/.autodev/skills/teams/scripts/label.sh +62 -0
  5. package/dist/python-src/.autodev/skills/teams/scripts/layout.sh +181 -0
  6. package/dist/python-src/.autodev/skills/teams/scripts/old_dispatch.sh +42 -0
  7. package/dist/python-src/.autodev/skills/teams/scripts/pipe.sh +19 -0
  8. package/dist/python-src/.autodev/skills/teams/scripts/pipe_dispatch.sh +59 -0
  9. package/dist/python-src/.autodev/skills/teams/scripts/run.sh +18 -0
  10. package/dist/python-src/.autodev/skills/teams/scripts/stop.sh +26 -0
  11. package/dist/python-src/.autodev/skills/teams/scripts/tmux-layout.sh +43 -0
  12. package/dist/python-src/entry.py +28 -1
  13. package/dist/python-src/main.py +382 -3
  14. package/dist/python-src/pyproject.toml +1 -1
  15. package/dist/python-src/src/ai_tcode.egg-info/PKG-INFO +30 -0
  16. package/dist/python-src/src/ai_tcode.egg-info/SOURCES.txt +48 -0
  17. package/dist/python-src/src/ai_tcode.egg-info/dependency_links.txt +1 -0
  18. package/dist/python-src/src/ai_tcode.egg-info/requires.txt +26 -0
  19. package/dist/python-src/src/ai_tcode.egg-info/top_level.txt +9 -0
  20. package/dist/python-src/src/managers/manager_agent.py +200 -0
  21. package/dist/python-src/src/managers/manager_context.py +49 -0
  22. package/dist/python-src/src/managers/manager_instruction.py +192 -0
  23. package/dist/python-src/src/managers/sandbox.py +3 -3
  24. package/dist/python-src/src/middlewares/dynamic_content.py +63 -0
  25. package/dist/python-src/src/middlewares/hitl.py +3 -3
  26. package/dist/python-src/src/middlewares/memory.py +44 -0
  27. package/dist/python-src/src/middlewares/subagents.py +25 -25
  28. package/dist/python-src/src/middlewares/summary.py +35 -35
  29. package/dist/python-src/src/middlewares/utils.py +5 -0
  30. package/dist/python-src/src/prompts/prompts.py +1 -0
  31. package/dist/python-src/src/stream/formatter.py +17 -17
  32. package/dist/python-src/src/stream/handler.py +109 -81
  33. package/dist/python-src/src/stream/handler_with_tracker.py +10 -10
  34. package/dist/python-src/src/tools/web.py +10 -9
  35. package/dist/python-src/src/tui/chatui.py +67 -51
  36. package/dist/python-src/src/tui/components/tlist.py +6 -6
  37. package/dist/python-src/src/tui/components/tscroll_panel.py +8 -8
  38. package/dist/python-src/src/tui/utils/trender.py +27 -27
  39. package/dist/python-src/src/utils/prompt.py +15 -4
  40. package/dist/python-src/uv.lock +1980 -2094
  41. package/package.json +1 -1
  42. package/dist/python-src/src/__pycache__/__init__.cpython-311.pyc +0 -0
  43. package/dist/python-src/src/managers/__pycache__/__init__.cpython-311.pyc +0 -0
  44. package/dist/python-src/src/managers/__pycache__/sandbox.cpython-311.pyc +0 -0
  45. package/dist/python-src/src/middlewares/__pycache__/__init__.cpython-311.pyc +0 -0
  46. package/dist/python-src/src/middlewares/__pycache__/hitl.cpython-311.pyc +0 -0
  47. package/dist/python-src/src/middlewares/dynamic_prompt.py +0 -15
  48. package/dist/python-src/src/stream/__pycache__/__init__.cpython-311.pyc +0 -0
  49. package/dist/python-src/src/stream/__pycache__/emitter.cpython-311.pyc +0 -0
  50. package/dist/python-src/src/stream/__pycache__/file_write_parser.cpython-311.pyc +0 -0
  51. package/dist/python-src/src/stream/__pycache__/formatter.cpython-311.pyc +0 -0
  52. package/dist/python-src/src/stream/__pycache__/handler.cpython-311.pyc +0 -0
  53. package/dist/python-src/src/stream/__pycache__/tracker.cpython-311.pyc +0 -0
  54. package/dist/python-src/src/stream/__pycache__/utils.cpython-311.pyc +0 -0
  55. package/dist/python-src/src/tools/__pycache__/__init__.cpython-311.pyc +0 -0
  56. package/dist/python-src/src/tools/__pycache__/skill_loader.cpython-311.pyc +0 -0
  57. package/dist/python-src/src/tools/__pycache__/tools.cpython-311.pyc +0 -0
  58. package/dist/python-src/src/tools/__pycache__/web.cpython-311.pyc +0 -0
  59. package/dist/python-src/src/tui/__pycache__/chatui.cpython-311.pyc +0 -0
  60. package/dist/python-src/src/tui/__pycache__/config.cpython-311.pyc +0 -0
  61. package/dist/python-src/src/tui/components/__pycache__/__init__.cpython-311.pyc +0 -0
  62. package/dist/python-src/src/tui/components/__pycache__/live_spinner.cpython-311.pyc +0 -0
  63. package/dist/python-src/src/tui/components/__pycache__/tdiff.cpython-311.pyc +0 -0
  64. package/dist/python-src/src/tui/components/__pycache__/tdisplay.cpython-311.pyc +0 -0
  65. package/dist/python-src/src/tui/components/__pycache__/tlist.cpython-311.pyc +0 -0
  66. package/dist/python-src/src/tui/components/__pycache__/tscroll_panel.cpython-311.pyc +0 -0
  67. package/dist/python-src/src/tui/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  68. package/dist/python-src/src/tui/utils/__pycache__/render.cpython-311.pyc +0 -0
  69. package/dist/python-src/src/tui/utils/__pycache__/trender.cpython-311.pyc +0 -0
  70. package/dist/python-src/src/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  71. package/dist/python-src/src/utils/__pycache__/utils.cpython-311.pyc +0 -0
@@ -0,0 +1,200 @@
1
+ _L='domain'
2
+ _K='default'
3
+ _J='source'
4
+ _I='utf-8'
5
+ _H='llm'
6
+ _G='tools'
7
+ _F='name'
8
+ _E=True
9
+ _D='description'
10
+ _C='user'
11
+ _B='project'
12
+ _A=None
13
+ from typing import Dict,Tuple,Any,List,Optional,Union
14
+ from pathlib import Path
15
+ import yaml,json,sys,re,os
16
+ sys.path.append('/Users/brandon/workspace/coder/autodev')
17
+ class AgentInfo:
18
+ def __init__(A,name,content,src_):B=content;A.name=name;A.original_content=B;A.src_=src_;A.meta,A.body=A.bt(B)
19
+ def bt(F,content):
20
+ B=content;C='^---\\n(.*?)\\n---\\n(.*)$';A=re.match(C,B,re.S)
21
+ if A:D=yaml.safe_load(A.group(1));E=A.group(2).strip();return D,E
22
+ else:return{},B.strip()
23
+ def info(A):B=A.body;return{_F:A.meta.get(_F,A.name),_D:A.meta.get(_D,''),_G:A.meta.get(_G,[]),_H:A.meta.get(_H,_A),'prompt':B,_J:A.src_}
24
+ class AgentManager:
25
+ def __init__(A,project_dir=_A):
26
+ C='agents';B='.autodev';A.project_dir=project_dir;A.user_agents_dir=os.path.join(str(Path.home()),B,C)
27
+ if A.project_dir:A.project_agents_dir=os.path.abspath(os.path.join(A.project_dir,B,C))
28
+ else:A.project_agents_dir=_A
29
+ A.agents={_B:{},_C:{}}
30
+ if A.project_agents_dir and not os.path.exists(A.project_agents_dir):os.makedirs(A.project_agents_dir)
31
+ if not os.path.exists(A.user_agents_dir):os.makedirs(A.user_agents_dir)
32
+ A.reload_agents()
33
+ def bv(O,dir_path,source):
34
+ E=source;D=dir_path;B={}
35
+ if not os.path.exists(D):return B
36
+ for(G,P,I)in os.walk(D):
37
+ H=os.path.relpath(G,D)
38
+ if H=='.':A=_K
39
+ else:A=H.replace(os.sep,'/')
40
+ if A not in B:B[A]={}
41
+ for F in I:
42
+ if F.endswith('.md'):
43
+ J=os.path.join(G,F);C=os.path.splitext(F)[0];print(f"加载 {E} 来源 agent: {A}/{C}")
44
+ try:
45
+ with open(J,'r',encoding=_I)as K:L=K.read()
46
+ M=AgentInfo(C,L,E);B[A][C]=M
47
+ except Exception as N:print(f"加载 {E} 来源 agent {A}/{C} 失败: {str(N)}")
48
+ return B
49
+ def reload_agents(A):
50
+ A.agents[_B].clear();A.agents[_C].clear();A.agents[_C]=A.bv(A.user_agents_dir,_C)
51
+ if A.project_agents_dir:A.agents[_B]=A.bv(A.project_agents_dir,_B)
52
+ def bu(A,source,domain,name):
53
+ B=source
54
+ if B==_B:
55
+ if not A.project_agents_dir:raise ValueError('项目目录未初始化,无法操作project来源的agent')
56
+ C=A.project_agents_dir
57
+ elif B==_C:C=A.user_agents_dir
58
+ else:raise ValueError(f"无效的来源: {B},仅支持 'project' 或 'user'")
59
+ D=os.path.join(C,domain.replace('/',os.sep));return os.path.join(D,f"{name}.md")
60
+ def exists(A,domain,name,source=_A):
61
+ C=source;B=domain
62
+ if C:return name in A.agents.get(C,{}).get(B,{})
63
+ else:
64
+ for D in[_B,_C]:
65
+ if name in A.agents.get(D,{}).get(B,{}):return _E
66
+ return False
67
+ def get_agent_with_source(A,domain,name):
68
+ C=name;B=domain
69
+ if C in A.agents.get(_B,{}).get(B,{}):return A.agents[_B][B][C],_B
70
+ elif C in A.agents.get(_C,{}).get(B,{}):return A.agents[_C][B][C],_C
71
+ else:return _A,_A
72
+ def create_agent(A,domain,name,meta,body,source=_B):
73
+ D=source;C=name;B=domain
74
+ if A.exists(B,C,D):raise ValueError(f"Agent '{D}/{B}/{C}' 已存在")
75
+ F=f"---\n{yaml.safe_dump(meta,allow_unicode=_E)}---\n{body.strip()}\n";E=A.bu(D,B,C);os.makedirs(os.path.dirname(E),exist_ok=_E)
76
+ with open(E,'w',encoding=_I)as G:G.write(F)
77
+ A.reload_agents()
78
+ def update_agent(C,domain,name,meta=_A,body=_A,source=_A):
79
+ D=source;B=name;A=domain
80
+ if D:
81
+ if not C.exists(A,B,D):raise ValueError(f"Agent '{D}/{A}/{B}' 不存在")
82
+ E=D
83
+ else:
84
+ L,E=C.get_agent_with_source(A,B)
85
+ if not E:raise ValueError(f"Agent '{A}/{B}' 不存在于任何来源")
86
+ F=C.agents[E][A][B];G=meta if meta is not _A else F.meta;H=body if body is not _A else F.body;I=f"---\n{yaml.safe_dump(G,allow_unicode=_E)}---\n{H.strip()}\n";J=C.bu(E,A,B)
87
+ with open(J,'w',encoding=_I)as K:K.write(I)
88
+ C.reload_agents()
89
+ def delete_agent(C,domain,name,source=_A):
90
+ D=source;B=name;A=domain
91
+ if D:
92
+ if not C.exists(A,B,D):raise ValueError(f"Agent '{D}/{A}/{B}' 不存在")
93
+ E=D
94
+ else:
95
+ G,E=C.get_agent_with_source(A,B)
96
+ if not E:raise ValueError(f"Agent '{A}/{B}' 不存在于任何来源")
97
+ F=C.bu(E,A,B)
98
+ if os.path.exists(F):os.remove(F)
99
+ C.reload_agents()
100
+ def get_agent(A,domain,name,source=_A):
101
+ D=source;C=name;B=domain
102
+ if D:return A.agents.get(D,{}).get(B,{}).get(C)
103
+ else:
104
+ E=A.agents.get(_B,{}).get(B,{}).get(C)
105
+ if E:return E
106
+ return A.agents.get(_C,{}).get(B,{}).get(C)
107
+ def list_domains(A,source=_A):
108
+ B=source;C=set()
109
+ if B:
110
+ if B in A.agents:C.update(A.agents[B].keys())
111
+ else:
112
+ for D in[_B,_C]:C.update(A.agents[D].keys())
113
+ return list(C)
114
+ def list_agents(G,domain=_A,source=_A):
115
+ I=source;B=domain;A={};J=[I]if I else[_B,_C]
116
+ for H in J:
117
+ if H not in G.agents:continue
118
+ if B:
119
+ if B in G.agents[H]:
120
+ if B not in A:A[B]=[]
121
+ A[B].extend(list(G.agents[H][B].keys()))
122
+ else:
123
+ for(D,K)in G.agents[H].items():
124
+ if D not in A:A[D]=[]
125
+ A[D].extend(list(K.keys()))
126
+ if B:
127
+ E=set();F=[]
128
+ for C in A.get(B,[]):
129
+ if C not in E:E.add(C);F.append(C)
130
+ return F
131
+ for D in A:
132
+ E=set();F=[]
133
+ for C in A[D]:
134
+ if C not in E:E.add(C);F.append(C)
135
+ A[D]=F
136
+ return A
137
+ def agent_info(D,domain,name,source=_A):
138
+ C=source;A=domain;B=D.get_agent(A,name,C)
139
+ if not B:raise ValueError(f"Agent '{A}/{name}' 不存在(来源: {C or'all'})")
140
+ E=B.info();return{_L:A,_J:B.src_,**E}
141
+ def get_conf(B,domain,source=_A):
142
+ E='members';A=domain;C={_L:A,E:{}};F=B.list_agents(domain=A,source=source)
143
+ for D in F:
144
+ try:G=B.agent_info(A,D);C[E][D]=G
145
+ except ValueError:continue
146
+ return C
147
+ def get_all_conf(A,source=_A):
148
+ B=source;C={};E=A.list_domains(source=B)
149
+ for D in E:C[D]=A.get_conf(D,source=B)
150
+ return C
151
+ def descriptions_(B,user=False,source=_A):
152
+ C=source;D={};H=[C]if C else[_B,_C]
153
+ for A in H:
154
+ if A not in B.agents:continue
155
+ for(E,I)in B.agents[A].items():
156
+ for(F,J)in I.items():
157
+ if user:G=f"@{E}/{F}[user_{A}]"
158
+ else:G=f"@{E}/{F}[{A}]"
159
+ D[G]=J.meta.get(_D,'')
160
+ return D
161
+ def parse_agent_file(file_path):
162
+ H="'";G='"'
163
+ with open(file_path,'r',encoding=_I)as M:J=M.read()
164
+ N='^---\\s*(.*?)\\s*---\\s*(.*)$';I=re.search(N,J,re.DOTALL|re.MULTILINE)
165
+ if not I:return{},J.strip()
166
+ K,O=I.group(1).strip(),I.group(2).strip();D={}
167
+ if K:
168
+ for E in K.splitlines():
169
+ E=E.strip()
170
+ if not E:continue
171
+ if': 'not in E:continue
172
+ B,A=E.split(': ',1);B=B.strip();A=A.strip()
173
+ if A.startswith('[')and A.endswith(']'):
174
+ L=A[1:-1].strip()
175
+ if L=='':F=[]
176
+ else:
177
+ P=[A.strip()for A in L.split(',')];F=[]
178
+ for C in P:
179
+ if C.startswith(G)and C.endswith(G)or C.startswith(H)and C.endswith(H):F.append(C[1:-1])
180
+ else:F.append(C)
181
+ D[B]=F
182
+ elif A.startswith(G)and A.endswith(G)or A.startswith(H)and A.endswith(H):D[B]=A[1:-1]
183
+ else:
184
+ try:Q=json.loads(A);D[B]=Q
185
+ except Exception:D[B]=A
186
+ return D,O
187
+ def curd():
188
+ D='user_helper';C='new_helper';B='coding';H=os.path.expanduser('~');A=AgentManager(H);print('=== 新增project来源的agent ===');A.create_agent(B,C,meta={_F:C,_D:'a test agent (project)',_G:['tool1','tool2'],_H:'gpt-4'},body='你是一个新的项目Agent',source=_B);print('\n=== 新增user来源的agent ===');A.create_agent(B,D,meta={_F:D,_D:'a test agent (user)',_G:['tool3'],_H:'gpt-3.5'},body='你是一个新的用户Agent',source=_C);print('\n=== 查询所有coding域的agents ===');E=A.list_agents(domain=B);print(f"coding域agents: {E}");print('\n=== 查询agent详细信息 ===')
189
+ try:F=A.agent_info(B,C,source=_B);print(f"project/new_helper: {F}")
190
+ except ValueError as G:print(G)
191
+ try:F=A.agent_info(B,D,source=_C);print(f"user/user_helper: {F}")
192
+ except ValueError as G:print(G)
193
+ print('\n=== 更新agent ===');A.update_agent(B,C,body='更新后的项目Agent prompt',source=_B);print('\n=== 删除agent ===');A.delete_agent(B,C,source=_B);A.delete_agent(B,D,source=_C);print('\n=== 删除后查询 ===');E=A.list_agents(domain=B);print(f"coding域剩余agents: {E}")
194
+ def main():
195
+ B=os.path.expanduser('~');A=AgentManager(B);print('=== 列出所有域 ===');print(A.list_domains());print('\n=== 列出default域的所有agents ===');print(A.list_agents(domain=_K));print('\n=== 列出所有域的agents ===');C=A.list_agents()
196
+ for(D,E)in C.items():print(f"{D}: {E}")
197
+ print('\n=== 所有agent描述(包含来源)===');F=A.descriptions_()
198
+ for(G,H)in F.items():print(f"{G}: {H}")
199
+ print('\n=== 获取所有配置 ===');I=A.get_all_conf();print(yaml.safe_dump(I,allow_unicode=_E,indent=2))
200
+ if __name__=='__main__':curd()
@@ -0,0 +1,49 @@
1
+ _C='sandbox'
2
+ _B='default'
3
+ _A=None
4
+ from typing import Dict
5
+ import sys,os
6
+ sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
7
+ from src.managers.manager_instruction import InstructionManager
8
+ from src.managers.manager_agent import AgentManager
9
+ from src.managers.sandbox import Container
10
+ DOCKERFILE_PATH=os.path.join('../../resources','dockerfiles',_C,'Dockerfile.sandbox')
11
+ class ContextManager:
12
+ def __init__(A,dockerfile_path=DOCKERFILE_PATH,mode=_C):A.mode=mode;A.dockerfile_path=dockerfile_path;A._docker_containers={};A._workspace_mapping={};A._instruction_managers={};A._agent_managers={}
13
+ def create_environment(A,session_id=_B,workspace_path=_A):
14
+ E='.autodev';D=True;C=session_id;B=workspace_path;print(f"create_environment: {C}, {B}")
15
+ if B:os.makedirs(B,exist_ok=D)
16
+ else:raise ValueError('workspace_path 不能为空')
17
+ A._workspace_mapping[C]=B
18
+ if A.mode==_C:A._docker_containers[C]=Container(user_id=C,workspace_path=B,dockerfile_path=A.dockerfile_path);A._docker_containers[C].start()
19
+ elif A.mode=='local':A._docker_containers[C]=_A
20
+ else:raise ValueError(f"不支持的模式: {A.mode}")
21
+ F=os.path.join(B,E,'commands');os.makedirs(F,exist_ok=D);A._instruction_managers[C]=InstructionManager(project_dir=B);G=os.path.join(B,E,'agents');os.makedirs(G,exist_ok=D);A._agent_managers[C]=AgentManager(project_dir=B)
22
+ def get_container(A,session_id=_B):
23
+ B=session_id;C=_A
24
+ if A._docker_containers.get(B,_A)is _A and A.mode==_C:A.create_environment(B)
25
+ C=A._docker_containers.get(B,_A);return C
26
+ def get_workdpace(A,session_id=_B):
27
+ B=session_id
28
+ if A._workspace_mapping.get(B,_A)is _A:A.create_environment(B)
29
+ C=A._workspace_mapping.get(B,_A);return C
30
+ def get_instruction_manager(A,session_id=_B):
31
+ B=session_id
32
+ if A._instruction_managers.get(B,_A)is _A:A.create_environment(B)
33
+ C=A._instruction_managers.get(B,_A);return C
34
+ def get_agent_manager(A,session_id=_B):
35
+ B=session_id
36
+ if A._agent_managers.get(B,_A)is _A:A.create_environment(B)
37
+ C=A._agent_managers.get(B,_A);return C
38
+ def shutdown(C,session_id=_A):
39
+ B=session_id
40
+ if B:
41
+ A=C._docker_containers.get(B,_A)
42
+ if A:A.shutdown()
43
+ else:
44
+ for(B,A)in C._docker_containers.items():A.shutdown()
45
+ def main():
46
+ A=ContextManager()
47
+ try:C='/Users/brandon/workspace/coder/coder_tui/_workspace';A.create_environment(workspace_path=C);C=A.get_workdpace();print(f"工作空间:\n{C}");D=A.get_command_mananger();B=D.parse('/git --persona-角色名:10 --persona-CI --think-hard 项目文档');print(f"命令执行内容:\n{B['executed_command']}");print(f"输入内容:\n{B['message']}");E=A.get_container();B=E.execute_command('ls -al');print(f"容器执行结果:\n{B}")
48
+ finally:A.shutdown()
49
+ if __name__=='__main__':main()
@@ -0,0 +1,192 @@
1
+ _J='---\n\n'
2
+ _I='utf-8'
3
+ _H='executed_instruction'
4
+ _G=True
5
+ _F='message'
6
+ _E='description'
7
+ _D='default'
8
+ _C='user'
9
+ _B='project'
10
+ _A=None
11
+ from typing import Dict,List,Tuple,Optional,Any
12
+ from pathlib import Path
13
+ import re,os
14
+ def read_instruction_file(file_path):
15
+ with open(file_path,'r',encoding=_I)as H:F=H.read()
16
+ I='^---\\s*(.*?)\\s*---\\s*(.*)$';E=re.search(I,F,re.DOTALL|re.MULTILINE)
17
+ if not E:return{},F.strip()
18
+ G=E.group(1).strip();J=E.group(2).strip();D={}
19
+ if G:
20
+ for B in G.split('\n'):
21
+ B=B.strip()
22
+ if not B:continue
23
+ if': 'in B:
24
+ C,A=B.split(': ',1);C=C.strip();A=A.strip()
25
+ if A.startswith('[')and A.endswith(']'):K=[A.strip().strip('"')for A in A[1:-1].split(',')if A.strip()];D[C]=K
26
+ elif A.startswith('"')and A.endswith('"'):D[C]=A[1:-1]
27
+ else:D[C]=A
28
+ return D,J
29
+ class Instruction:
30
+ def __init__(A,name,content,settings,src_):A.name=name;A.settings=settings;A.original_content=content;A.arguments_placeholder='$ARGUMENTS';A.src_=src_
31
+ def info(A):B='agents';C=A.original_content;return{'name':A.name,_E:A.settings.get(_E,''),B:A.settings.get(B,[]),'content':C,'source':A.src_}
32
+ def execute(A,arguments=''):B=A.original_content.replace(A.arguments_placeholder,arguments);return B
33
+ class InstructionManager:
34
+ def __init__(A,project_dir=_A):
35
+ C='commands';B='.autodev';A.project_dir=project_dir;A.user_dir=os.path.join(str(Path.home()),B,C)
36
+ if A.project_dir:A.project_commands_dir=os.path.abspath(os.path.join(A.project_dir,B,C))
37
+ else:A.project_commands_dir=_A
38
+ A.instructions={_B:{},_C:{}}
39
+ if A.project_commands_dir and not os.path.exists(A.project_commands_dir):os.makedirs(A.project_commands_dir)
40
+ if not os.path.exists(A.user_dir):os.makedirs(A.user_dir)
41
+ A.reload_instructions()
42
+ def bw(O,dir_path,source):
43
+ F=source;C=dir_path;A={}
44
+ if not os.path.exists(C):return A
45
+ for(G,P,I)in os.walk(C):
46
+ for D in I:
47
+ H=os.path.relpath(G,C)
48
+ if H=='.':B=_D
49
+ else:B=H.replace(os.sep,'/')
50
+ if B not in A:A[B]={}
51
+ if D.endswith('.md'):
52
+ J=os.path.join(G,D);E=os.path.splitext(D)[0]
53
+ try:K,L=read_instruction_file(J);M=Instruction(E,L,K,F);A[B][E]=M
54
+ except Exception as N:print(f"从 {F} 加载命令 {B}/{E} 失败: {str(N)}")
55
+ return A
56
+ def reload_instructions(A):
57
+ A.instructions[_B].clear();A.instructions[_C].clear();A.instructions[_C]=A.bw(A.user_dir,_C)
58
+ if A.project_commands_dir:A.instructions[_B]=A.bw(A.project_commands_dir,_B)
59
+ def bx(A,source,domain,name):
60
+ B=source
61
+ if B==_B:
62
+ if not A.project_commands_dir:raise ValueError('项目目录未初始化,无法操作project来源的指令')
63
+ C=A.project_commands_dir
64
+ elif B==_C:C=A.user_dir
65
+ else:raise ValueError(f"无效的来源: {B},仅支持 'project' 或 'user'")
66
+ D=os.path.join(C,domain.replace('/',os.sep));return os.path.join(D,f"{name}.md")
67
+ def exists(A,domain,name,source=_A):
68
+ C=source;B=domain
69
+ if C:return name in A.instructions.get(C,{}).get(B,{})
70
+ else:
71
+ for D in[_B,_C]:
72
+ if name in A.instructions.get(D,{}).get(B,{}):return _G
73
+ return False
74
+ def get_instruction_with_source(A,domain,name):
75
+ C=name;B=domain
76
+ if C in A.instructions.get(_B,{}).get(B,{}):return A.instructions[_B][B][C],_B
77
+ elif C in A.instructions.get(_C,{}).get(B,{}):return A.instructions[_C][B][C],_C
78
+ else:return _A,_A
79
+ def add_instruction(B,domain,name,settings,content,source=_B):
80
+ E=source;D=name;C=domain
81
+ if B.exists(C,D,E):raise ValueError(f"指令 '{E}/{C}/{D}' 已存在")
82
+ G=B.bx(E,C,D);os.makedirs(os.path.dirname(G),exist_ok=_G)
83
+ with open(G,'w',encoding=_I)as A:
84
+ A.write('---\n')
85
+ for(H,F)in settings.items():
86
+ if isinstance(F,list):A.write(f"{H}: [{', '.join([repr(A)for A in F])}]\n")
87
+ else:A.write(f'{H}: "{F}"\n')
88
+ A.write(_J);A.write(content)
89
+ B.reload_instructions();I,J=B.get_instruction_with_source(C,D);return I
90
+ def update_instruction(C,domain,name,settings=_A,content=_A,source=_A):
91
+ J=content;I=settings;F=source;B=name;A=domain
92
+ if F:
93
+ if not C.exists(A,B,F):raise ValueError(f"指令 '{F}/{A}/{B}' 不存在")
94
+ G=F
95
+ else:
96
+ M,G=C.get_instruction_with_source(A,B)
97
+ if not G:raise ValueError(f"指令 '{A}/{B}' 不存在于任何来源")
98
+ D=C.instructions[G][A][B]
99
+ if I is not _A:D.settings=I
100
+ if J is not _A:D.original_content=J
101
+ K=C.bx(G,A,B);os.makedirs(os.path.dirname(K),exist_ok=_G)
102
+ with open(K,'w',encoding=_I)as E:
103
+ E.write('---\n')
104
+ for(L,H)in D.settings.items():
105
+ if isinstance(H,list):E.write(f"{L}: [{', '.join([repr(A)for A in H])}]\n")
106
+ else:E.write(f'{L}: "{H}"\n')
107
+ E.write(_J);E.write(D.original_content)
108
+ C.reload_instructions();return D
109
+ def delete_instruction(C,domain,name,source=_A):
110
+ D=source;B=name;A=domain
111
+ if D:
112
+ if not C.exists(A,B,D):raise ValueError(f"指令 '{D}/{A}/{B}' 不存在")
113
+ E=D
114
+ else:
115
+ G,E=C.get_instruction_with_source(A,B)
116
+ if not E:raise ValueError(f"指令 '{A}/{B}' 不存在于任何来源")
117
+ F=C.bx(E,A,B)
118
+ if os.path.exists(F):os.remove(F)
119
+ C.reload_instructions()
120
+ def load_all_instructions(A,domain=_D,source=_A):
121
+ D=domain;B=source;C=[]
122
+ if B:
123
+ if B in A.instructions:C.extend(list(A.instructions[B].get(D,{}).values()))
124
+ else:
125
+ for E in[_B,_C]:C.extend(list(A.instructions[E].get(D,{}).values()))
126
+ return C
127
+ def get_instruction(A,domain,instruction_name,source=_A):
128
+ D=source;C=instruction_name;B=domain
129
+ if D:return A.instructions.get(D,{}).get(B,{}).get(C,_A)
130
+ else:
131
+ E=A.instructions.get(_B,{}).get(B,{}).get(C)
132
+ if E:return E
133
+ return A.instructions.get(_C,{}).get(B,{}).get(C,_A)
134
+ def list_domains(A,source=_A):
135
+ B=source;C=set()
136
+ if B:
137
+ if B in A.instructions:C.update(A.instructions[B].keys())
138
+ else:
139
+ for D in[_B,_C]:C.update(A.instructions[D].keys())
140
+ return list(C)
141
+ def list_instructions(D,domain=_A,source=_A):
142
+ F=source;B=domain;A={};L=[F]if F else[_B,_C]
143
+ for E in L:
144
+ if E not in D.instructions:continue
145
+ if B:
146
+ if B in D.instructions[E]:
147
+ if B not in A:A[B]=[]
148
+ A[B].extend(list(D.instructions[E][B].values()))
149
+ else:
150
+ for(C,M)in D.instructions[E].items():
151
+ if C not in A:A[C]=[]
152
+ A[C].extend(M.values())
153
+ if B:return A.get(B,[])
154
+ for C in A:
155
+ G=set();H=[]
156
+ for I in A[C]:
157
+ J=I.name
158
+ if J not in G:G.add(J);H.append(I)
159
+ A[C]=H
160
+ K=[]
161
+ for B in A.keys():N=A[B];K.extend(N)
162
+ return K
163
+ def descriptions_(B,source=_A):
164
+ C=source;D={};E=[C]if C else[_B,_C]
165
+ for A in E:
166
+ if A not in B.instructions:continue
167
+ for(F,G)in B.instructions[A].items():
168
+ for(H,I)in G.items():D[f"{A}/{F}/{H}"]=I.settings.get(_E,'')
169
+ return D
170
+ def execute_instruction(E,domain,instruction_name,arguments='',source=_A):
171
+ C=source;B=instruction_name;A=domain;D=E.get_instruction(A,B,C)
172
+ if not D:raise ValueError(f"命令 '{A}/{B}' 不存在(来源: {C or'all'})")
173
+ return D.execute(arguments)
174
+ def parse(F,query):
175
+ A=query
176
+ if not A.strip().startswith('/'):B=_D;C=_D;G=F.execute_instruction(B,C,arguments='');return{_H:_A,_F:A.strip()}
177
+ D=re.findall('"[^"]*"|\\S+',A.strip())
178
+ if not D:return{'instruction':_A,'args':[],_F:''}
179
+ L=D[0][1:];H=L.split('/');B='/'.join(H[:-1]);C=H[-1];I=[];J=[];K=False
180
+ for E in D[1:]:
181
+ if E.startswith('--')and not K:I.append(E)
182
+ else:K=_G;M=E.strip('"');J.append(M)
183
+ N=' '.join(J);O=' '.join(I);G=F.execute_instruction(B,C,O);return{_H:G,_F:N}
184
+ def curd():
185
+ E='backup';D='tags';B='deploy';G='/Users/brandon/workspace/coder/autocoder';A=InstructionManager(G);A.add_instruction(domain=_D,name=B,settings={_E:'部署项目',D:['ci','cd']},content='执行部署脚本: $ARGUMENTS',source=_B);A.add_instruction(domain=_D,name=E,settings={_E:'备份用户数据',D:[E]},content='执行备份脚本: $ARGUMENTS',source=_C);A.update_instruction(domain=_D,name=B,settings={_E:'更新部署流程',D:['ci',B]},content='新的部署命令: $ARGUMENTS',source=_B);C=A.load_all_instructions(domain=_D);print('所有指令:')
186
+ for F in C:print(f"- {F.name} (来源: {F.src_})")
187
+ A.delete_instruction(_D,B,source=_B);A.delete_instruction(_D,E,source=_C);C=A.load_all_instructions(domain=_D);print('\n删除后的指令:');print([A.name for A in C])
188
+ def main():
189
+ C='/Users/brandon/workspace/coder/autodev';A=InstructionManager(C);print('=== 列出所有域 ===');print(A.list_domains());print('\n=== 列出default域的所有指令 ===');print(A.list_instructions(domain=_D));print('\n=== 所有指令描述(包含来源)===');D=A.descriptions_()
190
+ for(E,F)in D.items():print(f"{E}: {F}")
191
+ print('\n=== 测试指令解析和执行 ===');B=A.parse('/git --persona-角色名:10 --persona-CI --think-hard 项目文档');print(f"命令执行内容:\n {B[_H]}");print(f"输入内容:\n {B[_F]}");print('\n=== 测试默认指令 ===');B=A.parse('@agent 你好,项目文档');print(f"命令执行内容:\n {B[_H]}");print(f"输入内容:\n {B[_F]}")
192
+ if __name__=='__main__':curd()
@@ -21,14 +21,14 @@ sys.path.append(PROJ_PATH)
21
21
  logger=logging.getLogger(__file__)
22
22
  class Container:
23
23
  def __init__(A,user_id=_C,workspace_path=_B,dockerfile_path='.',image_name=_J,container_basename='sandbox'):A.client=docker.from_env();A.container_basename=container_basename;A.workspace_path=workspace_path;A.dockerfile_path=dockerfile_path;A.image_name=image_name;A.sock=_B;A.queue=_B;A.container=_B;A.user_id=user_id;A.images={_G:'ubuntu:22.04',_H:'python:3.12-slim','node':'node:20-bullseye-slim',_C:_J}
24
- def br(A):
24
+ def bs(A):
25
25
  try:
26
26
  B=A.client.images.get(A.image_name)
27
27
  if B:logger.info(f"Image {A.image_name} exists.");return _A
28
28
  else:logger.info(f"Image {A.image_name} not exists.");return _E
29
29
  except docker.errors.ImageNotFound:logger.error(f"Image {A.image_name} not exists.");return _E
30
30
  except Exception as C:logger.error(f"检查镜像时出错: {str(C)}");return _E
31
- def bs(B):
31
+ def br(B):
32
32
  F='arm64';print('🔧 Building Docker image...')
33
33
  try:
34
34
  C=platform.machine()
@@ -44,7 +44,7 @@ class Container:
44
44
  except Exception as D:logger.error(f"An unexpected error occurred: {D}");raise
45
45
  def get_or_create_container(A,container_name,image_type=_C):
46
46
  E='running';C=image_type;B=container_name;D=_F;F=A.workspace_path;B=f"{A.container_basename}_{A.user_id}"
47
- if C==_C and not A.br():A.bs()
47
+ if C==_C and not A.bs():A.br()
48
48
  try:
49
49
  A.container=A.client.containers.get(B)
50
50
  if A.container.status==E:logger.info(f"容器 {B} 已存在且运行中,直接复用")
@@ -0,0 +1,63 @@
1
+ _H='.tcode/security.md'
2
+ _G='security.md'
3
+ _F='.tcode/review.md'
4
+ _E='review.md'
5
+ _D='security_contents'
6
+ _C='review_contents'
7
+ _B='utf-8'
8
+ _A='r'
9
+ from typing import TYPE_CHECKING,Annotated,NotRequired,TypedDict
10
+ import logging,os
11
+ if TYPE_CHECKING:from collections.abc import Awaitable,Callable;from langchain_core.runnables import RunnableConfig;from langgraph.runtime import Runtime
12
+ from langchain.agents.middleware.types import AgentMiddleware,AgentState,ContextT,ModelRequest,ModelResponse,PrivateStateAttr,ResponseT
13
+ from langchain.tools import ToolRuntime
14
+ from langchain_core.messages import ContextBlock,SystemMessage
15
+ from src.middlewares.utils import append_to_system_message
16
+ logger=logging.getLogger(__name__)
17
+ class DynamicContentState(AgentState):review_contents:NotRequired[Annotated[dict[str,str],PrivateStateAttr]];security_contents:NotRequired[Annotated[dict[str,str],PrivateStateAttr]]
18
+ class DynamicContentUpdate(TypedDict):review_contents:dict[str,str];security_contents:dict[str,str]
19
+ REVIEW_SYSTEM_PROMPT=' \n<review_rules>\n {review_rules}\n</review_rules>\n\n<review_guidelines>\n 如果用户要求对项目进行 Review ,请严格依照 review_rules 标签中的规则 对项目进行 Review 。\n</review_guidelines>\n'
20
+ SECURITY_SYSTEM_PROMPT=' \n<security_rules>\n {security_rules}\n</security_rules>\n\n<<security_guidelines>\n 如果用户要求对项目进行 安全检查 ,请严格依照 security_rules 标签中的规则 对项目进行安全检查 。\n</security_guidelines>\n'
21
+ class DynamicContentMiddleware(AgentMiddleware[DynamicContentState,ContextT,ResponseT]):
22
+ def __init__(A,*,home_path=os.path.expanduser('~'),project_path=os.getcwd()):A.home_path=home_path;A.project_path=project_path
23
+ def cu(G,prompt,content_type,contents):
24
+ E='( No rules loaded)';C=contents;B=content_type;A=prompt
25
+ if not C:return A.format(**{B:E})
26
+ D=[f"{A}\n{C[A]}"for A in C]
27
+ if not D:return A.format(**{B:E})
28
+ F='\n\n'.join(D);return A.format(**{B:F})
29
+ def before_agent(A,state,runtime,config):
30
+ I=state
31
+ if _C in I and _D in I:return
32
+ C={};D=os.path.join(A.project_path,_E);E=os.path.join(A.home_path,_F)
33
+ if A.project_path and os.path.exists(D):
34
+ with open(D,_A,encoding=_B)as B:C[D]=B.read()
35
+ if A.home_path and os.path.exists(E):
36
+ with open(E,_A,encoding=_B)as B:C[E]=B.read()
37
+ F={};G=os.path.join(A.project_path,_G);H=os.path.join(A.home_path,_H)
38
+ if A.project_path and os.path.exists(G):
39
+ with open(G,_A,encoding=_B)as B:F[G]=B.read()
40
+ if A.home_path and os.path.exists(H):
41
+ with open(H,_A,encoding=_B)as B:F[H]=B.read()
42
+ return DynamicContentUpdate(review_contents=C,security_contents=F)
43
+ async def after_agent(A,state,runtime,config):
44
+ I=state
45
+ if _C in I and _D in I:return
46
+ C={};D=os.path.join(A.project_path,_E);E=os.path.join(A.home_path,_F)
47
+ if A.project_path and os.path.exists(D):
48
+ with open(D,_A,encoding=_B)as B:C[D]=B.read()
49
+ if A.home_path and os.path.exists(E):
50
+ with open(E,_A,encoding=_B)as B:C[E]=B.read()
51
+ F={};G=os.path.join(A.project_path,_G);H=os.path.join(A.home_path,_H)
52
+ if A.project_path and os.path.exists(G):
53
+ with open(G,_A,encoding=_B)as B:F[G]=B.read()
54
+ if A.home_path and os.path.exists(H):
55
+ with open(H,_A,encoding=_B)as B:F[H]=B.read()
56
+ return DynamicContentUpdate(review_contents=C,security_contents=F)
57
+ def modify_request(E,request):
58
+ B=request;F=B.state.get(_C,{});G=B.state.get(_D,{});C=E.cu(C,'review_rules',F);D=E.cu(D,'security_rules',G);A=B.system_message
59
+ if C:A=append_to_system_message(A,C)
60
+ if D:A=append_to_system_message(A,D)
61
+ return B.override(system_message=A)
62
+ def wrap_model_call(A,request,handler):B=A.modify_request(request);return handler(B)
63
+ async def awrap_model_call(A,request,handler):B=A.modify_request(request);return await handler(B)
@@ -21,12 +21,12 @@ class ReviewConfig(TypedDict):action_name:str;allowed_decisions:list[DecisionTyp
21
21
  class HITLRequest(TypedDict):action_requests:list[ActionRequest];review_configs:list[ReviewConfig]
22
22
  class HumanInTheLoopMiddleware(AgentMiddleware[StateT,ContextT]):
23
23
  def __init__(A,interrupt_on=[],*,description_perfix='Tool execution requires approval'):super().__init__();A.interrupt_on=interrupt_on;A.description_prefix=description_perfix
24
- def by(D,tool_call):A=tool_call;B=A[_E];C=A[_F];E=A['id'];F=f"{D.description_prefix}\n\nTool: {B}\nArgs: {C}";G=ActionRequest(name=B,id=E,args=C,description=F);H=ReviewConfig(action_name=B,allowed_decisions=[_B,_A,_C]);return G,H
24
+ def cd(D,tool_call):A=tool_call;B=A[_E];C=A[_F];E=A['id'];F=f"{D.description_prefix}\n\nTool: {B}\nArgs: {C}";G=ActionRequest(name=B,id=E,args=C,description=F);H=ReviewConfig(action_name=B,allowed_decisions=[_B,_A,_C]);return G,H
25
25
  async def awrap_tool_call(E,request,handler):
26
26
  C=handler;A=request;F=A.tool_call['id'];D=A.tool_call[_E];R=A.tool_call[_F];G=A.runtime;H=G.context;I=H.tool_mode
27
27
  if I==_A:return await C(A)
28
28
  if len(E.interrupt_on)>0 and not D.strip().lower()in E.interrupt_on:return await C(A)
29
- J,K=E.by(A.tool_call);L=HITLRequest(action_requests=[J],review_configs=[K]);M=interrupt(L);B=M[_G][0][_D]
29
+ J,K=E.cd(A.tool_call);L=HITLRequest(action_requests=[J],review_configs=[K]);M=interrupt(L);B=M[_G][0][_D]
30
30
  if B==_B:return await C(A)
31
31
  if B==_A:return await C(A)
32
32
  if B==_C:N=f"User rejected the tool call for `{D}` with id {F}";O=ToolMessage(content=N,name=D,tool_call_id=F,status='error');return O
@@ -35,7 +35,7 @@ class HumanInTheLoopMiddleware(AgentMiddleware[StateT,ContextT]):
35
35
  C=handler;A=request;F=A.tool_call['id'];D=A.tool_call[_E];R=A.tool_call[_F];H=A.runtime;I=H.context;J=I.tool_mode
36
36
  if J==_A:return C(A)
37
37
  if len(E.interrupt_on)>0 and not D.strip().lower()in E.interrupt_on:return C(A)
38
- K,L=E.by(A.tool_call);M=HITLRequest(action_requests=[K],review_configs=[L]);G=interrupt(M);print(f"[HITL] -> Human decision: {G}");B=G[_G][0][_D]
38
+ K,L=E.cd(A.tool_call);M=HITLRequest(action_requests=[K],review_configs=[L]);G=interrupt(M);print(f"[HITL] -> Human decision: {G}");B=G[_G][0][_D]
39
39
  if B==_B:return C(A)
40
40
  if B==_A:return C(A)
41
41
  if B==_C:N=f"User rejected the tool call for `{D}` with id {F}";O=ToolMessage(content=N,name=D,tool_call_id=F,status='error');return O
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+ _B='utf-8'
3
+ _A='memory_contents'
4
+ import logging,os
5
+ from typing import TYPE_CHECKING,Annotated,NotRequired,TypedDict
6
+ if TYPE_CHECKING:from collections.abc import Awaitable,Callable;from langchain_core.runnables import RunnableConfig;from langgraph.runtime import Runtime
7
+ from langchain.agents.middleware.types import AgentMiddleware,AgentState,ContextT,ModelRequest,ModelResponse,PrivateStateAttr,ResponseT
8
+ from langchain.tools import ToolRuntime
9
+ logger=logging.getLogger(__name__)
10
+ from src.middlewares.utils import append_to_system_message
11
+ class MemoryState(AgentState):memory_contents:NotRequired[Annotated[dict[str,str],PrivateStateAttr]]
12
+ class MemoryStateUpdate(TypedDict):memory_contents:dict[str,str]
13
+ MEMORY_SYSTEM_PROMPT=' \n<agent_memory>\n{agent_memory}\n</agent_memory>\n\n<memory_guidelines>\n The above <agent_memory> was loaded in from files in your filesystem. As you learn from your interactions with the user, you can save new knowledge by calling the `edit_file` tool.\n\n **Learning from feedback:**\n - One of your MAIN PRIORITIES is to learn from your interactions with the user. These learnings can be implicit or explicit. This means that in the future, you will remember this important information.\n - When you need to remember something, updating memory must be your FIRST, IMMEDIATE action - before responding to the user, before calling other tools, before doing anything else. Just update memory immediately.\n - When user says something is better/worse, capture WHY and encode it as a pattern.\n - Each correction is a chance to improve permanently - don\'t just fix the immediate issue, update your instructions.\n - A great opportunity to update your memories is when the user interrupts a tool call and provides feedback. You should update your memories immediately before revising the tool call.\n - Look for the underlying principle behind corrections, not just the specific mistake.\n - The user might not explicitly ask you to remember something, but if they provide information that is useful for future use, you should update your memories immediately.\n\n **Asking for information:**\n - If you lack context to perform an action (e.g. send a Slack DM, requires a user ID/email) you should explicitly ask the user for this information.\n - It is preferred for you to ask for information, don\'t assume anything that you do not know!\n - When the user provides information that is useful for future use, you should update your memories immediately.\n\n **When to update memories:**\n - When the user explicitly asks you to remember something (e.g., "remember my email", "save this preference")\n - When the user describes your role or how you should behave (e.g., "you are a web researcher", "always do X")\n - When the user gives feedback on your work - capture what was wrong and how to improve\n - When the user provides information required for tool use (e.g., slack channel ID, email addresses)\n - When the user provides context useful for future tasks, such as how to use tools, or which actions to take in a particular situation\n - When you discover new patterns or preferences (coding styles, conventions, workflows)\n\n **When to NOT update memories:**\n - When the information is temporary or transient (e.g., "I\'m running late", "I\'m on my phone right now")\n - When the information is a one-time task request (e.g., "Find me a recipe", "What\'s 25 * 4?")\n - When the information is a simple question that doesn\'t reveal lasting preferences (e.g., "What day is it?", "Can you explain X?")\n - When the information is an acknowledgment or small talk (e.g., "Sounds good!", "Hello", "Thanks for that")\n - When the information is stale or irrelevant in future conversations\n - Never store API keys, access tokens, passwords, or any other credentials in any file, memory, or system prompt.\n - If the user asks where to put API keys or provides an API key, do NOT echo or save it.\n\n **Examples:**\n Example 1 (remembering user information):\n User: Can you connect to my google account?\n Agent: Sure, I\'ll connect to your google account, what\'s your google account email?\n User: john@example.com\n Agent: Let me save this to my memory.\n Tool Call: edit_file(...) -> remembers that the user\'s google account email is john@example.com\n\n Example 2 (remembering implicit user preferences):\n User: Can you write me an example for creating a deep agent in LangChain?\n Agent: Sure, I\'ll write you an example for creating a deep agent in LangChain <example code in Python>\n User: Can you do this in JavaScript\n Agent: Let me save this to my memory.\n Tool Call: edit_file(...) -> remembers that the user prefers to get LangChain code examples in JavaScript\n Agent: Sure, here is the JavaScript example<example code in JavaScript>\n\n Example 3 (do not remember transient information):\n User: I\'m going to play basketball tonight so I will be offline for a few hours.\n Agent: Okay I\'ll add a block to your calendar.\n Tool Call: create_calendar_event(...) -> just calls a tool, does not commit anything to memory, as it is transient information\n</memory_guidelines>\n'
14
+ class MemoryMiddleware(AgentMiddleware[MemoryState,ContextT,ResponseT]):
15
+ state_schema=MemoryState
16
+ def __init__(A,*,home_path=os.path.expanduser('~'),project_path=os.getcwd()):A.home_path=home_path;A.project_path=project_path
17
+ def ce(D,contents):
18
+ C='(No memory loaded)';A=contents
19
+ if not A:return MEMORY_SYSTEM_PROMPT.format(agent_memory=C)
20
+ B=[f"{B}\n{A[B]}"for B in D.sources if A.get(B)]
21
+ if not B:return MEMORY_SYSTEM_PROMPT.format(agent_memory=C)
22
+ E='\n\n'.join(B);return MEMORY_SYSTEM_PROMPT.format(agent_memory=E)
23
+ def before_agent(A,state,runtime,config):
24
+ F='.tcode/MEMORY.md'
25
+ if _A in state:return
26
+ B={};C=os.path.join(A.project_path,F);D=os.path.join(A.home_path,F)
27
+ if A.project_path and os.path.exists(C):
28
+ with open(C,'r',encoding=_B)as E:B[C]=E.read()
29
+ if A.home_path and os.path.exists(D):
30
+ with open(D,'r',encoding=_B)as E:B[D]=E.read()
31
+ return MemoryStateUpdate(memory_contents=B)
32
+ async def abefore_agent(B,state,runtime,config):
33
+ D=state
34
+ if _A in D:return
35
+ F=B._get_backend(D,runtime,config);E={};G=await F.adownload_files(list(B.sources))
36
+ for(C,A)in zip(B.sources,G,strict=True):
37
+ if A.error is not None:
38
+ if A.error=='file_not_found':continue
39
+ H=f"Failed to download {C}: {A.error}";raise ValueError(H)
40
+ if A.content is not None:E[C]=A.content.decode(_B);logger.debug('Loaded memory from: %s',C)
41
+ return MemoryStateUpdate(memory_contents=E)
42
+ def modify_request(B,request):A=request;C=A.state.get(_A,{});D=B.ce(C);E=append_to_system_message(A.system_message,D);return A.override(system_message=E)
43
+ def wrap_model_call(A,request,handler):B=A.modify_request(request);return handler(B)
44
+ async def awrap_model_call(A,request,handler):B=A.modify_request(request);return await handler(B)