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,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.100
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
- ## 打包(Build)
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-202506.1-py3-none-any.whl
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,,