jupyter-agent 2025.6.103__py3-none-any.whl → 2025.6.105__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/bot_actions.py +270 -0
- jupyter_agent/bot_agents/__init__.py +0 -42
- jupyter_agent/bot_agents/base.py +85 -45
- jupyter_agent/bot_agents/master_planner.py +2 -0
- jupyter_agent/bot_agents/output_task_result.py +6 -7
- jupyter_agent/bot_agents/request_user_supply.py +186 -0
- jupyter_agent/bot_agents/task_planner_v3.py +12 -13
- jupyter_agent/bot_agents/task_reasoner.py +2 -2
- jupyter_agent/bot_agents/task_structrue_reasoner.py +19 -12
- jupyter_agent/bot_agents/task_structrue_summarier.py +19 -18
- jupyter_agent/bot_agents/task_summarier.py +2 -2
- jupyter_agent/bot_agents/task_verifier.py +1 -1
- jupyter_agent/bot_agents/task_verify_summarier.py +5 -6
- jupyter_agent/bot_chat.py +2 -2
- jupyter_agent/bot_contexts.py +28 -23
- jupyter_agent/bot_evaluation.py +325 -0
- jupyter_agent/bot_evaluators/__init__.py +0 -0
- jupyter_agent/bot_evaluators/base.py +42 -0
- jupyter_agent/bot_evaluators/dummy_flow.py +20 -0
- jupyter_agent/bot_evaluators/dummy_global.py +20 -0
- jupyter_agent/bot_evaluators/dummy_task.py +20 -0
- jupyter_agent/bot_evaluators/flow_global_planning.py +88 -0
- jupyter_agent/bot_evaluators/flow_task_executor.py +152 -0
- jupyter_agent/bot_flows/__init__.py +0 -4
- jupyter_agent/bot_flows/base.py +114 -10
- jupyter_agent/bot_flows/master_planner.py +7 -2
- jupyter_agent/bot_flows/task_executor_v3.py +45 -20
- jupyter_agent/bot_magics.py +108 -53
- jupyter_agent/bot_outputs.py +56 -3
- jupyter_agent/utils.py +20 -31
- {jupyter_agent-2025.6.103.dist-info → jupyter_agent-2025.6.105.dist-info}/METADATA +39 -8
- jupyter_agent-2025.6.105.dist-info/RECORD +40 -0
- jupyter_agent-2025.6.105.dist-info/entry_points.txt +2 -0
- jupyter_agent/bot_agents/task_planner_v1.py +0 -158
- jupyter_agent/bot_agents/task_planner_v2.py +0 -172
- jupyter_agent/bot_flows/task_executor_v1.py +0 -86
- jupyter_agent/bot_flows/task_executor_v2.py +0 -84
- jupyter_agent-2025.6.103.dist-info/RECORD +0 -33
- {jupyter_agent-2025.6.103.dist-info → jupyter_agent-2025.6.105.dist-info}/WHEEL +0 -0
- {jupyter_agent-2025.6.103.dist-info → jupyter_agent-2025.6.105.dist-info}/licenses/LICENSE +0 -0
- {jupyter_agent-2025.6.103.dist-info → jupyter_agent-2025.6.105.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,186 @@
|
|
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 uuid
|
10
|
+
import json
|
11
|
+
|
12
|
+
from enum import Enum
|
13
|
+
from typing import List, Optional, Dict, Any, Tuple
|
14
|
+
from pydantic import BaseModel, Field
|
15
|
+
from IPython.display import Markdown
|
16
|
+
from .base import BaseChatAgent, AgentOutputFormat
|
17
|
+
from ..bot_outputs import _D, _I, _W, _E, _F, _M, _B, _C, _O
|
18
|
+
from ..bot_actions import (
|
19
|
+
get_action_dispatcher,
|
20
|
+
RequestUserSupplyInfo,
|
21
|
+
UserSupplyInfoReply,
|
22
|
+
ActionRequestUserSupplyInfo,
|
23
|
+
RequestUserSupplyInfoParams,
|
24
|
+
ActionReceiveUserSupplyInfo,
|
25
|
+
ReceiveUserSupplyInfoParams,
|
26
|
+
ActionSetCellContent,
|
27
|
+
SetCellContentParams,
|
28
|
+
)
|
29
|
+
from ..utils import get_env_capbilities
|
30
|
+
|
31
|
+
MOCK_USER_REPLY_PROMPT = """\
|
32
|
+
**角色定义**:
|
33
|
+
|
34
|
+
你是一个用户需求补充专家,负责补充用户的需求信息,以便于更好的完成任务。
|
35
|
+
|
36
|
+
**任务要求**:
|
37
|
+
|
38
|
+
根据提示补充待确认的信息,以便于更好的完成任务。
|
39
|
+
|
40
|
+
|
41
|
+
{% include "TASK_OUTPUT_FORMAT" %}
|
42
|
+
|
43
|
+
---
|
44
|
+
|
45
|
+
{% include "TASK_CONTEXTS" %}
|
46
|
+
|
47
|
+
---
|
48
|
+
|
49
|
+
{% include "CODE_CONTEXTS" %}
|
50
|
+
|
51
|
+
---
|
52
|
+
|
53
|
+
**当前子任务信息**:
|
54
|
+
|
55
|
+
### 当前子任务目标:
|
56
|
+
{{ task.subject }}
|
57
|
+
|
58
|
+
### 当前子任务代码需求:
|
59
|
+
{{ task.coding_prompt }}
|
60
|
+
|
61
|
+
### 当前代码:
|
62
|
+
```python
|
63
|
+
{{ task.source }}
|
64
|
+
```
|
65
|
+
|
66
|
+
### 当前代码执行的输出与结果:
|
67
|
+
{{ task.output }}
|
68
|
+
|
69
|
+
### 当前任务总结要求:
|
70
|
+
{{ task.summary_prompt }}
|
71
|
+
|
72
|
+
### 当前任务总结结果:
|
73
|
+
{{ task.result }}
|
74
|
+
|
75
|
+
---
|
76
|
+
|
77
|
+
需要补充确认的信息:
|
78
|
+
|
79
|
+
{% for issue in request_supply_infos %}
|
80
|
+
- {{ issue.prompt }}, (例如: {{ issue.example }})
|
81
|
+
{% endfor %}
|
82
|
+
|
83
|
+
---
|
84
|
+
|
85
|
+
请按要求补充上述待确认的信息:
|
86
|
+
"""
|
87
|
+
|
88
|
+
|
89
|
+
def format_request_user_supply_info(
|
90
|
+
issues: list[RequestUserSupplyInfo], title="用户补充确认信息", use_markdown_block=True
|
91
|
+
) -> str:
|
92
|
+
result = f"### {title}\n\n"
|
93
|
+
result += "\n".join(
|
94
|
+
[f"- **Assistant**: {prompt.prompt} (例如: {prompt.example})\n- **User Reply**: " for prompt in issues]
|
95
|
+
)
|
96
|
+
if use_markdown_block:
|
97
|
+
result = f"```markdown\n{result}\n```\n"
|
98
|
+
return result
|
99
|
+
|
100
|
+
|
101
|
+
def format_received_user_supply_info(
|
102
|
+
replies: list[UserSupplyInfoReply], title="用户补充确认信息", use_markdown_block=True
|
103
|
+
) -> str:
|
104
|
+
result = f"### {title}\n\n"
|
105
|
+
result += "\n".join([f"- **Assistant**: {reply.prompt}\n- **User Reply**: {reply.reply}" for reply in replies])
|
106
|
+
if use_markdown_block:
|
107
|
+
result = f"```markdown\n{result}\n```\n"
|
108
|
+
return result
|
109
|
+
|
110
|
+
|
111
|
+
class RequestUserSupplyAgent(BaseChatAgent):
|
112
|
+
|
113
|
+
PROMPT = MOCK_USER_REPLY_PROMPT
|
114
|
+
OUTPUT_FORMAT = AgentOutputFormat.JSON
|
115
|
+
OUTPUT_JSON_SCHEMA = ReceiveUserSupplyInfoParams
|
116
|
+
DISPLAY_REPLY = True
|
117
|
+
MOCK_USER_SUPPLY: bool = False
|
118
|
+
WHERE_USER_SUPPLY = "below" # "above" or "below"
|
119
|
+
|
120
|
+
def on_reply(self, reply: ReceiveUserSupplyInfoParams):
|
121
|
+
assert reply, "Reply is empty"
|
122
|
+
if get_env_capbilities().set_cell_content:
|
123
|
+
insert_cell_idx = -1 if self.WHERE_USER_SUPPLY == "above" else 1
|
124
|
+
action = ActionSetCellContent(
|
125
|
+
source=self.__class__.__name__,
|
126
|
+
params=SetCellContentParams(
|
127
|
+
index=insert_cell_idx,
|
128
|
+
type="markdown",
|
129
|
+
source=format_received_user_supply_info(reply.replies, use_markdown_block=False),
|
130
|
+
),
|
131
|
+
)
|
132
|
+
get_action_dispatcher().send_action(action, need_reply=False)
|
133
|
+
else:
|
134
|
+
_M("### 用户补充确认的信息\n\n请将下面的内容保存到单独的单元格中,以便于更好的完成任务\n\n")
|
135
|
+
_M(format_received_user_supply_info(reply.replies))
|
136
|
+
|
137
|
+
def __call__(self, **kwargs) -> Tuple[bool, Any]:
|
138
|
+
request_supply_infos = (
|
139
|
+
self.task.request_above_supply_infos
|
140
|
+
if self.WHERE_USER_SUPPLY == "above"
|
141
|
+
else self.task.request_below_supply_infos
|
142
|
+
)
|
143
|
+
kwargs["request_supply_infos"] = request_supply_infos
|
144
|
+
if self.MOCK_USER_SUPPLY:
|
145
|
+
return super().__call__(**kwargs)
|
146
|
+
else:
|
147
|
+
if get_env_capbilities().user_supply_info:
|
148
|
+
_M(f"**需要用户补充确认信息**,请按要求补充确认信息。")
|
149
|
+
action = ActionRequestUserSupplyInfo(
|
150
|
+
source=self.__class__.__name__,
|
151
|
+
params=RequestUserSupplyInfoParams(title="用户需求补充确认", issues=request_supply_infos),
|
152
|
+
)
|
153
|
+
get_action_dispatcher().send_action(action, need_reply=True)
|
154
|
+
res = get_action_dispatcher().get_action_reply(action, wait=True)
|
155
|
+
return False, self.on_reply(res and res.params) # type: ignore
|
156
|
+
elif get_env_capbilities().set_cell_content:
|
157
|
+
_M(
|
158
|
+
f"**需要用户补充确认信息**,"
|
159
|
+
f"请将{'下面' if self.WHERE_USER_SUPPLY == 'below' else '上面'}的单元格中的内容补充完整,"
|
160
|
+
f"以便于更好的完成任务"
|
161
|
+
)
|
162
|
+
insert_cell_idx = -1 if self.WHERE_USER_SUPPLY == "above" else 1
|
163
|
+
action = ActionSetCellContent(
|
164
|
+
source=self.__class__.__name__,
|
165
|
+
params=SetCellContentParams(
|
166
|
+
index=insert_cell_idx,
|
167
|
+
type="markdown",
|
168
|
+
source=format_request_user_supply_info(request_supply_infos, use_markdown_block=False),
|
169
|
+
),
|
170
|
+
)
|
171
|
+
get_action_dispatcher().send_action(action, need_reply=False)
|
172
|
+
else:
|
173
|
+
_M(
|
174
|
+
"### 需要补充确认的信息\n\n"
|
175
|
+
"请将下面的内容保存到单独的单元格中并将其补充完整,以便于更好的完成任务\n\n"
|
176
|
+
)
|
177
|
+
_M(format_request_user_supply_info(request_supply_infos))
|
178
|
+
return False, None
|
179
|
+
|
180
|
+
|
181
|
+
class RequestAboveUserSupplyAgent(RequestUserSupplyAgent):
|
182
|
+
WHERE_USER_SUPPLY = "above"
|
183
|
+
|
184
|
+
|
185
|
+
class RequestBelowUserSupplyAgent(RequestUserSupplyAgent):
|
186
|
+
WHERE_USER_SUPPLY = "below"
|
@@ -11,7 +11,7 @@ from pydantic import BaseModel, Field
|
|
11
11
|
from IPython.display import Markdown
|
12
12
|
from .base import BaseChatAgent, AgentOutputFormat, AgentModelType
|
13
13
|
from ..bot_outputs import ReplyType, _D, _I, _W, _E, _F, _A, _O, _C, _M, _B
|
14
|
-
from ..
|
14
|
+
from ..bot_actions import RequestUserSupplyInfo
|
15
15
|
|
16
16
|
|
17
17
|
TASK_PLANNER_PROMPT = """\
|
@@ -131,7 +131,7 @@ class TaskPlannerOutput(BaseModel):
|
|
131
131
|
),
|
132
132
|
examples=["请对当前任务的结果进行总结,输出以下要素:..."],
|
133
133
|
)
|
134
|
-
request_supply_infos: Optional[List[
|
134
|
+
request_supply_infos: Optional[List[RequestUserSupplyInfo]] = Field(
|
135
135
|
None, description=f'需要用户补充更详细的信息的 Prompt, 在 state="{TaskPlannerState.REQUEST_INFO}" 时必填'
|
136
136
|
)
|
137
137
|
|
@@ -151,8 +151,7 @@ class TaskPlannerAgentV3(BaseChatAgent):
|
|
151
151
|
return False, reply.state
|
152
152
|
elif reply.state == TaskPlannerState.REQUEST_INFO:
|
153
153
|
assert reply.request_supply_infos, "Request info prompt is empty"
|
154
|
-
|
155
|
-
_O(Markdown(format_user_prompts(reply.request_supply_infos)))
|
154
|
+
self.task.agent_data.request_above_supply_infos = reply.request_supply_infos
|
156
155
|
return True, reply.state
|
157
156
|
elif reply.state == TaskPlannerState.CODING_PLANNED:
|
158
157
|
assert reply.subtask_id, "Subtask id is empty"
|
@@ -165,11 +164,11 @@ class TaskPlannerAgentV3(BaseChatAgent):
|
|
165
164
|
f"- Coding: {reply.subtask_coding_prompt}\n"
|
166
165
|
f"- Summary: {reply.subtask_summary_prompt}\n"
|
167
166
|
)
|
168
|
-
self.task.
|
169
|
-
self.task.
|
170
|
-
self.task.
|
171
|
-
self.task.
|
172
|
-
self.task.
|
167
|
+
self.task.agent_data.task_id = reply.subtask_id
|
168
|
+
self.task.agent_data.subject = reply.subtask_subject
|
169
|
+
self.task.agent_data.coding_prompt = reply.subtask_coding_prompt
|
170
|
+
self.task.agent_data.summary_prompt = reply.subtask_summary_prompt
|
171
|
+
self.task.agent_data.result = ""
|
173
172
|
return False, reply.state
|
174
173
|
elif reply.state == TaskPlannerState.REASONING_PLANNED:
|
175
174
|
assert reply.subtask_id, "Subtask id is empty"
|
@@ -180,10 +179,10 @@ class TaskPlannerAgentV3(BaseChatAgent):
|
|
180
179
|
f"- ID: {reply.subtask_id}\n"
|
181
180
|
f"- Reasoning: {reply.subtask_summary_prompt}\n"
|
182
181
|
)
|
183
|
-
self.task.
|
184
|
-
self.task.
|
185
|
-
self.task.
|
186
|
-
self.task.
|
182
|
+
self.task.agent_data.task_id = reply.subtask_id
|
183
|
+
self.task.agent_data.subject = reply.subtask_subject
|
184
|
+
self.task.agent_data.summary_prompt = reply.subtask_summary_prompt
|
185
|
+
self.task.agent_data.result = ""
|
187
186
|
return False, reply.state
|
188
187
|
else:
|
189
188
|
raise ValueError(f"Unknown task planner state: {reply.state}")
|
@@ -56,6 +56,6 @@ class TaskReasoningAgent(BaseChatAgent):
|
|
56
56
|
DISPLAY_REPLY = False
|
57
57
|
|
58
58
|
def on_reply(self, reply: str):
|
59
|
-
_C(Markdown("### 任务总结\n" + reply), reply_type=ReplyType.TASK_RESULT)
|
60
59
|
assert reply, "Reply is empty"
|
61
|
-
|
60
|
+
_M("### 任务总结\n" + reply)
|
61
|
+
self.task.agent_data.result = reply
|
@@ -13,7 +13,8 @@ from pydantic import BaseModel, Field
|
|
13
13
|
from IPython.display import Markdown
|
14
14
|
from .base import BaseChatAgent, AgentOutputFormat
|
15
15
|
from ..bot_outputs import ReplyType, _D, _I, _W, _E, _F, _M, _B, _C, _O, markdown_block
|
16
|
-
from ..
|
16
|
+
from ..bot_actions import RequestUserSupplyInfo
|
17
|
+
|
17
18
|
|
18
19
|
TASK_REASONER_PROMPT = """\
|
19
20
|
**角色定义**:
|
@@ -58,6 +59,11 @@ TASK_REASONER_PROMPT = """\
|
|
58
59
|
"""
|
59
60
|
|
60
61
|
|
62
|
+
class TaskStructureReasonState(str, Enum):
|
63
|
+
DONE = "done"
|
64
|
+
REQUEST_INFO = "request_info"
|
65
|
+
|
66
|
+
|
61
67
|
class TaskStructureReasonOutput(BaseModel):
|
62
68
|
|
63
69
|
summary: str = Field(description=f"任务总结的详细描述", examples=["..."])
|
@@ -77,7 +83,7 @@ class TaskStructureReasonOutput(BaseModel):
|
|
77
83
|
}
|
78
84
|
],
|
79
85
|
)
|
80
|
-
request_confirm_infos: Optional[List[
|
86
|
+
request_confirm_infos: Optional[List[RequestUserSupplyInfo]] = Field(
|
81
87
|
None, description="需要用户补充确认的信息,问题应尽量简单,只需要用户回答是/否或在备选项中选择即可"
|
82
88
|
)
|
83
89
|
|
@@ -91,16 +97,17 @@ class TaskStructureReasoningAgent(BaseChatAgent):
|
|
91
97
|
|
92
98
|
def on_reply(self, reply: TaskStructureReasonOutput):
|
93
99
|
assert reply.summary, "Reply is empty"
|
94
|
-
|
95
|
-
self.task.
|
100
|
+
_M("### 任务总结\n\n" + reply.summary)
|
101
|
+
self.task.agent_data.result = reply.summary
|
96
102
|
if reply.important_infos:
|
97
|
-
self.task.
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
+
self.task.agent_data.important_infos = reply.important_infos
|
104
|
+
_B(
|
105
|
+
json.dumps(reply.important_infos, indent=4, ensure_ascii=False),
|
106
|
+
title="重要信息",
|
107
|
+
format="code",
|
108
|
+
code_language="json",
|
103
109
|
)
|
104
110
|
if reply.request_confirm_infos:
|
105
|
-
|
106
|
-
|
111
|
+
self.task.agent_data.request_below_supply_infos = reply.request_confirm_infos
|
112
|
+
return TaskStructureReasonState.REQUEST_INFO
|
113
|
+
return TaskStructureReasonState.DONE
|
@@ -13,7 +13,7 @@ from pydantic import BaseModel, Field
|
|
13
13
|
from IPython.display import Markdown
|
14
14
|
from .base import BaseChatAgent, AgentOutputFormat
|
15
15
|
from ..bot_outputs import ReplyType, _D, _I, _W, _E, _F, _M, _B, _C, _O, markdown_block
|
16
|
-
from ..
|
16
|
+
from ..bot_actions import RequestUserSupplyInfo
|
17
17
|
|
18
18
|
TASK_SUMMARY_PROMPT = """\
|
19
19
|
**角色定义**:
|
@@ -70,12 +70,12 @@ TASK_SUMMARY_PROMPT = """\
|
|
70
70
|
"""
|
71
71
|
|
72
72
|
|
73
|
-
class
|
74
|
-
|
75
|
-
|
73
|
+
class TaskStructureSummaryState(str, Enum):
|
74
|
+
DONE = "done"
|
75
|
+
REQUEST_INFO = "request_info"
|
76
76
|
|
77
77
|
|
78
|
-
class
|
78
|
+
class TaskStructureSummaryOutput(BaseModel):
|
79
79
|
|
80
80
|
summary: str = Field(description=f"任务总结的详细描述", examples=["..."])
|
81
81
|
important_infos: Optional[Dict[str, Any]] = Field(
|
@@ -94,7 +94,7 @@ class TaskStructureSumaryOutput(BaseModel):
|
|
94
94
|
}
|
95
95
|
],
|
96
96
|
)
|
97
|
-
request_confirm_infos: Optional[List[
|
97
|
+
request_confirm_infos: Optional[List[RequestUserSupplyInfo]] = Field(
|
98
98
|
None, description="需要用户补充确认的信息,问题应尽量简单,只需要用户回答是/否或在备选项中选择即可"
|
99
99
|
)
|
100
100
|
|
@@ -103,21 +103,22 @@ class TaskStructureSummaryAgent(BaseChatAgent):
|
|
103
103
|
|
104
104
|
PROMPT = TASK_SUMMARY_PROMPT
|
105
105
|
OUTPUT_FORMAT = AgentOutputFormat.JSON
|
106
|
-
OUTPUT_JSON_SCHEMA =
|
106
|
+
OUTPUT_JSON_SCHEMA = TaskStructureSummaryOutput
|
107
107
|
DISPLAY_REPLY = True
|
108
108
|
|
109
|
-
def on_reply(self, reply:
|
109
|
+
def on_reply(self, reply: TaskStructureSummaryOutput):
|
110
110
|
assert reply.summary, "Reply is empty"
|
111
|
-
|
112
|
-
self.task.
|
111
|
+
_M("### 任务总结\n\n" + reply.summary)
|
112
|
+
self.task.agent_data.result = reply.summary
|
113
113
|
if reply.important_infos:
|
114
|
-
self.task.
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
114
|
+
self.task.agent_data.important_infos = reply.important_infos
|
115
|
+
_B(
|
116
|
+
json.dumps(reply.important_infos, indent=4, ensure_ascii=False),
|
117
|
+
format="code",
|
118
|
+
code_language="json",
|
119
|
+
title="重要信息",
|
120
120
|
)
|
121
121
|
if reply.request_confirm_infos:
|
122
|
-
|
123
|
-
|
122
|
+
self.task.agent_data.request_below_supply_infos = reply.request_confirm_infos
|
123
|
+
return TaskStructureSummaryState.REQUEST_INFO
|
124
|
+
return TaskStructureSummaryState.DONE
|
@@ -71,6 +71,6 @@ class TaskSummaryAgent(BaseChatAgent):
|
|
71
71
|
DISPLAY_REPLY = False
|
72
72
|
|
73
73
|
def on_reply(self, reply: str):
|
74
|
-
_C(Markdown("### 任务总结\n" + reply), reply_type=ReplyType.TASK_RESULT)
|
75
74
|
assert reply, "Reply is empty"
|
76
|
-
|
75
|
+
_M("### 任务总结\n" + reply)
|
76
|
+
self.task.agent_data.result = reply
|
@@ -109,10 +109,9 @@ class TaskVerifySummaryAgent(BaseChatAgent):
|
|
109
109
|
def on_reply(self, reply: TaskSummaryOutput):
|
110
110
|
|
111
111
|
if reply.state == TaskSummaryState.SUCCESS:
|
112
|
-
_O(Markdown("### 任务总结"))
|
113
112
|
assert reply.summary, "Summary is empty"
|
114
|
-
|
115
|
-
self.task.
|
113
|
+
_M("### 任务总结\n\n" + reply.summary)
|
114
|
+
self.task.agent_data.result = reply.summary
|
116
115
|
return False, reply.state
|
117
116
|
else:
|
118
117
|
_M("### 任务验证不通过!\n")
|
@@ -124,9 +123,9 @@ class TaskVerifySummaryAgent(BaseChatAgent):
|
|
124
123
|
if reply.enhancement.issues:
|
125
124
|
for issue in reply.enhancement.issues:
|
126
125
|
task_issue += "- {}\n".format(issue)
|
127
|
-
self.task.
|
128
|
-
self.task.
|
129
|
-
self.task.
|
126
|
+
self.task.agent_data.issue = task_issue
|
127
|
+
self.task.agent_data.coding_prompt = reply.enhancement.code_prompt
|
128
|
+
self.task.agent_data.summary_prompt = reply.enhancement.summary_prompt
|
130
129
|
_M(task_issue)
|
131
130
|
_M("### 修改后的子任务信息\n")
|
132
131
|
_M(f"### 当前子任务代码需求:\n\n{reply.enhancement.code_prompt}")
|
jupyter_agent/bot_chat.py
CHANGED
@@ -63,7 +63,7 @@ class BotChat:
|
|
63
63
|
self.base_url = base_url
|
64
64
|
self.api_key = api_key
|
65
65
|
self.model_name = model_name
|
66
|
-
self.
|
66
|
+
self.display_think = chat_kwargs.get("display_think", self.display_think)
|
67
67
|
self.display_message = chat_kwargs.get("display_message", self.display_message)
|
68
68
|
self.display_response = chat_kwargs.get("display_response", self.display_response)
|
69
69
|
|
@@ -143,7 +143,7 @@ class BotChat:
|
|
143
143
|
if token == "<think>":
|
144
144
|
think_block = _read_think_block(iter_tokens)
|
145
145
|
raw_think_block = token + think_block + "</think>"
|
146
|
-
if (self.
|
146
|
+
if (self.display_think or display_reply) and think_block and think_block.strip():
|
147
147
|
_B(think_block, title="Thought Block")
|
148
148
|
if ret_think_block and (ret_empty_block or think_block and think_block.strip()):
|
149
149
|
yield {"type": "think", "content": think_block, "raw": raw_think_block}
|
jupyter_agent/bot_contexts.py
CHANGED
@@ -21,6 +21,7 @@ from enum import Enum
|
|
21
21
|
from pydantic import BaseModel, Field
|
22
22
|
from IPython.core.getipython import get_ipython
|
23
23
|
from .bot_outputs import _D, _I, _W, _E, _F, _A, ReplyType
|
24
|
+
from .utils import get_env_capbilities
|
24
25
|
|
25
26
|
|
26
27
|
class CellType(str, Enum):
|
@@ -175,24 +176,25 @@ class AgentData(BaseModel):
|
|
175
176
|
issue: str = Field("", description="Agent验证不通过的问题")
|
176
177
|
result: str = Field("", description="Agent执行结果")
|
177
178
|
important_infos: Optional[dict] = Field(None, description="重要信息[JSON]")
|
179
|
+
request_above_supply_infos: Optional[list] = Field(None, description="前置用户需求补充[JSON]")
|
180
|
+
request_below_supply_infos: Optional[list] = Field(None, description="后置用户需求补充[JSON]")
|
178
181
|
|
179
182
|
@classmethod
|
180
|
-
def default(cls):
|
183
|
+
def default(cls) -> "AgentData":
|
181
184
|
model_fields = getattr(cls, "model_fields", None)
|
182
185
|
if model_fields and hasattr(model_fields, "items"):
|
183
|
-
|
186
|
+
default = {
|
184
187
|
name: field.examples[0] if getattr(field, "examples", None) else getattr(field, "default", None)
|
185
188
|
for name, field in model_fields.items()
|
186
189
|
}
|
187
190
|
else:
|
188
|
-
|
191
|
+
default = {}
|
192
|
+
return cls(**default) # type: ignore
|
189
193
|
|
190
194
|
|
191
195
|
class AgentCellContext(CodeCellContext):
|
192
196
|
"""任务单元格上下文类"""
|
193
197
|
|
194
|
-
SUPPORT_SAVE_META: bool = False
|
195
|
-
|
196
198
|
def __init__(self, idx: int, cell: dict):
|
197
199
|
"""初始化任务单元格上下文"""
|
198
200
|
super().__init__(idx, cell)
|
@@ -202,8 +204,8 @@ class AgentCellContext(CodeCellContext):
|
|
202
204
|
self.magic_argv = shlex.split(self.magic_line)
|
203
205
|
self.magic_name = self.magic_argv[0]
|
204
206
|
self.magic_argv = self.magic_argv[1:]
|
207
|
+
self.agent_data = AgentData.default()
|
205
208
|
self._remain_args = []
|
206
|
-
self._agent_data = AgentData.default()
|
207
209
|
self._cell_code = ""
|
208
210
|
self.parse_magic_argv()
|
209
211
|
self.load_result_from_outputs(cell)
|
@@ -224,16 +226,19 @@ class AgentCellContext(CodeCellContext):
|
|
224
226
|
|
225
227
|
@property
|
226
228
|
def result(self):
|
227
|
-
return self.
|
229
|
+
return self.agent_data.result
|
228
230
|
|
229
231
|
def __getattr__(self, name):
|
230
|
-
return self.
|
232
|
+
return getattr(self.agent_data, name)
|
233
|
+
|
234
|
+
def has_data(self, name):
|
235
|
+
return hasattr(self.agent_data, name)
|
231
236
|
|
232
237
|
def get_data(self, name):
|
233
|
-
return self.
|
238
|
+
return getattr(self.agent_data, name)
|
234
239
|
|
235
240
|
def set_data(self, name, value):
|
236
|
-
self.
|
241
|
+
setattr(self.agent_data, name, value)
|
237
242
|
|
238
243
|
def parse_magic_argv(self):
|
239
244
|
"""解析任务单元格的magic命令参数"""
|
@@ -283,11 +288,11 @@ class AgentCellContext(CodeCellContext):
|
|
283
288
|
try:
|
284
289
|
cell_options = yaml.safe_load(cell_options)
|
285
290
|
for key, value in cell_options.items():
|
286
|
-
if
|
287
|
-
if isinstance(self.
|
291
|
+
if self.has_data(key):
|
292
|
+
if isinstance(self.get_data(key), (dict, list)) and isinstance(value, str):
|
288
293
|
value = json.loads(value)
|
289
294
|
_D("CELL[{}] Load task option {}: {}".format(self.cell_idx, key, value))
|
290
|
-
self.
|
295
|
+
self.set_data(key, value)
|
291
296
|
except Exception as e:
|
292
297
|
_W("Failed to load task options {}: {}".format(type(e), str(e)))
|
293
298
|
_W(traceback.format_exc(limit=2))
|
@@ -304,15 +309,15 @@ class AgentCellContext(CodeCellContext):
|
|
304
309
|
_D(f"CELL[{self.cell_idx}] Task result: {repr(output_text)[:80]}")
|
305
310
|
task_result += "\n" + output_text
|
306
311
|
if task_result.strip():
|
307
|
-
self.
|
312
|
+
self.agent_data.result = task_result
|
308
313
|
|
309
314
|
def load_data_from_metadata(self, cell):
|
310
315
|
agent_meta_infos = cell.get("metadata", {}).get("jupyter-agent-data", {})
|
311
316
|
_D("CELL[{}] Agent Meta Data: {}".format(self.cell_idx, repr(agent_meta_infos)[:80]))
|
312
317
|
for k, v in agent_meta_infos.items():
|
313
|
-
if
|
318
|
+
if self.has_data(k):
|
314
319
|
_D(f"CELL[{self.cell_idx}] Load agent meta data: {k}: {repr(v)[:80]}")
|
315
|
-
self.
|
320
|
+
self.set_data(k, v)
|
316
321
|
|
317
322
|
def format_magic_line(self):
|
318
323
|
magic_args = ["%%bot"]
|
@@ -365,13 +370,13 @@ class AgentCellContext(CodeCellContext):
|
|
365
370
|
|
366
371
|
def format_cell_options(self):
|
367
372
|
cell_options = {}
|
368
|
-
if
|
369
|
-
if self.
|
370
|
-
cell_options["task_id"] = self.
|
371
|
-
if self.
|
372
|
-
cell_options["subject"] = self.
|
373
|
+
if get_env_capbilities().save_metadata:
|
374
|
+
if self.agent_data.task_id:
|
375
|
+
cell_options["task_id"] = self.agent_data.task_id
|
376
|
+
if self.agent_data.subject:
|
377
|
+
cell_options["subject"] = self.agent_data.subject
|
373
378
|
else:
|
374
|
-
for key, value in self.
|
379
|
+
for key, value in self.agent_data.model_dump().items():
|
375
380
|
if key == "result" and self.type == CellType.PLANNING:
|
376
381
|
continue
|
377
382
|
if value:
|
@@ -394,7 +399,7 @@ class AgentCellContext(CodeCellContext):
|
|
394
399
|
def update_cell(self):
|
395
400
|
"""生成Cell内容"""
|
396
401
|
_I("Updating Cell ...")
|
397
|
-
_A(**self.
|
402
|
+
_A(**self.agent_data.model_dump())
|
398
403
|
cell_source = ""
|
399
404
|
cell_source += self.format_magic_line()
|
400
405
|
cell_source += "\n" + self.format_cell_options()
|