From 8341feb1fb905efeeb89050d87bad391853591e7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:47:55 +0000 Subject: [PATCH 1/2] Initial plan From 5a3178b7c9bdeb06b17aafe28a5e7bebd0f2e12c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:53:50 +0000 Subject: [PATCH 2/2] Address PR 238 review thread comments --- python/examples/drawing/render.py | 105 +++++++++++++++++++ python/examples/drawing/schema.py | 83 +++++++++++++++ python/src/typechat/_internal/interactive.py | 2 +- 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 python/examples/drawing/render.py create mode 100644 python/examples/drawing/schema.py diff --git a/python/examples/drawing/render.py b/python/examples/drawing/render.py new file mode 100644 index 00000000..aff72135 --- /dev/null +++ b/python/examples/drawing/render.py @@ -0,0 +1,105 @@ +import tkinter as tk + +from schema import Style, Box, Ellipse, Arrow, Drawing, UnknownText + + +# Map line style to dash patterns +dash_pattern = { + "solid": "", + "dashed": (4, 4), # 4 pixels drawn, 4 pixels space + "dotted": (1, 1), # 1 pixel drawn, 1 pixel space +} + + +def render_drawing(canvas: tk.Canvas, drawing: Drawing): + + def draw_box(box: Box): + x1, y1 = box.x, box.y + x2, y2 = x1 + box.width, y1 + box.height + canvas.create_rectangle( + x1, + y1, + x2, + y2, + outline=getattr(box.style, "line_color", None) or "black", + fill=getattr(box.style, "fill_color", None) or "", + ) + if box.text: + canvas.create_text((x1 + x2) / 2, (y1 + y2) / 2, text=box.text, fill="black") + + def draw_ellipse(ellipse: Ellipse): + x1, y1 = ellipse.x, ellipse.y + x2, y2 = x1 + ellipse.width, y1 + ellipse.height + canvas.create_oval( + x1, + y1, + x2, + y2, + outline=getattr(ellipse.style, "line_color", None) or "black", + fill=getattr(ellipse.style, "fill_color", None) or "", + ) + if ellipse.text: + canvas.create_text((x1 + x2) / 2, (y1 + y2) / 2, text=ellipse.text, fill="black") + + def draw_arrow(arrow: Arrow): + canvas.create_line( + arrow.start_x, + arrow.start_y, + arrow.end_x, + arrow.end_y, + dash=dash_pattern.get(getattr(arrow.style, "line_style", None) or "solid", ""), + arrow=tk.LAST, + fill=getattr(arrow.style, "line_color", None) or "black", + ) + + for item in drawing.items: + match item: + case Box(): + draw_box(item) + case Ellipse(): + draw_ellipse(item) + case Arrow(): + draw_arrow(item) + case UnknownText(): + print(f"Unknown text: {item.text}") + + +if __name__ == "__main__": + example_drawing = Drawing( + type="Drawing", + items=[ + Box( + type="Box", + x=50, + y=50, + width=100, + height=100, + text="Hello", + style=Style(type="Style"), + ), + Ellipse( + type="Ellipse", + x=200, + y=50, + width=150, + height=100, + text="World", + style=Style(type="Style", fill_color="lightblue"), + ), + Arrow( + type="Arrow", + start_x=50, + start_y=200, + end_x=150, + end_y=200, + style=Style(type="Style", line_style="dashed"), + ), + ], + ) + + window = tk.Tk() + window.title("Drawing") + canvas = tk.Canvas(window, width=800, height=600, bg="white", highlightthickness=0) + canvas.pack(padx=10, pady=10) + render_drawing(canvas, example_drawing) + window.mainloop() diff --git a/python/examples/drawing/schema.py b/python/examples/drawing/schema.py new file mode 100644 index 00000000..58a66330 --- /dev/null +++ b/python/examples/drawing/schema.py @@ -0,0 +1,83 @@ +"""Schema for a drawing with boxes, ellipses, arrows, etc.""" + +from dataclasses import dataclass +from typing_extensions import Literal, Annotated, Doc, Optional + + +@dataclass +class Style: + """Style settings for drawing elements.""" + + type: Literal["Style"] + + corners: Annotated[ + Optional[Literal["rounded", "sharp"]], + Doc("Corner style of the drawing elements."), + ] = None + line_thickness: Annotated[Optional[int], Doc("Thickness of the lines.")] = None + line_color: Annotated[Optional[str], Doc("CSS-style color code for line color.")] = None + fill_color: Annotated[Optional[str], Doc("CSS-style color code for fill color.")] = None + line_style: Annotated[ + Optional[Literal["solid", "dashed", "dotted"]], + Doc("Style of the line: 'solid', 'dashed', 'dotted'."), + ] = None + + +@dataclass +class Box: + """A rectangular box defined by a coordinate system with the origin at the top left.""" + + type: Literal["Box"] + + x: Annotated[int, Doc("X-coordinate of the top left corner.")] + y: Annotated[int, Doc("Y-coordinate of the top left corner.")] + width: Annotated[int, Doc("Width of the box.")] + height: Annotated[int, Doc("Height of the box.")] + text: Annotated[Optional[str], Doc("Optional text centered in the box.")] = None + style: Annotated[Optional[Style], Doc("Optional style settings for the box.")] = None + + +@dataclass +class Ellipse: + """An ellipse defined by its bounding box dimensions.""" + + type: Literal["Ellipse"] + + x: Annotated[int, Doc("X-coordinate of the top left corner of the bounding box.")] + y: Annotated[int, Doc("Y-coordinate of the top left corner of the bounding box.")] + width: Annotated[int, Doc("Width of the bounding box.")] + height: Annotated[int, Doc("Height of the bounding box.")] + text: Annotated[Optional[str], Doc("Optional text centered in the box.")] = None + style: Annotated[Optional[Style], Doc("Optional style settings for the ellipse.")] = None + + +@dataclass +class Arrow: + """A line with a directional arrow at the end, defined by start and end points.""" + + type: Literal["Arrow"] + + start_x: Annotated[int, Doc("Starting X-coordinate.")] + start_y: Annotated[int, Doc("Starting Y-coordinate.")] + end_x: Annotated[int, Doc("Ending X-coordinate.")] + end_y: Annotated[int, Doc("Ending Y-coordinate.")] + style: Annotated[Optional[Style], Doc("Optional style settings for the arrow.")] = None + head_size: Annotated[Optional[int], Doc("Size of the arrowhead, if present.")] = None + + +@dataclass +class UnknownText: + """Used for input that does not match any other specified type.""" + + type: Literal["Unknown"] + + text: Annotated[str, Doc("The text that wasn't understood.")] + + +@dataclass +class Drawing: + """A collection of graphical elements including boxes, ellipses, arrows, and unrecognized text.""" + + type: Literal["Drawing"] + + items: Annotated[list[Box | Arrow | Ellipse | UnknownText], Doc("List of drawable elements.")] diff --git a/python/src/typechat/_internal/interactive.py b/python/src/typechat/_internal/interactive.py index d6f29595..d5a266cd 100644 --- a/python/src/typechat/_internal/interactive.py +++ b/python/src/typechat/_internal/interactive.py @@ -22,7 +22,7 @@ async def process_requests(interactive_prompt: str, input_file_name: str | None, else: try: # Use readline to enable input editing and history - import readline # type: ignore + import readline # type: ignore # noqa: F401 except ImportError: pass while True: