jupyter-agent 2025.6.100__py3-none-any.whl → 2025.6.101__py3-none-any.whl

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 (35) hide show
  1. jupyter_agent/__init__.py +0 -0
  2. jupyter_agent/bot_agents/__init__.py +42 -0
  3. jupyter_agent/bot_agents/base.py +324 -0
  4. jupyter_agent/bot_agents/master_planner.py +45 -0
  5. jupyter_agent/bot_agents/output_task_result.py +29 -0
  6. jupyter_agent/bot_agents/task_code_executor.py +53 -0
  7. jupyter_agent/bot_agents/task_coder.py +71 -0
  8. jupyter_agent/bot_agents/task_debuger.py +69 -0
  9. jupyter_agent/bot_agents/task_planner_v1.py +158 -0
  10. jupyter_agent/bot_agents/task_planner_v2.py +172 -0
  11. jupyter_agent/bot_agents/task_planner_v3.py +189 -0
  12. jupyter_agent/bot_agents/task_reasoner.py +61 -0
  13. jupyter_agent/bot_agents/task_structrue_reasoner.py +106 -0
  14. jupyter_agent/bot_agents/task_structrue_summarier.py +123 -0
  15. jupyter_agent/bot_agents/task_summarier.py +76 -0
  16. jupyter_agent/bot_agents/task_verifier.py +99 -0
  17. jupyter_agent/bot_agents/task_verify_summarier.py +134 -0
  18. jupyter_agent/bot_chat.py +218 -0
  19. jupyter_agent/bot_contexts.py +466 -0
  20. jupyter_agent/bot_flows/__init__.py +20 -0
  21. jupyter_agent/bot_flows/base.py +209 -0
  22. jupyter_agent/bot_flows/master_planner.py +16 -0
  23. jupyter_agent/bot_flows/task_executor_v1.py +86 -0
  24. jupyter_agent/bot_flows/task_executor_v2.py +84 -0
  25. jupyter_agent/bot_flows/task_executor_v3.py +89 -0
  26. jupyter_agent/bot_magics.py +127 -0
  27. jupyter_agent/bot_outputs.py +480 -0
  28. jupyter_agent/utils.py +138 -0
  29. {jupyter_agent-2025.6.100.dist-info → jupyter_agent-2025.6.101.dist-info}/METADATA +13 -7
  30. jupyter_agent-2025.6.101.dist-info/RECORD +33 -0
  31. jupyter_agent-2025.6.101.dist-info/top_level.txt +1 -0
  32. jupyter_agent-2025.6.100.dist-info/RECORD +0 -5
  33. jupyter_agent-2025.6.100.dist-info/top_level.txt +0 -1
  34. {jupyter_agent-2025.6.100.dist-info → jupyter_agent-2025.6.101.dist-info}/WHEEL +0 -0
  35. {jupyter_agent-2025.6.100.dist-info → jupyter_agent-2025.6.101.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,209 @@
1
+ """
2
+ Copyright (c) 2025 viewstar000
3
+
4
+ This software is released under the MIT License.
5
+ https://opensource.org/licenses/MIT
6
+ """
7
+
8
+ import traceback
9
+
10
+ from pydantic import BaseModel
11
+ from enum import Enum
12
+ from typing import List, Dict, Optional, Type
13
+ from IPython.display import Markdown
14
+ from ..bot_agents.base import BaseAgent
15
+ from ..bot_outputs import _D, _I, _W, _E, _F, _M, _B, set_stage, flush_output
16
+
17
+ TASK_AGENT_STATE_ERROR = "_AGENT_STATE_ERROR_32534526_"
18
+ TASK_STAGE_START = "start"
19
+ TASK_STAGE_COMPLETED = "completed"
20
+
21
+
22
+ class TaskAction(str, Enum):
23
+ DEFAULT = "*"
24
+ CONTINUE = "continue"
25
+ RETRY = "retry"
26
+ SKIP = "skip"
27
+ STOP = "stop"
28
+
29
+
30
+ class StageNext[ST](BaseModel):
31
+ action: Optional[TaskAction] = None
32
+ stage: ST | str
33
+ message: str = ""
34
+
35
+
36
+ class StageTransition[ST, AS](BaseModel):
37
+ stage: ST | str
38
+ agent: Type[BaseAgent] | str
39
+ states: Dict[AS | str, StageNext[ST] | List[StageNext[ST]] | Dict[TaskAction, StageNext[ST]] | ST | str] = {}
40
+ next_stage: Optional[StageNext[ST] | List[StageNext[ST]] | Dict[TaskAction, StageNext[ST]] | ST | str] = None
41
+
42
+
43
+ class BaseTaskFlow:
44
+ """
45
+ 基础任务流程
46
+ """
47
+
48
+ STAGE_TRANSITIONS: List[StageTransition] = []
49
+ START_STAGE = TASK_STAGE_START
50
+ STOP_STAGES = [TASK_STAGE_COMPLETED]
51
+
52
+ def __init__(self, notebook_context, agent_factory):
53
+ self.notebook_context = notebook_context
54
+ self.agent_factory = agent_factory
55
+ self.stage_transitions = {}
56
+ self.prepare_stage_transitions()
57
+
58
+ @property
59
+ def task(self):
60
+ return self.notebook_context.cur_task
61
+
62
+ @property
63
+ def cells(self):
64
+ return self.notebook_context.cells
65
+
66
+ def prepare_stage_transitions(self):
67
+ for st in self.STAGE_TRANSITIONS:
68
+ assert not (st.next_stage and st.states), "next_stage and states are mutually exclusive"
69
+ self.stage_transitions[st.stage] = st
70
+ if st.next_stage:
71
+ st.states[TaskAction.DEFAULT] = st.next_stage
72
+ st.next_stage = None
73
+ for state, ns in st.states.items():
74
+ st.states[state] = {}
75
+ if isinstance(ns, str):
76
+ st.states[state] = {TaskAction.DEFAULT: StageNext(stage=ns)}
77
+ elif isinstance(ns, StageNext):
78
+ action = ns.action or TaskAction.DEFAULT
79
+ st.states[state] = {action: ns}
80
+ elif isinstance(ns, list):
81
+ state_dict = {}
82
+ for n in ns:
83
+ action = n.action or TaskAction.DEFAULT
84
+ state_dict[action] = n
85
+ st.states[state] = state_dict
86
+ elif isinstance(ns, dict):
87
+ st.states[state] = ns
88
+ else:
89
+ raise ValueError(f"Unknown next stage: {ns}")
90
+ state_ns: Dict = st.states[state] # type: ignore
91
+ state_ns[TaskAction.CONTINUE] = state_ns.get(TaskAction.CONTINUE) or state_ns.get(TaskAction.DEFAULT)
92
+ state_ns[TaskAction.RETRY] = state_ns.get(TaskAction.RETRY) or StageNext(stage=st.stage)
93
+ state_ns[TaskAction.STOP] = state_ns.get(TaskAction.STOP) or StageNext(stage=st.stage)
94
+ state_ns[TaskAction.SKIP] = state_ns.get(TaskAction.SKIP) or state_ns.get(TaskAction.CONTINUE)
95
+ if TASK_AGENT_STATE_ERROR not in st.states:
96
+ st.states[TASK_AGENT_STATE_ERROR] = {"*": StageNext(stage=st.stage)}
97
+
98
+ def get_stage_agent(self, stage):
99
+ for t in self.STAGE_TRANSITIONS:
100
+ if t.stage == stage:
101
+ return self.agent_factory(t.agent)
102
+ raise ValueError(f"No agent for stage `{stage}`")
103
+
104
+ def _get_next_stage_trans(self, stage, state, action=TaskAction.CONTINUE):
105
+
106
+ st = self.stage_transitions.get(stage)
107
+ if st:
108
+ state_ns = st.states.get(state) or st.states.get("*")
109
+ assert state_ns, f"No next stage for stage `{stage}` and state `{state}`"
110
+ act_ns = state_ns.get(action) or state_ns.get("*")
111
+ assert act_ns, f"No next stage for stage `{stage}`, state `{state}`, action `{action}`"
112
+ return act_ns
113
+ else:
114
+ raise ValueError(f"No next stage for stage `{stage}`")
115
+
116
+ def get_prompt_message(self, stage, state, failed):
117
+
118
+ ns = self._get_next_stage_trans(stage, state)
119
+ if failed:
120
+ msg = ns.message or f"Staget `{stage}` FAILED!"
121
+ return (
122
+ f"{msg}\n Continue from stage `{ns.stage}`? \n"
123
+ f"(C)ontinue, (R)etry, s(K)ip, (S)top, default `continue`"
124
+ )
125
+ else:
126
+ return (
127
+ f"{ns.message}\n Continue to stage `{ns.stage}`? \n"
128
+ f"(C)ontinue, (R)etry, s(K)ip, (S)top, default `continue`"
129
+ )
130
+
131
+ def match_action(self, input):
132
+ input = input.lower().strip()
133
+ if input == "" or input == "c" or (len(input) > 1 and TaskAction.CONTINUE.value.startswith(input)):
134
+ return TaskAction.CONTINUE
135
+ elif input == "r" or (len(input) > 1 and TaskAction.RETRY.value.startswith(input)):
136
+ return TaskAction.RETRY
137
+ elif input == "k" or (len(input) > 1 and TaskAction.SKIP.value.startswith(input)):
138
+ return TaskAction.SKIP
139
+ elif input == "s" or (len(input) > 1 and TaskAction.STOP.value.startswith(input)):
140
+ return TaskAction.STOP
141
+ else:
142
+ raise ValueError(f"Unknown action: {input}")
143
+
144
+ def get_next_stage(self, stage, state, action):
145
+
146
+ ns = self._get_next_stage_trans(stage, state, action)
147
+ return ns.stage
148
+
149
+ def __call__(self, stage, max_tries=3, stage_continue=True, stage_confirm=True):
150
+
151
+ n_tries = 0
152
+ stage = stage or self.START_STAGE
153
+ while n_tries <= max_tries:
154
+ try:
155
+ stage_name = stage.value if isinstance(stage, Enum) else stage
156
+ stage_name = stage_name.replace(".", "-").capitalize()
157
+ set_stage(stage_name)
158
+ agent = self.get_stage_agent(stage)
159
+ _M(f"**Executing** stage `{stage}` with agent `{type(agent).__name__}` ...")
160
+ failed, state = agent()
161
+ except Exception as e:
162
+ _M(f"**Error** during task execution stage `{stage}`: `{type(e)}`: `{e}`")
163
+ _M(f"```python\n{traceback.format_exc()}\n```")
164
+ state = TASK_AGENT_STATE_ERROR
165
+ failed = True
166
+
167
+ if state != TASK_AGENT_STATE_ERROR:
168
+ # Agent did not fail, check if we have reached the final stage
169
+ next_stage = self.get_next_stage(stage, state, TaskAction.CONTINUE)
170
+ self.task.agent_stage = next_stage
171
+ self.task.update_cell()
172
+ if next_stage in self.STOP_STAGES:
173
+ _M(f"Task execution **Stopped** at stage `{next_stage}`")
174
+ break
175
+
176
+ if failed:
177
+ # Agent failed
178
+ n_tries += 1
179
+
180
+ if failed or stage_confirm:
181
+ # Agent failed or we need to confirm
182
+ message = self.get_prompt_message(stage, state, failed)
183
+ _M("**Confirm**: " + message)
184
+ flush_output()
185
+ action = self.match_action(input(message))
186
+ next_stage = self.get_next_stage(stage, state, action)
187
+ self.task.agent_stage = next_stage
188
+ self.task.update_cell()
189
+ if action == TaskAction.STOP:
190
+ _M(f"Task execution **Stopped**, and set next stage to `{next_stage}`")
191
+ break
192
+ elif n_tries > max_tries:
193
+ _M(f"**Max tries reached** during task execution stage `{stage}`, **Stop!**")
194
+ break
195
+ else:
196
+ _M(f"**Action**: `{action}` transits stage to `{next_stage}`")
197
+ stage = next_stage
198
+ else:
199
+ # Agent succeeded, transit to the next stage without confirmation
200
+ next_stage = self.get_next_stage(stage, state, TaskAction.CONTINUE)
201
+ self.task.agent_stage = next_stage
202
+ self.task.update_cell()
203
+ _M(f"**Transits** stage to `{next_stage}`")
204
+ stage = next_stage
205
+
206
+ if not stage_continue:
207
+ break
208
+ flush_output()
209
+ return stage
@@ -0,0 +1,16 @@
1
+ """
2
+ Copyright (c) 2025 viewstar000
3
+
4
+ This software is released under the MIT License.
5
+ https://opensource.org/licenses/MIT
6
+ """
7
+
8
+ from .base import BaseTaskFlow, StageTransition, TASK_STAGE_START, TASK_STAGE_COMPLETED
9
+
10
+
11
+ class MasterPlannerFlow(BaseTaskFlow):
12
+
13
+ STAGE_TRANSITIONS = [
14
+ StageTransition(stage=TASK_STAGE_START, agent="MasterPlannerAgent", next_stage=TASK_STAGE_START)
15
+ ]
16
+ STOP_STAGES = [TASK_STAGE_START]
@@ -0,0 +1,86 @@
1
+ """
2
+ Copyright (c) 2025 viewstar000
3
+
4
+ This software is released under the MIT License.
5
+ https://opensource.org/licenses/MIT
6
+ """
7
+
8
+ from enum import Enum
9
+ from .base import BaseTaskFlow, StageTransition, StageNext, TaskAction
10
+ from ..bot_agents import (
11
+ TaskPlannerAgentV1,
12
+ TaskCodingAgent,
13
+ CodeDebugerAgent,
14
+ CodeExecutor,
15
+ TaskVerifyAgent,
16
+ TaskSummaryAgent,
17
+ TaskVerifyState,
18
+ )
19
+ from ..bot_agents.task_planner_v1 import TaskPlannerState
20
+
21
+
22
+ class TaskStage(str, Enum):
23
+ PLANNING = "planning"
24
+ PLANNING_PAUSED = "planning_paused"
25
+ CODING = "coding"
26
+ EXECUTING = "executing"
27
+ DEBUGGING = "debugging"
28
+ VERIFYING = "verifying"
29
+ SUMMARY = "summary"
30
+ COMPLETED = "completed"
31
+
32
+
33
+ class TaskExecutorFlowV1(BaseTaskFlow):
34
+
35
+ START_STAGE = TaskStage.PLANNING
36
+ STOP_STAGES = [TaskStage.COMPLETED, TaskStage.PLANNING_PAUSED]
37
+ STAGE_TRANSITIONS = [
38
+ StageTransition[TaskStage, TaskPlannerState](
39
+ stage=TaskStage.PLANNING,
40
+ agent=TaskPlannerAgentV1,
41
+ states={
42
+ TaskPlannerState.PLANNED: TaskStage.CODING,
43
+ TaskPlannerState.REQUEST_INFO: TaskStage.PLANNING_PAUSED,
44
+ TaskPlannerState.GLOBAL_FINISHED: TaskStage.COMPLETED,
45
+ },
46
+ ),
47
+ StageTransition[TaskStage, TaskPlannerState](
48
+ stage=TaskStage.PLANNING_PAUSED,
49
+ agent=TaskPlannerAgentV1,
50
+ states={
51
+ TaskPlannerState.PLANNED: TaskStage.CODING,
52
+ TaskPlannerState.REQUEST_INFO: TaskStage.PLANNING_PAUSED,
53
+ TaskPlannerState.GLOBAL_FINISHED: TaskStage.COMPLETED,
54
+ },
55
+ ),
56
+ StageTransition[TaskStage, None](
57
+ stage=TaskStage.CODING, agent=TaskCodingAgent, next_stage=TaskStage.EXECUTING
58
+ ),
59
+ StageTransition[TaskStage, bool](
60
+ stage=TaskStage.EXECUTING,
61
+ agent=CodeExecutor,
62
+ states={True: TaskStage.VERIFYING, False: TaskStage.DEBUGGING},
63
+ ),
64
+ StageTransition[TaskStage, None](
65
+ stage=TaskStage.DEBUGGING, agent=CodeDebugerAgent, next_stage=TaskStage.EXECUTING
66
+ ),
67
+ StageTransition[TaskStage, TaskVerifyState](
68
+ stage=TaskStage.VERIFYING,
69
+ agent=TaskVerifyAgent,
70
+ states={
71
+ TaskVerifyState.PASSED: TaskStage.SUMMARY,
72
+ TaskVerifyState.FAILED: [
73
+ StageNext[TaskStage](action=TaskAction.CONTINUE, stage=TaskStage.PLANNING),
74
+ StageNext[TaskStage](action=TaskAction.SKIP, stage=TaskStage.SUMMARY),
75
+ ],
76
+ },
77
+ ),
78
+ StageTransition[TaskStage, None](
79
+ stage=TaskStage.SUMMARY, agent=TaskSummaryAgent, next_stage=TaskStage.COMPLETED
80
+ ),
81
+ StageTransition[TaskStage, bool](
82
+ stage=TaskStage.COMPLETED,
83
+ agent=CodeExecutor,
84
+ states={True: TaskStage.COMPLETED, False: TaskStage.DEBUGGING},
85
+ ),
86
+ ]
@@ -0,0 +1,84 @@
1
+ """
2
+ Copyright (c) 2025 viewstar000
3
+
4
+ This software is released under the MIT License.
5
+ https://opensource.org/licenses/MIT
6
+ """
7
+
8
+ from enum import Enum
9
+ from .base import BaseTaskFlow, StageTransition, StageNext, TaskAction
10
+ from ..bot_agents import (
11
+ TaskPlannerAgentV2,
12
+ TaskCodingAgent,
13
+ CodeDebugerAgent,
14
+ CodeExecutor,
15
+ TaskSummaryAgent,
16
+ TaskReasoningAgent,
17
+ )
18
+ from ..bot_agents.task_planner_v2 import TaskPlannerState
19
+
20
+
21
+ class TaskStage(str, Enum):
22
+ PLANNING = "planning"
23
+ PLANNING_PAUSED = "planning_paused"
24
+ CODING = "coding"
25
+ EXECUTING = "executing"
26
+ DEBUGGING = "debugging"
27
+ REASONING = "reasoning"
28
+ SUMMARY = "summary"
29
+ COMPLETED = "completed"
30
+
31
+
32
+ class TaskExecutorFlowV2(BaseTaskFlow):
33
+
34
+ START_STAGE = TaskStage.PLANNING
35
+ STOP_STAGES = [TaskStage.COMPLETED, TaskStage.PLANNING_PAUSED]
36
+ STAGE_TRANSITIONS = [
37
+ StageTransition[TaskStage, TaskPlannerState](
38
+ stage=TaskStage.PLANNING,
39
+ agent=TaskPlannerAgentV2,
40
+ states={
41
+ TaskPlannerState.CODING_PLANNED: TaskStage.CODING,
42
+ TaskPlannerState.REASONING_PLANNED: TaskStage.REASONING,
43
+ TaskPlannerState.REQUEST_INFO: TaskStage.PLANNING_PAUSED,
44
+ TaskPlannerState.GLOBAL_FINISHED: TaskStage.COMPLETED,
45
+ },
46
+ ),
47
+ StageTransition[TaskStage, TaskPlannerState](
48
+ stage=TaskStage.PLANNING_PAUSED,
49
+ agent=TaskPlannerAgentV2,
50
+ states={
51
+ TaskPlannerState.CODING_PLANNED: TaskStage.CODING,
52
+ TaskPlannerState.REASONING_PLANNED: TaskStage.REASONING,
53
+ TaskPlannerState.REQUEST_INFO: TaskStage.PLANNING_PAUSED,
54
+ TaskPlannerState.GLOBAL_FINISHED: TaskStage.COMPLETED,
55
+ },
56
+ ),
57
+ StageTransition[TaskStage, None](
58
+ stage=TaskStage.CODING, agent=TaskCodingAgent, next_stage=TaskStage.EXECUTING
59
+ ),
60
+ StageTransition[TaskStage, bool](
61
+ stage=TaskStage.EXECUTING,
62
+ agent=CodeExecutor,
63
+ states={True: TaskStage.SUMMARY, False: TaskStage.DEBUGGING},
64
+ ),
65
+ StageTransition[TaskStage, None](
66
+ stage=TaskStage.DEBUGGING, agent=CodeDebugerAgent, next_stage=TaskStage.EXECUTING
67
+ ),
68
+ StageTransition[TaskStage, None](
69
+ stage=TaskStage.REASONING, agent=TaskReasoningAgent, next_stage=TaskStage.COMPLETED
70
+ ),
71
+ StageTransition[TaskStage, None](
72
+ stage=TaskStage.SUMMARY,
73
+ agent=TaskSummaryAgent,
74
+ next_stage={
75
+ TaskAction.DEFAULT: StageNext(stage=TaskStage.COMPLETED),
76
+ TaskAction.STOP: StageNext(stage=TaskStage.EXECUTING),
77
+ },
78
+ ),
79
+ StageTransition[TaskStage, bool](
80
+ stage=TaskStage.COMPLETED,
81
+ agent=CodeExecutor,
82
+ states={True: TaskStage.COMPLETED, False: TaskStage.DEBUGGING},
83
+ ),
84
+ ]
@@ -0,0 +1,89 @@
1
+ """
2
+ Copyright (c) 2025 viewstar000
3
+
4
+ This software is released under the MIT License.
5
+ https://opensource.org/licenses/MIT
6
+ """
7
+
8
+ from enum import Enum
9
+ from .base import BaseTaskFlow, StageTransition, StageNext, TaskAction
10
+ from ..bot_agents import (
11
+ TaskPlannerAgentV3,
12
+ TaskCodingAgent,
13
+ CodeDebugerAgent,
14
+ CodeExecutor,
15
+ TaskStructureSummaryAgent,
16
+ TaskStructureReasoningAgent,
17
+ OutputTaskResult,
18
+ )
19
+ from ..bot_agents.task_planner_v3 import TaskPlannerState
20
+
21
+
22
+ class TaskStage(str, Enum):
23
+ PLANNING = "planning"
24
+ PLANNING_PAUSED = "planning_paused"
25
+ CODING = "coding"
26
+ EXECUTING = "executing"
27
+ DEBUGGING = "debugging"
28
+ REASONING = "reasoning"
29
+ SUMMARY = "summary"
30
+ COMPLETED = "completed"
31
+ OUTPUT_RESULT = "output_result"
32
+
33
+
34
+ class TaskExecutorFlowV3(BaseTaskFlow):
35
+
36
+ START_STAGE = TaskStage.PLANNING
37
+ STOP_STAGES = [TaskStage.COMPLETED, TaskStage.PLANNING_PAUSED]
38
+ STAGE_TRANSITIONS = [
39
+ StageTransition[TaskStage, TaskPlannerState](
40
+ stage=TaskStage.PLANNING,
41
+ agent=TaskPlannerAgentV3,
42
+ states={
43
+ TaskPlannerState.CODING_PLANNED: TaskStage.CODING,
44
+ TaskPlannerState.REASONING_PLANNED: TaskStage.REASONING,
45
+ TaskPlannerState.REQUEST_INFO: TaskStage.PLANNING_PAUSED,
46
+ TaskPlannerState.GLOBAL_FINISHED: TaskStage.COMPLETED,
47
+ },
48
+ ),
49
+ StageTransition[TaskStage, TaskPlannerState](
50
+ stage=TaskStage.PLANNING_PAUSED,
51
+ agent=TaskPlannerAgentV3,
52
+ states={
53
+ TaskPlannerState.CODING_PLANNED: TaskStage.CODING,
54
+ TaskPlannerState.REASONING_PLANNED: TaskStage.REASONING,
55
+ TaskPlannerState.REQUEST_INFO: TaskStage.PLANNING_PAUSED,
56
+ TaskPlannerState.GLOBAL_FINISHED: TaskStage.COMPLETED,
57
+ },
58
+ ),
59
+ StageTransition[TaskStage, None](
60
+ stage=TaskStage.CODING, agent=TaskCodingAgent, next_stage=TaskStage.EXECUTING
61
+ ),
62
+ StageTransition[TaskStage, bool](
63
+ stage=TaskStage.EXECUTING,
64
+ agent=CodeExecutor,
65
+ states={True: TaskStage.SUMMARY, False: TaskStage.DEBUGGING},
66
+ ),
67
+ StageTransition[TaskStage, None](
68
+ stage=TaskStage.DEBUGGING, agent=CodeDebugerAgent, next_stage=TaskStage.EXECUTING
69
+ ),
70
+ StageTransition[TaskStage, None](
71
+ stage=TaskStage.REASONING, agent=TaskStructureReasoningAgent, next_stage=TaskStage.COMPLETED
72
+ ),
73
+ StageTransition[TaskStage, None](
74
+ stage=TaskStage.SUMMARY,
75
+ agent=TaskStructureSummaryAgent,
76
+ next_stage={
77
+ TaskAction.DEFAULT: StageNext(stage=TaskStage.COMPLETED),
78
+ TaskAction.STOP: StageNext(stage=TaskStage.EXECUTING),
79
+ },
80
+ ),
81
+ StageTransition[TaskStage, bool](
82
+ stage=TaskStage.COMPLETED,
83
+ agent=CodeExecutor,
84
+ states={True: TaskStage.OUTPUT_RESULT, False: TaskStage.DEBUGGING},
85
+ ),
86
+ StageTransition[TaskStage, None](
87
+ stage=TaskStage.OUTPUT_RESULT, agent=OutputTaskResult, next_stage=TaskStage.COMPLETED
88
+ ),
89
+ ]
@@ -0,0 +1,127 @@
1
+ """
2
+ Copyright (c) 2025 viewstar000
3
+
4
+ This software is released under the MIT License.
5
+ https://opensource.org/licenses/MIT
6
+ """
7
+
8
+ import time
9
+ import shlex
10
+ import argparse
11
+ import ipynbname
12
+ import traceback
13
+
14
+ from IPython.display import Markdown
15
+ from IPython.core.magic import Magics, magics_class, cell_magic
16
+ from traitlets import Unicode, Int, Bool
17
+ from traitlets.config.configurable import Configurable
18
+ from .bot_contexts import NotebookContext, AgentCellContext
19
+ from .bot_agents import AgentFactory
20
+ from .bot_agents.base import AgentModelType
21
+ from .bot_flows import MasterPlannerFlow, TaskExecutorFlowV1, TaskExecutorFlowV2, TaskExecutorFlowV3
22
+ from .bot_outputs import _D, _I, _W, _E, _F, _M, _B, _O, reset_output, set_logging_level
23
+
24
+
25
+ @magics_class
26
+ class BotMagics(Magics, Configurable):
27
+ """Jupyter cell magic for OpenAI bot integration"""
28
+
29
+ # 配置项
30
+ logging_level = Unicode("INFO", help="Debug level for logging").tag(config=True)
31
+ default_api_url = Unicode(None, allow_none=True, help="Default API URL").tag(config=True)
32
+ default_api_key = Unicode("API_KEY", help="Default API Key").tag(config=True)
33
+ default_model_name = Unicode("", help="Default Model Name").tag(config=True)
34
+ planner_api_url = Unicode(None, allow_none=True, help="Planner API URL").tag(config=True)
35
+ planner_api_key = Unicode("API_KEY", help="Planner API Key").tag(config=True)
36
+ planner_model_name = Unicode("", help="Planner Model Name").tag(config=True)
37
+ coding_api_url = Unicode(None, allow_none=True, help="Coding API URL").tag(config=True)
38
+ coding_api_key = Unicode("API_KEY", help="Coding API Key").tag(config=True)
39
+ coding_model_name = Unicode("", help="Coding Model Name").tag(config=True)
40
+ reasoning_api_url = Unicode(None, allow_none=True, help="Reasoning API URL").tag(config=True)
41
+ reasoning_api_key = Unicode("API_KEY", help="Reasoning API Key").tag(config=True)
42
+ reasoning_model_name = Unicode("", help="Reasoning Model Name").tag(config=True)
43
+ display_message = Bool(False, help="Display chat message").tag(config=True)
44
+ display_think = Bool(True, help="Display chatthink response").tag(config=True)
45
+ display_response = Bool(False, help="Display chat full response").tag(config=True)
46
+ notebook_path = Unicode(None, allow_none=True, help="Path to Notebook file").tag(config=True)
47
+ default_task_flow = Unicode("v3", allow_none=True, help="Default task flow").tag(config=True)
48
+ support_save_meta = Bool(False, help="Support save metadata to cell").tag(config=True)
49
+
50
+ def parse_args(self, line):
51
+ """解析命令行参数"""
52
+ parser = argparse.ArgumentParser()
53
+ parser.add_argument("-l", "--logging-level", type=str, default=self.logging_level, help="level for logging")
54
+ parser.add_argument("-P", "--planning", action="store_true", default=False, help="Run in planning mode")
55
+ parser.add_argument("-s", "--stage", type=str, default=None, help="Task stage")
56
+ parser.add_argument("-f", "--flow", type=str, default=self.default_task_flow, help="Flow name")
57
+ parser.add_argument("-m", "--max-tries", type=int, default=3, help="Max tries")
58
+ parser.add_argument("-S", "--step-mode", action="store_true", default=False, help="Run in single step mode")
59
+ parser.add_argument("-Y", "--auto-confirm", action="store_true", default=False, help="Run without confirm")
60
+ options, _ = parser.parse_known_args(shlex.split(line.strip()))
61
+
62
+ return options
63
+
64
+ @cell_magic
65
+ def bot(self, line, cell):
66
+ """Jupyter cell magic: %%bot"""
67
+ try:
68
+ AgentCellContext.SUPPORT_SAVE_META = self.support_save_meta
69
+ reset_output(stage="Logging", logging_level=self.logging_level)
70
+ _I("Cell magic %%bot executing ...")
71
+ _D(f"Cell magic called with line: {line}")
72
+ _D(f"Cell magic called with cell: {repr(cell)[:50]} ...")
73
+ if not cell.strip():
74
+ _O(
75
+ Markdown(
76
+ "The cell is **empty**, we can't do anything.\n\n"
77
+ "We will fill it with some random characters, please **RERUN** the cell again."
78
+ )
79
+ )
80
+ if self.shell is not None:
81
+ self.shell.set_next_input(
82
+ "%%bot {}\n\n# {}".format(line.strip(), time.strftime("%Y-%m-%d %H:%M:%S")), replace=True
83
+ )
84
+ return
85
+ options = self.parse_args(line)
86
+ _D(f"Cell magic called with options: {options}")
87
+ set_logging_level(options.logging_level)
88
+ self.notebook_path = self.notebook_path or ipynbname.path()
89
+ _D(f"Cell magic called with notebook path: {self.notebook_path}")
90
+ nb_context = NotebookContext(line, cell, notebook_path=self.notebook_path)
91
+ agent_factory = AgentFactory(
92
+ nb_context,
93
+ display_think=self.display_think,
94
+ display_message=self.display_message,
95
+ display_response=self.display_response,
96
+ )
97
+ agent_factory.config_model(
98
+ AgentModelType.DEFAULT, self.default_api_url, self.default_api_key, self.default_model_name
99
+ )
100
+ agent_factory.config_model(
101
+ AgentModelType.PLANNER, self.planner_api_url, self.planner_api_key, self.planner_model_name
102
+ )
103
+ agent_factory.config_model(
104
+ AgentModelType.CODING, self.coding_api_url, self.coding_api_key, self.coding_model_name
105
+ )
106
+ agent_factory.config_model(
107
+ AgentModelType.REASONING, self.reasoning_api_url, self.reasoning_api_key, self.reasoning_model_name
108
+ )
109
+ if options.planning:
110
+ flow = MasterPlannerFlow(nb_context, agent_factory)
111
+ else:
112
+ if options.flow == "v1":
113
+ flow = TaskExecutorFlowV1(nb_context, agent_factory)
114
+ elif options.flow == "v2":
115
+ flow = TaskExecutorFlowV2(nb_context, agent_factory)
116
+ elif options.flow == "v3":
117
+ flow = TaskExecutorFlowV3(nb_context, agent_factory)
118
+ else:
119
+ raise ValueError(f"Unknown flow: {options.flow}")
120
+ flow(options.stage, options.max_tries, not options.step_mode, not options.auto_confirm)
121
+ except Exception as e:
122
+ traceback.print_exc()
123
+
124
+
125
+ def load_ipython_extension(ipython):
126
+ """Load the bot magic extension."""
127
+ ipython.register_magics(BotMagics)