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.
- jupyter_agent/__init__.py +0 -0
- jupyter_agent/bot_agents/__init__.py +42 -0
- jupyter_agent/bot_agents/base.py +324 -0
- jupyter_agent/bot_agents/master_planner.py +45 -0
- jupyter_agent/bot_agents/output_task_result.py +29 -0
- jupyter_agent/bot_agents/task_code_executor.py +53 -0
- jupyter_agent/bot_agents/task_coder.py +71 -0
- jupyter_agent/bot_agents/task_debuger.py +69 -0
- jupyter_agent/bot_agents/task_planner_v1.py +158 -0
- jupyter_agent/bot_agents/task_planner_v2.py +172 -0
- jupyter_agent/bot_agents/task_planner_v3.py +189 -0
- jupyter_agent/bot_agents/task_reasoner.py +61 -0
- jupyter_agent/bot_agents/task_structrue_reasoner.py +106 -0
- jupyter_agent/bot_agents/task_structrue_summarier.py +123 -0
- jupyter_agent/bot_agents/task_summarier.py +76 -0
- jupyter_agent/bot_agents/task_verifier.py +99 -0
- jupyter_agent/bot_agents/task_verify_summarier.py +134 -0
- jupyter_agent/bot_chat.py +218 -0
- jupyter_agent/bot_contexts.py +466 -0
- jupyter_agent/bot_flows/__init__.py +20 -0
- jupyter_agent/bot_flows/base.py +209 -0
- jupyter_agent/bot_flows/master_planner.py +16 -0
- jupyter_agent/bot_flows/task_executor_v1.py +86 -0
- jupyter_agent/bot_flows/task_executor_v2.py +84 -0
- jupyter_agent/bot_flows/task_executor_v3.py +89 -0
- jupyter_agent/bot_magics.py +127 -0
- jupyter_agent/bot_outputs.py +480 -0
- jupyter_agent/utils.py +138 -0
- {jupyter_agent-2025.6.100.dist-info → jupyter_agent-2025.6.101.dist-info}/METADATA +13 -7
- jupyter_agent-2025.6.101.dist-info/RECORD +33 -0
- jupyter_agent-2025.6.101.dist-info/top_level.txt +1 -0
- jupyter_agent-2025.6.100.dist-info/RECORD +0 -5
- jupyter_agent-2025.6.100.dist-info/top_level.txt +0 -1
- {jupyter_agent-2025.6.100.dist-info → jupyter_agent-2025.6.101.dist-info}/WHEEL +0 -0
- {jupyter_agent-2025.6.100.dist-info → jupyter_agent-2025.6.101.dist-info}/licenses/LICENSE +0 -0
File without changes
|
@@ -0,0 +1,42 @@
|
|
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 BaseChatAgent, AgentFactory
|
9
|
+
from .master_planner import MasterPlannerAgent
|
10
|
+
from .output_task_result import OutputTaskResult
|
11
|
+
from .task_code_executor import CodeExecutor
|
12
|
+
from .task_planner_v1 import TaskPlannerAgentV1
|
13
|
+
from .task_planner_v2 import TaskPlannerAgentV2
|
14
|
+
from .task_planner_v3 import TaskPlannerAgentV3
|
15
|
+
from .task_coder import TaskCodingAgent
|
16
|
+
from .task_debuger import CodeDebugerAgent
|
17
|
+
from .task_verifier import TaskVerifyAgent, TaskVerifyState
|
18
|
+
from .task_summarier import TaskSummaryAgent
|
19
|
+
from .task_verify_summarier import TaskVerifySummaryAgent
|
20
|
+
from .task_structrue_summarier import TaskStructureSummaryAgent
|
21
|
+
from .task_reasoner import TaskReasoningAgent
|
22
|
+
from .task_structrue_reasoner import TaskStructureReasoningAgent
|
23
|
+
|
24
|
+
__all__ = [
|
25
|
+
"AgentFactory",
|
26
|
+
"BaseChatAgent",
|
27
|
+
"CodeDebugerAgent",
|
28
|
+
"CodeExecutor",
|
29
|
+
"MasterPlannerAgent",
|
30
|
+
"TaskCodingAgent",
|
31
|
+
"TaskPlannerAgentV1",
|
32
|
+
"TaskPlannerAgentV2",
|
33
|
+
"TaskPlannerAgentV3",
|
34
|
+
"TaskReasoningAgent",
|
35
|
+
"TaskStructureReasoningAgent",
|
36
|
+
"TaskStructureSummaryAgent",
|
37
|
+
"TaskSummaryAgent",
|
38
|
+
"TaskVerifyAgent",
|
39
|
+
"TaskVerifyState",
|
40
|
+
"TaskVerifySummaryAgent",
|
41
|
+
"OutputTaskResult",
|
42
|
+
]
|
@@ -0,0 +1,324 @@
|
|
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 json
|
9
|
+
import importlib
|
10
|
+
|
11
|
+
from typing import Tuple, Any
|
12
|
+
from enum import Enum, unique
|
13
|
+
from IPython.display import Markdown
|
14
|
+
from ..bot_outputs import _C, flush_output
|
15
|
+
from ..bot_chat import BotChat
|
16
|
+
from ..utils import no_indent
|
17
|
+
|
18
|
+
_TASK_CONTEXTS = no_indent(
|
19
|
+
"""
|
20
|
+
**全局任务规划及子任务完成情况**:
|
21
|
+
|
22
|
+
{% for cell in cells %}
|
23
|
+
{% if cell.type == "planning" and cell.source.strip() %}
|
24
|
+
{{ cell.source }}
|
25
|
+
{{ cell.result }}
|
26
|
+
{% elif cell.type == "task" and cell.subject.strip() %}
|
27
|
+
## 子任务[{{ cell.task_id }}] - {{ '已完成' if cell.result else '未完成' }}
|
28
|
+
|
29
|
+
### 任务目标
|
30
|
+
|
31
|
+
{{ cell.subject }}
|
32
|
+
|
33
|
+
### 任务结果
|
34
|
+
|
35
|
+
{{ cell.result }}
|
36
|
+
|
37
|
+
{% if cell.important_infos %}
|
38
|
+
### 任务结论中的重要信息(Important Infos)
|
39
|
+
|
40
|
+
```json
|
41
|
+
{{ cell.important_infos | json }}
|
42
|
+
```
|
43
|
+
{%+ endif %}
|
44
|
+
{% elif cell.is_task_context and cell.source.strip() %}
|
45
|
+
{{ cell.source }}
|
46
|
+
{% endif %}
|
47
|
+
{% endfor %}
|
48
|
+
"""
|
49
|
+
)
|
50
|
+
|
51
|
+
|
52
|
+
_CODE_CONTEXTS = no_indent(
|
53
|
+
"""
|
54
|
+
**已执行的代码**:
|
55
|
+
|
56
|
+
```python
|
57
|
+
{% for cell in cells +%}
|
58
|
+
{% if cell.type == "task" and cell.source.strip() %}
|
59
|
+
######## Cell[{{ cell.cell_idx }}] for Task[{{ cell.task_id }}] ########
|
60
|
+
|
61
|
+
{{ cell.source }}
|
62
|
+
{% elif cell.is_code_context and cell.source.strip() %}
|
63
|
+
######## Cell[{{ cell.cell_idx }}] ########
|
64
|
+
|
65
|
+
{{ cell.source }}
|
66
|
+
{% endif %}
|
67
|
+
{%+ endfor %}
|
68
|
+
```
|
69
|
+
"""
|
70
|
+
)
|
71
|
+
|
72
|
+
_TASK_OUTPUT_FORMAT = """
|
73
|
+
{% if OUTPUT_FORMAT == "code" %}
|
74
|
+
**输出格式**:
|
75
|
+
|
76
|
+
输出{{ OUTPUT_CODE_LANG }}代码块,以Markdown格式显示,使用```{{ OUTPUT_CODE_LANG }}...```包裹。
|
77
|
+
|
78
|
+
示例代码:
|
79
|
+
|
80
|
+
```python
|
81
|
+
def xxx(xxx):
|
82
|
+
...
|
83
|
+
return xxx
|
84
|
+
|
85
|
+
xxx(...)
|
86
|
+
```
|
87
|
+
|
88
|
+
{% elif OUTPUT_FORMAT == "json" %}
|
89
|
+
**输出格式**:
|
90
|
+
|
91
|
+
输出JSON格式数据,以Markdown格式显示,使用```json...```包裹。
|
92
|
+
|
93
|
+
数据符合JSON Schema:
|
94
|
+
|
95
|
+
```json
|
96
|
+
{{ OUTPUT_JSON_SCHEMA }}
|
97
|
+
```
|
98
|
+
|
99
|
+
数据示例:
|
100
|
+
|
101
|
+
```json
|
102
|
+
{{ OUTPUT_JSON_EXAMPLE }}
|
103
|
+
```
|
104
|
+
|
105
|
+
{% endif %}
|
106
|
+
"""
|
107
|
+
|
108
|
+
PREDEFINE_PROMPT_BLOCKS = {
|
109
|
+
"TASK_CONTEXTS": _TASK_CONTEXTS,
|
110
|
+
"CODE_CONTEXTS": _CODE_CONTEXTS,
|
111
|
+
"TASK_OUTPUT_FORMAT": _TASK_OUTPUT_FORMAT,
|
112
|
+
}
|
113
|
+
|
114
|
+
|
115
|
+
@unique
|
116
|
+
class AgentOutputFormat(str, Enum):
|
117
|
+
RAW = "raw"
|
118
|
+
TEXT = "text"
|
119
|
+
CODE = "code"
|
120
|
+
JSON = "json"
|
121
|
+
|
122
|
+
|
123
|
+
@unique
|
124
|
+
class AgentCombineReply(str, Enum):
|
125
|
+
FIRST = "first"
|
126
|
+
LAST = "last"
|
127
|
+
LIST = "list"
|
128
|
+
MERGE = "merge"
|
129
|
+
|
130
|
+
|
131
|
+
@unique
|
132
|
+
class AgentModelType(str, Enum):
|
133
|
+
DEFAULT = "default"
|
134
|
+
PLANNER = "planner"
|
135
|
+
CODING = "coding"
|
136
|
+
REASONING = "reasoning"
|
137
|
+
|
138
|
+
|
139
|
+
class BaseAgent:
|
140
|
+
"""基础代理类"""
|
141
|
+
|
142
|
+
def __init__(self, notebook_context):
|
143
|
+
self.notebook_context = notebook_context
|
144
|
+
|
145
|
+
@property
|
146
|
+
def task(self):
|
147
|
+
return self.notebook_context.cur_task
|
148
|
+
|
149
|
+
@property
|
150
|
+
def cells(self):
|
151
|
+
return self.notebook_context.cells
|
152
|
+
|
153
|
+
|
154
|
+
class BaseChatAgent(BotChat, BaseAgent):
|
155
|
+
"""基础聊天代理类"""
|
156
|
+
|
157
|
+
PROMPT = "You are a helpful assistant. {{ prompt }}\n\nAnswer:"
|
158
|
+
OUTPUT_FORMAT = AgentOutputFormat.RAW
|
159
|
+
OUTPUT_CODE_LANG = "python"
|
160
|
+
OUTPUT_JSON_SCHEMA = None # Pydantic Model
|
161
|
+
DISPLAY_REPLY = True
|
162
|
+
COMBINE_REPLY = AgentCombineReply.MERGE
|
163
|
+
ACCEPT_EMPYT_REPLY = False
|
164
|
+
MODEL_TYPE = AgentModelType.REASONING
|
165
|
+
|
166
|
+
def __init__(self, notebook_context, base_url, api_key, model_name, **chat_kwargs):
|
167
|
+
"""初始化基础任务代理"""
|
168
|
+
BaseAgent.__init__(self, notebook_context)
|
169
|
+
BotChat.__init__(self, base_url, api_key, model_name, **chat_kwargs)
|
170
|
+
|
171
|
+
def prepare_contexts(self, **kwargs):
|
172
|
+
contexts = {
|
173
|
+
"cells": self.cells,
|
174
|
+
"task": self.task,
|
175
|
+
"OUTPUT_FORMAT": self.OUTPUT_FORMAT,
|
176
|
+
"OUTPUT_CODE_LANG": self.OUTPUT_CODE_LANG,
|
177
|
+
}
|
178
|
+
if self.OUTPUT_JSON_SCHEMA:
|
179
|
+
json_schema = self.OUTPUT_JSON_SCHEMA.model_json_schema()
|
180
|
+
model_fields = getattr(self.OUTPUT_JSON_SCHEMA, "model_fields", None)
|
181
|
+
if model_fields and hasattr(model_fields, "items"):
|
182
|
+
json_example = {
|
183
|
+
name: field.examples[0] if getattr(field, "examples", None) else getattr(field, "default", None)
|
184
|
+
for name, field in model_fields.items()
|
185
|
+
}
|
186
|
+
else:
|
187
|
+
json_example = {}
|
188
|
+
contexts["OUTPUT_JSON_SCHEMA"] = json.dumps(json_schema, indent=2, ensure_ascii=False)
|
189
|
+
contexts["OUTPUT_JSON_EXAMPLE"] = json.dumps(json_example, indent=2, ensure_ascii=False)
|
190
|
+
contexts.update(kwargs)
|
191
|
+
return contexts
|
192
|
+
|
193
|
+
def create_messages(self, contexts):
|
194
|
+
messages = super().create_messages(contexts, templates=PREDEFINE_PROMPT_BLOCKS)
|
195
|
+
messages.add(self.PROMPT)
|
196
|
+
return messages
|
197
|
+
|
198
|
+
def combine_raw_replies(self, replies):
|
199
|
+
if self.COMBINE_REPLY == AgentCombineReply.FIRST:
|
200
|
+
return replies[0]["raw"]
|
201
|
+
elif self.COMBINE_REPLY == AgentCombineReply.LAST:
|
202
|
+
return replies[-1]["raw"]
|
203
|
+
elif self.COMBINE_REPLY == AgentCombineReply.MERGE:
|
204
|
+
return "".join([reply["raw"] for reply in replies])
|
205
|
+
else:
|
206
|
+
raise ValueError("Unsupported combine_reply: {} for raw output".format(self.COMBINE_REPLY))
|
207
|
+
|
208
|
+
def combine_code_replies(self, replies):
|
209
|
+
code_replies = [
|
210
|
+
reply for reply in replies if reply["type"] == "code" and reply["lang"] == self.OUTPUT_CODE_LANG
|
211
|
+
]
|
212
|
+
if self.COMBINE_REPLY == AgentCombineReply.FIRST:
|
213
|
+
return code_replies[0]["content"]
|
214
|
+
elif self.COMBINE_REPLY == AgentCombineReply.LAST:
|
215
|
+
return code_replies[-1]["content"]
|
216
|
+
elif self.COMBINE_REPLY == AgentCombineReply.MERGE:
|
217
|
+
return "\n".join([reply["content"] for reply in code_replies])
|
218
|
+
else:
|
219
|
+
raise ValueError("Unsupported combine_reply: {} for code output".format(self.COMBINE_REPLY))
|
220
|
+
|
221
|
+
def combine_json_replies(self, replies):
|
222
|
+
json_replies = [reply for reply in replies if reply["type"] == "code" and reply["lang"] == "json"]
|
223
|
+
if self.COMBINE_REPLY == AgentCombineReply.FIRST:
|
224
|
+
json_obj = json.loads(json_replies[0]["content"])
|
225
|
+
if self.OUTPUT_JSON_SCHEMA:
|
226
|
+
json_obj = self.OUTPUT_JSON_SCHEMA(**json_obj)
|
227
|
+
return json_obj
|
228
|
+
elif self.COMBINE_REPLY == AgentCombineReply.LAST:
|
229
|
+
json_obj = json.loads(json_replies[-1]["content"])
|
230
|
+
if self.OUTPUT_JSON_SCHEMA:
|
231
|
+
json_obj = self.OUTPUT_JSON_SCHEMA(**json_obj)
|
232
|
+
return json_obj
|
233
|
+
elif self.COMBINE_REPLY == AgentCombineReply.LIST:
|
234
|
+
json_objs = [json.loads(reply["content"]) for reply in json_replies]
|
235
|
+
if self.OUTPUT_JSON_SCHEMA:
|
236
|
+
json_objs = [self.OUTPUT_JSON_SCHEMA(**json_obj) for json_obj in json_objs]
|
237
|
+
return json_objs
|
238
|
+
elif self.COMBINE_REPLY == AgentCombineReply.MERGE:
|
239
|
+
json_obj = {}
|
240
|
+
for json_reply in json_replies:
|
241
|
+
json_obj.update(json.loads(json_reply["content"]))
|
242
|
+
if self.OUTPUT_JSON_SCHEMA:
|
243
|
+
json_obj = self.OUTPUT_JSON_SCHEMA(**json_obj)
|
244
|
+
return json_obj
|
245
|
+
else:
|
246
|
+
raise ValueError("Unsupported combine_reply: {} for json output".format(self.COMBINE_REPLY))
|
247
|
+
|
248
|
+
def combine_text_replies(self, replies):
|
249
|
+
text_replies = [reply for reply in replies if reply["type"] == "text"]
|
250
|
+
if self.COMBINE_REPLY == AgentCombineReply.FIRST:
|
251
|
+
return text_replies[0]["content"]
|
252
|
+
elif self.COMBINE_REPLY == AgentCombineReply.LAST:
|
253
|
+
return text_replies[-1]["content"]
|
254
|
+
elif self.COMBINE_REPLY == AgentCombineReply.MERGE:
|
255
|
+
return "".join([reply["content"] for reply in text_replies])
|
256
|
+
else:
|
257
|
+
raise ValueError("Unsupported combine_reply: {} for text output".format(self.COMBINE_REPLY))
|
258
|
+
|
259
|
+
def combine_replies(self, replies):
|
260
|
+
if self.OUTPUT_FORMAT == AgentOutputFormat.RAW:
|
261
|
+
return self.combine_raw_replies(replies).strip()
|
262
|
+
elif self.OUTPUT_FORMAT == AgentOutputFormat.TEXT:
|
263
|
+
return self.combine_text_replies(replies).strip()
|
264
|
+
elif self.OUTPUT_FORMAT == AgentOutputFormat.CODE:
|
265
|
+
return self.combine_code_replies(replies).strip()
|
266
|
+
elif self.OUTPUT_FORMAT == AgentOutputFormat.JSON:
|
267
|
+
return self.combine_json_replies(replies)
|
268
|
+
else:
|
269
|
+
raise ValueError("Unsupported output format: {}".format(self.OUTPUT_FORMAT))
|
270
|
+
|
271
|
+
def on_reply(self, reply) -> Tuple[bool, Any] | Any:
|
272
|
+
_C(Markdown(reply))
|
273
|
+
|
274
|
+
def __call__(self, **kwargs) -> Tuple[bool, Any]:
|
275
|
+
contexts = self.prepare_contexts(**kwargs)
|
276
|
+
messages = self.create_messages(contexts)
|
277
|
+
replies = self.chat(messages.get(), display_reply=self.DISPLAY_REPLY)
|
278
|
+
reply = self.combine_replies(replies)
|
279
|
+
if not self.ACCEPT_EMPYT_REPLY and not reply:
|
280
|
+
raise ValueError("Reply is empty")
|
281
|
+
result = self.on_reply(reply)
|
282
|
+
flush_output()
|
283
|
+
if not isinstance(result, tuple):
|
284
|
+
return False, result
|
285
|
+
else:
|
286
|
+
return result
|
287
|
+
|
288
|
+
|
289
|
+
class AgentFactory:
|
290
|
+
|
291
|
+
def __init__(self, notebook_context, **chat_kwargs):
|
292
|
+
self.notebook_context = notebook_context
|
293
|
+
self.chat_kwargs = chat_kwargs
|
294
|
+
self.models = {AgentModelType.DEFAULT: {"api_url": None, "api_key": None, "model": None}}
|
295
|
+
|
296
|
+
def config_model(self, agent_model, api_url, api_key, model_name):
|
297
|
+
self.models[agent_model] = {
|
298
|
+
"api_url": api_url,
|
299
|
+
"api_key": api_key,
|
300
|
+
"model": model_name,
|
301
|
+
}
|
302
|
+
|
303
|
+
def __call__(self, agent_class):
|
304
|
+
|
305
|
+
if isinstance(agent_class, str):
|
306
|
+
bot_agents = importlib.import_module("..bot_agents", __package__)
|
307
|
+
agent_class = getattr(bot_agents, agent_class)
|
308
|
+
|
309
|
+
if issubclass(agent_class, BaseChatAgent):
|
310
|
+
agent_model = agent_class.MODEL_TYPE if hasattr(agent_class, "MODEL_TYPE") else AgentModelType.DEFAULT
|
311
|
+
return agent_class(
|
312
|
+
notebook_context=self.notebook_context,
|
313
|
+
base_url=self.models.get(agent_model, {}).get("api_url")
|
314
|
+
or self.models[AgentModelType.DEFAULT]["api_url"],
|
315
|
+
api_key=self.models.get(agent_model, {}).get("api_key")
|
316
|
+
or self.models[AgentModelType.DEFAULT]["api_key"],
|
317
|
+
model_name=self.models.get(agent_model, {}).get("model")
|
318
|
+
or self.models[AgentModelType.DEFAULT]["model"],
|
319
|
+
**self.chat_kwargs,
|
320
|
+
)
|
321
|
+
elif issubclass(agent_class, BaseAgent):
|
322
|
+
return agent_class(notebook_context=self.notebook_context)
|
323
|
+
else:
|
324
|
+
raise ValueError("Unsupported agent class: {}".format(agent_class))
|
@@ -0,0 +1,45 @@
|
|
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 IPython.display import Markdown
|
9
|
+
from .base import BaseChatAgent, AgentModelType
|
10
|
+
from ..bot_outputs import _C, ReplyType
|
11
|
+
|
12
|
+
MASTER_PLANNER_PROMPT = """\
|
13
|
+
**角色定义**:
|
14
|
+
|
15
|
+
你是一个高级分析规划专家,擅长将自然语言任务拆解为可执行的Jupyter Notebook分析流程。
|
16
|
+
|
17
|
+
**任务要求**:
|
18
|
+
|
19
|
+
- 解析用户输入的自然语言指令(目标Prompt),提取核心需求(如数据来源、分析目标、输出格式等)
|
20
|
+
- 将核心需求转化为可执行的Jupyter Notebook分析流程
|
21
|
+
- 流程的每个环节应尽量简单明确
|
22
|
+
- 生成**目标规划说明**,包含:
|
23
|
+
1. 需要执行的子任务列表(按逻辑顺序排列)
|
24
|
+
3. 每个子任务的输入/输出依赖关系
|
25
|
+
4. 预期的最终输出形式(文字/图表/表格等)
|
26
|
+
|
27
|
+
**用户需求**:
|
28
|
+
|
29
|
+
{{ task.source }}
|
30
|
+
|
31
|
+
---
|
32
|
+
|
33
|
+
请根据上述信息为用户规划全局执行计划:
|
34
|
+
"""
|
35
|
+
|
36
|
+
|
37
|
+
class MasterPlannerAgent(BaseChatAgent):
|
38
|
+
"""全局规划器代理类"""
|
39
|
+
|
40
|
+
PROMPT = MASTER_PLANNER_PROMPT
|
41
|
+
DISPLAY_REPLY = False
|
42
|
+
MODEL_TYPE = AgentModelType.PLANNER
|
43
|
+
|
44
|
+
def on_reply(self, reply):
|
45
|
+
_C(Markdown(reply), reply_type=ReplyType.TASK_RESULT)
|
@@ -0,0 +1,29 @@
|
|
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 json
|
9
|
+
|
10
|
+
from IPython.display import Markdown
|
11
|
+
from .base import BaseAgent
|
12
|
+
from ..bot_outputs import _D, _I, _W, _E, _F, _M, _B, _C, _O, ReplyType, markdown_block
|
13
|
+
|
14
|
+
|
15
|
+
class OutputTaskResult(BaseAgent):
|
16
|
+
|
17
|
+
def __call__(self):
|
18
|
+
"""执行代码逻辑"""
|
19
|
+
if self.task.result:
|
20
|
+
_O(Markdown("### 任务结果\n\n"))
|
21
|
+
_C(Markdown(self.task.result), reply_type=ReplyType.TASK_RESULT)
|
22
|
+
if self.task.important_infos:
|
23
|
+
_O(
|
24
|
+
markdown_block(
|
25
|
+
f"```json\n{json.dumps(self.task.important_infos, indent=4, ensure_ascii=False)}\n```",
|
26
|
+
title="重要信息",
|
27
|
+
)
|
28
|
+
)
|
29
|
+
return False, None
|
@@ -0,0 +1,53 @@
|
|
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 re
|
9
|
+
|
10
|
+
from IPython.core.getipython import get_ipython
|
11
|
+
from IPython.display import Markdown, clear_output
|
12
|
+
from .base import BaseAgent
|
13
|
+
from ..utils import TeeOutputCapture
|
14
|
+
from ..bot_outputs import _D, _I, _W, _E, _F, _M, _B, _C, ReplyType
|
15
|
+
|
16
|
+
|
17
|
+
class CodeExecutor(BaseAgent):
|
18
|
+
|
19
|
+
def __call__(self):
|
20
|
+
"""执行代码逻辑"""
|
21
|
+
_D(f"执行代码: {repr(self.task.source)[:80]}")
|
22
|
+
ipython = get_ipython()
|
23
|
+
exec_failed = False
|
24
|
+
with TeeOutputCapture() as captured:
|
25
|
+
if ipython is None:
|
26
|
+
exec_failed = True
|
27
|
+
self.task.cell_error = "IPython environment not found."
|
28
|
+
_E("执行失败: IPython environment not found.")
|
29
|
+
result = None
|
30
|
+
else:
|
31
|
+
result = ipython.run_cell(self.task.source)
|
32
|
+
if result.success:
|
33
|
+
self.task.cell_result = "{}".format(result.result)
|
34
|
+
_D(f"执行结果: {repr(self.task.cell_result)[:80]}")
|
35
|
+
else:
|
36
|
+
exec_failed = True
|
37
|
+
exc_info = ipython._format_exception_for_storage(result.error_before_exec or result.error_in_exec)
|
38
|
+
ansi_escape = re.compile(r"\x1b\[[0-9;]*m")
|
39
|
+
clean_traceback = "\n".join(ansi_escape.sub("", line) for line in exc_info["traceback"])
|
40
|
+
self.task.cell_error = clean_traceback
|
41
|
+
_E(f"执行失败: {clean_traceback}")
|
42
|
+
self.task.cell_output = ""
|
43
|
+
if captured.stdout:
|
44
|
+
self.task.cell_output += "Stdout:\n" + captured.stdout + "\n"
|
45
|
+
if captured.stderr:
|
46
|
+
self.task.cell_output += "Stderr:\n" + captured.stderr + "\n"
|
47
|
+
if captured.outputs:
|
48
|
+
self.task.cell_output += "Outputs:\n"
|
49
|
+
for output in captured.outputs:
|
50
|
+
output_content = output.data.get("text/markdown", "") or output.data.get("text/plain", "")
|
51
|
+
self.task.cell_output += output_content
|
52
|
+
self.task.cell_output += "\n"
|
53
|
+
return exec_failed, not exec_failed
|
@@ -0,0 +1,71 @@
|
|
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
|
+
|
10
|
+
from .base import BaseChatAgent, AgentOutputFormat, AgentModelType
|
11
|
+
|
12
|
+
|
13
|
+
TASK_CODING_PROMPT = """\
|
14
|
+
**角色定义**:
|
15
|
+
|
16
|
+
你是一个代码生成器,能够将自然语言描述转化为可执行的Jupyter Notebook代码。
|
17
|
+
|
18
|
+
**任务要求**:
|
19
|
+
|
20
|
+
- 根据子任务Prompt生成**Python代码**(需包含必要的依赖导入)
|
21
|
+
- 代码需严格遵守以下原则:
|
22
|
+
- 使用已存在的变量(如`cleaned_sales_df`)
|
23
|
+
- 新生成的变量需命名清晰(如`growth_rates_df`)
|
24
|
+
- 发生错误时,直接抛出异常,不需要进行任何错误处理,以便于执行器发现问题
|
25
|
+
- 代码在Jupyter环境中执行,但也应考虑通用性,尽量封装为函数或类
|
26
|
+
- 执行结果应保存在变量中,同时打印输出(或做为cell的返回值输出)
|
27
|
+
- 代码中应保含必要的文档注释
|
28
|
+
- 避免生成重复的代码
|
29
|
+
|
30
|
+
{% include "TASK_OUTPUT_FORMAT" %}
|
31
|
+
|
32
|
+
---
|
33
|
+
|
34
|
+
{% include "TASK_CONTEXTS" %}
|
35
|
+
|
36
|
+
---
|
37
|
+
|
38
|
+
{% include "CODE_CONTEXTS" %}
|
39
|
+
|
40
|
+
---
|
41
|
+
|
42
|
+
**当前子任务信息**:
|
43
|
+
|
44
|
+
### 当前子任务目标:
|
45
|
+
{{ task.subject }}
|
46
|
+
|
47
|
+
### 当前子任务代码需求:
|
48
|
+
{{ task.coding_prompt }}
|
49
|
+
|
50
|
+
{% if task.issue %}
|
51
|
+
### 尽量避免的问题:
|
52
|
+
{{ task.issue }}
|
53
|
+
{% endif %}
|
54
|
+
|
55
|
+
---
|
56
|
+
|
57
|
+
请按要求生成任务代码:
|
58
|
+
"""
|
59
|
+
|
60
|
+
|
61
|
+
class TaskCodingAgent(BaseChatAgent):
|
62
|
+
|
63
|
+
PROMPT = TASK_CODING_PROMPT
|
64
|
+
OUTPUT_FORMAT = AgentOutputFormat.CODE
|
65
|
+
OUTPUT_CODE_LANG = "python"
|
66
|
+
MODEL_TYPE = AgentModelType.CODING
|
67
|
+
|
68
|
+
def on_reply(self, reply: str):
|
69
|
+
generated_code = "# Generated by Jupyter Agent (Coder) {}\n".format(time.strftime("%Y-%m-%d %H:%M:%S"))
|
70
|
+
generated_code += reply
|
71
|
+
self.task.source = generated_code
|
@@ -0,0 +1,69 @@
|
|
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
|
+
|
10
|
+
from .base import BaseChatAgent, AgentOutputFormat, AgentModelType
|
11
|
+
|
12
|
+
TASK_DEBUGGER_PROMPT = """\
|
13
|
+
**角色定义**:
|
14
|
+
|
15
|
+
你是一个代码调试专家,擅长定位并修复Jupyter Notebook中的错误。
|
16
|
+
|
17
|
+
**任务要求**:
|
18
|
+
|
19
|
+
- 分析执行失败的代码和错误信息,提出修复方案
|
20
|
+
- 修复方案需包含错误原因分析(语法错误/逻辑错误/依赖缺失等)
|
21
|
+
|
22
|
+
{% include "TASK_OUTPUT_FORMAT" %}
|
23
|
+
|
24
|
+
---
|
25
|
+
|
26
|
+
{% include "TASK_CONTEXTS" %}
|
27
|
+
|
28
|
+
---
|
29
|
+
|
30
|
+
{% include "CODE_CONTEXTS" %}
|
31
|
+
|
32
|
+
---
|
33
|
+
|
34
|
+
**当前子任务信息**:
|
35
|
+
|
36
|
+
### 当前子任务目标:
|
37
|
+
{{ task.subject }}
|
38
|
+
|
39
|
+
### 当前子任务代码需求:
|
40
|
+
{{ task.coding_prompt }}
|
41
|
+
|
42
|
+
### 当前代码:
|
43
|
+
```python
|
44
|
+
{{ task.source }}
|
45
|
+
```
|
46
|
+
|
47
|
+
### 当前输出:
|
48
|
+
{{ task.cell_output }}
|
49
|
+
|
50
|
+
### 当前错误:
|
51
|
+
{{ task.cell_error }}
|
52
|
+
|
53
|
+
---
|
54
|
+
|
55
|
+
请输出修复后的代码:
|
56
|
+
"""
|
57
|
+
|
58
|
+
|
59
|
+
class CodeDebugerAgent(BaseChatAgent):
|
60
|
+
|
61
|
+
PROMPT = TASK_DEBUGGER_PROMPT
|
62
|
+
OUTPUT_FORMAT = AgentOutputFormat.CODE
|
63
|
+
OUTPUT_CODE_LANG = "python"
|
64
|
+
MODEL_TYPE = AgentModelType.CODING
|
65
|
+
|
66
|
+
def on_reply(self, reply: str):
|
67
|
+
generated_code = "# Generated by Jupyter Agent (Debugger) {}\n".format(time.strftime("%Y-%m-%d %H:%M:%S"))
|
68
|
+
generated_code += reply
|
69
|
+
self.task.source = generated_code
|