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
@@ -0,0 +1,480 @@
|
|
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 time
|
10
|
+
import datetime
|
11
|
+
import jinja2
|
12
|
+
|
13
|
+
from enum import Enum
|
14
|
+
from IPython.display import display, Markdown
|
15
|
+
from .utils import no_indent, no_wrap
|
16
|
+
|
17
|
+
STAGE_SWITCHER_SCRIPT = no_wrap(
|
18
|
+
"""
|
19
|
+
this.parentElement.parentElement.querySelectorAll('.agent-stage-title').forEach(function(item) {
|
20
|
+
item.classList.remove('active');
|
21
|
+
});
|
22
|
+
this.parentElement.parentElement.querySelectorAll('.agent-stage-output-panel').forEach(function(item) {
|
23
|
+
item.classList.remove('active');
|
24
|
+
});
|
25
|
+
this.parentElement.parentElement.querySelectorAll('.agent-stage-{{ stage }}').forEach(function(item) {
|
26
|
+
item.classList.add('active');
|
27
|
+
});
|
28
|
+
"""
|
29
|
+
)
|
30
|
+
|
31
|
+
|
32
|
+
AGENT_OUTPUT_TEMPLEATE = no_indent(
|
33
|
+
"""
|
34
|
+
<style>
|
35
|
+
.agent-output-panel * {
|
36
|
+
box-sizing: border-box;
|
37
|
+
}
|
38
|
+
|
39
|
+
.agent-output-panel {
|
40
|
+
background-color: rgba(128,128,128,0.1);
|
41
|
+
border-radius: 0.5rem;
|
42
|
+
}
|
43
|
+
|
44
|
+
.agent-output-title {
|
45
|
+
cursor: pointer;
|
46
|
+
font-style: italic;
|
47
|
+
color: #888888;
|
48
|
+
padding: 0.5rem;
|
49
|
+
}
|
50
|
+
|
51
|
+
.agent-output-content {
|
52
|
+
width: unset;
|
53
|
+
padding: 0.5rem;
|
54
|
+
padding-top: 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
.agent-output-title.collapsed + .agent-output-content {
|
58
|
+
display: none;
|
59
|
+
}
|
60
|
+
|
61
|
+
.agent-stage-switcher {
|
62
|
+
background-color: rgba(128,128,128,0.1);
|
63
|
+
border-bottom: 2px solid rgba(128,128,128,0.3);
|
64
|
+
padding: 0.5rem 0;
|
65
|
+
}
|
66
|
+
|
67
|
+
.agent-stage-title {
|
68
|
+
cursor: pointer;
|
69
|
+
font-style: italic;
|
70
|
+
color: #888888;
|
71
|
+
padding: 0.5rem;
|
72
|
+
}
|
73
|
+
|
74
|
+
.agent-stage-title.active {
|
75
|
+
background-color: rgba(128,128,128,0.3);
|
76
|
+
}
|
77
|
+
|
78
|
+
.agent-stage-output-panel {
|
79
|
+
display: none;
|
80
|
+
}
|
81
|
+
|
82
|
+
.agent-stage-output-panel.active {
|
83
|
+
display: block;
|
84
|
+
margin-top: 0.5rem;
|
85
|
+
overflow: auto;
|
86
|
+
}
|
87
|
+
|
88
|
+
.agent-output-block {
|
89
|
+
background-color: rgba(128,128,128,0.2);
|
90
|
+
border-radius: 0.5rem;
|
91
|
+
margin-top: 0.5rem;
|
92
|
+
margin-bottom: 0.5rem;
|
93
|
+
}
|
94
|
+
|
95
|
+
.agent-output-block-title {
|
96
|
+
cursor: pointer;
|
97
|
+
font-style: italic;
|
98
|
+
color: #888888;
|
99
|
+
padding: 0.5rem;
|
100
|
+
}
|
101
|
+
|
102
|
+
.agent-output-block-content {
|
103
|
+
width: unset;
|
104
|
+
padding: 0.5rem;
|
105
|
+
}
|
106
|
+
|
107
|
+
.agent-output-block-title.collapsed + .agent-output-block-content {
|
108
|
+
display: none;
|
109
|
+
}
|
110
|
+
</style>
|
111
|
+
|
112
|
+
<div class="agent-output-panel">
|
113
|
+
<div class="agent-output-title {{ 'collapsed' if collapsed else ''}}" onclick="this.classList.toggle('collapsed')">
|
114
|
+
{{ title if title else 'Agent Output' }} - {{ active_stage }}
|
115
|
+
</div>
|
116
|
+
<div class="agent-output-content">
|
117
|
+
<div class="agent-stage-switcher">
|
118
|
+
{% for stage in contents.keys() %}
|
119
|
+
<span class="agent-stage-title agent-stage-{{ stage }} {{ 'active' if stage == active_stage }}" onclick="{% include 'switcher_script' %}">
|
120
|
+
{{ stage }}
|
121
|
+
</span>
|
122
|
+
{% endfor %}
|
123
|
+
</div>
|
124
|
+
{% for stage, contents in contents.items() %}
|
125
|
+
<div class="agent-stage-output-panel agent-stage-{{ stage }} {{ 'active' if stage == active_stage }}">
|
126
|
+
{% if stage == 'Logging' +%}
|
127
|
+
```log
|
128
|
+
{% for content in contents %}
|
129
|
+
{{ content['content'] }}
|
130
|
+
{% endfor %}
|
131
|
+
```
|
132
|
+
{% else %}
|
133
|
+
{% for content in contents %}
|
134
|
+
{% if content['type'] == 'block' %}
|
135
|
+
<div class="agent-output-block">
|
136
|
+
<div class="agent-output-block-title {{ 'collapsed' if content['collapsed'] else ''}}" onclick="this.classList.toggle('collapsed')">
|
137
|
+
{{ content['title'] }}
|
138
|
+
</div>
|
139
|
+
<div class="agent-output-block-content">
|
140
|
+
{% if content['format'] == 'markdown' %}
|
141
|
+
{{ content['content'] }}
|
142
|
+
{% elif content['format'] == 'code' +%}
|
143
|
+
```{{ content['code_language'] }}
|
144
|
+
{{ content['content'] }}
|
145
|
+
```
|
146
|
+
{% endif %}
|
147
|
+
</div>
|
148
|
+
</div>
|
149
|
+
{% elif content['type'] == 'markdown' +%}
|
150
|
+
{{ content['content'] }}
|
151
|
+
{% elif content['type'] == 'text' +%}
|
152
|
+
```{{ content['code_language'] }}
|
153
|
+
{{ content['content'] }}
|
154
|
+
```
|
155
|
+
{%+ endif %}
|
156
|
+
{% endfor %}
|
157
|
+
{% endif %}
|
158
|
+
</div>
|
159
|
+
{% endfor %}
|
160
|
+
</div>
|
161
|
+
</div>
|
162
|
+
"""
|
163
|
+
)
|
164
|
+
|
165
|
+
LOGGING_LEVELS = {
|
166
|
+
"DEBUG": 10,
|
167
|
+
"INFO": 20,
|
168
|
+
"WARN": 30,
|
169
|
+
"ERROR": 40,
|
170
|
+
"FATAL": 50,
|
171
|
+
}
|
172
|
+
|
173
|
+
|
174
|
+
class AgentOutput:
|
175
|
+
"""
|
176
|
+
AgentOutput 是一个用于在 Jupyter Notebook 中显示 Agent 输出的类。
|
177
|
+
"""
|
178
|
+
|
179
|
+
def __init__(self, title=None, collapsed=False, logging_level="INFO"):
|
180
|
+
self.title = title
|
181
|
+
self.collapsed = collapsed
|
182
|
+
self.logging_level = (
|
183
|
+
logging_level if isinstance(logging_level, int) else LOGGING_LEVELS.get(logging_level.upper(), 20)
|
184
|
+
)
|
185
|
+
self.jinja_env = jinja2.Environment(
|
186
|
+
trim_blocks=True, lstrip_blocks=True, loader=jinja2.DictLoader({"switcher_script": STAGE_SWITCHER_SCRIPT})
|
187
|
+
)
|
188
|
+
self.template = self.jinja_env.from_string(AGENT_OUTPUT_TEMPLEATE)
|
189
|
+
self.handler = None
|
190
|
+
self._latest_display_tm = 0
|
191
|
+
self._contents = {}
|
192
|
+
self._active_stage = None
|
193
|
+
self._agent_data_timestamp = None
|
194
|
+
self._agent_data = {}
|
195
|
+
self._logging_records = []
|
196
|
+
|
197
|
+
@property
|
198
|
+
def content(self):
|
199
|
+
contents = dict(self._contents)
|
200
|
+
if self._agent_data:
|
201
|
+
contents["Metadata"] = [
|
202
|
+
{
|
203
|
+
"type": "text",
|
204
|
+
"content": json.dumps(self.metadata, indent=2, ensure_ascii=False),
|
205
|
+
"code_language": "json",
|
206
|
+
}
|
207
|
+
]
|
208
|
+
filtered_logs = [log for log in self._logging_records if log["level"] >= self.logging_level]
|
209
|
+
if len(filtered_logs) > 0:
|
210
|
+
contents["Logging"] = filtered_logs
|
211
|
+
return self.template.render(
|
212
|
+
title=self.title,
|
213
|
+
collapsed=self.collapsed,
|
214
|
+
active_stage=self._active_stage,
|
215
|
+
contents=contents,
|
216
|
+
)
|
217
|
+
|
218
|
+
@property
|
219
|
+
def metadata(self):
|
220
|
+
metadata = {"reply_type": "AgentOutput", "exclude_from_context": True}
|
221
|
+
if self._agent_data:
|
222
|
+
metadata.update(
|
223
|
+
{
|
224
|
+
"jupyter-agent-data-store": True,
|
225
|
+
"jupyter-agent-data-timestamp": self._agent_data_timestamp,
|
226
|
+
"jupyter-agent-data": self._agent_data,
|
227
|
+
}
|
228
|
+
)
|
229
|
+
return metadata
|
230
|
+
|
231
|
+
def display(self, stage=None, force=False, wait=True):
|
232
|
+
if stage is not None:
|
233
|
+
self._active_stage = stage
|
234
|
+
if not force and time.time() - self._latest_display_tm < 1:
|
235
|
+
if wait:
|
236
|
+
time.sleep(1 - (time.time() - self._latest_display_tm))
|
237
|
+
else:
|
238
|
+
return
|
239
|
+
if self.handler is None:
|
240
|
+
self.handler = display(Markdown(self.content), metadata=self.metadata, display_id=True)
|
241
|
+
else:
|
242
|
+
self.handler.update(Markdown(self.content), metadata=self.metadata)
|
243
|
+
self._latest_display_tm = time.time()
|
244
|
+
|
245
|
+
def clear(self, stage=None, clear_metadata=False):
|
246
|
+
if stage is None:
|
247
|
+
self._contents = {}
|
248
|
+
else:
|
249
|
+
self._contents[stage] = []
|
250
|
+
if clear_metadata:
|
251
|
+
self._agent_data = {}
|
252
|
+
self.display(force=False, wait=False)
|
253
|
+
|
254
|
+
def output_block(
|
255
|
+
self, content, title="Block", collapsed=True, stage=None, format="markdown", code_language="python"
|
256
|
+
):
|
257
|
+
if stage is None:
|
258
|
+
stage = self._active_stage
|
259
|
+
if stage not in self._contents:
|
260
|
+
self._contents[stage] = []
|
261
|
+
self._contents[stage].append(
|
262
|
+
{
|
263
|
+
"type": "block",
|
264
|
+
"title": title,
|
265
|
+
"content": content,
|
266
|
+
"collapsed": collapsed,
|
267
|
+
"format": format,
|
268
|
+
"code_language": code_language,
|
269
|
+
}
|
270
|
+
)
|
271
|
+
self.display(stage, force=False, wait=False)
|
272
|
+
|
273
|
+
def output_text(self, content, stage=None, code_language="python"):
|
274
|
+
if stage is None:
|
275
|
+
stage = self._active_stage
|
276
|
+
if stage not in self._contents:
|
277
|
+
self._contents[stage] = []
|
278
|
+
if (
|
279
|
+
len(self._contents[stage]) > 0
|
280
|
+
and self._contents[stage][-1]["type"] == "text"
|
281
|
+
and self._contents[stage][-1]["code_language"] == code_language
|
282
|
+
):
|
283
|
+
self._contents[stage][-1]["content"] += "\n" + content
|
284
|
+
else:
|
285
|
+
self._contents[stage].append({"type": "text", "content": content, "code_language": code_language})
|
286
|
+
self.display(stage, force=False, wait=False)
|
287
|
+
|
288
|
+
def output_markdown(self, content, stage=None):
|
289
|
+
if stage is None:
|
290
|
+
stage = self._active_stage
|
291
|
+
if stage not in self._contents:
|
292
|
+
self._contents[stage] = []
|
293
|
+
self._contents[stage].append({"type": "markdown", "content": content})
|
294
|
+
self.display(stage, force=False, wait=False)
|
295
|
+
|
296
|
+
def output_agent_data(self, **kwargs):
|
297
|
+
self.log(f"output agent data {kwargs}", level="DEBUG")
|
298
|
+
self._agent_data.update(kwargs)
|
299
|
+
self._agent_data_timestamp = int(time.time() * 1000)
|
300
|
+
self.display(force=False, wait=False)
|
301
|
+
|
302
|
+
def log(self, msg, level="INFO"):
|
303
|
+
level = level.upper()
|
304
|
+
assert level in LOGGING_LEVELS
|
305
|
+
tm = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
|
306
|
+
level_n = LOGGING_LEVELS[level]
|
307
|
+
content = f"[{tm}] {level}: {msg}"
|
308
|
+
if self._logging_records and self._logging_records[-1]["level"] == level_n:
|
309
|
+
self._logging_records[-1]["content"] += "\n" + content
|
310
|
+
else:
|
311
|
+
self._logging_records.append(
|
312
|
+
{
|
313
|
+
"type": "logging",
|
314
|
+
"level": level_n,
|
315
|
+
"level_name": level,
|
316
|
+
"time": tm,
|
317
|
+
"msg": msg,
|
318
|
+
"content": content,
|
319
|
+
}
|
320
|
+
)
|
321
|
+
self.display(force=False, wait=False)
|
322
|
+
|
323
|
+
|
324
|
+
__agent_output = None
|
325
|
+
|
326
|
+
|
327
|
+
def get_output():
|
328
|
+
global __agent_output
|
329
|
+
if __agent_output is None:
|
330
|
+
__agent_output = AgentOutput()
|
331
|
+
return __agent_output
|
332
|
+
|
333
|
+
|
334
|
+
def set_stage(stage):
|
335
|
+
get_output().display(stage)
|
336
|
+
|
337
|
+
|
338
|
+
def reset_output(title=None, collapsed=False, stage=None, logging_level="INFO"):
|
339
|
+
global __agent_output
|
340
|
+
__agent_output = AgentOutput(title, collapsed, logging_level)
|
341
|
+
if stage is not None:
|
342
|
+
__agent_output.display(stage)
|
343
|
+
return __agent_output
|
344
|
+
|
345
|
+
|
346
|
+
def log(msg, level="INFO"):
|
347
|
+
get_output().log(msg, level)
|
348
|
+
|
349
|
+
|
350
|
+
def output_block(content, title="Block", collapsed=True, stage=None, format="markdown", code_language="python"):
|
351
|
+
get_output().output_block(content, title, collapsed, stage, format, code_language)
|
352
|
+
|
353
|
+
|
354
|
+
def output_text(content, stage=None, code_language="python"):
|
355
|
+
get_output().output_text(content, stage, code_language)
|
356
|
+
|
357
|
+
|
358
|
+
def output_markdown(content, stage=None):
|
359
|
+
get_output().output_markdown(content, stage)
|
360
|
+
|
361
|
+
|
362
|
+
def output_agent_data(**kwargs):
|
363
|
+
get_output().output_agent_data(**kwargs)
|
364
|
+
|
365
|
+
|
366
|
+
def clear_output(stage=None, clear_metadata=False):
|
367
|
+
get_output().clear(stage, clear_metadata)
|
368
|
+
|
369
|
+
|
370
|
+
def flush_output(force=False):
|
371
|
+
get_output().display(force=force, wait=True)
|
372
|
+
|
373
|
+
|
374
|
+
def set_title(title):
|
375
|
+
get_output().title = title
|
376
|
+
|
377
|
+
|
378
|
+
def set_collapsed(collapsed):
|
379
|
+
get_output().collapsed = collapsed
|
380
|
+
|
381
|
+
|
382
|
+
def set_logging_level(logging_level):
|
383
|
+
if isinstance(logging_level, int):
|
384
|
+
get_output().logging_level = logging_level
|
385
|
+
else:
|
386
|
+
logging_level = logging_level.upper()
|
387
|
+
assert logging_level in LOGGING_LEVELS
|
388
|
+
get_output().logging_level = LOGGING_LEVELS[logging_level]
|
389
|
+
|
390
|
+
|
391
|
+
class ReplyType(str, Enum):
|
392
|
+
CELL_CODE = "cell_code"
|
393
|
+
CELL_OUTPUT = "cell_output"
|
394
|
+
CELL_RESULT = "cell_result"
|
395
|
+
CELL_ERROR = "cell_error"
|
396
|
+
TASK_PROMPT = "task_prompt"
|
397
|
+
TASK_RESULT = "task_result"
|
398
|
+
TASK_ISSUE = "task_issue"
|
399
|
+
DEBUG = "debug"
|
400
|
+
THINK = "think"
|
401
|
+
CODE = "code"
|
402
|
+
FENCE = "fence"
|
403
|
+
TEXT = "text"
|
404
|
+
|
405
|
+
|
406
|
+
def agent_display(obj, reply_type=None, exclude_from_context=False, **kwargs):
|
407
|
+
"""自定义的 display 函数,用于在 Jupyter 中显示对象"""
|
408
|
+
assert "metadata" not in kwargs
|
409
|
+
metadata = {"reply_type": reply_type, "exclude_from_context": exclude_from_context}
|
410
|
+
metadata.update(kwargs)
|
411
|
+
return display(obj, metadata=metadata)
|
412
|
+
|
413
|
+
|
414
|
+
_block_style = """
|
415
|
+
<style>
|
416
|
+
.block-panel * {
|
417
|
+
box-sizing: border-box;
|
418
|
+
}
|
419
|
+
|
420
|
+
.block-panel {
|
421
|
+
background-color: rgba(128,128,128,0.2);
|
422
|
+
border-radius: 0.5rem;
|
423
|
+
box-sizing: border-box;
|
424
|
+
}
|
425
|
+
|
426
|
+
.block-title {
|
427
|
+
cursor: pointer;
|
428
|
+
font-style: italic;
|
429
|
+
color: #888888;
|
430
|
+
padding: 0.5rem;
|
431
|
+
}
|
432
|
+
|
433
|
+
.block-content {
|
434
|
+
width: unset;
|
435
|
+
padding: 0.5rem;
|
436
|
+
}
|
437
|
+
|
438
|
+
.block-title.collapsed + .block-content {
|
439
|
+
display: none;
|
440
|
+
}
|
441
|
+
</style>
|
442
|
+
"""
|
443
|
+
|
444
|
+
|
445
|
+
def markdown_block(block, title="Block", collapsed=True):
|
446
|
+
|
447
|
+
default_state = "collapsed" if collapsed else ""
|
448
|
+
|
449
|
+
return Markdown(
|
450
|
+
_block_style
|
451
|
+
+ '<div class="block-panel" >'
|
452
|
+
+ f'<div class="block-title {default_state}" onclick="this.classList.toggle(\'collapsed\')">'
|
453
|
+
+ f"{title} (click to expand)"
|
454
|
+
+ "</div>"
|
455
|
+
+ '<div class="block-content" >\n\n'
|
456
|
+
+ block
|
457
|
+
+ "\n\n</div>"
|
458
|
+
+ "</div>"
|
459
|
+
)
|
460
|
+
|
461
|
+
|
462
|
+
_O = lambda obj, reply_type=None, **kwargs: agent_display(
|
463
|
+
obj, reply_type=reply_type, exclude_from_context=True, **kwargs
|
464
|
+
)
|
465
|
+
|
466
|
+
|
467
|
+
_C = lambda obj, reply_from=None, reply_type=None, **kwargs: agent_display(
|
468
|
+
obj, reply_type=reply_type, exclude_from_context=False, **kwargs
|
469
|
+
)
|
470
|
+
|
471
|
+
_M = output_markdown
|
472
|
+
_T = output_text
|
473
|
+
_B = output_block
|
474
|
+
_A = output_agent_data
|
475
|
+
_L = log
|
476
|
+
_D = lambda msg: log(msg, level="DEBUG")
|
477
|
+
_I = lambda msg: log(msg, level="INFO")
|
478
|
+
_W = lambda msg: log(msg, level="WARNING")
|
479
|
+
_E = lambda msg: log(msg, level="ERROR")
|
480
|
+
_F = lambda msg: log(msg, level="FATAL")
|
jupyter_agent/utils.py
ADDED
@@ -0,0 +1,138 @@
|
|
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 io
|
9
|
+
import os
|
10
|
+
import re
|
11
|
+
import sys
|
12
|
+
import json
|
13
|
+
import jinja2
|
14
|
+
import openai
|
15
|
+
|
16
|
+
from enum import Enum
|
17
|
+
from typing import Optional
|
18
|
+
from pydantic import BaseModel, Field
|
19
|
+
from IPython.display import display as ipython_display, Markdown
|
20
|
+
from IPython.core.getipython import get_ipython
|
21
|
+
from IPython.core.displaypub import CapturingDisplayPublisher
|
22
|
+
from IPython.core.displayhook import CapturingDisplayHook
|
23
|
+
from IPython.utils.capture import capture_output, CapturedIO
|
24
|
+
from IPython.utils.io import Tee
|
25
|
+
|
26
|
+
|
27
|
+
class CloselessStringIO(io.StringIO):
|
28
|
+
def close(self):
|
29
|
+
pass
|
30
|
+
|
31
|
+
def __del__(self):
|
32
|
+
super().close()
|
33
|
+
return super().__del__()
|
34
|
+
|
35
|
+
|
36
|
+
class TeeCapturingDisplayPublisher(CapturingDisplayPublisher):
|
37
|
+
|
38
|
+
def __init__(self, *args, original_display_pub=None, **kwargs):
|
39
|
+
super().__init__(*args, **kwargs)
|
40
|
+
ipy = get_ipython()
|
41
|
+
self.original_display_pub = original_display_pub or (ipy.display_pub if ipy is not None else None)
|
42
|
+
|
43
|
+
def publish(self, *args, **kwargs):
|
44
|
+
super().publish(*args, **kwargs)
|
45
|
+
if self.original_display_pub is not None:
|
46
|
+
self.original_display_pub.publish(*args, **kwargs)
|
47
|
+
|
48
|
+
|
49
|
+
class TeeCapturingDisplayHook(CapturingDisplayHook):
|
50
|
+
|
51
|
+
def __init__(self, *args, original_display_hook=None, **kwargs):
|
52
|
+
super().__init__(*args, **kwargs)
|
53
|
+
self.original_display_hook = original_display_hook or sys.displayhook
|
54
|
+
|
55
|
+
def __call__(self, *args, **kwargs):
|
56
|
+
super().__call__(*args, **kwargs)
|
57
|
+
self.original_display_hook(*args, **kwargs)
|
58
|
+
|
59
|
+
|
60
|
+
class TeeOutputCapture(capture_output):
|
61
|
+
|
62
|
+
def __enter__(self):
|
63
|
+
|
64
|
+
self.sys_stdout = sys.stdout
|
65
|
+
self.sys_stderr = sys.stderr
|
66
|
+
|
67
|
+
if self.display:
|
68
|
+
self.shell = get_ipython()
|
69
|
+
if self.shell is None:
|
70
|
+
self.save_display_pub = None
|
71
|
+
self.display = False
|
72
|
+
|
73
|
+
stdout = stderr = outputs = None
|
74
|
+
if self.stdout:
|
75
|
+
stdout = CloselessStringIO()
|
76
|
+
sys.stdout = Tee(stdout, channel="stdout")
|
77
|
+
if self.stderr:
|
78
|
+
stderr = CloselessStringIO()
|
79
|
+
sys.stderr = Tee(stderr, channel="stderr")
|
80
|
+
if self.display:
|
81
|
+
if self.shell is not None:
|
82
|
+
self.save_display_pub = self.shell.display_pub
|
83
|
+
self.shell.display_pub = TeeCapturingDisplayPublisher()
|
84
|
+
outputs = self.shell.display_pub.outputs
|
85
|
+
self.save_display_hook = sys.displayhook
|
86
|
+
sys.displayhook = TeeCapturingDisplayHook(shell=self.shell, outputs=outputs)
|
87
|
+
else:
|
88
|
+
self.save_display_pub = None
|
89
|
+
outputs = None
|
90
|
+
|
91
|
+
return CapturedIO(stdout, stderr, outputs)
|
92
|
+
|
93
|
+
|
94
|
+
class RequestUserPrompt(BaseModel):
|
95
|
+
prompt: str = Field(
|
96
|
+
description="需要用户补充详细信息的Prompt",
|
97
|
+
examples=["请补充与...相关的详细的信息", "请确认...是否...", "请提供..."],
|
98
|
+
)
|
99
|
+
example: Optional[str] = Field(None, description="示例", examples=["..."])
|
100
|
+
|
101
|
+
|
102
|
+
class UserPromptResponse(BaseModel):
|
103
|
+
prompt: str = Field(description="需要用户补充详细信息的Prompt", examples=["..."])
|
104
|
+
response: str = Field(description="用户补充的详细信息", examples=["..."])
|
105
|
+
|
106
|
+
|
107
|
+
def request_user_response(prompts: list[RequestUserPrompt]) -> list[UserPromptResponse]:
|
108
|
+
responses = []
|
109
|
+
for prompt in prompts:
|
110
|
+
response = input(f"{prompt.prompt} (例如: {prompt.example})")
|
111
|
+
responses.append(UserPromptResponse(prompt=prompt.prompt, response=response))
|
112
|
+
return responses
|
113
|
+
|
114
|
+
|
115
|
+
def format_user_prompts(prompts: list[RequestUserPrompt], title="用户补充详细信息") -> str:
|
116
|
+
result = "```markdown\n"
|
117
|
+
result += f"### {title}\n\n"
|
118
|
+
result += "\n".join(
|
119
|
+
[f"- **Issue**: {prompt.prompt} (例如: {prompt.example})\n- **Reply**: " for prompt in prompts]
|
120
|
+
)
|
121
|
+
result += "\n```\n"
|
122
|
+
return result
|
123
|
+
|
124
|
+
|
125
|
+
def no_indent(text: str) -> str:
|
126
|
+
return re.sub(r"^\s+", "", text, flags=re.MULTILINE)
|
127
|
+
|
128
|
+
|
129
|
+
def no_wrap(text: str) -> str:
|
130
|
+
return re.sub(r"\s+", " ", text, flags=re.MULTILINE)
|
131
|
+
|
132
|
+
|
133
|
+
def no_newline(text: str) -> str:
|
134
|
+
return re.sub(r"\n+", " ", text, flags=re.MULTILINE)
|
135
|
+
|
136
|
+
|
137
|
+
def no_space(text: str) -> str:
|
138
|
+
return re.sub(r"\s+", "", text, flags=re.MULTILINE)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: jupyter-agent
|
3
|
-
Version: 2025.6.
|
3
|
+
Version: 2025.6.101
|
4
4
|
Summary: 调用LLM实现Jupyter代码的自动生成、执行、调试等功能
|
5
5
|
Author: viewstar000
|
6
6
|
License: MIT
|
@@ -29,7 +29,16 @@ Dynamic: license-file
|
|
29
29
|
- 提供`%%bot`指令,在juyter环境中,通过调用LLM实现代码生成、执行、调试等能力
|
30
30
|
- 支持调用OpenAI兼容API,实现LLM相关的功能
|
31
31
|
|
32
|
-
##
|
32
|
+
## 安装
|
33
|
+
|
34
|
+
```bash
|
35
|
+
# 激活目标环境(视情况选择)
|
36
|
+
source /path/to/target_env/bin/activate
|
37
|
+
|
38
|
+
pip install jupyter-agent
|
39
|
+
```
|
40
|
+
|
41
|
+
## 源码打包安全(Build)
|
33
42
|
|
34
43
|
```bash
|
35
44
|
# 下载代码
|
@@ -46,15 +55,12 @@ python -m build
|
|
46
55
|
|
47
56
|
# 退出打包环境
|
48
57
|
deactivate
|
49
|
-
```
|
50
|
-
|
51
|
-
## 安装
|
52
58
|
|
53
|
-
```bash
|
54
59
|
# 激活目标环境
|
55
60
|
source /path/to/target_env/bin/activate
|
61
|
+
|
56
62
|
# 安装编译好的wheel包
|
57
|
-
pip install /path/to/upyter-agent/dist/jupyter_agent-
|
63
|
+
pip install /path/to/upyter-agent/dist/jupyter_agent-xxxx-py3-none-any.whl
|
58
64
|
```
|
59
65
|
|
60
66
|
## 使用方法
|
@@ -0,0 +1,33 @@
|
|
1
|
+
jupyter_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
jupyter_agent/bot_chat.py,sha256=RkaT-Cpkp3G24F1AtbcgqjKo-LBxwMNAYHVitaPZNOg,8834
|
3
|
+
jupyter_agent/bot_contexts.py,sha256=eFezr7ImokMz33jJJMlLLQspQBYnuE6Bc2bE1wLbXWU,19123
|
4
|
+
jupyter_agent/bot_magics.py,sha256=PQib9GoefCAkh2Hy1InfdoiFo-KE-9wJ4qKEj_k9zO4,6570
|
5
|
+
jupyter_agent/bot_outputs.py,sha256=7_cbOBaGdoYMR6qu43nZEsB9KY6wp4zA0Dh7Jq7LMTg,14065
|
6
|
+
jupyter_agent/utils.py,sha256=jbvDtVK6MfGaf5ZLoam_sq9R5TMriEG4HbMF0bHHDes,4387
|
7
|
+
jupyter_agent/bot_agents/__init__.py,sha256=IdlBlvfaDUfp3qhkNuwUVV_CdplafZsgLezLVkZCREw,1323
|
8
|
+
jupyter_agent/bot_agents/base.py,sha256=50XtKBVRj83zALGgw4klGLZkUlqHNhs1WIX5av9bIm4,10893
|
9
|
+
jupyter_agent/bot_agents/master_planner.py,sha256=nIY3F4ALtEU8QOO6dqe7pI5V-o_pwdM2MllH-n2Jb-Y,1289
|
10
|
+
jupyter_agent/bot_agents/output_task_result.py,sha256=p_fq4zKUMZIz5W7y2Bvq0uhjwgHUn_MIt9Qr24nFR58,837
|
11
|
+
jupyter_agent/bot_agents/task_code_executor.py,sha256=M3oeEBlmsNz89f-yk3_nzsWKGH2C0o7AH059D_J94D8,2206
|
12
|
+
jupyter_agent/bot_agents/task_coder.py,sha256=7fXq9nk1yH3F_mJfCMZBktHmxGfgmpuChMQbpEuL0w4,1783
|
13
|
+
jupyter_agent/bot_agents/task_debuger.py,sha256=77pa_Awgvzxm3XkFA1oZsGr8SPJkjApKMtkmoySShmI,1367
|
14
|
+
jupyter_agent/bot_agents/task_planner_v1.py,sha256=3teMKJz82Jtms0ERLGCCRoui-gzmTDpi8So6ZjR5z3w,5990
|
15
|
+
jupyter_agent/bot_agents/task_planner_v2.py,sha256=BYFDRC8q9AT00iL4l54GZWhgjs_m5R0F_vOVmmGEiLA,7632
|
16
|
+
jupyter_agent/bot_agents/task_planner_v3.py,sha256=KP6qj7lLUeebPZwypmK_oKYa-84RpkCrJVJk7yJkTJw,8545
|
17
|
+
jupyter_agent/bot_agents/task_reasoner.py,sha256=Am7ZNZNnn6aMm4UMCDLdb3CA73nNvydx8bmGXJAsJ2k,1469
|
18
|
+
jupyter_agent/bot_agents/task_structrue_reasoner.py,sha256=KRs_dRwsBisMT5A5SqzSi4rbRnj6wpapABtlOKVFvSk,3733
|
19
|
+
jupyter_agent/bot_agents/task_structrue_summarier.py,sha256=jirpFP2UmhJxbrkOWx45AOZnSXbhim_XfZmVU-RzcNk,4087
|
20
|
+
jupyter_agent/bot_agents/task_summarier.py,sha256=bvYEKW_NWRwe-kNNxR7uhJTMKMJXSyfnGgOpxCoBleU,1791
|
21
|
+
jupyter_agent/bot_agents/task_verifier.py,sha256=9Tlyb7hP7tBHMrh5XkRD30mYLodNum33X6v2snjm0QI,2478
|
22
|
+
jupyter_agent/bot_agents/task_verify_summarier.py,sha256=mhpqgcBPOur0TtG8rYUT-BCAYgAiJxDgXVnCAE5Cucs,4963
|
23
|
+
jupyter_agent/bot_flows/__init__.py,sha256=vbb3GJLu6aZdJ2ox4eaHn5cg0d4WQM6zmhIbMAlHIFo,488
|
24
|
+
jupyter_agent/bot_flows/base.py,sha256=o94y9H8E9FCGz7srdyJDl7UcAj7RCEJCBjtSSREvcWY,8437
|
25
|
+
jupyter_agent/bot_flows/master_planner.py,sha256=2MvAMikMsBIarTL4QNYTjAs70bxo7VAV0DbHus325Es,430
|
26
|
+
jupyter_agent/bot_flows/task_executor_v1.py,sha256=WzTfoOTjBpk1emvpiL3yeiudKdDf6EpVdJIugxxbqM4,2975
|
27
|
+
jupyter_agent/bot_flows/task_executor_v2.py,sha256=IyfxhzA4TljNd6iqqUYxxzB63r9lxfe1Zbu177hytRs,2949
|
28
|
+
jupyter_agent/bot_flows/task_executor_v3.py,sha256=NwJy7iAo2U3rl5iQYpACWVAkIA5DRMDdx0JadheRMMQ,3198
|
29
|
+
jupyter_agent-2025.6.101.dist-info/licenses/LICENSE,sha256=nWMmSIg7OepTIDX_OPP0-T9ImeCBBoog7eJxm5awtcM,1068
|
30
|
+
jupyter_agent-2025.6.101.dist-info/METADATA,sha256=NYsa293tWtXEWVKS_SUzIq0cxHiSbUOUzXRrmCpILkU,3815
|
31
|
+
jupyter_agent-2025.6.101.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
32
|
+
jupyter_agent-2025.6.101.dist-info/top_level.txt,sha256=c3USTBZ7DZGuvLKlEW-QfGIx0tzn98iCEn3bpdYnDtE,14
|
33
|
+
jupyter_agent-2025.6.101.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
jupyter_agent
|
@@ -1,5 +0,0 @@
|
|
1
|
-
jupyter_agent-2025.6.100.dist-info/licenses/LICENSE,sha256=nWMmSIg7OepTIDX_OPP0-T9ImeCBBoog7eJxm5awtcM,1068
|
2
|
-
jupyter_agent-2025.6.100.dist-info/METADATA,sha256=39YUZaaG0ZJY0gZHzX64jOMuTRk434KAn3zIhsYGoN8,3700
|
3
|
-
jupyter_agent-2025.6.100.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
4
|
-
jupyter_agent-2025.6.100.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
5
|
-
jupyter_agent-2025.6.100.dist-info/RECORD,,
|