codebind 0.1.1__tar.gz → 0.1.3__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codebind
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: A minimal model loop over a persistent IPython session.
5
5
  Keywords: ai,ipython,llm,repl,agents
6
6
  Author: Giovanni Gravili
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codebind"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  description = "A minimal model loop over a persistent IPython session."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codebind"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  description = "A minimal model loop over a persistent IPython session."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -39,14 +39,18 @@ class IPythonExecutor:
39
39
  raise ValueError("cell must be a non-empty string")
40
40
 
41
41
  original_prompts = getattr(self.shell, "prompts", None)
42
+ displayhook = self.shell.displayhook
43
+ original_output_prompt = displayhook.write_output_prompt
42
44
  if prompts is not None and original_prompts is not None:
43
45
  self.shell.prompts = prompts
46
+ displayhook.write_output_prompt = lambda: None
44
47
  try:
45
48
  with capture_output() as captured:
46
49
  result = self.shell.run_cell(cell, store_history=False)
47
50
  finally:
48
51
  if prompts is not None and original_prompts is not None:
49
52
  self.shell.prompts = original_prompts
53
+ displayhook.write_output_prompt = original_output_prompt
50
54
 
51
55
  displays: list[str] = []
52
56
  for output in captured.outputs:
@@ -2,6 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import sys
6
+
5
7
  from IPython.terminal.prompts import Prompts
6
8
  from IPython.terminal.ptutils import IPythonPTLexer
7
9
  from prompt_toolkit.document import Document
@@ -44,6 +46,7 @@ def render_cell(shell: object, cell: str, prompts: CellPrompts) -> None:
44
46
  lexer = IPythonPTLexer().lex_document(Document(cell))
45
47
  pt_app = getattr(shell, "pt_app", None)
46
48
  style = pt_app.app.style if pt_app is not None else None
49
+ sys.stdout.write(getattr(shell, "separate_in", "\n"))
47
50
 
48
51
  for index, _line in enumerate(cell.split("\n")):
49
52
  prompt_tokens = (
@@ -53,3 +56,11 @@ def render_cell(shell: object, cell: str, prompts: CellPrompts) -> None:
53
56
  )
54
57
  print_formatted_text(PygmentsTokens(prompt_tokens), style=style, end="")
55
58
  print_formatted_text(FormattedText(lexer(index)), style=style)
59
+
60
+
61
+ def render_output_prompt(shell: object, prompts: CellPrompts) -> None:
62
+ """Render an output prompt with IPython's terminal style."""
63
+ pt_app = getattr(shell, "pt_app", None)
64
+ style = pt_app.app.style if pt_app is not None else None
65
+ sys.stdout.write(getattr(shell, "separate_out", "") or "\n")
66
+ print_formatted_text(PygmentsTokens(prompts.out_prompt_tokens()), style=style, end="")
@@ -2,17 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from itertools import chain
6
-
7
5
  from rich.console import Console
8
6
  from rich.markdown import Markdown
9
- from rich.segment import Segments
10
7
  from rich.text import Text
11
8
 
12
9
  from .execution import ExecutionReport
13
-
14
-
15
- _MAX_OUTPUT_LINES = 10
10
+ from .prompts import CellPrompts, render_output_prompt
16
11
 
17
12
 
18
13
  def _visible_output(report: ExecutionReport) -> str:
@@ -27,26 +22,20 @@ def _visible_output(report: ExecutionReport) -> str:
27
22
 
28
23
 
29
24
  class TerminalRenderer:
30
- """Render concise tool previews and Markdown answers to the active terminal."""
25
+ """Render tool output and Markdown answers to the active terminal."""
31
26
 
32
27
  def __init__(self) -> None:
33
28
  self.console = Console()
34
29
 
35
- def tool_output(self, report: ExecutionReport) -> None:
36
- """Show a bounded preview while leaving the report itself intact for the model."""
30
+ def tool_output(self, report: ExecutionReport, shell: object, prompts: CellPrompts) -> None:
31
+ """Show the complete tool output."""
37
32
  visible = _visible_output(report)
38
33
  if not visible:
39
34
  return
40
35
  output = Text.from_ansi(visible)
41
- options = self.console.options
42
- complete = self.console.render_lines(output, options, pad=False, new_lines=True)
43
- preview = complete[:_MAX_OUTPUT_LINES]
44
- self.console.print(Segments(chain.from_iterable(preview)), end="")
45
- if len(complete) > len(preview):
46
- self.console.print(
47
- f"[dim]{len(preview)} of {len(complete)} lines shown; "
48
- "the complete result was returned to the model.[/dim]"
49
- )
36
+ if report.ok:
37
+ render_output_prompt(shell, prompts)
38
+ self.console.print(output)
50
39
 
51
40
  def assistant(self, text: str) -> None:
52
41
  """Render the final model response as terminal Markdown."""
@@ -77,7 +77,6 @@ class Session:
77
77
  self.instructions = instructions.strip() if instructions else None
78
78
  self.messages: list[BaseMessage] = []
79
79
  self.last_response: AIMessage | None = None
80
- self.cell_number = 0
81
80
  if self.instructions:
82
81
  self.messages.append(SystemMessage(self.instructions))
83
82
 
@@ -85,7 +84,6 @@ class Session:
85
84
  """Clear conversation history without clearing the shared Python namespace."""
86
85
  self.messages.clear()
87
86
  self.last_response = None
88
- self.cell_number = 0
89
87
  if self.instructions:
90
88
  self.messages.append(SystemMessage(self.instructions))
91
89
 
@@ -136,12 +134,11 @@ class Session:
136
134
  return _tool_error("InvalidArguments", "ipython requires a string cell argument")
137
135
 
138
136
  cell = arguments["cell"]
139
- self.cell_number += 1
140
- prompts = CellPrompts(self.shell, self.cell_number)
137
+ prompts = CellPrompts(self.shell, self.shell.execution_count - 1)
141
138
  render_cell(self.shell, cell, prompts)
142
139
  try:
143
140
  report = self.executor.execute(cell, prompts=prompts)
144
141
  except Exception as error: # The failure must be returned to the model, not end the session.
145
142
  report = _tool_error(type(error).__name__, str(error))
146
- self.renderer.tool_output(report)
143
+ self.renderer.tool_output(report, self.shell, prompts)
147
144
  return report
File without changes
File without changes
File without changes
File without changes