@brandon_9527/tcode 1.0.2 → 1.0.6

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 (73) 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 +71 -2
  13. package/dist/python-src/main.py +440 -3
  14. package/dist/python-src/pyproject.toml +3 -2
  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/core/deepagents.py +1 -1
  21. package/dist/python-src/src/managers/manager_agent.py +200 -0
  22. package/dist/python-src/src/managers/manager_context.py +49 -0
  23. package/dist/python-src/src/managers/manager_instruction.py +192 -0
  24. package/dist/python-src/src/middlewares/dynamic_content.py +66 -0
  25. package/dist/python-src/src/middlewares/hitl.py +3 -3
  26. package/dist/python-src/src/middlewares/inject_content.py +0 -0
  27. package/dist/python-src/src/middlewares/memory.py +44 -0
  28. package/dist/python-src/src/middlewares/subagents.py +25 -25
  29. package/dist/python-src/src/middlewares/summary.py +37 -37
  30. package/dist/python-src/src/middlewares/utils.py +5 -0
  31. package/dist/python-src/src/prompts/prompts.py +1 -0
  32. package/dist/python-src/src/stream/formatter.py +19 -19
  33. package/dist/python-src/src/stream/handler.py +105 -78
  34. package/dist/python-src/src/stream/handler_with_tracker.py +7 -7
  35. package/dist/python-src/src/tools/tools.py +2 -2
  36. package/dist/python-src/src/tools/web.py +10 -9
  37. package/dist/python-src/src/tui/chatui.py +57 -45
  38. package/dist/python-src/src/tui/components/tlist.py +6 -6
  39. package/dist/python-src/src/tui/demo.py +22 -0
  40. package/dist/python-src/src/tui/utils/trender.py +32 -32
  41. package/dist/python-src/src/utils/prompt.py +15 -4
  42. package/dist/python-src/uv.lock +2019 -2098
  43. package/package.json +1 -1
  44. package/dist/python-src/src/__pycache__/__init__.cpython-311.pyc +0 -0
  45. package/dist/python-src/src/managers/__pycache__/__init__.cpython-311.pyc +0 -0
  46. package/dist/python-src/src/managers/__pycache__/sandbox.cpython-311.pyc +0 -0
  47. package/dist/python-src/src/middlewares/__pycache__/__init__.cpython-311.pyc +0 -0
  48. package/dist/python-src/src/middlewares/__pycache__/hitl.cpython-311.pyc +0 -0
  49. package/dist/python-src/src/middlewares/dynamic_prompt.py +0 -15
  50. package/dist/python-src/src/stream/__pycache__/__init__.cpython-311.pyc +0 -0
  51. package/dist/python-src/src/stream/__pycache__/emitter.cpython-311.pyc +0 -0
  52. package/dist/python-src/src/stream/__pycache__/file_write_parser.cpython-311.pyc +0 -0
  53. package/dist/python-src/src/stream/__pycache__/formatter.cpython-311.pyc +0 -0
  54. package/dist/python-src/src/stream/__pycache__/handler.cpython-311.pyc +0 -0
  55. package/dist/python-src/src/stream/__pycache__/tracker.cpython-311.pyc +0 -0
  56. package/dist/python-src/src/stream/__pycache__/utils.cpython-311.pyc +0 -0
  57. package/dist/python-src/src/tools/__pycache__/__init__.cpython-311.pyc +0 -0
  58. package/dist/python-src/src/tools/__pycache__/skill_loader.cpython-311.pyc +0 -0
  59. package/dist/python-src/src/tools/__pycache__/tools.cpython-311.pyc +0 -0
  60. package/dist/python-src/src/tools/__pycache__/web.cpython-311.pyc +0 -0
  61. package/dist/python-src/src/tui/__pycache__/chatui.cpython-311.pyc +0 -0
  62. package/dist/python-src/src/tui/__pycache__/config.cpython-311.pyc +0 -0
  63. package/dist/python-src/src/tui/components/__pycache__/__init__.cpython-311.pyc +0 -0
  64. package/dist/python-src/src/tui/components/__pycache__/live_spinner.cpython-311.pyc +0 -0
  65. package/dist/python-src/src/tui/components/__pycache__/tdiff.cpython-311.pyc +0 -0
  66. package/dist/python-src/src/tui/components/__pycache__/tdisplay.cpython-311.pyc +0 -0
  67. package/dist/python-src/src/tui/components/__pycache__/tlist.cpython-311.pyc +0 -0
  68. package/dist/python-src/src/tui/components/__pycache__/tscroll_panel.cpython-311.pyc +0 -0
  69. package/dist/python-src/src/tui/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  70. package/dist/python-src/src/tui/utils/__pycache__/render.cpython-311.pyc +0 -0
  71. package/dist/python-src/src/tui/utils/__pycache__/trender.cpython-311.pyc +0 -0
  72. package/dist/python-src/src/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  73. package/dist/python-src/src/utils/__pycache__/utils.cpython-311.pyc +0 -0
@@ -1,7 +1,7 @@
1
1
  _O='success'
2
2
  _N='pending'
3
- _M=False
4
- _L='tool_call'
3
+ _M='tool_call'
4
+ _L=False
5
5
  _K='status'
6
6
  _J='result'
7
7
  _I='interrupt_id'
@@ -29,12 +29,12 @@ from langgraph.config import get_stream_writer
29
29
  from src.middlewares.hitl import HumanInTheLoopMiddleware
30
30
  class SubAgent(TypedDict):name:str;description:str;system_prompt:str;tools:Sequence[BaseTool|Callable|dict[str,Any]];model:NotRequired[str|BaseChatModel];middleware:NotRequired[list[AgentMiddleware]];interrupt_on:NotRequired[dict[str,bool|InterruptOnConfig]]
31
31
  class CompiledSubAgent(TypedDict):name:str;description:str;runnable:Runnable
32
- DEFAULT_SUBAGENT_PROMPT='In order to complete the objective that the user asks of you, you have access to a number of standard tools.'
32
+ DEFAULT_SUBAGENT_PROMPT='You may use a variety of standard tools to complete tasks that you believe will take a long time to process, as proposed by users, or tasks explicitly requested by users.'
33
33
  _EXCLUDED_STATE_KEYS=_B,'todos'
34
34
  TASK_TOOL_DESCRIPTION='Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.\n\nAvailable agent types and the tools they have access to:\n{available_agents}\n\nWhen using the Task tool, you must specify a subagent_type parameter to select which agent type to use.\n\n## Usage notes:\n1. Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses\n2. When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.\n3. Each agent invocation is stateless. You will not be able to send additional messages to the agent, nor will the agent be able to communicate with you outside of its final report. Therefore, your prompt should contain a highly detailed task description for the agent to perform autonomously and you should specify exactly what information the agent should return back to you in its final and only message to you.\n4. The agent\'s outputs should generally be trusted\n5. Clearly tell the agent whether you expect it to create content, perform analysis, or just do research (search, file reads, web fetches, etc.), since it is not aware of the user\'s intent\n6. If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.\n7. When only the general-purpose agent is provided, you should use it for all tasks. It is great for isolating context and token usage, and completing specific, complex tasks, as it has all the same capabilities as the main agent.\n\n### Example usage of the general-purpose agent:\n\n<example_agent_descriptions>\n"general-purpose": use this agent for general purpose tasks, it has access to all tools as the main agent.\n</example_agent_descriptions>\n\n<example>\nUser: "I want to conduct research on the accomplishments of Lebron James, Michael Jordan, and Kobe Bryant, and then compare them."\nAssistant: *Uses the task tool in parallel to conduct isolated research on each of the three players*\nAssistant: *Synthesizes the results of the three isolated research tasks and responds to the User*\n<commentary>\nResearch is a complex, multi-step task in it of itself.\nThe research of each individual player is not dependent on the research of the other players.\nThe assistant uses the task tool to break down the complex objective into three isolated tasks.\nEach research task only needs to worry about context and tokens about one player, then returns synthesized information about each player as the Tool Result.\nThis means each research task can dive deep and spend tokens and context deeply researching each player, but the final result is synthesized information, and saves us tokens in the long run when comparing the players to each other.\n</commentary>\n</example>\n\n<example>\nUser: "Analyze a single large code repository for security vulnerabilities and generate a report."\nAssistant: *Launches a single `task` subagent for the repository analysis*\nAssistant: *Receives report and integrates results into final summary*\n<commentary>\nSubagent is used to isolate a large, context-heavy task, even though there is only one. This prevents the main thread from being overloaded with details.\nIf the user then asks followup questions, we have a concise report to reference instead of the entire history of analysis and tool calls, which is good and saves us time and money.\n</commentary>\n</example>\n\n<example>\nUser: "Schedule two meetings for me and prepare agendas for each."\nAssistant: *Calls the task tool in parallel to launch two `task` subagents (one per meeting) to prepare agendas*\nAssistant: *Returns final schedules and agendas*\n<commentary>\nTasks are simple individually, but subagents help silo agenda preparation.\nEach subagent only needs to worry about the agenda for one meeting.\n</commentary>\n</example>\n\n<example>\nUser: "I want to order a pizza from Dominos, order a burger from McDonald\'s, and order a salad from Subway."\nAssistant: *Calls tools directly in parallel to order a pizza from Dominos, a burger from McDonald\'s, and a salad from Subway*\n<commentary>\nThe assistant did not use the task tool because the objective is super simple and clear and only requires a few trivial tool calls.\nIt is better to just complete the task directly and NOT use the `task`tool.\n</commentary>\n</example>\n\n### Example usage with custom agents:\n\n<example_agent_descriptions>\n"content-reviewer": use this agent after you are done creating significant content or documents\n"greeting-responder": use this agent when to respond to user greetings with a friendly joke\n"research-analyst": use this agent to conduct thorough research on complex topics\n</example_agent_description>\n\n<example>\nuser: "Please write a function that checks if a number is prime"\nassistant: Sure let me write a function that checks if a number is prime\nassistant: First let me use the Write tool to write a function that checks if a number is prime\nassistant: I\'m going to use the Write tool to write the following code:\n<code>\nfunction isPrime(n) {{\n if (n <= 1) return false\n for (let i = 2; i * i <= n; i++) {{\n if (n % i === 0) return false\n }}\n return true\n}}\n</code>\n<commentary>\nSince significant content was created and the task was completed, now use the content-reviewer agent to review the work\n</commentary>\nassistant: Now let me use the content-reviewer agent to review the code\nassistant: Uses the Task tool to launch with the content-reviewer agent\n</example>\n\n<example>\nuser: "Can you help me research the environmental impact of different renewable energy sources and create a comprehensive report?"\n<commentary>\nThis is a complex research task that would benefit from using the research-analyst agent to conduct thorough analysis\n</commentary>\nassistant: I\'ll help you research the environmental impact of renewable energy sources. Let me use the research-analyst agent to conduct comprehensive research on this topic.\nassistant: Uses the Task tool to launch with the research-analyst agent, providing detailed instructions about what research to conduct and what format the report should take\n</example>\n\n<example>\nuser: "Hello"\n<commentary>\nSince the user is greeting, use the greeting-responder agent to respond with a friendly joke\n</commentary>\nassistant: "I\'m going to use the Task tool to launch with the greeting-responder agent"\n</example>'
35
- TASK_SYSTEM_PROMPT='## `task` (subagent spawner)\n\nYou have access to a `task` tool to launch short-lived subagents that handle isolated tasks. These agents are ephemeral — they live only for the duration of the task and return a single result.\n\nWhen to use the task tool:\n- When a task is complex and multi-step, and can be fully delegated in isolation\n- When a task is independent of other tasks and can run in parallel\n- When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread\n- When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)\n- When you only care about the output of the subagent, and not the intermediate steps (ex. performing a lot of research and then returned a synthesized report, performing a series of computations or lookups to achieve a concise, relevant answer.)\n\nSubagent lifecycle:\n1. **Spawn** → Provide clear role, instructions, and expected output\n2. **Run** → The subagent completes the task autonomously\n3. **Return** → The subagent provides a single structured result\n4. **Reconcile** → Incorporate or synthesize the result into the main thread\n\nWhen NOT to use the task tool:\n- If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)\n- If the task is trivial (a few tool calls or simple lookup)\n- If delegating does not reduce token usage, complexity, or context switching\n- If splitting would add latency without benefit\n\n## Important Task Tool Usage Notes to Remember\n- Whenever possible, parallelize the work that you do. This is true for both tool_calls, and for tasks. Whenever you have independent steps to complete - make tool_calls, or kick off tasks (subagents) in parallel to accomplish them faster. This saves time for the user, which is incredibly important.\n- Remember to use the `task` tool to silo independent tasks within a multi-part objective.\n- You should use the `task` tool whenever you have a complex task that will take multiple steps, and is independent from other tasks that the agent needs to complete. These agents are highly competent and efficient.'
35
+ TASK_SYSTEM_PROMPT='## `task` (subagent spawner)\n\nYou have access to a `task` tool to launch short-lived subagents that handle isolated tasks. These agents are ephemeral — they live only for the duration of the task and return a single result.\n\nWhen to use the task tool:\n- When a task is complex and multi-step, and can be fully delegated in isolation\n- When a task is independent of other tasks and can run in parallel\n- When a task requires focused reasoning or heavy token/context usage that would bloat the orchestrator thread\n- When sandboxing improves reliability (e.g. code execution, structured searches, data formatting)\n- When you only care about the output of the subagent, and not the intermediate steps (ex. performing a lot of research and then returned a synthesized report, performing a series of computations or lookups to achieve a concise, relevant answer.)\n\nSubagent lifecycle:\n1. **Spawn** → Provide clear role, instructions, and expected output\n2. **Run** → The subagent completes the task autonomously\n3. **Return** → The subagent provides a single structured result\n4. **Reconcile** → Incorporate or synthesize the result into the main thread\n\nWhen NOT to use the task tool:\n- If you need to see the intermediate reasoning or steps after the subagent has completed (the task tool hides them)\n- If the task is trivial (a few tool calls or simple lookup)\n- If delegating does not reduce token usage, complexity, or context switching\n- If splitting would add latency without benefit\n- 用户仅仅时普通寒暄时,不应该使用任务工具。\n\n## Important Task Tool Usage Notes to Remember\n- Whenever possible, parallelize the work that you do. This is true for both tool_calls, and for tasks. Whenever you have independent steps to complete - make tool_calls, or kick off tasks (subagents) in parallel to accomplish them faster. This saves time for the user, which is incredibly important.\n- Remember to use the `task` tool to silo independent tasks within a multi-part objective.\n- You should use the `task` tool whenever you have a complex task that will take multiple steps, and is independent from other tasks that the agent needs to complete. These agents are highly competent and efficient.'
36
36
  DEFAULT_GENERAL_PURPOSE_DESCRIPTION='General-purpose agent for researching complex questions, searching for files and content, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. This agent has access to all tools as the main agent.'
37
- def bv(*,default_model,default_tools,default_middleware,default_interrupt_on,subagents,general_purpose_agent):
37
+ def cc(*,default_model,default_tools,default_middleware,default_interrupt_on,subagents,general_purpose_agent):
38
38
  M='middleware';L='runnable';F=default_tools;E=default_model;C=default_interrupt_on;D=default_middleware or[];B={};G=[]
39
39
  if general_purpose_agent:
40
40
  H=[*D]
@@ -59,28 +59,28 @@ def stream_handler(stream,runtime):
59
59
  if isinstance(B[_B],list)and len(B[_B])>0:
60
60
  for A in B[_B]:
61
61
  if isinstance(A,AIMessage)and len(A.tool_calls)>0:
62
- for F in A.tool_calls:G=F[_C];M=F[_D];H=F['id'];I={_E:_L,_G:D.tool_call_id,_H:H,_I:'',_C:G,_D:M,_J:'',_K:_N};J(json.dumps(I,indent=2,ensure_ascii=_M))
63
- if isinstance(A,AIMessage)and len(A.tool_calls)==0:print(f"[DEBUG - SubAgent] AIMessage: {A.content}");C=A
64
- if isinstance(A,ToolMessage):G=A.name;N=A.content;H=A.tool_call_id;I={_E:_L,_G:D.tool_call_id,_H:H,_I:'',_C:G,_D:{},_J:N,_K:_O};J(json.dumps(I,indent=2,ensure_ascii=_M))
62
+ for F in A.tool_calls:G=F[_C];M=F[_D];H=F['id'];I={_E:_M,_G:D.tool_call_id,_H:H,_I:'',_C:G,_D:M,_J:'',_K:_N};J(json.dumps(I,indent=2,ensure_ascii=_L))
63
+ if isinstance(A,AIMessage)and len(A.tool_calls)==0:C=A
64
+ if isinstance(A,ToolMessage):G=A.name;N=A.content;H=A.tool_call_id;I={_E:_M,_G:D.tool_call_id,_H:H,_I:'',_C:G,_D:{},_J:N,_K:_O};J(json.dumps(I,indent=2,ensure_ascii=_L))
65
65
  O={_B:[C]if C and isinstance(C,AIMessage)else[]};return O
66
66
  async def astream_handler(stream,runtime):
67
- F=runtime;J=F.stream_writer;E=_A
68
- async for G in stream:
69
- if not isinstance(G,tuple)or len(G)!=2:continue
70
- N,K=G
71
- if N==_F:
67
+ D=runtime;J=D.stream_writer;C=_A
68
+ async for E in stream:
69
+ if not isinstance(E,tuple)or len(E)!=2:continue
70
+ L,K=E
71
+ if L==_F:
72
72
  if not isinstance(K,dict):continue
73
73
  for(P,B)in K.items():
74
74
  if B is _A or isinstance(B,tuple):continue
75
75
  if isinstance(B[_B],list)and len(B[_B])>0:
76
76
  for A in B[_B]:
77
77
  if isinstance(A,AIMessage)and len(A.tool_calls)>0:
78
- for H in A.tool_calls:C=H[_C];L=H[_D];D=H['id'];I={_E:_L,_G:F.tool_call_id,_H:D,_I:'',_C:C,_D:L,_J:'',_K:_N};J(json.dumps(I,indent=2,ensure_ascii=_M));print(f"[DEBUG - SubAgent] tool_call: {C}, {L}, {D}")
79
- if isinstance(A,AIMessage)and len(A.tool_calls)==0:print(f"[DEBUG - SubAgent] AIMessage: {A.content}");E=A
80
- if isinstance(A,ToolMessage):C=A.name;M=A.content;D=A.tool_call_id;I={_E:_L,_G:F.tool_call_id,_H:D,_I:'',_C:C,_D:{},_J:M,_K:_O};print(f"[DEBUG - SubAgent] ToolMessage: {C}, {M}, {D}");J(json.dumps(I,indent=2,ensure_ascii=_M))
81
- O={_B:[E]if E and isinstance(E,AIMessage)else[]};return O
82
- def bt(*,default_model,default_tools,default_middleware,default_interrupt_on,subagents,general_purpose_agent,task_description=_A):
83
- G='Tool call ID is required for subagent invocation';F='custom';A=task_description;B,H=bv(default_model=default_model,default_tools=default_tools,default_middleware=default_middleware,default_interrupt_on=default_interrupt_on,subagents=subagents,general_purpose_agent=general_purpose_agent);C='\n'.join(H)
78
+ for F in A.tool_calls:G=F[_C];M=F[_D];H=F['id'];I={_E:_M,_G:D.tool_call_id,_H:H,_I:'',_C:G,_D:M,_J:'',_K:_N};J(json.dumps(I,indent=2,ensure_ascii=_L))
79
+ if isinstance(A,AIMessage)and len(A.tool_calls)==0:C=A
80
+ if isinstance(A,ToolMessage):G=A.name;N=A.content;H=A.tool_call_id;I={_E:'tool_result',_G:D.tool_call_id,_H:H,_I:'',_C:G,_D:{},_J:N,_K:_O};J(json.dumps(I,indent=2,ensure_ascii=_L))
81
+ O={_B:[C]if C and isinstance(C,AIMessage)else[]};return O
82
+ def bz(*,default_model,default_tools,default_middleware,default_interrupt_on,subagents,general_purpose_agent,task_description=_A):
83
+ G='Tool call ID is required for subagent invocation';F='custom';A=task_description;B,H=cc(default_model=default_model,default_tools=default_tools,default_middleware=default_middleware,default_interrupt_on=default_interrupt_on,subagents=subagents,general_purpose_agent=general_purpose_agent);C='\n'.join(H)
84
84
  def D(result,tool_call_id):A=result;B={A:B for(A,B)in A.items()if A not in _EXCLUDED_STATE_KEYS};C=A[_B][-1];D=I(C);return Command(update={**B,_B:[ToolMessage(D,tool_call_id=tool_call_id)]})
85
85
  def I(msg):
86
86
  D='text';B=msg.content
@@ -97,11 +97,11 @@ def bt(*,default_model,default_tools,default_middleware,default_interrupt_on,sub
97
97
  if A is _A:A=TASK_TOOL_DESCRIPTION.format(available_agents=C)
98
98
  elif'{available_agents}'in A:A=A.format(available_agents=C)
99
99
  def J(description,subagent_type,runtime):
100
- H=description;C=subagent_type;A=runtime;print(f"[Task tool ]: {C} - {H}")
101
- if C not in B:I=', '.join([f"`{A}`"for A in B]);return f"We cannot invoke subagent {C} because it does not exist, the only allowed types are {I}"
102
- J,K=E(C,H,A);L=J.stream(K,config={**A.config},stream_mode=[_F,F],context=A.context);M=stream_handler(L,A)
103
- if not A.tool_call_id:N=G;raise ValueError(N)
104
- return D(M,A.tool_call_id)
100
+ C=subagent_type;A=runtime
101
+ if C not in B:H=', '.join([f"`{A}`"for A in B]);return f"We cannot invoke subagent {C} because it does not exist, the only allowed types are {H}"
102
+ I,J=E(C,description,A);K=I.stream(J,config={**A.config},stream_mode=[_F,F],context=A.context);L=stream_handler(K,A)
103
+ if not A.tool_call_id:M=G;raise ValueError(M)
104
+ return D(L,A.tool_call_id)
105
105
  async def K(description,subagent_type,runtime):
106
106
  C=subagent_type;A=runtime
107
107
  if C not in B:H=', '.join([f"`{A}`"for A in B]);return f"We cannot invoke subagent {C} because it does not exist, the only allowed types are {H}"
@@ -110,7 +110,7 @@ def bt(*,default_model,default_tools,default_middleware,default_interrupt_on,sub
110
110
  return D(L,A.tool_call_id)
111
111
  return StructuredTool.from_function(name='task',func=J,coroutine=K,description=A)
112
112
  class SubAgentMiddleware(AgentMiddleware):
113
- def __init__(A,*,default_model,default_tools=_A,default_middleware=_A,default_interrupt_on=_A,subagents=_A,system_prompt=TASK_SYSTEM_PROMPT,general_purpose_agent=True,task_description=_A):super().__init__();A.system_prompt=system_prompt;B=bt(default_model=default_model,default_tools=default_tools or[],default_middleware=default_middleware,default_interrupt_on=default_interrupt_on,subagents=subagents or[],general_purpose_agent=general_purpose_agent,task_description=task_description);A.tools=[B]
113
+ def __init__(A,*,default_model,default_tools=_A,default_middleware=_A,default_interrupt_on=_A,subagents=_A,system_prompt=TASK_SYSTEM_PROMPT,general_purpose_agent=True,task_description=_A):super().__init__();A.system_prompt=system_prompt;B=bz(default_model=default_model,default_tools=default_tools or[],default_middleware=default_middleware,default_interrupt_on=default_interrupt_on,subagents=subagents or[],general_purpose_agent=general_purpose_agent,task_description=task_description);A.tools=[B]
114
114
  def wrap_model_call(B,request,handler):
115
115
  C=handler;A=request
116
116
  if B.system_prompt is not _A:D=A.system_prompt+'\n\n'+B.system_prompt if A.system_prompt else B.system_prompt;return C(A.override(system_prompt=D))
@@ -27,7 +27,7 @@ ContextFraction=tuple[Literal[_D],float]
27
27
  ContextTokens=tuple[Literal[_E],int]
28
28
  ContextMessages=tuple[Literal[_B],int]
29
29
  ContextSize=ContextFraction|ContextTokens|ContextMessages
30
- def cm(model):
30
+ def ck(model):
31
31
  if model._llm_type=='anthropic-chat':return partial(count_tokens_approximately,chars_per_token=3.3)
32
32
  return count_tokens_approximately
33
33
  class SummaryState(AgentState):compact:NotRequired[bool]=_F
@@ -44,61 +44,61 @@ class SummarizationMiddleware(AgentMiddleware):
44
44
  if isinstance(C,str):C=init_chat_model(C)
45
45
  A.model=C
46
46
  if B is _A:A.trigger=_A;G=[]
47
- elif isinstance(B,list):I=[A.cg(B,N)for B in B];A.trigger=I;G=I
48
- else:J=A.cg(B,N);A.trigger=J;G=[J]
49
- A._trigger_conditions=G;A.keep=A.cg(F,'keep')
50
- if H is count_tokens_approximately:A.token_counter=cm(A.model)
47
+ elif isinstance(B,list):I=[A.ch(B,N)for B in B];A.trigger=I;G=I
48
+ else:J=A.ch(B,N);A.trigger=J;G=[J]
49
+ A._trigger_conditions=G;A.keep=A.ch(F,'keep')
50
+ if H is count_tokens_approximately:A.token_counter=ck(A.model)
51
51
  else:A.token_counter=H
52
52
  A.summary_prompt=summary_prompt;A.trim_tokens_to_summarize=trim_tokens_to_summarize;K=any(A[0]==_D for A in A._trigger_conditions)
53
53
  if A.keep[0]==_D:K=_C
54
- if K and A.cc()is _A:O='Model profile information is required to use fractional token limits, and is unavailable for the specified model. Please use absolute token counts instead, or pass `\n\nChatModel(..., profile={"max_input_tokens": ...})`.\n\nwith a desired integer value of the model\'s maximum input tokens.';raise ValueError(O)
55
- def ch(B,state):A=state.get(_G,_F);return bool(A)
54
+ if K and A.cp()is _A:O='Model profile information is required to use fractional token limits, and is unavailable for the specified model. Please use absolute token counts instead, or pass `\n\nChatModel(..., profile={"max_input_tokens": ...})`.\n\nwith a desired integer value of the model\'s maximum input tokens.';raise ValueError(O)
55
+ def cl(B,state):A=state.get(_G,_F);return bool(A)
56
56
  @override
57
57
  def before_model(self,state,runtime):
58
- C=state;A=self;B=C[_B];A.cf(B);E=A.token_counter(B);F=A.ch(C);G=A.ca(B,E)
58
+ C=state;A=self;B=C[_B];A.cq(B);E=A.token_counter(B);F=A.cl(C);G=A.co(B,E)
59
59
  if not G and not F:return
60
- D=A.cb(B)
60
+ D=A.cn(B)
61
61
  if D<=0:return
62
- H,I=A.cj(B,D);J=A.cd(H);K=A.ce(J);return{_B:[RemoveMessage(id=REMOVE_ALL_MESSAGES),*K,*I],_G:_F}
62
+ H,I=A.cg(B,D);J=A.cm(H);K=A.cj(J);return{_B:[RemoveMessage(id=REMOVE_ALL_MESSAGES),*K,*I],_G:_F}
63
63
  @override
64
64
  async def abefore_model(self,state,runtime):
65
- C=state;A=self;B=C[_B];A.cf(B);E=A.token_counter(B);F=A.ch(C);G=A.ca(B,E)
65
+ C=state;A=self;B=C[_B];A.cq(B);E=A.token_counter(B);F=A.cl(C);G=A.co(B,E)
66
66
  if not G and not F:return
67
- D=A.cb(B)
67
+ D=A.cn(B)
68
68
  if D<=0:return
69
- H,I=A.cj(B,D);J=await A._acreate_summary(H);K=A.ce(J);return{_B:[RemoveMessage(id=REMOVE_ALL_MESSAGES),*K,*I],_G:_F}
70
- def cn(B,messages,threshold):
69
+ H,I=A.cg(B,D);J=await A._acreate_summary(H);K=A.cj(J);return{_B:[RemoveMessage(id=REMOVE_ALL_MESSAGES),*K,*I],_G:_F}
70
+ def cs(B,messages,threshold):
71
71
  A=next((A for A in reversed(messages)if isinstance(A,AIMessage)),_A)
72
72
  if isinstance(A,AIMessage)and A.usage_metadata is not _A and(C:=A.usage_metadata.get('total_tokens',-1))and C>=threshold and(D:=A.response_metadata.get('model_provider'))and D==B.model._get_ls_params().get('ls_provider'):return _C
73
73
  return _F
74
- def ca(A,messages,total_tokens):
74
+ def co(A,messages,total_tokens):
75
75
  F=total_tokens;E=messages
76
76
  if not A._trigger_conditions:return _F
77
77
  for(B,C)in A._trigger_conditions:
78
78
  if B==_B and len(E)>=C:return _C
79
79
  if B==_E and F>=C:return _C
80
- if B==_E and A.cn(E,C):return _C
80
+ if B==_E and A.cs(E,C):return _C
81
81
  if B==_D:
82
- G=A.cc()
82
+ G=A.cp()
83
83
  if G is _A:continue
84
84
  D=int(G*C)
85
85
  if D<=0:D=1
86
86
  if F>=D:return _C
87
- if A.cn(E,D):return _C
87
+ if A.cs(E,D):return _C
88
88
  return _F
89
- def cb(A,messages):
89
+ def cn(A,messages):
90
90
  B=messages;D,E=A.keep
91
91
  if D in{_E,_D}:
92
- C=A.ci(B)
92
+ C=A.cf(B)
93
93
  if C is not _A:return C
94
- return A.ck(B,_DEFAULT_MESSAGES_TO_KEEP)
95
- return A.ck(B,cast('int',E))
96
- def ci(C,messages):
94
+ return A.cr(B,_DEFAULT_MESSAGES_TO_KEEP)
95
+ return A.cr(B,cast('int',E))
96
+ def cf(C,messages):
97
97
  A=messages
98
98
  if not A:return 0
99
99
  H,I=C.keep
100
100
  if H==_D:
101
- J=C.cc()
101
+ J=C.cp()
102
102
  if J is _A:return
103
103
  F=int(J*I)
104
104
  elif H==_E:F=int(I)
@@ -114,8 +114,8 @@ class SummarizationMiddleware(AgentMiddleware):
114
114
  if B>=len(A):
115
115
  if len(A)==1:return 0
116
116
  B=len(A)-1
117
- return C.cl(A,B)
118
- def cc(C):
117
+ return C.ct(A,B)
118
+ def cp(C):
119
119
  try:A=C.model.profile
120
120
  except AttributeError:return
121
121
  if not isinstance(A,Mapping):return
@@ -123,7 +123,7 @@ class SummarizationMiddleware(AgentMiddleware):
123
123
  if not isinstance(B,int):return
124
124
  return B
125
125
  @staticmethod
126
- def cg(context,parameter_name):
126
+ def ch(context,parameter_name):
127
127
  E=context;C=parameter_name;D,B=E
128
128
  if D==_D:
129
129
  if not 0<B<=1:A=f"Fractional {C} values must be between 0 and 1, got {B}.";raise ValueError(A)
@@ -132,19 +132,19 @@ class SummarizationMiddleware(AgentMiddleware):
132
132
  else:A=f"Unsupported context size type {D} for {C}.";raise ValueError(A)
133
133
  return E
134
134
  @staticmethod
135
- def ce(summary):return[HumanMessage(content=f"Here is a summary of the conversation to date:\n\n{summary}",additional_kwargs={'lc_source':'summarization'})]
135
+ def cj(summary):return[HumanMessage(content=f"Here is a summary of the conversation to date:\n\n{summary}",additional_kwargs={'lc_source':'summarization'})]
136
136
  @staticmethod
137
- def cf(messages):
137
+ def cq(messages):
138
138
  for A in messages:
139
139
  if A.id is _A:A.id=str(uuid.uuid4())
140
140
  @staticmethod
141
- def cj(conversation_messages,cutoff_index):B=cutoff_index;A=conversation_messages;C=A[:B];D=A[B:];return C,D
142
- def ck(C,messages,messages_to_keep):
141
+ def cg(conversation_messages,cutoff_index):B=cutoff_index;A=conversation_messages;C=A[:B];D=A[B:];return C,D
142
+ def cr(C,messages,messages_to_keep):
143
143
  B=messages_to_keep;A=messages
144
144
  if len(A)<=B:return 0
145
- D=len(A)-B;return C.cl(A,D)
145
+ D=len(A)-B;return C.ct(A,D)
146
146
  @staticmethod
147
- def cl(messages,cutoff_index):
147
+ def ct(messages,cutoff_index):
148
148
  B=cutoff_index;A=messages
149
149
  if B>=len(A)or not isinstance(A[B],ToolMessage):return B
150
150
  E=set();C=B
@@ -158,10 +158,10 @@ class SummarizationMiddleware(AgentMiddleware):
158
158
  H={A.get('id')for A in D.tool_calls if A.get('id')}
159
159
  if E&H:return G
160
160
  return C
161
- def cd(A,messages_to_sumarize):
161
+ def cm(A,messages_to_sumarize):
162
162
  B=messages_to_sumarize
163
163
  if not B:return _H
164
- C=A.bz(B)
164
+ C=A.ci(B)
165
165
  if not C:return'Previous conversation was too long to summarize'
166
166
  D=get_buffer_string(C)
167
167
  try:E=A.model.invoke(A.summary_prompt.format(messages=D));return E.text.strip()
@@ -169,12 +169,12 @@ class SummarizationMiddleware(AgentMiddleware):
169
169
  async def _acreate_summary(A,messages_to_summarize):
170
170
  B=messages_to_summarize
171
171
  if not B:return _H
172
- C=A.bz(B)
172
+ C=A.ci(B)
173
173
  if not C:return'Previous conversation was too long to summarize.'
174
174
  D=get_buffer_string(C)
175
175
  try:E=await A.model.ainvoke(A.summary_prompt.format(messages=D));return E.text.strip()
176
176
  except Exception as F:return f"Error generating sumamry: {F!s}"
177
- def bz(A,messages):
177
+ def ci(A,messages):
178
178
  B=messages
179
179
  try:
180
180
  if A.trim_tokens_to_summarize is _A:return B
@@ -0,0 +1,5 @@
1
+ from langchain_core.messages import ContentBlock,SystemMessage
2
+ def append_to_system_message(system_message,text):
3
+ D='text';C=system_message;A=text;B=list(C.content_blocks)if C else[]
4
+ if B:A=f"\n\n{A}"
5
+ B.append({'type':D,D:A});return SystemMessage(content_blocks=B)
@@ -0,0 +1 @@
1
+ leader=' \n## 工作环境\n\nCURRENT_TIME: {CURRENT_TIME}\nWORKSPACE: {WORKSPACE}\n\n## 角色定位\n你的名字是 David。\n你是一位拥有15年以上经验的资深项目任务指挥师专家,擅长通过系统化分析项目需求和现状,将复杂的项目目标分解为清晰、可执行的任务分配方案。\n你具备敏锐的项目管理洞察力和团队协调能力,能够快速识别项目关键路径、资源需求和风险点,从而为团队成员制定详细的分步骤执行计划。\n你专注于任务分解、资源配置和团队协作,将宏观的项目目标转化为微观的可执行任务。\n\n\n注意: 严禁你代替成员完成任务,只能协调和分配任务,不能直接执行任务。\n\n## 工作空间说明\n 你的工作空间(WORKSPACE)位置为: {WORKSPACE}, 你的项目文件夹可以放在 {{WORKSPACE}} 下。\n\n## 核心能力 \n 1. **项目需求分析**:\n 深入理解项目目标、范围、约束条件和成功标准,识别关键需求和优先级。\n \n\n 2. **任务分解与规划**:\n 2.1 根据需求分析的结果判断项目的规模和复杂度。\n 2.2 如果是简单任务则按照其涉及到的工作内容直接分配给对应的团队成员执行。\n 2.3 如果不能明确判断任务和哪个团队成员相匹配,则优先分配给 通用代理 general-purpose 进行处理。\n 2.4 如果任务需要协调多个团队成员合作完成,则将项目目标分解为可管理的工作包,并明确任务间的依赖关系和执行顺序。\n 3. **团队角色分配**:根据任务特性和团队成员能力,合理分配团队成员的工作职责。\n 4. **协作流程设计**:设计高效的团队协作流程,明确沟通机制和决策流程。\n 5. **沟通协调**: \n 【注意】当团队成员在执行任务过程中需要与用户沟通,询问用户问题时,你需要接收成员的请求或询问, \n 终止当前的对话,将请求或询问内容放在 FINISH 的task中转发给用户。此时严禁自行回复成员或者分发任务。\n\n## 工作方式\n 你在指挥团队完成任务时需要严格遵循以下INSTRUCTION指令,不要执行超出指令范围之外的工作。\n 该指令约束了工作涉及范围以及定义了工作常规执行流程,并约束了工作涉及到的团队成员,\n 需要注意的是除了指令中指定的团队成员,不要调用其他的团队成员。\n\n\n## 约束条件\n - **沟通语言:** 必须使用**中文**与用户进行交流,以及回复用户问题和报告执行状态\n\n## 交互规则\n\n 【注意】在接收到用户回复时,你需要判断是否是处于团队成员与用户交互过程中:\n 1. 如果是,你直接将用户的回复转发给团队成员,无需额外处理和任务分解。\n 2. 如果不是,你需要根据用户的问题进行任务分解和分配。\n\n 【注意】如果团队成员回复内容为询问,提问的形式,你如果不能给出答案,则向用户询问。\n\n'
@@ -16,33 +16,33 @@ class ToolResultFormatter:
16
16
  def detect_type(B,content):
17
17
  A=content;A=A.strip()
18
18
  if A.statswith(SUCCESS_PREFIX):
19
- C=B.bc(A)
20
- if B.ba(C):return ContentType.JSON
19
+ C=B.bi(A)
20
+ if B.bd(C):return ContentType.JSON
21
21
  return ContentType.SUCCESS
22
22
  if A.startswith(FAILURE_PREFIX):return ContentType.ERROR
23
- if B.ba(A):return ContentType.JSON
24
- if B.bh(A):return ContentType.ERROR
25
- if B.bj(A):return ContentType.MARKDOWN
23
+ if B.bd(A):return ContentType.JSON
24
+ if B.bg(A):return ContentType.ERROR
25
+ if B.bc(A):return ContentType.MARKDOWN
26
26
  return ContentType.TEXT
27
27
  def is_success(A,content):return _is_success(content)
28
- def format(A,name,content,max_length=800):B=content;C=A.detect_type(B);D=A.is_success(B);E={ContentType.SUCCESS:A.bf,ContentType.ERROR:A.bg,ContentType.JSON:A.bb,ContentType.MARKDOWN:A.be,ContentType.TEXT:A.bi};F=E.get(C,A.bi);G=F(name,B,max_length);return FormattedResult(content_type=C,elements=G,success=D)
29
- def bc(B,content):A=content.split('\n',2);return A[2].strip()if len(A)>2 else''
30
- def ba(B,content):
28
+ def format(A,name,content,max_length=800):B=content;C=A.detect_type(B);D=A.is_success(B);E={ContentType.SUCCESS:A.bf,ContentType.ERROR:A.bh,ContentType.JSON:A.bj,ContentType.MARKDOWN:A.bb,ContentType.TEXT:A.be};F=E.get(C,A.be);G=F(name,B,max_length);return FormattedResult(content_type=C,elements=G,success=D)
29
+ def bi(B,content):A=content.split('\n',2);return A[2].strip()if len(A)>2 else''
30
+ def bd(B,content):
31
31
  A=content;A=A.strip()
32
32
  if not A:return _A
33
33
  if A.startswith('{')and A.endswith('}')or A.startswith('[')and A.endswith(']'):
34
34
  try:json.loads(A);return True
35
35
  except(json.JSONDecodeError,ValueError):pass
36
36
  return _A
37
- def bh(B,content):A=['Traceback (most recent call last)','Exception:','Error:'];return any(A in content for A in A)
38
- def bj(C,content):A=content;B=['```','**','##','- **'];return A.startswith('#')or any(B in A for B in B)
39
- def bf(B,name,content,max_length):A='green';C=B.bd(content,max_length);return[Panel(Text(C,style=A),title=f"📤 {name} ✓",border_style=A)]
40
- def bg(B,name,content,max_length):A='red';C=B.bd(content,max_length);return[Panel(Text(C,style=A),title=f"📤 {name} ✗",border_style=A)]
41
- def bb(B,name,content,max_length):
37
+ def bg(B,content):A=['Traceback (most recent call last)','Exception:','Error:'];return any(A in content for A in A)
38
+ def bc(C,content):A=content;B=['```','**','##','- **'];return A.startswith('#')or any(B in A for B in B)
39
+ def bf(B,name,content,max_length):A='green';C=B.ba(content,max_length);return[Panel(Text(C,style=A),title=f"📤 {name} ✓",border_style=A)]
40
+ def bh(B,name,content,max_length):A='red';C=B.ba(content,max_length);return[Panel(Text(C,style=A),title=f"📤 {name} ✗",border_style=A)]
41
+ def bj(B,name,content,max_length):
42
42
  D=max_length;A=content;E=A
43
- if A.startswith(SUCCESS_PREFIX):E=B.bc(A)
44
- try:F=json.loads(E);C=json.dumps(F,indent=2,ensure_ascii=_A);C=B.bd(C,D);return[Text(f"📤 {name} ✓",style=_B),Syntax(C,'json',theme='monokai',line_numbers=_A)]
45
- except(json.JSONDecodeError,ValueError):return B.bi(name,A,D)
46
- def be(A,name,content,max_length):B=A.bd(content,max_length);return[Panel(Markdown(B),title=f"📤 {name}",border_style='cyan dim')]
47
- def bi(A,name,content,max_length):B=A.bd(content,max_length);return[Text(f"📤 {name}:",style=_B),Text(f" {B}",style='dim')]
48
- def bd(A,content,max_length):return truncate(content,max_length)
43
+ if A.startswith(SUCCESS_PREFIX):E=B.bi(A)
44
+ try:F=json.loads(E);C=json.dumps(F,indent=2,ensure_ascii=_A);C=B.ba(C,D);return[Text(f"📤 {name} ✓",style=_B),Syntax(C,'json',theme='monokai',line_numbers=_A)]
45
+ except(json.JSONDecodeError,ValueError):return B.be(name,A,D)
46
+ def bb(A,name,content,max_length):B=A.ba(content,max_length);return[Panel(Markdown(B),title=f"📤 {name}",border_style='cyan dim')]
47
+ def be(A,name,content,max_length):B=A.ba(content,max_length);return[Text(f"📤 {name}:",style=_B),Text(f" {B}",style='dim')]
48
+ def ba(A,content,max_length):return truncate(content,max_length)
@@ -1,120 +1,147 @@
1
- _a='[DEBUG] Stream completed normally'
2
- _Z='tool_result'
3
- _Y='tool_call'
4
- _X='pending'
5
- _W='result'
6
- _V='tool_id'
7
- _U='parent_id'
8
- _T='custom'
9
- _S='INTERRUPT'
10
- _R='total_tokens'
11
- _Q='output_tokens'
12
- _P='input_tokens'
13
- _O='success'
1
+ _b='[DEBUG] Stream completed normally'
2
+ _a='INTERRUPT'
3
+ _Z='total_tokens'
4
+ _Y='output_tokens'
5
+ _X='input_tokens'
6
+ _W='success'
7
+ _V='interrupt_id'
8
+ _U='tool_result'
9
+ _T='tool_call'
10
+ _S='pending'
11
+ _R='result'
12
+ _Q='tool_id'
13
+ _P='parent_id'
14
+ _O='custom'
14
15
  _N='updates'
15
- _M='status'
16
- _L='interrupt_id'
17
- _K='type'
18
- _J='text'
19
- _I='value'
20
- _H='__interrupt__'
21
- _G='id'
22
- _F='auto'
23
- _E='args'
24
- _D='content'
25
- _C='name'
26
- _B=None
16
+ _M=False
17
+ _L='text'
18
+ _K='value'
19
+ _J='__interrupt__'
20
+ _I='auto'
21
+ _H='status'
22
+ _G='type'
23
+ _F='id'
24
+ _E='content'
25
+ _D='args'
26
+ _C=None
27
+ _B='name'
27
28
  _A='messages'
28
- import json
29
+ import json,asyncio
29
30
  from langchain_core.messages import AIMessage,AIMessageChunk,ToolMessage
30
31
  from langgraph.types import Command,Interrupt
31
32
  from src.stream.utils import DisplayLimits,is_success
32
33
  from src.stream.emitter import StreamEventEmitter as emitter
33
34
  from src.stream.tracker import ToolCallTracker
34
35
  from src.stream.file_write_parser import StreamParser
35
- async def astream_handler(stream,debug=False,interrupt_tools=[],tool_mode=_F):
36
- J=debug;K=[];R='';S=StreamParser(top_fields=['path',_D])
36
+ async def ainput(prompt=''):return await asyncio.to_thread(input,prompt)
37
+ async def anormal_handler(stream,detail=_M):
38
+ E=detail;M=''
37
39
  async for F in stream:
38
40
  if not isinstance(F,tuple)or len(F)!=2:continue
39
- L,C=F
41
+ J,G=F
42
+ if J==_N:
43
+ if not isinstance(G,dict):continue
44
+ for(N,C)in G.items():
45
+ if C is _C or isinstance(C,tuple):continue
46
+ if _A in C and isinstance(C[_A],list)and len(C[_A])>0:
47
+ for A in C[_A]:
48
+ if isinstance(A,AIMessage)and len(A.tool_calls)>0:
49
+ for B in A.tool_calls:
50
+ D=B[_B];H=B[_D];K=B[_F]
51
+ if E:print(f"[TOOL_CALL]: {D} \nargs: ({H}) ")
52
+ if isinstance(A,AIMessage)and A.content and A.content!='':print(f"bot> {A.content}");M+=A.content
53
+ if isinstance(A,ToolMessage):
54
+ D=A.name;I=A.content;K=A.tool_call_id
55
+ if E:print(f"[TOOL_RESULT]: {D} \nresult: {I}")
56
+ elif J==_O:
57
+ B=json.loads(G);L=B.get(_G,'');O=B.get(_P,'');K=B.get(_Q,'');D=B.get(_B,'');H=B.get(_D,'');I=B.get(_R,'');P=B.get(_H,_S)
58
+ if L==_T:
59
+ if E:print(f"[SUB TOOL_CALL]: {D} \nargs: ({H}) ")
60
+ elif L==_U:
61
+ if E:print(f"[SUB TOOL_RESULT]: {D} \nresult: {I}")
62
+ async def astream_handler(stream,debug=_M,interrupt_tools=[],tool_mode=_I):
63
+ P=interrupt_tools;J=debug;K=[];S='';T=StreamParser(top_fields=['path',_E])
64
+ async for F in stream:
65
+ if not isinstance(F,tuple)or len(F)!=2:continue
66
+ L,D=F
40
67
  if L==_N:
41
- if not isinstance(C,dict):continue
42
- for(c,H)in C.items():
43
- if H is _B or isinstance(H,tuple):continue
68
+ if not isinstance(D,dict):continue
69
+ for(d,H)in D.items():
70
+ if H is _C or isinstance(H,tuple):continue
44
71
  if _A in H and isinstance(H[_A],list)and len(H[_A])>0:
45
- for D in H[_A]:
46
- if isinstance(D,AIMessage)and len(D.tool_calls)>0:
47
- for B in D.tool_calls:
48
- E=B[_C];I=B[_E];G=B[_G]
49
- if tool_mode!=_F and E.strip().lower()in interrupt_tools:continue
72
+ for C in H[_A]:
73
+ if isinstance(C,AIMessage)and len(C.tool_calls)>0:
74
+ for B in C.tool_calls:
75
+ E=B[_B];I=B[_D];G=B[_F]
76
+ if len(P)>0 and tool_mode!=_I and E.strip().lower()in P:continue
50
77
  A=emitter.tool_call(E,I,G);yield A.data
51
- if isinstance(D,ToolMessage):E=D.name;M=D.content;G=D.tool_call_id;A=emitter.tool_result(E,M,_O,G);yield A.data
52
- if isinstance(D,AIMessage)and D.usage_metadata:N=D.usage_metadata;T=N.get(_P,_B);U=N.get(_Q);V=N.get(_R,_B);A=emitter.token_usage(T,U,V);yield A.data
53
- if _H in C:
54
- K=C[_H]
78
+ if isinstance(C,ToolMessage):E=C.name;M=C.content;G=C.tool_call_id;A=emitter.tool_result(E,M,_W,G);yield A.data
79
+ if isinstance(C,AIMessage)and C.usage_metadata:N=C.usage_metadata;U=N.get(_X,_C);V=N.get(_Y);W=N.get(_Z,_C);A=emitter.token_usage(U,V,W);yield A.data
80
+ if _J in D:
81
+ K=D[_J]
55
82
  if K:
56
- d=_S;W=list(map(lambda interrupt:{_L:interrupt.id,_I:interrupt.value},K))
57
- for O in W:X='hitl';Y=O[_L];Z=O[_I];B=Z['action_requests'][0];E=B[_C];G=B[_G];I=B[_E];A=emitter.tool_call(E,I,G);yield A.data;A=emitter.interrupt(interrupt_type=X,interrupt_id=Y,value=O);yield A.data
83
+ e=_a;X=list(map(lambda interrupt:{_V:interrupt.id,_K:interrupt.value},K))
84
+ for O in X:Y='hitl';Z=O[_V];a=O[_K];B=a['action_requests'][0];E=B[_B];G=B[_F];I=B[_D];A=emitter.tool_call(E,I,G);yield A.data;A=emitter.interrupt(interrupt_type=Y,interrupt_id=Z,value=O);yield A.data
58
85
  elif L==_A:
59
- if isinstance(C,tuple)and len(C)>=2:F=C[0]
60
- else:F=C
61
- if J:a=type(F).__name__;print(f"[DEBUG] Event: {a}")
86
+ if isinstance(D,tuple)and len(D)>=2:F=D[0]
87
+ else:F=D
88
+ if J:b=type(F).__name__;print(f"[DEBUG] Event: {b}")
62
89
  if isinstance(F,(AIMessageChunk,AIMessage)):
63
- for A in bk(F,S):
64
- if A.type==_J:R+=A.data.get(_D,'')
90
+ for A in bk(F,T):
91
+ if A.type==_L:S+=A.data.get(_E,'')
65
92
  if J:print(f"[DEBUG] Yielding: {A.type}")
66
93
  yield A.data
67
- elif L==_T:
68
- print(f"[CUSTOM]: {C}");B=json.loads(C);P=getattr(B,_K,'');Q=getattr(B,_U,'');G=getattr(B,_V,'');E=getattr(B,_C,'');I=getattr(B,_E,'');M=getattr(B,_W,'');b=getattr(B,_M,_X)
69
- if P==_Y:A=emitter.tool_call(E,I,G,Q);yield A.data
70
- elif P==_Z:A=emitter.tool_result(E,M,b,G,Q);yield A.data
71
- if J:print(_a)
72
- def stream_handler(stream,debug=False,interrupts=[],tool_mode=_F):
73
- R='role';J=debug;G=interrupts;G=[];S='';T=StreamParser(top_fields=['path',_D])
94
+ elif L==_O:
95
+ B=json.loads(D);Q=B.get(_G,'');R=B.get(_P,'');G=B.get(_Q,'');E=B.get(_B,'');I=B.get(_D,'');M=B.get(_R,'');c=B.get(_H,_S)
96
+ if Q==_T:A=emitter.tool_call(E,I,G,R);yield A.data
97
+ elif Q==_U:A=emitter.tool_result(E,M,c,G,R);yield A.data
98
+ if J:print(_b)
99
+ def stream_handler(stream,debug=_M,interrupts=[],tool_mode=_I):
100
+ R='role';J=debug;G=interrupts;G=[];S='';T=StreamParser(top_fields=['path',_E])
74
101
  for E in stream:
75
102
  if not isinstance(E,tuple)or len(E)!=2:continue
76
103
  K,C=E
77
104
  if K==_N:
78
105
  if not isinstance(C,dict):continue
79
106
  for(Y,I)in C.items():
80
- if I is _B or isinstance(I,tuple):continue
107
+ if I is _C or isinstance(I,tuple):continue
81
108
  if isinstance(I[_A],list)and len(I[_A])>0:
82
109
  for D in I[_A]:
83
110
  if isinstance(D,AIMessage)and len(D.tool_calls)>0:
84
111
  for B in D.tool_calls:
85
- F=B[_C];L=B[_E];H=B[_G]
86
- if tool_mode!=_F and F.strip().lower()in G:continue
112
+ F=B[_B];L=B[_D];H=B[_F]
113
+ if tool_mode!=_I and F.strip().lower()in G:continue
87
114
  A=emitter.tool_call(F,L,H);yield A.data
88
115
  if isinstance(D,ToolMessage):F=D.name;M=D.content;H=D.tool_call_id;A=emitter.tool_result(F,M,True,H);yield A.data
89
- if isinstance(D,AIMessage)and D.response_metadata['finish_reason']=='stop':N=D.response_metadata.get('token_usage',{});Z=N.get(_P,0);a=N.get(_Q,0);b=N.get(_R,0)
90
- if _H in C:
91
- G=C[_H]
116
+ if isinstance(D,AIMessage)and D.response_metadata['finish_reason']=='stop':N=D.response_metadata.get('token_usage',{});Z=N.get(_X,0);a=N.get(_Y,0);b=N.get(_Z,0)
117
+ if _J in C:
118
+ G=C[_J]
92
119
  if G:
93
- print('--'*30);print(f"[INTERRUPT EVENT]: {G}");c=_S;U=list(map(lambda interrupt:{_L:interrupt.id,_I:interrupt.value,R:'ask_human'},G))
94
- for O in U:d=O[R];V=O[_I][_K];emitter.interrupt(event_name='interrupt',event_type=V,event_data=O);break
120
+ print('--'*30);print(f"[INTERRUPT EVENT]: {G}");c=_a;U=list(map(lambda interrupt:{_V:interrupt.id,_K:interrupt.value,R:'ask_human'},G))
121
+ for O in U:d=O[R];V=O[_K][_G];emitter.interrupt(event_name='interrupt',event_type=V,event_data=O);break
95
122
  elif K==_A:
96
123
  if isinstance(C,tuple)and len(C)>=2:E=C[0]
97
124
  else:E=C
98
125
  if J:W=type(E).__name__;print(f"[DEBUG] Event: {W}")
99
126
  if isinstance(E,(AIMessageChunk,AIMessage)):
100
127
  for A in bk(E,T):
101
- if A.type==_J:S+=A.data.get(_D,'')
128
+ if A.type==_L:S+=A.data.get(_E,'')
102
129
  if J:print(f"[DEBUG] Yielding: {A.type}")
103
130
  yield A.data
104
- elif K==_T:
105
- print(f"[CUSTOM]: {C}");B=json.loads(C);P=getattr(B,_K,'');Q=getattr(B,_U,'');H=getattr(B,_V,'');F=getattr(B,_C,'');L=getattr(B,_E,'');M=getattr(B,_W,'');X=getattr(B,_M,_X)
106
- if P==_Y:A=emitter.tool_call(F,L,H,Q);yield A.data
107
- elif P==_Z:A=emitter.tool_result(F,M,X,H,Q);yield A.data
108
- if J:print(_a)
131
+ elif K==_O:
132
+ print(f"[CUSTOM]: {C}");B=json.loads(C);P=getattr(B,_G,'');Q=getattr(B,_P,'');H=getattr(B,_Q,'');F=getattr(B,_B,'');L=getattr(B,_D,'');M=getattr(B,_R,'');X=getattr(B,_H,_S)
133
+ if P==_T:A=emitter.tool_call(F,L,H,Q);yield A.data
134
+ elif P==_U:A=emitter.tool_result(F,M,X,H,Q);yield A.data
135
+ if J:print(_b)
109
136
  def bk(chunk,stream_parser):
110
137
  M='reasoning';L='thinking';I='write_file';F=stream_parser;E=chunk;B=E.content
111
138
  if isinstance(B,str):
112
139
  if B:yield emitter.text(B);return
113
- C=_B
140
+ C=_C
114
141
  if hasattr(E,'content_blocks'):
115
142
  try:C=E.content_blocks
116
- except Exception:C=_B
117
- if C is _B:
143
+ except Exception:C=_C
144
+ if C is _C:
118
145
  if isinstance(B,dict):C=[B]
119
146
  elif isinstance(B,list):C=B
120
147
  else:return
@@ -124,22 +151,22 @@ def bk(chunk,stream_parser):
124
151
  if hasattr(A,'model_dump'):A=A.model_dump()
125
152
  elif hasattr(A,'dict'):A=A.dict()
126
153
  else:continue
127
- G=A.get(_K)
154
+ G=A.get(_G)
128
155
  if G in(L,M):
129
156
  J=A.get(L)or A.get(M)or''
130
157
  if J:yield emitter.thinking(J)
131
- elif G==_J:
132
- K=A.get(_J)or A.get(_D)or''
158
+ elif G==_L:
159
+ K=A.get(_L)or A.get(_E)or''
133
160
  if K:yield emitter.text(K)
134
161
  elif G=='tool_call_chunk':
135
- O=A.get(_G,'');H=A.get(_C,'')
162
+ O=A.get(_F,'');H=A.get(_B,'')
136
163
  if O:
137
164
  if H==I:F.reset()
138
- D=A.get(_E,'')
165
+ D=A.get(_D,'')
139
166
  if isinstance(D,str)and D:
140
167
  if H==I:F.feed(D)
141
168
  if H==I and D=='':F.reset()
142
169
  def bl(chunk):
143
- A=chunk;D=getattr(A,_C,'unknown');B=str(getattr(A,_D,''));E=getattr(A,'tool_call_id','');F=getattr(A,_M,_O);C=B[:DisplayLimits.TOOL_RESULT_MAX]
170
+ A=chunk;D=getattr(A,_B,'unknown');B=str(getattr(A,_E,''));E=getattr(A,'tool_call_id','');F=getattr(A,_H,_W);C=B[:DisplayLimits.TOOL_RESULT_MAX]
144
171
  if len(B)>DisplayLimits.TOOL_RESULT_MAX:C+='\n... (truncated)'
145
172
  yield emitter.tool_result(D,C,F,E)