From 7c2888e2610296d4619d0c3b45583f945ecc2d39 Mon Sep 17 00:00:00 2001 From: liqun Date: Fri, 23 Jan 2026 18:46:03 +0800 Subject: [PATCH 1/5] add variables to code generator prompt --- AGENTS.md | 292 ++++++++++++++++++ docs/design/code-interpreter-vars.md | 62 ++++ taskweaver/ces/common.py | 1 + taskweaver/ces/environment.py | 2 + taskweaver/ces/kernel/ctx_magic.py | 1 + taskweaver/ces/runtime/context.py | 56 ++++ taskweaver/ces/runtime/executor.py | 1 + taskweaver/code_interpreter/code_executor.py | 6 + .../code_interpreter/code_generator.py | 35 ++- .../code_interpreter/code_interpreter.py | 7 + taskweaver/memory/attachment.py | 3 + taskweaver/utils/__init__.py | 12 + 12 files changed, 473 insertions(+), 5 deletions(-) create mode 100644 AGENTS.md create mode 100644 docs/design/code-interpreter-vars.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..8171f6e70 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,292 @@ +# AGENTS.md - TaskWeaver Development Guide + +This document provides guidance for AI coding agents working on the TaskWeaver codebase. + +## Project Overview + +TaskWeaver is a **code-first agent framework** for data analytics tasks. It uses Python 3.10+ and follows a modular architecture with dependency injection (using `injector`). + +## Build & Development Commands + +### Installation +```bash +# Use the existing conda environment +conda activate taskweaver + +# Or create a new one +conda create -n taskweaver python=3.10 +conda activate taskweaver + +# Install dependencies +pip install -r requirements.txt + +# Install in editable mode +pip install -e . +``` + +**Note**: The project uses a conda environment named `taskweaver`. + +### Running Tests +```bash +# Run all unit tests +pytest tests/unit_tests -v + +# Run a single test file +pytest tests/unit_tests/test_plugin.py -v + +# Run a specific test function +pytest tests/unit_tests/test_plugin.py::test_load_plugin_yaml -v + +# Run tests with coverage +pytest tests/unit_tests -v --cov=taskweaver --cov-report=html + +# Collect tests without running (useful for verification) +pytest tests/unit_tests --collect-only +``` + +### Linting & Formatting +```bash +# Run pre-commit hooks (autoflake, isort, black, flake8) +pre-commit run --all-files + +# Run individual tools +black --config=.linters/pyproject.toml . +isort --settings-path=.linters/pyproject.toml . +flake8 --config=.linters/tox.ini taskweaver/ +``` + +### Running the Application +```bash +# CLI mode +python -m taskweaver -p ./project/ + +# As a module +python -m taskweaver +``` + +## Code Style Guidelines + +### Formatting Configuration +- **Line length**: 120 characters (configured in `.linters/pyproject.toml`) +- **Formatter**: Black with `--config=.linters/pyproject.toml` +- **Import sorting**: isort with `profile = "black"` + +### Import Organization +```python +# Standard library imports first +import os +from dataclasses import dataclass +from typing import Any, Dict, List, Optional + +# Third-party imports +from injector import inject + +# Local imports (known_first_party = ["taskweaver"]) +from taskweaver.config.config_mgt import AppConfigSource +from taskweaver.logging import TelemetryLogger +``` + +### Type Annotations +- **Required**: All function parameters and return types must have type hints +- **Use `Optional[T]`** for nullable types +- **Use `List`, `Dict`, `Tuple`** from `typing` module +- **Dataclasses** are preferred for structured data + +```python +from dataclasses import dataclass +from typing import Any, Dict, List, Optional + +@dataclass +class Post: + id: str + send_from: str + send_to: str + message: str + attachment_list: List[Attachment] + + @staticmethod + def create( + message: Optional[str], + send_from: str, + send_to: str = "Unknown", + ) -> Post: + ... +``` + +### Naming Conventions +- **Classes**: PascalCase (`CodeGenerator`, `PluginRegistry`) +- **Functions/methods**: snake_case (`compose_prompt`, `get_attachment`) +- **Variables**: snake_case (`plugin_pool`, `chat_history`) +- **Constants**: UPPER_SNAKE_CASE (`MAX_RETRY_COUNT`) +- **Private members**: prefix with underscore (`_configure`, `_get_config_value`) +- **Config classes**: suffix with `Config` (`PlannerConfig`, `RoleConfig`) + +### Dependency Injection Pattern +TaskWeaver uses the `injector` library for DI. Follow this pattern: + +```python +from injector import inject, Module, provider + +class MyConfig(ModuleConfig): + def _configure(self) -> None: + self._set_name("my_module") + self.some_setting = self._get_str("setting_name", "default_value") + +class MyService: + @inject + def __init__( + self, + config: MyConfig, + logger: TelemetryLogger, + other_dependency: OtherService, + ): + self.config = config + self.logger = logger +``` + +### Error Handling +- Use specific exception types when possible +- Log errors with context before re-raising +- Use assertions for internal invariants + +```python +try: + result = self.llm_api.chat_completion_stream(...) +except (JSONDecodeError, AssertionError) as e: + self.logger.error(f"Failed to parse LLM output due to {str(e)}") + self.tracing.set_span_status("ERROR", str(e)) + raise +``` + +### Docstrings +Use triple-quoted docstrings for classes and public methods: + +```python +def get_embeddings(self, strings: List[str]) -> List[List[float]]: + """ + Embedding API + + :param strings: list of strings to be embedded + :return: list of embeddings + """ +``` + +### Trailing Commas +Always use trailing commas in multi-line structures (enforced by `add-trailing-comma`): + +```python +app_injector = Injector( + [LoggingModule, PluginModule], # trailing comma +) + +config = { + "key1": "value1", + "key2": "value2", # trailing comma +} +``` + +## Project Structure + +``` +taskweaver/ +├── app/ # Application entry points and session management +├── ces/ # Code execution service +├── chat/ # Chat interfaces (console, web) +├── cli/ # CLI implementation +├── code_interpreter/ # Code generation and interpretation +├── config/ # Configuration management +├── ext_role/ # Extended roles (web_search, image_reader, etc.) +├── llm/ # LLM integrations (OpenAI, Anthropic, etc.) +├── logging/ # Logging and telemetry +├── memory/ # Conversation memory and attachments +├── misc/ # Utilities and component registry +├── module/ # Core modules (tracing, events) +├── planner/ # Planning logic +├── plugin/ # Plugin system +├── role/ # Role base classes +├── session/ # Session management +├── utils/ # Helper utilities +└── workspace/ # Workspace management + +tests/ +└── unit_tests/ # Unit tests (pytest) + ├── data/ # Test fixtures (plugins, prompts, examples) + └── ces/ # Code execution tests +``` + +### Module and Role Overview (what lives where) + +- **app/**: Bootstraps dependency injection; wires TaskWeaverApp, SessionManager, config binding. +- **session/**: Orchestrates Planner + worker roles, memory, workspace management, event emitter, tracing. +- **planner/**: Planner role; LLM-powered task decomposition and planning logic. +- **code_interpreter/**: Code generation and execution (full, CLI-only, plugin-only); code verification/AST checks. +- **memory/**: Conversation history, rounds, posts, attachments, experiences; RoundCompressor utilities. +- **llm/**: LLM API facades; providers include OpenAI/Azure, Anthropic, Ollama, Google GenAI, Qwen, ZhipuAI, Groq, Azure ML, mock; embeddings via OpenAI/Azure, Ollama, Google GenAI, sentence_transformers, Qwen, ZhipuAI. +- **plugin/**: Plugin base classes and registry/context for function-style plugins. +- **role/**: Core role abstractions, RoleRegistry, PostTranslator. +- **ext_role/**: Extended roles (web_search, web_explorer, image_reader, document_retriever, recepta, echo). +- **module/**: Core modules like tracing and event_emitter wiring. +- **logging/**: TelemetryLogger and logging setup. +- **workspace/**: Session-scoped working directories and execution cwd helpers. + +## Testing Patterns + +### Using Fixtures +```python +import pytest +from injector import Injector + +@pytest.fixture() +def app_injector(request: pytest.FixtureRequest): + from taskweaver.config.config_mgt import AppConfigSource + config = {"llm.api_key": "test_key"} + app_injector = Injector([LoggingModule, PluginModule]) + app_config = AppConfigSource(config=config) + app_injector.binder.bind(AppConfigSource, to=app_config) + return app_injector +``` + +### Test Markers +```python +@pytest.mark.app_config({"custom.setting": "value"}) +def test_with_custom_config(app_injector): + ... +``` + +## Flake8 Ignores +The following are intentionally ignored (see `.linters/tox.ini`): +- `E402`: Module level import not at top of file +- `W503`: Line break before binary operator +- `W504`: Line break after binary operator +- `E203`: Whitespace before ':' +- `F401`: Import not used (only in `__init__.py`) + +## Key Patterns + +### Creating Unique IDs +```python +from taskweaver.utils import create_id +post_id = "post-" + create_id() # Format: post-YYYYMMDD-HHMMSS- +``` + +### Reading/Writing YAML +```python +from taskweaver.utils import read_yaml, write_yaml +data = read_yaml("path/to/file.yaml") +write_yaml("path/to/file.yaml", data) +``` + +### Configuration Access +```python +class MyConfig(ModuleConfig): + def _configure(self) -> None: + self._set_name("my_module") + self.enabled = self._get_bool("enabled", False) + self.path = self._get_path("base_path", "/default/path") + self.model = self._get_str("model", None, required=False) +``` + +## CI/CD +- Tests run on Python 3.11 via GitHub Actions +- Pre-commit hooks include: autoflake, isort, black, flake8, gitleaks, detect-secrets +- All PRs to `main` trigger the pytest workflow diff --git a/docs/design/code-interpreter-vars.md b/docs/design/code-interpreter-vars.md new file mode 100644 index 000000000..18f4cd53e --- /dev/null +++ b/docs/design/code-interpreter-vars.md @@ -0,0 +1,62 @@ +# Code Interpreter Visible Variable Surfacing + +## Problem +The code interpreter generates Python in a persistent kernel but the prompt does not explicitly remind the model which variables already exist in that kernel. This can lead to redundant redefinitions or missed reuse of prior results. We want to surface only the newly defined (non-library) variables to the model in subsequent turns. + +## Goals +- Capture the current user/kernel-visible variables after each execution (excluding standard libs and plugins). +- Propagate these variables to the code interpreter’s prompt so it can reuse them. +- Keep noise low: skip modules/functions and internal/builtin names; truncate large reprs. +- Maintain backward compatibility; do not break existing attachments or execution flow. + +## Non-Goals +- Full introspection of module internals or large data snapshots. +- Persisting variables across sessions beyond current conversation. + +## Design Overview +1) **Collect kernel variables after execution** + - In the IPython magics layer (`_taskweaver_exec_post_check`) call a context helper to extract visible variables from `local_ns`. + - Filtering rules: + - Skip names starting with `_`. + - Skip builtins and common libs: `__builtins__`, `In`, `Out`, `get_ipython`, `exit`, `quit`, `pd`, `np`, `plt`. + - Skip modules and any defined functions (only keep data-bearing variables). + - For other values, store `(name, repr(value))`, truncated to 500 chars and fall back to `` on repr errors. + - Store the snapshot on `ExecutorPluginContext.latest_variables`. + +2) **Return variables with execution result** + - `Executor.get_post_execution_state` now includes `variables` (list of `(name, repr)` tuples). + - `Environment._parse_exec_result` copies these into `ExecutionResult.variables` (added to dataclass). + +3) **Surface variables to user and prompt** + - `CodeExecutor.format_code_output` renders available variables when there is no explicit result/output, using `pretty_repr` to keep lines concise. + - `CodeInterpreter.reply` attaches a new `session_variables` attachment (JSON list of tuples) when variables are present. + - `CodeGenerator.compose_conversation` ignores this attachment in assistant-message rendering but includes it in feedback via `format_code_feedback`, adding an “Available Variables” section for the model’s context. + +4) **Attachment type** + - Added `AttachmentType.session_variables` to carry the variable snapshot per execution. + +## Open Items / Next Steps +- Wire the variables directly into the final user turn’s prompt text (e.g., under a “Currently available variables” block) to make reuse even clearer. +- Revisit filtering to ensure we skip large data/DF previews (could add size/type caps). +- Validate end-to-end with unit tests for: variable capture, attachment propagation, prompt inclusion, and formatting. + +## Files Touched +- `taskweaver/ces/runtime/context.py` — collect and store visible variables. +- `taskweaver/ces/runtime/executor.py` — expose variables in post-execution state. +- `taskweaver/ces/environment.py` — carry variables into `ExecutionResult`. +- `taskweaver/ces/common.py` — add `variables` to `ExecutionResult` dataclass. +- `taskweaver/memory/attachment.py` — add `session_variables` attachment type. +- `taskweaver/code_interpreter/code_interpreter/code_interpreter.py` — attach captured vars to posts. +- `taskweaver/code_interpreter/code_interpreter/code_generator.py` — ignore var attachments in assistant text; include in feedback. +- `taskweaver/code_interpreter/code_executor.py` — display available variables when no explicit output. +- `taskweaver/utils/__init__.py` — add `pretty_repr` helper for safe truncation. + +## Rationale +- Keeps the model aware of live state without inflating prompts with full outputs. +- Avoids re-importing/recomputing when variables already exist. +- Uses attachments so downstream consumers (UI/logs) can also show the state. + +## Risks / Mitigations +- **Large values**: truncated repr and filtered types keep prompt size bounded; consider type-based caps later. +- **Noise from libs**: explicit ignore list for common imports; can expand as needed. +- **Compatibility**: new attachment type is additive; existing flows remain unchanged. diff --git a/taskweaver/ces/common.py b/taskweaver/ces/common.py index ebcd89fef..5fd5f1f7e 100644 --- a/taskweaver/ces/common.py +++ b/taskweaver/ces/common.py @@ -68,6 +68,7 @@ class ExecutionResult: log: List[Tuple[str, str, str]] = dataclasses.field(default_factory=list) artifact: List[ExecutionArtifact] = dataclasses.field(default_factory=list) + variables: List[Tuple[str, str]] = dataclasses.field(default_factory=list) class Client(ABC): diff --git a/taskweaver/ces/environment.py b/taskweaver/ces/environment.py index e5f30ed16..5b2cfe868 100644 --- a/taskweaver/ces/environment.py +++ b/taskweaver/ces/environment.py @@ -697,6 +697,8 @@ def _parse_exec_result( preview=artifact_dict["preview"], ) result.artifact.append(artifact_item) + elif key == "variables": + result.variables = value else: pass diff --git a/taskweaver/ces/kernel/ctx_magic.py b/taskweaver/ces/kernel/ctx_magic.py index efc672486..cf9dba4e5 100644 --- a/taskweaver/ces/kernel/ctx_magic.py +++ b/taskweaver/ces/kernel/ctx_magic.py @@ -58,6 +58,7 @@ def _taskweaver_exec_pre_check(self, line: str): def _taskweaver_exec_post_check(self, line: str, local_ns: Dict[str, Any]): if "_" in local_ns: self.executor.ctx.set_output(local_ns["_"]) + self.executor.ctx.extract_visible_variables(local_ns) return fmt_response(True, "", self.executor.get_post_execution_state()) @cell_magic diff --git a/taskweaver/ces/runtime/context.py b/taskweaver/ces/runtime/context.py index e5ad1c142..1c4b38818 100644 --- a/taskweaver/ces/runtime/context.py +++ b/taskweaver/ces/runtime/context.py @@ -1,7 +1,14 @@ import os +import types from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple +try: + import numpy as _np # type: ignore +except Exception: # pragma: no cover - optional dependency + _np = None + from taskweaver.module.prompt_util import PromptUtil +from taskweaver.plugin.base import Plugin from taskweaver.plugin.context import ArtifactType, LogErrorLevel, PluginContext if TYPE_CHECKING: @@ -15,6 +22,7 @@ def __init__(self, executor: Any) -> None: self.artifact_list: List[Dict[str, str]] = [] self.log_messages: List[Tuple[LogErrorLevel, str, str]] = [] self.output: List[Tuple[str, str]] = [] + self.latest_variables: List[Tuple[str, str]] = [] @property def execution_id(self) -> str: @@ -147,6 +155,54 @@ def get_session_var( return self.executor.session_var[variable_name] return default + def extract_visible_variables(self, local_ns: Dict[str, Any]) -> List[Tuple[str, str]]: + ignore_names = { + "__builtins__", + "In", + "Out", + "get_ipython", + "exit", + "quit", + "pd", + "np", + "plt", + } + + visible: List[Tuple[str, str]] = [] + for name, value in local_ns.items(): + if name.startswith("_") or name in ignore_names: + continue + + if isinstance(value, (types.ModuleType, types.FunctionType)): + continue + + if isinstance(value, Plugin) or getattr(value, "__module__", "").startswith("taskweaver_ext.plugin"): + continue + + if _np is not None and isinstance(value, _np.ndarray): + try: + rendered = _np.array2string( + value, + max_line_width=120, + threshold=20, + edgeitems=3, + ) + rendered = f"ndarray shape={value.shape} dtype={value.dtype} value={rendered}" + except Exception: + rendered = "" + visible.append((name, rendered[:500])) + continue + + try: + rendered = repr(value) + except Exception: + rendered = "" + + visible.append((name, rendered[:500])) + + self.latest_variables = visible + return visible + def wrap_text_with_delimiter_temporal(self, text: str) -> str: """wrap text with delimiter""" return PromptUtil.wrap_text_with_delimiter( diff --git a/taskweaver/ces/runtime/executor.py b/taskweaver/ces/runtime/executor.py index 6359c3ba6..9a7420348 100644 --- a/taskweaver/ces/runtime/executor.py +++ b/taskweaver/ces/runtime/executor.py @@ -226,6 +226,7 @@ def get_post_execution_state(self): "artifact": self.ctx.artifact_list, "log": self.ctx.log_messages, "output": self.ctx.get_normalized_output(), + "variables": list(self.ctx.latest_variables), } def log(self, level: LogErrorLevel, message: str): diff --git a/taskweaver/code_interpreter/code_executor.py b/taskweaver/code_interpreter/code_executor.py index 40974950d..f7859f0d5 100644 --- a/taskweaver/code_interpreter/code_executor.py +++ b/taskweaver/code_interpreter/code_executor.py @@ -10,6 +10,7 @@ from taskweaver.module.tracing import Tracing, get_tracer, tracing_decorator from taskweaver.plugin.context import ArtifactType from taskweaver.session import SessionMetadata +from taskweaver.utils import pretty_repr TRUNCATE_CHAR_LENGTH = 1500 @@ -190,6 +191,11 @@ def format_code_output( lines.append( "The result of above Python code after execution is:\n" + str(output), ) + elif len(result.variables) > 0: + lines.append("The following variables are currently available in the Python session:\n") + for name, val in result.variables: + lines.append(f"- {name}: {pretty_repr(val, limit=500)}") + lines.append("") elif result.is_success: if len(result.stdout) > 0: lines.append( diff --git a/taskweaver/code_interpreter/code_interpreter/code_generator.py b/taskweaver/code_interpreter/code_interpreter/code_generator.py index 5800fb1c0..321631dc3 100644 --- a/taskweaver/code_interpreter/code_interpreter/code_generator.py +++ b/taskweaver/code_interpreter/code_interpreter/code_generator.py @@ -1,7 +1,7 @@ import datetime import json import os -from typing import List, Optional +from typing import List, Literal, Optional, Union from injector import inject @@ -119,10 +119,10 @@ def compose_verification_requirements( + ", ".join([f"{module}" for module in self.allowed_modules]), ) - if len(self.allowed_modules) == 0: + if self.allowed_modules is not None and len(self.allowed_modules) == 0: requirements.append(f"- {self.role_name} cannot import any Python modules.") - if len(self.blocked_functions) > 0: + if self.blocked_functions is not None and len(self.blocked_functions) > 0: requirements.append( f"- {self.role_name} cannot use the following Python functions: " + ", ".join([f"{function}" for function in self.blocked_functions]), @@ -207,10 +207,11 @@ def compose_conversation( AttachmentType.code_error, AttachmentType.execution_status, AttachmentType.execution_result, + AttachmentType.session_variables, ] is_first_post = True - last_post: Post = None + last_post: Optional[Post] = None for round_index, conversation_round in enumerate(rounds): for post_index, post in enumerate(conversation_round.post_list): # compose user query @@ -292,10 +293,24 @@ def compose_conversation( if len(user_message) > 0: # add requirements to the last user message if is_final_post and add_requirements: + available_vars_section = "" + session_vars = post.get_attachment(AttachmentType.session_variables) + if session_vars is not None and len(session_vars) > 0: + try: + decoded_vars = json.loads(session_vars[0].content) + if isinstance(decoded_vars, list) and len(decoded_vars) > 0: + formatted_vars = "\n".join([f"- {name}: {value}" for name, value in decoded_vars]) + available_vars_section = ( + "\nCurrently available variables in the Python session:\n" + formatted_vars + ) + except Exception: + pass user_message += "\n" + self.query_requirements_template.format( CODE_GENERATION_REQUIREMENTS=self.compose_verification_requirements(), ROLE_NAME=self.role_name, ) + if available_vars_section: + user_message += available_vars_section chat_history.append( format_chat_message(role="user", message=user_message), ) @@ -365,7 +380,7 @@ def reply( }, ) - def early_stop(_type: AttachmentType, value: str) -> bool: + def early_stop(_type: Union[AttachmentType, Literal["message", "send_to"]], value: str) -> bool: if _type in [AttachmentType.reply_content]: return True else: @@ -443,6 +458,7 @@ def format_code_feedback(post: Post) -> str: feedback = "" verification_status = "" execution_status = "" + variable_lines = [] for attachment in post.attachment_list: if attachment.type == AttachmentType.verification and attachment.content == "CORRECT": feedback += "## Verification\nCode verification has been passed.\n" @@ -466,4 +482,13 @@ def format_code_feedback(post: Post) -> str: execution_status = "FAILURE" elif attachment.type == AttachmentType.execution_result and execution_status != "NONE": feedback += f"{attachment.content}\n" + elif attachment.type == AttachmentType.session_variables: + try: + variables = json.loads(attachment.content) + if isinstance(variables, list) and len(variables) > 0: + variable_lines.extend([f"- {name}: {value}" for name, value in variables]) + except Exception: + pass + if len(variable_lines) > 0: + feedback += "## Available Variables\n" + "\n".join(variable_lines) + "\n" return feedback diff --git a/taskweaver/code_interpreter/code_interpreter/code_interpreter.py b/taskweaver/code_interpreter/code_interpreter/code_interpreter.py index 82dc9da6e..9770da325 100644 --- a/taskweaver/code_interpreter/code_interpreter/code_interpreter.py +++ b/taskweaver/code_interpreter/code_interpreter/code_interpreter.py @@ -1,3 +1,4 @@ +import json import os from typing import Dict, Literal, Optional @@ -247,6 +248,12 @@ def reply( code=executable_code, ) + if len(exec_result.variables) > 0: + post_proxy.update_attachment( + json.dumps(exec_result.variables), + AttachmentType.session_variables, + ) + code_output = self.executor.format_code_output( exec_result, with_code=False, diff --git a/taskweaver/memory/attachment.py b/taskweaver/memory/attachment.py index dc9bcd334..609f9524c 100644 --- a/taskweaver/memory/attachment.py +++ b/taskweaver/memory/attachment.py @@ -44,6 +44,9 @@ class AttachmentType(Enum): invalid_response = "invalid_response" text = "text" + # CodeInterpreter - visible variables snapshot + session_variables = "session_variables" + # shared memory entry shared_memory_entry = "shared_memory_entry" diff --git a/taskweaver/utils/__init__.py b/taskweaver/utils/__init__.py index e82610ae7..ee773773f 100644 --- a/taskweaver/utils/__init__.py +++ b/taskweaver/utils/__init__.py @@ -80,6 +80,18 @@ def json_dump(obj: Any, fp: Any): json.dump(obj, fp, cls=EnhancedJSONEncoder) +def pretty_repr(val: Any, limit: int = 200) -> str: + try: + rendered = repr(val) + except Exception: + rendered = "" + + if len(rendered) > limit: + omitted = len(rendered) - limit + return f"{rendered[:limit]}...omitted {omitted} chars..." + return rendered + + def generate_md5_hash(content: str) -> str: from hashlib import md5 From 1d1a8ea7853fcd3bcfeba65639115062755b674b Mon Sep 17 00:00:00 2001 From: liqun Date: Mon, 26 Jan 2026 10:39:34 +0800 Subject: [PATCH 2/5] init deep --- AGENTS.md | 19 +++-- docs/design/code-interpreter-vars.md | 14 ++-- taskweaver/ces/AGENTS.md | 73 ++++++++++++++++++ taskweaver/code_interpreter/AGENTS.md | 83 ++++++++++++++++++++ taskweaver/ext_role/AGENTS.md | 104 +++++++++++++++++++++++++ taskweaver/llm/AGENTS.md | 62 +++++++++++++++ taskweaver/memory/AGENTS.md | 106 ++++++++++++++++++++++++++ 7 files changed, 450 insertions(+), 11 deletions(-) create mode 100644 taskweaver/ces/AGENTS.md create mode 100644 taskweaver/code_interpreter/AGENTS.md create mode 100644 taskweaver/ext_role/AGENTS.md create mode 100644 taskweaver/llm/AGENTS.md create mode 100644 taskweaver/memory/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index 8171f6e70..227e2edbe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,16 @@ # AGENTS.md - TaskWeaver Development Guide +**Generated:** 2026-01-26 | **Commit:** 7c2888e | **Branch:** liqun/add_variables_to_code_generator + This document provides guidance for AI coding agents working on the TaskWeaver codebase. +## Subdirectory Knowledge Bases +- [`taskweaver/llm/AGENTS.md`](taskweaver/llm/AGENTS.md) - LLM provider abstractions +- [`taskweaver/ces/AGENTS.md`](taskweaver/ces/AGENTS.md) - Code execution service (Jupyter kernels) +- [`taskweaver/code_interpreter/AGENTS.md`](taskweaver/code_interpreter/AGENTS.md) - Code interpreter role variants +- [`taskweaver/memory/AGENTS.md`](taskweaver/memory/AGENTS.md) - Memory data model (Post/Round/Conversation) +- [`taskweaver/ext_role/AGENTS.md`](taskweaver/ext_role/AGENTS.md) - Extended role definitions + ## Project Overview TaskWeaver is a **code-first agent framework** for data analytics tasks. It uses Python 3.10+ and follows a modular architecture with dependency injection (using `injector`). @@ -190,15 +199,15 @@ config = { ``` taskweaver/ ├── app/ # Application entry points and session management -├── ces/ # Code execution service +├── ces/ # Code execution service (see ces/AGENTS.md) ├── chat/ # Chat interfaces (console, web) ├── cli/ # CLI implementation -├── code_interpreter/ # Code generation and interpretation +├── code_interpreter/ # Code generation and interpretation (see code_interpreter/AGENTS.md) ├── config/ # Configuration management -├── ext_role/ # Extended roles (web_search, image_reader, etc.) -├── llm/ # LLM integrations (OpenAI, Anthropic, etc.) +├── ext_role/ # Extended roles (see ext_role/AGENTS.md) +├── llm/ # LLM integrations (see llm/AGENTS.md) ├── logging/ # Logging and telemetry -├── memory/ # Conversation memory and attachments +├── memory/ # Conversation memory (see memory/AGENTS.md) ├── misc/ # Utilities and component registry ├── module/ # Core modules (tracing, events) ├── planner/ # Planning logic diff --git a/docs/design/code-interpreter-vars.md b/docs/design/code-interpreter-vars.md index 18f4cd53e..5ebf847df 100644 --- a/docs/design/code-interpreter-vars.md +++ b/docs/design/code-interpreter-vars.md @@ -19,27 +19,29 @@ The code interpreter generates Python in a persistent kernel but the prompt does - Filtering rules: - Skip names starting with `_`. - Skip builtins and common libs: `__builtins__`, `In`, `Out`, `get_ipython`, `exit`, `quit`, `pd`, `np`, `plt`. - - Skip modules and any defined functions (only keep data-bearing variables). - - For other values, store `(name, repr(value))`, truncated to 500 chars and fall back to `` on repr errors. + - Skip modules, functions, and plugin instances (data-only snapshot). + - For values, store `(name, repr(value))`, truncated to 500 chars; numpy arrays get shape/dtype-aware pretty repr; fall back to `` on repr errors. - Store the snapshot on `ExecutorPluginContext.latest_variables`. 2) **Return variables with execution result** - - `Executor.get_post_execution_state` now includes `variables` (list of `(name, repr)` tuples). + - `Executor.get_post_execution_state` includes `variables` (list of `(name, repr)` tuples). - `Environment._parse_exec_result` copies these into `ExecutionResult.variables` (added to dataclass). 3) **Surface variables to user and prompt** - `CodeExecutor.format_code_output` renders available variables when there is no explicit result/output, using `pretty_repr` to keep lines concise. - - `CodeInterpreter.reply` attaches a new `session_variables` attachment (JSON list of tuples) when variables are present. - - `CodeGenerator.compose_conversation` ignores this attachment in assistant-message rendering but includes it in feedback via `format_code_feedback`, adding an “Available Variables” section for the model’s context. + - `CodeInterpreter.reply` attaches a `session_variables` attachment (JSON list of tuples) when variables are present. + - Prompt threading strategy: + - Assistant turns: `session_variables` is **ignored** via `ignored_types` to avoid polluting assistant history with execution-state metadata. + - Final user turn of the latest round: the attachment is decoded and appended as a “Currently available variables” block so the model can reuse state in the next code generation. 4) **Attachment type** - Added `AttachmentType.session_variables` to carry the variable snapshot per execution. ## Open Items / Next Steps -- Wire the variables directly into the final user turn’s prompt text (e.g., under a “Currently available variables” block) to make reuse even clearer. - Revisit filtering to ensure we skip large data/DF previews (could add size/type caps). - Validate end-to-end with unit tests for: variable capture, attachment propagation, prompt inclusion, and formatting. + ## Files Touched - `taskweaver/ces/runtime/context.py` — collect and store visible variables. - `taskweaver/ces/runtime/executor.py` — expose variables in post-execution state. diff --git a/taskweaver/ces/AGENTS.md b/taskweaver/ces/AGENTS.md new file mode 100644 index 000000000..dc06fb748 --- /dev/null +++ b/taskweaver/ces/AGENTS.md @@ -0,0 +1,73 @@ +# Code Execution Service (CES) - AGENTS.md + +Jupyter kernel-based code execution with local and container modes. + +## Structure + +``` +ces/ +├── environment.py # Environment class - kernel management (~700 lines) +├── common.py # ExecutionResult, ExecutionArtifact, EnvPlugin dataclasses +├── client.py # CES client for remote execution +├── __init__.py # Exports +├── kernel/ # Custom Jupyter kernel implementation +│ └── ext.py # IPython magic commands for TaskWeaver +├── runtime/ # Runtime support files +└── manager/ # Session/kernel lifecycle management +``` + +## Key Classes + +### Environment (environment.py) +Main orchestrator for code execution: +- `EnvMode.Local`: Direct kernel via `MultiKernelManager` +- `EnvMode.Container`: Docker container with mounted volumes + +### ExecutionResult (common.py) +```python +@dataclass +class ExecutionResult: + execution_id: str + code: str + is_success: bool + error: str + output: str + stdout: List[str] + stderr: List[str] + log: List[str] + artifact: List[ExecutionArtifact] + variables: Dict[str, str] # Session variables from execution +``` + +## Execution Flow + +1. `start_session()` - Creates kernel (local or container) +2. `load_plugin()` - Registers plugins in kernel namespace +3. `execute_code()` - Runs code, captures output/artifacts +4. `stop_session()` - Cleanup kernel/container + +## Container Mode Specifics + +- Image: `taskweavercontainers/taskweaver-executor:latest` +- Ports: 5 ports mapped (shell, iopub, stdin, hb, control) +- Volumes: `ces/` and `cwd/` mounted read-write +- Connection file written to `ces/conn-{session}-{kernel}.json` + +## Custom Kernel Magics (kernel/ext.py) + +```python +%_taskweaver_session_init {session_id} +%_taskweaver_plugin_register {name} +%_taskweaver_plugin_load {name} +%_taskweaver_exec_pre_check {index} {exec_id} +%_taskweaver_exec_post_check {index} {exec_id} +%%_taskweaver_update_session_var +``` + +## Adding Plugin Support + +Plugins are loaded via magic commands: +1. `_taskweaver_plugin_register` - Registers plugin class +2. `_taskweaver_plugin_load` - Instantiates with config + +Session variables updated via `%%_taskweaver_update_session_var` magic. diff --git a/taskweaver/code_interpreter/AGENTS.md b/taskweaver/code_interpreter/AGENTS.md new file mode 100644 index 000000000..cb545e7ab --- /dev/null +++ b/taskweaver/code_interpreter/AGENTS.md @@ -0,0 +1,83 @@ +# Code Interpreter - AGENTS.md + +Code generation and execution roles with multiple variants. + +## Structure + +``` +code_interpreter/ +├── interpreter.py # Interpreter ABC (update_session_variables) +├── code_executor.py # CodeExecutor - bridges to CES +├── code_verification.py # AST-based code validation +├── plugin_selection.py # Plugin selection logic +├── code_interpreter/ # Full code interpreter +│ ├── code_interpreter.py # CodeInterpreter role (~320 lines) +│ ├── code_generator.py # LLM-based code generation +│ └── code_interpreter.role.yaml +├── code_interpreter_cli_only/ # CLI-only variant (no plugins) +│ ├── code_interpreter_cli_only.py +│ ├── code_generator_cli_only.py +│ └── code_interpreter_cli_only.role.yaml +└── code_interpreter_plugin_only/ # Plugin-only variant (no free-form code) + ├── code_interpreter_plugin_only.py + ├── code_generator_plugin_only.py + └── code_interpreter_plugin_only.role.yaml +``` + +## Role Variants + +| Variant | Plugins | Free-form Code | Use Case | +|---------|---------|----------------|----------| +| `code_interpreter` | Yes | Yes | Full capability | +| `code_interpreter_cli_only` | No | Yes | Restricted to CLI | +| `code_interpreter_plugin_only` | Yes | No | Only plugin calls | + +## Key Classes + +### CodeInterpreter (Role, Interpreter) +- Orchestrates: CodeGenerator -> verification -> CodeExecutor +- Retry logic: up to `max_retry_count` (default 3) on failures +- Config: `CodeInterpreterConfig` (verification settings, blocked functions) + +### CodeGenerator +- LLM-based code generation from conversation context +- Outputs: code + explanation via PostEventProxy +- Configurable verification: allowed_modules, blocked_functions + +### CodeExecutor +- Wraps CES Environment +- Plugin loading from PluginRegistry +- Session variable management + +## Code Verification (code_verification.py) + +AST-based checks: +- `allowed_modules`: Whitelist of importable modules +- `blocked_functions`: Blacklist (default: `eval`, `exec`, `open`, etc.) + +```python +code_verify_errors = code_snippet_verification( + code, + code_verification_on=True, + allowed_modules=["pandas", "numpy"], + blocked_functions=["eval", "exec"], +) +``` + +## Role YAML Schema + +```yaml +module: taskweaver.code_interpreter.code_interpreter.code_interpreter.CodeInterpreter +alias: CodeInterpreter # Used in message routing +intro: | + - Description of capabilities + - {plugin_description} placeholder for dynamic plugin list +``` + +## Execution Flow + +1. `reply()` called with Memory context +2. CodeGenerator produces code via LLM +3. Code verification (if enabled) +4. CodeExecutor runs code in CES kernel +5. Results formatted back to Post diff --git a/taskweaver/ext_role/AGENTS.md b/taskweaver/ext_role/AGENTS.md new file mode 100644 index 000000000..3768efa54 --- /dev/null +++ b/taskweaver/ext_role/AGENTS.md @@ -0,0 +1,104 @@ +# Extended Roles - AGENTS.md + +Custom role definitions extending TaskWeaver capabilities. + +## Structure + +``` +ext_role/ +├── __init__.py +├── web_search/ # Web search role +│ ├── web_search.py +│ └── web_search.role.yaml +├── web_explorer/ # Browser automation role +│ ├── web_explorer.py +│ ├── driver.py # Selenium/Playwright driver +│ ├── planner.py # Web action planning +│ └── web_explorer.role.yaml +├── image_reader/ # Image analysis role +│ ├── image_reader.py +│ └── image_reader.role.yaml +├── document_retriever/ # Document RAG role +│ ├── document_retriever.py +│ └── document_retriever.role.yaml +├── recepta/ # Custom tool orchestration +│ ├── recepta.py +│ └── recepta.role.yaml +└── echo/ # Debug/test echo role + ├── echo.py + └── echo.role.yaml +``` + +## Role YAML Schema + +Each role requires a `.role.yaml` file: + +```yaml +module: taskweaver.ext_role.{name}.{name}.{ClassName} +alias: {DisplayName} # Used in message routing +intro: | + - Capability description line 1 + - Capability description line 2 +``` + +## Creating a New Extended Role + +1. Create directory: `ext_role/my_role/` +2. Create `my_role.py`: +```python +from taskweaver.role import Role +from taskweaver.role.role import RoleConfig, RoleEntry + +class MyRoleConfig(RoleConfig): + def _configure(self): + # Config inherits from parent dir name + self.custom_setting = self._get_str("custom", "default") + +class MyRole(Role): + @inject + def __init__( + self, + config: MyRoleConfig, + logger: TelemetryLogger, + tracing: Tracing, + event_emitter: SessionEventEmitter, + role_entry: RoleEntry, + ): + super().__init__(config, logger, tracing, event_emitter, role_entry) + + def reply(self, memory: Memory, **kwargs) -> Post: + # Implement role logic + post_proxy = self.event_emitter.create_post_proxy(self.alias) + # ... process and respond + return post_proxy.end() +``` + +3. Create `my_role.role.yaml`: +```yaml +module: taskweaver.ext_role.my_role.my_role.MyRole +alias: MyRole +intro: | + - This role does X + - It can handle Y +``` + +4. Enable in session config: +```json +{ + "session.roles": ["planner", "code_interpreter", "my_role"] +} +``` + +## Role Discovery + +RoleRegistry scans: +- `ext_role/*/\*.role.yaml` +- `code_interpreter/*/\*.role.yaml` + +Registry refreshes every 5 minutes (TTL). + +## Naming Convention + +- Directory name = role name = config namespace +- Class name = PascalCase of directory name +- Alias used for `send_to`/`send_from` in Posts diff --git a/taskweaver/llm/AGENTS.md b/taskweaver/llm/AGENTS.md new file mode 100644 index 000000000..f631a8165 --- /dev/null +++ b/taskweaver/llm/AGENTS.md @@ -0,0 +1,62 @@ +# LLM Module - AGENTS.md + +Provider abstraction layer for LLM and embedding services. + +## Structure + +``` +llm/ +├── base.py # Abstract base: CompletionService, EmbeddingService, LLMModuleConfig +├── util.py # ChatMessageType, format_chat_message, token counting +├── openai.py # OpenAI/Azure OpenAI provider (largest file ~430 lines) +├── anthropic.py # Anthropic Claude provider +├── google_genai.py # Google Generative AI provider +├── ollama.py # Ollama local LLM provider +├── qwen.py # Alibaba Qwen provider +├── zhipuai.py # ZhipuAI provider +├── groq.py # Groq provider +├── azure_ml.py # Azure ML endpoints +├── sentence_transformer.py # Local embedding via sentence_transformers +├── mock.py # Mock provider for testing +├── placeholder.py # Placeholder when no LLM configured +└── __init__.py # LLMApi facade class +``` + +## Key Patterns + +### Provider Registration +New providers must: +1. Subclass `CompletionService` or `EmbeddingService` from `base.py` +2. Implement `chat_completion()` generator or `get_embeddings()` +3. Register in `__init__.py` LLMApi class's provider mapping + +### Config Hierarchy +```python +class MyProviderConfig(LLMServiceConfig): + def _configure(self) -> None: + self._set_name("my_provider") # creates llm.my_provider.* namespace + self.custom_setting = self._get_str("custom_setting", "default") +``` + +### ChatMessageType +```python +ChatMessageType = TypedDict("ChatMessageType", { + "role": str, # "system", "user", "assistant" + "content": str, + "name": NotRequired[str], +}) +``` + +## Adding a New LLM Provider + +1. Create `taskweaver/llm/newprovider.py` +2. Implement config class extending `LLMServiceConfig` +3. Implement service class extending `CompletionService` +4. Add to `_completion_service_map` in `__init__.py` +5. Document in `llm.api_type` config options + +## Common Gotchas + +- `response_format` options: `"json_object"`, `"text"`, `"json_schema"` +- Streaming: All providers return `Generator[ChatMessageType, None, None]` +- OpenAI file is largest (~430 lines) - handles both OpenAI and Azure OpenAI diff --git a/taskweaver/memory/AGENTS.md b/taskweaver/memory/AGENTS.md new file mode 100644 index 000000000..355379f46 --- /dev/null +++ b/taskweaver/memory/AGENTS.md @@ -0,0 +1,106 @@ +# Memory Module - AGENTS.md + +Conversation history data model: Post, Round, Conversation, Attachment. + +## Structure + +``` +memory/ +├── memory.py # Memory class - session conversation store +├── conversation.py # Conversation - list of Rounds +├── round.py # Round - single user query + responses +├── post.py # Post - single message between roles +├── attachment.py # Attachment - typed data on Posts +├── type_vars.py # Type aliases (RoleName, etc.) +├── experience.py # Experience storage and retrieval +├── compression.py # RoundCompressor for prompt compression +├── plugin.py # PluginModule for DI +├── shared_memory_entry.py # SharedMemoryEntry for cross-role data +└── utils.py # Utility functions +``` + +## Data Model Hierarchy + +``` +Memory +└── Conversation + └── Round[] + ├── user_query: str + ├── state: "created" | "finished" | "failed" + └── Post[] + ├── send_from: str (role name) + ├── send_to: str (role name) + ├── message: str + └── Attachment[] + ├── type: AttachmentType + ├── content: str + └── extra: Any +``` + +## Key Classes + +### Post (post.py) +```python +@dataclass +class Post: + id: str + send_from: str + send_to: str + message: str + attachment_list: List[Attachment] + + @staticmethod + def create(message: str, send_from: str, send_to: str) -> Post +``` + +### AttachmentType (attachment.py) +```python +class AttachmentType(str, Enum): + # Planning + init_plan = "init_plan" + plan = "plan" + current_plan_step = "current_plan_step" + + # Code execution + reply_content = "reply_content" # Generated code + verification = "verification" + execution_status = "execution_status" + execution_result = "execution_result" + + # Control flow + revise_message = "revise_message" + invalid_response = "invalid_response" + + # Shared state + shared_memory_entry = "shared_memory_entry" + session_variables = "session_variables" +``` + +### SharedMemoryEntry (shared_memory_entry.py) +Cross-role communication: +```python +@dataclass +class SharedMemoryEntry: + type: str # "plan", "experience_sub_path", etc. + scope: str # "round" or "conversation" + content: str +``` + +## Memory Patterns + +### Role-specific Round Filtering +```python +# Get rounds relevant to a specific role +rounds = memory.get_role_rounds(role="Planner", include_failure_rounds=False) +``` + +### Shared Memory Queries +```python +# Get shared entries by type +entries = memory.get_shared_memory_entries(entry_type="plan") +``` + +## Serialization + +All dataclasses support `to_dict()` and `from_dict()` for YAML/JSON persistence. +Experience saving: `memory.save_experience(exp_dir, thin_mode=True)` From 7bade76feda06cb9df97a2dff3b4e43cb9704978 Mon Sep 17 00:00:00 2001 From: liqun Date: Mon, 26 Jan 2026 11:00:25 +0800 Subject: [PATCH 3/5] remove chainlit --- .gitignore | 3 + docs/design/threading_model.md | 330 ++++++++++++++++++ playground/UI/.chainlit/config.toml | 84 ----- playground/UI/app.py | 462 ------------------------- playground/UI/chainlit.md | 16 - playground/UI/public/favicon.ico | Bin 67646 -> 0 bytes playground/UI/public/logo_dark.png | Bin 65635 -> 0 bytes playground/UI/public/logo_light.png | Bin 65635 -> 0 bytes playground/UI/public/style_v1.css | 192 ---------- project/taskweaver_config.json | 5 - project/taskweaver_config.json.example | 6 + taskweaver/cli/web.py | 54 --- website/docs/quickstart.md | 5 +- website/docs/usage/webui.md | 36 -- website/sidebars.js | 1 - website/static/img/ui_screenshot_1.png | Bin 95022 -> 0 bytes website/static/img/ui_screenshot_2.png | Bin 73462 -> 0 bytes 17 files changed, 342 insertions(+), 852 deletions(-) create mode 100644 docs/design/threading_model.md delete mode 100644 playground/UI/.chainlit/config.toml delete mode 100644 playground/UI/app.py delete mode 100644 playground/UI/chainlit.md delete mode 100644 playground/UI/public/favicon.ico delete mode 100644 playground/UI/public/logo_dark.png delete mode 100644 playground/UI/public/logo_light.png delete mode 100644 playground/UI/public/style_v1.css delete mode 100644 project/taskweaver_config.json create mode 100644 project/taskweaver_config.json.example delete mode 100644 taskweaver/cli/web.py delete mode 100644 website/docs/usage/webui.md delete mode 100644 website/static/img/ui_screenshot_1.png delete mode 100644 website/static/img/ui_screenshot_2.png diff --git a/.gitignore b/.gitignore index b67ecefe9..e1b579559 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ workspace/* set_env.sh sample_case_results.csv +# Project config (use taskweaver_config.json.example as template) +project/taskweaver_config.json + # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/docs/design/threading_model.md b/docs/design/threading_model.md new file mode 100644 index 000000000..23c3e207d --- /dev/null +++ b/docs/design/threading_model.md @@ -0,0 +1,330 @@ +# TaskWeaver Threading Model - Design Document + +**Generated:** 2026-01-26 | **Author:** AI Agent | **Status:** Documentation + +## Overview + +TaskWeaver employs a **dual-thread architecture** for console-based user interaction. When a user submits a request, the main process spawns two threads: + +1. **Execution Thread** - Runs the actual task processing (LLM calls, code execution) +2. **Animation Thread** - Handles real-time console display with status updates and animations + +These threads communicate via an **event-driven architecture** using a shared update queue protected by threading primitives. + +## Architecture Diagram + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ Main Thread │ +│ ┌─────────────────────────────────────────────────────────────────────┐ │ +│ │ TaskWeaverChatApp.run() │ │ +│ │ └── _handle_message(input) │ │ +│ │ └── TaskWeaverRoundUpdater.handle_message() │ │ +│ └─────────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌───────────────┴───────────────┐ │ +│ ▼ ▼ │ +│ ┌─────────────────────────────┐ ┌─────────────────────────────┐ │ +│ │ Execution Thread (t_ex) │ │ Animation Thread (t_ui) │ │ +│ │ │ │ │ │ +│ │ session.send_message() │ │ _animate_thread() │ │ +│ │ ├── Planner.reply() │ │ ├── Process updates │ │ +│ │ ├── CodeInterpreter │ │ ├── Render status bar │ │ +│ │ │ .reply() │ │ ├── Display messages │ │ +│ │ └── Event emission ──────┼───┼──► └── Animate spinner │ │ +│ │ │ │ │ │ +│ └─────────────────────────────┘ └─────────────────────────────┘ │ +│ │ │ │ +│ └───────────────┬───────────────┘ │ +│ ▼ │ +│ exit_event.set() │ +│ Main thread joins │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +## Key Components + +### 1. TaskWeaverRoundUpdater (chat/console/chat.py) + +The central coordinator that manages both threads and handles events. + +```python +class TaskWeaverRoundUpdater(SessionEventHandlerBase): + def __init__(self): + self.exit_event = threading.Event() # Signals completion + self.update_cond = threading.Condition() # Wakes animation thread + self.lock = threading.Lock() # Protects shared state + + self.pending_updates: List[Tuple[str, str]] = [] # Event queue + self.result: Optional[str] = None +``` + +### 2. Thread Spawning (handle_message) + +```python +def handle_message(self, session, message, files): + def execution_thread(): + try: + round = session.send_message(message, event_handler=self, files=files) + last_post = round.post_list[-1] + if last_post.send_to == "User": + self.result = last_post.message + finally: + self.exit_event.set() + with self.update_cond: + self.update_cond.notify_all() + + t_ui = threading.Thread(target=lambda: self._animate_thread(), daemon=True) + t_ex = threading.Thread(target=execution_thread, daemon=True) + + t_ui.start() + t_ex.start() + + # Main thread waits for completion + while True: + self.exit_event.wait(0.1) + if self.exit_event.is_set(): + break +``` + +### 3. Event Flow + +``` +┌──────────────────┐ emit() ┌──────────────────┐ handle() ┌──────────────────┐ +│ PostEventProxy │─────────────►│ SessionEventEmitter│────────────►│TaskWeaverRoundUpdater│ +└──────────────────┘ └──────────────────┘ └──────────────────┘ + │ + ▼ + ┌──────────────────┐ + │ pending_updates │ + │ (queue) │ + └──────────────────┘ + │ + ▼ + ┌──────────────────┐ + │ Animation Thread │ + │ (consumer) │ + └──────────────────┘ +``` + +## Event Types + +### Session Events (EventScope.session) +| Event | Description | +|-------|-------------| +| `session_start` | Session initialization | +| `session_end` | Session termination | +| `session_new_round` | New conversation round | + +### Round Events (EventScope.round) +| Event | Description | +|-------|-------------| +| `round_start` | User query processing begins | +| `round_end` | User query processing complete | +| `round_error` | Error during processing | +| `round_new_post` | New message in round | + +### Post Events (EventScope.post) +| Event | Description | +|-------|-------------| +| `post_start` | Role begins generating response | +| `post_end` | Role finished response | +| `post_error` | Error in post generation | +| `post_status_update` | Status text change ("generating code", "executing") | +| `post_send_to_update` | Recipient change | +| `post_message_update` | Message content streaming | +| `post_attachment_update` | Attachment (code, plan, etc.) update | + +## Animation Thread Details + +The animation thread (`_animate_thread`) runs a continuous loop: + +```python +def _animate_thread(self): + while True: + clear_line() + + # Process all pending updates atomically + with self.lock: + for action, opt in self.pending_updates: + if action == "start_post": + # Display role header: ╭───< Planner > + elif action == "end_post": + # Display completion: ╰──● sending to User + elif action == "attachment_start": + # Begin attachment display + elif action == "attachment_add": + # Append to current attachment + elif action == "attachment_end": + # Finalize and render attachment + elif action == "status_update": + # Update status message + self.pending_updates.clear() + + if self.exit_event.is_set(): + break + + # Display animated status bar + # " TaskWeaver ▶ [Planner] generating code <=💡=>" + display_status_bar(role, status, get_ani_frame(counter)) + + # Rate limit animation (~30Hz visual, 5Hz animation) + with self.update_cond: + self.update_cond.wait(0.2) +``` + +### Console Output Format + +``` + ╭───< Planner > + ├─► [init_plan] Analyze the user request... + ├─► [plan] 1. Parse input data... + ├──● The task involves processing the CSV file... + ╰──● sending message to CodeInterpreter + + ╭───< CodeInterpreter > + ├─► [reply_content] import pandas as pd... + ├─► [verification] CORRECT + ├─► [execution_status] SUCCESS + ├──● [Execution result]... + ╰──● sending message to Planner +``` + +## Synchronization Primitives + +| Primitive | Purpose | +|-----------|---------| +| `threading.Lock` | Protects `pending_updates` queue during read/write | +| `threading.Event` | Signals execution completion (`exit_event`) | +| `threading.Condition` | Wakes animation thread when updates available | + +### Critical Sections + +1. **Event emission** (execution thread writes): +```python +with self.lock: + self.pending_updates.append(("status_update", msg)) +``` + +2. **Update processing** (animation thread reads): +```python +with self.lock: + for action, opt in self.pending_updates: + # Process... + self.pending_updates.clear() +``` + +## Additional Threading: Stream Smoother + +The LLM module (`llm/__init__.py`) uses a separate threading model for **LLM response streaming**: + +```python +def _stream_smoother(self, stream_init): + """ + Smooths LLM token streaming for better UX. + + Problem: LLM tokens arrive in bursts (fast) then pauses (slow). + Solution: Buffer tokens and emit at normalized rate. + """ + buffer_content = "" + finished = False + + def base_stream_puller(): + # Thread: Pull from LLM, add to buffer + for msg in stream_init(): + with update_lock: + buffer_content += msg["content"] + + thread = threading.Thread(target=base_stream_puller) + thread.start() + + # Main: Drain buffer at smoothed rate + while not finished: + yield normalized_chunk() +``` + +## Thread Lifecycle + +``` +Time ──────────────────────────────────────────────────────────► + +Main ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████████████ + spawn wait(exit_event) join threads + +Execution ░░░░████████████████████████████████████████░░░░░░░░░░ + send_message() → Planner → CodeInterpreter → result + +Animation ░░░░██░██░██░██░██░██░██░██░██░██░██░██░██░░░░░░░░░░░░ + render → sleep(0.2) → render → sleep → render + +Legend: █ = active, ░ = waiting/idle +``` + +## Error Handling + +### Keyboard Interrupt +```python +try: + while True: + self.exit_event.wait(0.1) + if self.exit_event.is_set(): + break +except KeyboardInterrupt: + error_message("Interrupted by user") + exit(1) # Immediate exit - session state unknown +``` + +### Execution Errors +```python +def execution_thread(): + try: + round = session.send_message(...) + except Exception as e: + self.response.append("Error") + raise e + finally: + self.exit_event.set() # Always signal completion +``` + +## Design Rationale + +### Why Two Threads? + +1. **Non-blocking UI**: LLM calls and code execution can take seconds/minutes. Animation thread keeps UI responsive. + +2. **Real-time feedback**: Users see incremental progress (streaming text, status updates) rather than waiting for complete response. + +3. **Clean separation**: Execution logic doesn't need to know about display; display doesn't block execution. + +### Why Event Queue? + +1. **Decoupling**: Event emitters (Planner, CodeInterpreter) don't know about console display. + +2. **Batching**: Multiple rapid events can be processed in single animation frame. + +3. **Thread safety**: Queue with lock is simpler than direct UI updates from multiple threads. + +## Comparison with Other Modes + +| Mode | Threading | Display | +|------|-----------|---------| +| Console (`chat_taskweaver`) | 2 threads (exec + anim) | Real-time animated | +| Web/API | Single thread per request | WebSocket/SSE streaming | +| Programmatic | Caller's thread | Event callbacks | + +## File References + +| File | Component | +|------|-----------| +| `chat/console/chat.py` | `TaskWeaverRoundUpdater`, `_animate_thread` | +| `module/event_emitter.py` | `SessionEventEmitter`, `TaskWeaverEvent`, `PostEventProxy` | +| `llm/__init__.py` | `_stream_smoother` (LLM streaming) | +| `ces/manager/defer.py` | `deferred_var` (kernel warm-up) | + +## Summary + +TaskWeaver's console interface uses a clean dual-thread model: +- **Execution thread**: Runs the agent pipeline (Planner → CodeInterpreter → result) +- **Animation thread**: Consumes events and renders real-time console output + +Communication happens via an event queue (`pending_updates`) protected by a lock, with a condition variable for efficient wake-up. This design provides responsive UI feedback during long-running AI operations while maintaining clean separation of concerns. diff --git a/playground/UI/.chainlit/config.toml b/playground/UI/.chainlit/config.toml deleted file mode 100644 index 874bf08c5..000000000 --- a/playground/UI/.chainlit/config.toml +++ /dev/null @@ -1,84 +0,0 @@ -[project] -# Whether to enable telemetry (default: true). No personal data is collected. -enable_telemetry = false - -# List of environment variables to be provided by each user to use the app. -user_env = [] - -# Duration (in seconds) during which the session is saved when the connection is lost -session_timeout = 3600 - -# Enable third parties caching (e.g LangChain cache) -cache = false - -# Follow symlink for asset mount (see https://github.com/Chainlit/chainlit/issues/317) -# follow_symlink = true - -[features] -# Show the prompt playground -prompt_playground = true - -# Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript) -unsafe_allow_html = true - -# Process and display mathematical expressions. This can clash with "$" characters in messages. -latex = false - -# Authorize users to upload files with messages -spontaneous_file_upload.enabled = true - -# Allows user to use speech to text -[features.speech_to_text] - enabled = false - # See all languages here https://github.com/JamesBrill/react-speech-recognition/blob/HEAD/docs/API.md#language-string - # language = "en-US" - -[UI] -# Name of the app and chatbot. -name = "TaskWeaver" - -# Show the readme while the conversation is empty. -show_readme_as_default = true - -# Description of the app and chatbot. This is used for HTML tags. -# description = "Chat with TaskWeaver" - -# Large size content are by default collapsed for a cleaner ui -default_collapse_content = false - -# The default value for the expand messages settings. -default_expand_messages = true - -# Hide the chain of thought details from the user in the UI. -hide_cot = false - -# Link to your github repo. This will add a github button in the UI's header. -# github = "https://github.com/microsoft/TaskWeaver" - -# Specify a CSS file that can be used to customize the user interface. -# The CSS file can be served from the public directory or via an external link. -custom_css = "/public/style_v1.css" - -# Override default MUI light theme. (Check theme.ts) -[UI.theme.light] - #background = "#FAFAFA" - #paper = "#FFFFFF" - - [UI.theme.light.primary] - #main = "#F80061" - #dark = "#980039" - #light = "#FFE7EB" - -# Override default MUI dark theme. (Check theme.ts) -[UI.theme.dark] - #background = "#FAFAFA" - #paper = "#FFFFFF" - - [UI.theme.dark.primary] - #main = "#F80061" - #dark = "#980039" - #light = "#FFE7EB" - - -[meta] -generated_by = "0.7.700" diff --git a/playground/UI/app.py b/playground/UI/app.py deleted file mode 100644 index 6a081c1a3..000000000 --- a/playground/UI/app.py +++ /dev/null @@ -1,462 +0,0 @@ -import atexit -import functools -import os -import re -import sys -from typing import Any, Dict, List, Optional, Tuple, Union - -import requests - -# change current directory to the directory of this file for loading resources -os.chdir(os.path.dirname(__file__)) - -try: - import chainlit as cl - - print( - "If UI is not started, please go to the folder playground/UI and run `chainlit run app.py` to start the UI", - ) -except Exception: - raise Exception( - "Package chainlit is required for using UI. Please install it manually by running: " - "`pip install chainlit` and then run `chainlit run app.py`", - ) - -repo_path = os.path.join(os.path.dirname(__file__), "../../") -sys.path.append(repo_path) -from taskweaver.app.app import TaskWeaverApp -from taskweaver.memory.attachment import AttachmentType -from taskweaver.memory.type_vars import RoleName -from taskweaver.module.event_emitter import PostEventType, RoundEventType, SessionEventHandlerBase -from taskweaver.session.session import Session - -project_path = os.path.join(repo_path, "project") -app = TaskWeaverApp(app_dir=project_path, use_local_uri=True) -atexit.register(app.stop) -app_session_dict: Dict[str, Session] = {} - - -def elem(name: str, cls: str = "", attr: Dict[str, str] = {}, **attr_dic: str): - all_attr = {**attr, **attr_dic} - if cls: - all_attr.update({"class": cls}) - - attr_str = "" - if len(all_attr) > 0: - attr_str += "".join(f' {k}="{v}"' for k, v in all_attr.items()) - - def inner(*children: str): - children_str = "".join(children) - return f"<{name}{attr_str}>{children_str}" - - return inner - - -def txt(content: str, br: bool = True): - content = content.replace("<", "<").replace(">", ">") - if br: - content = content.replace("\n", "
") - else: - content = content.replace("\n", " ") - return content - - -div = functools.partial(elem, "div") -span = functools.partial(elem, "span") -blinking_cursor = span("tw-end-cursor")() - - -def file_display(files: List[Tuple[str, str]], session_cwd_path: str): - elements: List[cl.Element] = [] - for file_name, file_path in files: - # if image, no need to display as another file - if file_path.endswith((".png", ".jpg", ".jpeg", ".gif")): - image = cl.Image( - name=file_path, - display="inline", - path=file_path if os.path.isabs(file_path) else os.path.join(session_cwd_path, file_path), - size="large", - ) - elements.append(image) - elif file_path.endswith((".mp3", ".wav", ".flac")): - audio = cl.Audio( - name="converted_speech", - display="inline", - path=file_path if os.path.isabs(file_path) else os.path.join(session_cwd_path, file_path), - ) - elements.append(audio) - else: - if file_path.endswith(".csv"): - import pandas as pd - - data = ( - pd.read_csv(file_path) - if os.path.isabs(file_path) - else pd.read_csv(os.path.join(session_cwd_path, file_path)) - ) - row_count = len(data) - table = cl.Text( - name=file_path, - content=f"There are {row_count} in the data. The top {min(row_count, 5)} rows are:\n" - + data.head(n=5).to_markdown(), - display="inline", - ) - elements.append(table) - else: - print(f"Unsupported file type: {file_name} for inline display.") - # download files from plugin context - file = cl.File( - name=file_name, - display="inline", - path=file_path if os.path.isabs(file_path) else os.path.join(session_cwd_path, file_path), - ) - elements.append(file) - return elements - - -def is_link_clickable(url: str): - if url: - try: - response = requests.get(url) - # If the response status code is 200, the link is clickable - return response.status_code == 200 - except requests.exceptions.RequestException: - return False - else: - return False - - -class ChainLitMessageUpdater(SessionEventHandlerBase): - def __init__(self, root_step: cl.Step): - self.root_step = root_step - self.reset_cur_step() - self.suppress_blinking_cursor() - - def reset_cur_step(self): - self.cur_step: Optional[cl.Step] = None - self.cur_attachment_list: List[Tuple[str, AttachmentType, str, bool]] = [] - self.cur_post_status: str = "Updating" - self.cur_send_to: RoleName = "Unknown" - self.cur_message: str = "" - self.cur_message_is_end: bool = False - self.cur_message_sent: bool = False - - def suppress_blinking_cursor(self): - cl.run_sync(self.root_step.stream_token("")) - if self.cur_step is not None: - cl.run_sync(self.cur_step.stream_token("")) - - def handle_round( - self, - type: RoundEventType, - msg: str, - extra: Any, - round_id: str, - **kwargs: Any, - ): - if type == RoundEventType.round_error: - self.root_step.is_error = True - self.root_step.output = msg - cl.run_sync(self.root_step.update()) - - def handle_post( - self, - type: PostEventType, - msg: str, - extra: Any, - post_id: str, - round_id: str, - **kwargs: Any, - ): - if type == PostEventType.post_start: - self.reset_cur_step() - self.cur_step = cl.Step(name=extra["role"], show_input=True, root=False) - cl.run_sync(self.cur_step.__aenter__()) - elif type == PostEventType.post_end: - assert self.cur_step is not None - content = self.format_post_body(True) - cl.run_sync(self.cur_step.stream_token(content, True)) - cl.run_sync(self.cur_step.__aexit__(None, None, None)) # type: ignore - self.reset_cur_step() - elif type == PostEventType.post_error: - pass - elif type == PostEventType.post_attachment_update: - assert self.cur_step is not None, "cur_step should not be None" - id: str = extra["id"] - a_type: AttachmentType = extra["type"] - is_end: bool = extra["is_end"] - # a_extra: Any = extra["extra"] - if len(self.cur_attachment_list) == 0 or id != self.cur_attachment_list[-1][0]: - self.cur_attachment_list.append((id, a_type, msg, is_end)) - - else: - prev_msg = self.cur_attachment_list[-1][2] - self.cur_attachment_list[-1] = (id, a_type, prev_msg + msg, is_end) - - elif type == PostEventType.post_send_to_update: - self.cur_send_to = extra["role"] - elif type == PostEventType.post_message_update: - self.cur_message += msg - if extra["is_end"]: - self.cur_message_is_end = True - elif type == PostEventType.post_status_update: - self.cur_post_status = msg - - if self.cur_step is not None: - content = self.format_post_body(False) - cl.run_sync(self.cur_step.stream_token(content, True)) - if self.cur_message_is_end and not self.cur_message_sent: - self.cur_message_sent = True - self.cur_step.elements = [ - *(self.cur_step.elements or []), - cl.Text( - content=self.cur_message, - display="inline", - ), - ] - cl.run_sync(self.cur_step.update()) - self.suppress_blinking_cursor() - - def get_message_from_user(self, prompt: str, timeout: int = 120) -> Optional[str]: - ask_user_msg = cl.AskUserMessage(content=prompt, author=" ", timeout=timeout) - res = cl.run_sync(ask_user_msg.send()) - cl.run_sync(ask_user_msg.remove()) - if res is not None: - res_msg = cl.Message.from_dict(res) - msg_txt = res_msg.content - cl.run_sync(res_msg.remove()) - return msg_txt - return None - - def get_confirm_from_user( - self, - prompt: str, - actions: List[Union[Tuple[str, str], str]], - timeout: int = 120, - ) -> Optional[str]: - cl_actions: List[cl.Action] = [] - for arg_action in actions: - if isinstance(arg_action, str): - cl_actions.append(cl.Action(name=arg_action, value=arg_action)) - else: - name, value = arg_action - cl_actions.append(cl.Action(name=name, value=value)) - ask_user_msg = cl.AskActionMessage(content=prompt, actions=cl_actions, author=" ", timeout=timeout) - res = cl.run_sync(ask_user_msg.send()) - cl.run_sync(ask_user_msg.remove()) - if res is not None: - for action in cl_actions: - if action.value == res["value"]: - return action.value - return None - - def format_post_body(self, is_end: bool) -> str: - content_chunks: List[str] = [] - - for attachment in self.cur_attachment_list: - a_type = attachment[1] - - # skip artifact paths always - if a_type in [AttachmentType.artifact_paths]: - continue - - # skip Python in final result - if is_end and a_type in [AttachmentType.reply_content]: - continue - - content_chunks.append(self.format_attachment(attachment)) - - if self.cur_message != "": - if self.cur_send_to == "Unknown": - content_chunks.append("**Message**:") - else: - content_chunks.append(f"**Message To {self.cur_send_to}**:") - - if not self.cur_message_sent: - content_chunks.append( - self.format_message(self.cur_message, self.cur_message_is_end), - ) - - if not is_end: - content_chunks.append( - div("tw-status")( - span("tw-status-updating")( - elem("svg", viewBox="22 22 44 44")(elem("circle")()), - ), - span("tw-status-msg")(txt(self.cur_post_status + "...")), - ), - ) - - return "\n\n".join(content_chunks) - - def format_attachment( - self, - attachment: Tuple[str, AttachmentType, str, bool], - ) -> str: - id, a_type, msg, is_end = attachment - header = div("tw-atta-header")( - div("tw-atta-key")( - " ".join([item.capitalize() for item in a_type.value.split("_")]), - ), - div("tw-atta-id")(id), - ) - atta_cnt: List[str] = [] - - if a_type in [AttachmentType.plan, AttachmentType.init_plan]: - items: List[str] = [] - lines = msg.split("\n") - for idx, row in enumerate(lines): - item = row - if "." in row and row.split(".")[0].isdigit(): - item = row.split(".", 1)[1].strip() - items.append( - div("tw-plan-item")( - div("tw-plan-idx")(str(idx + 1)), - div("tw-plan-cnt")( - txt(item), - blinking_cursor if not is_end and idx == len(lines) - 1 else "", - ), - ), - ) - atta_cnt.append(div("tw-plan")(*items)) - elif a_type in [AttachmentType.execution_result]: - atta_cnt.append( - elem("pre", "tw-execution-result")( - elem("code")(txt(msg)), - ), - ) - elif a_type in [AttachmentType.reply_content]: - atta_cnt.append( - elem("pre", "tw-python", {"data-lang": "python"})( - elem("code", "language-python")(txt(msg, br=False)), - ), - ) - else: - atta_cnt.append(txt(msg)) - if not is_end: - atta_cnt.append(blinking_cursor) - - return div("tw-atta")( - header, - div("tw-atta-cnt")(*atta_cnt), - ) - - def format_message(self, message: str, is_end: bool) -> str: - content = txt(message, br=False) - begin_regex = re.compile(r"^```(\w*)$\n", re.MULTILINE) - end_regex = re.compile(r"^```$\n?", re.MULTILINE) - - if not is_end: - end_tag = " " + blinking_cursor - else: - end_tag = "" - - while True: - start_label = begin_regex.search(content) - if not start_label: - break - start_pos = content.index(start_label[0]) - lang_tag = start_label[1] - content = "".join( - [ - content[:start_pos], - f'
',
-                    content[start_pos + len(start_label[0]) :],
-                ],
-            )
-
-            end_pos = end_regex.search(content)
-            if not end_pos:
-                content += end_tag + "
" - end_tag = "" - break - end_pos_pos = content.index(end_pos[0]) - content = f"{content[:end_pos_pos]}{content[end_pos_pos + len(end_pos[0]):]}" - - content += end_tag - return content - - -@cl.on_chat_start -async def start(): - user_session_id = cl.user_session.get("id") - app_session_dict[user_session_id] = app.get_session() - print("Starting new session") - - -@cl.on_chat_end -async def end(): - user_session_id = cl.user_session.get("id") - app_session = app_session_dict[user_session_id] - print(f"Stopping session {app_session.session_id}") - app_session.stop() - app_session_dict.pop(user_session_id) - - -@cl.on_message -async def main(message: cl.Message): - user_session_id = cl.user_session.get("id") # type: ignore - session: Session = app_session_dict[user_session_id] # type: ignore - session_cwd_path = session.execution_cwd - - # display loader before sending message - async with cl.Step(name="", show_input=True, root=True) as root_step: - response_round = await cl.make_async(session.send_message)( - message.content, - files=[ - { - "name": element.name if element.name else "file", - "path": element.path, - } - for element in message.elements - if element.type == "file" or element.type == "image" - ], - event_handler=ChainLitMessageUpdater(root_step), - ) - - artifact_paths = [ - p - for p in response_round.post_list - for a in p.attachment_list - if a.type == AttachmentType.artifact_paths - for p in a.content - ] - - for post in [p for p in response_round.post_list if p.send_to == "User"]: - files: List[Tuple[str, str]] = [] - if len(artifact_paths) > 0: - for file_path in artifact_paths: - # if path is image or csv (the top 5 rows), display it - file_name = os.path.basename(file_path) - files.append((file_name, file_path)) - - # Extract the file path from the message and display it - user_msg_content = post.message - pattern = r"(!?)\[(.*?)\]\((.*?)\)" - matches = re.findall(pattern, user_msg_content) - for match in matches: - img_prefix, file_name, file_path = match - if "://" in file_path: - if not is_link_clickable(file_path): - user_msg_content = user_msg_content.replace( - f"{img_prefix}[{file_name}]({file_path})", - file_name, - ) - continue - files.append((file_name, file_path)) - user_msg_content = user_msg_content.replace( - f"{img_prefix}[{file_name}]({file_path})", - file_name, - ) - elements = file_display(files, session_cwd_path) - await cl.Message( - author="TaskWeaver", - content=f"{user_msg_content}", - elements=elements if len(elements) > 0 else None, - ).send() - - -if __name__ == "__main__": - from chainlit.cli import run_chainlit - - run_chainlit(__file__) diff --git a/playground/UI/chainlit.md b/playground/UI/chainlit.md deleted file mode 100644 index 4eae7eafc..000000000 --- a/playground/UI/chainlit.md +++ /dev/null @@ -1,16 +0,0 @@ -# Welcome to *TaskWeaver* ! - -*Hi there, User! 👋 We're excited to have you on board.* - -TaskWeaver is a code-first agent framework for seamlessly planning and executing data analytics tasks. This innovative framework interprets user requests through coded snippets and efficiently coordinates a variety of plugins in the form of functions to execute data analytics tasks. It supports key Features like: rich data structure, customized algorithms, incorporating domain-specific knowledge, stateful conversation, code verification, easy to use, debug and extend. - -## Useful Links 🔗 - -- **Quick Start:** Quick start TaskWeaver with [README](https://github.com/microsoft/TaskWeaver?tab=readme-ov-file#-quick-start) ✨ -- **Advanced Configurations:** Get started with our [TaskWeaver Documents](https://microsoft.github.io/TaskWeaver/) 📚 -- **Technical Report:** Check out our [TaskWeaver Report](https://export.arxiv.org/abs/2311.17541) for more details! 📖 -- **Discord Channel:** Join the TaskWeaver [Discord Channel](https://discord.gg/Z56MXmZgMb) for discussions 💬 - -We can't wait to see what you create with TaskWeaver! - -**Start the Conversation!** diff --git a/playground/UI/public/favicon.ico b/playground/UI/public/favicon.ico deleted file mode 100644 index be759b29740d763d47bc4a2f11ed76b55cf0a3a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67646 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 HPN)AL!HJ`O diff --git a/playground/UI/public/logo_dark.png b/playground/UI/public/logo_dark.png deleted file mode 100644 index 5e4eaa009328352b823b61c930aa72ae5dba3491..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65635 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 diff --git a/playground/UI/public/logo_light.png b/playground/UI/public/logo_light.png deleted file mode 100644 index 5e4eaa009328352b823b61c930aa72ae5dba3491..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65635 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 diff --git a/playground/UI/public/style_v1.css b/playground/UI/public/style_v1.css deleted file mode 100644 index 65758fb8b..000000000 --- a/playground/UI/public/style_v1.css +++ /dev/null @@ -1,192 +0,0 @@ -img[alt='logo'] { - max-height: 40px !important; - display: inline-block; -} - -.post { - border: 1px solid #ccc; - padding: 10px; - margin-bottom: 10px; - max-width: 800px; -} -.markdown-body { - padding-left: 10px; - padding-right: 10px; -} - -.tw-atta { - display: block; - border: solid 2px #aaa5; - border-radius: 10px; - background-color: #fff4; - overflow: hidden; - box-shadow: 0 0 10px 2px #ccc5; - margin: 10px 0; -} - -.tw-atta-header { - height: 20px; - border-bottom: solid 2px #aaa5; - padding: 5px 10px; - background-color: #5090ff55; - font-weight: 500; - display: flex; -} - -.tw-atta-key { - flex: 1; -} -.tw-atta-id { - opacity: 0.3; - font-size: 0.8em; -} - -.tw-atta-cnt { - padding: 10px 20px; -} - -.markdown-body .tw-plan { - position: relative; -} -div.markdown-body div.tw-plan::before { - content: ''; - display: block; - width: 4px; - height: calc(100% + 20px); - position: absolute; - background-color: #eee; - top: -10px; - left: 15px; -} - -div.markdown-body div.tw-plan-item { - display: flex; -} - -.markdown-body div.tw-plan-idx { - flex: 0 0 20px; - position: relative; - width: 20px; - height: 20px; - border-radius: 12px; - text-align: center; - line-height: 20px; - border: solid 2px #a0c0ff; - background-color: #c0e0ff; - margin: 5px !important; - margin-top: 5px; - font-weight: 500; - color: #555; -} - -.markdown-body div.tw-plan-cnt { - margin: 5px 10px; - margin-top: 5px; -} - -.markdown-body .tw-status { - display: inline-block; - padding: 5px 10px; - border-radius: 3px; - font-size: 14px; - line-height: 20px; - font-weight: 500; - color: #555; - white-space: nowrap; - background-color: #eee; - min-width: 120px; - margin: 10px; -} - -.markdown-body .tw-status-msg { - margin: 10px; - padding: 0; - height: 20px; -} - -/* Updater spinner (adopted from MUI for align with Chainlit) */ -@keyframes tw-updating-status-ani-dash { - 0% { - stroke-dasharray: 1px, 200px; - stroke-dashoffset: 0; - } - - 50% { - stroke-dasharray: 100px, 200px; - stroke-dashoffset: -15px; - } - - 100% { - stroke-dasharray: 100px, 200px; - stroke-dashoffset: -125px; - } -} - -@keyframes tw-updating-status-ani-circle { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } -} - -.markdown-body .tw-status-updating { - width: 20px; - height: 20px; - display: inline-block; - color: #aaa; - animation: 1.4s linear 0s infinite normal none running - tw-updating-status-ani-circle; -} - -.markdown-body .tw-status-updating svg { - display: block; -} - -.markdown-body .tw-status-updating svg circle { - stroke: currentColor; - stroke-dasharray: 80px, 200px; - stroke-dashoffset: 0; - stroke-width: 4; - fill: none; - r: 20; - cx: 44; - cy: 44; - animation: tw-updating-status-ani-dash 1.4s ease-in-out infinite; -} - -@keyframes tw-blinking-dot { - 0% { - opacity: 0.2; - } - - 20% { - opacity: 1; - } - - 100% { - opacity: 0.2; - } -} - -span.tw-end-cursor { - content: ''; - display: inline-flex; - width: 10px; - border-radius: 5px; - margin-left: 10px; -} - -span.tw-end-cursor::after { - content: ''; - position: relative; - display: block; - width: 10px; - height: 10px; - border-radius: 5px; - background-color: #a0c0ff; - margin: auto; - animation: tw-blinking-dot 0.7s ease-in-out infinite; -} diff --git a/project/taskweaver_config.json b/project/taskweaver_config.json deleted file mode 100644 index 7a17b3d89..000000000 --- a/project/taskweaver_config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "llm.api_base": "https://api.openai.com/v1", - "llm.api_key": "", - "llm.model": "gpt-4-1106-preview" -} \ No newline at end of file diff --git a/project/taskweaver_config.json.example b/project/taskweaver_config.json.example new file mode 100644 index 000000000..24d30a9b6 --- /dev/null +++ b/project/taskweaver_config.json.example @@ -0,0 +1,6 @@ +{ + "llm.api_type": "openai", + "llm.api_base": "https://api.openai.com/v1", + "llm.api_key": "YOUR_API_KEY", + "llm.model": "gpt-4" +} diff --git a/taskweaver/cli/web.py b/taskweaver/cli/web.py deleted file mode 100644 index b05b8e4c7..000000000 --- a/taskweaver/cli/web.py +++ /dev/null @@ -1,54 +0,0 @@ -import click - -from taskweaver.cli.util import require_workspace - - -@click.command() -@require_workspace() -@click.option( - "--host", - "-h", - default="localhost", - help="Host to run TaskWeaver web server", - type=str, - show_default=True, -) -@click.option("--port", "-p", default=8080, help="Port to run TaskWeaver web server", type=int, show_default=True) -@click.option( - "--debug", - "-d", - is_flag=True, - default=False, - help="Run TaskWeaver web server in debug mode", - show_default=True, -) -@click.option( - "--open/--no-open", - "-o/-n", - is_flag=True, - default=True, - help="Open TaskWeaver web server in browser", - show_default=True, -) -def web(host: str, port: int, debug: bool, open: bool): - """Start TaskWeaver web server""" - - from taskweaver.chat.web import start_web_service - - if not debug: - # debug mode will restart app iteratively, skip the plugin listing - # display_enabled_examples_plugins() - pass - - def post_app_start(): - if open: - click.secho("launching web browser...", fg="green") - open_url = f"http://{'localhost' if host == '0.0.0.0' else host}:{port}" - click.launch(open_url) - - start_web_service( - host, - port, - is_debug=debug, - post_app_start=post_app_start if open else None, - ) diff --git a/website/docs/quickstart.md b/website/docs/quickstart.md index e5b89ad8c..5ab018828 100644 --- a/website/docs/quickstart.md +++ b/website/docs/quickstart.md @@ -37,7 +37,9 @@ A project directory typically contains the following files and folders: ## OpenAI Configuration Before running TaskWeaver, you need to provide your OpenAI API key and other necessary information. -You can do this by editing the `taskweaver_config.json` file. +You can do this by creating a `taskweaver_config.json` file in your project directory. +A template file `taskweaver_config.json.example` is provided - copy it to `taskweaver_config.json` and fill in your credentials. + If you are using Azure OpenAI, you need to set the following parameters in the `taskweaver_config.json` file: ### Azure OpenAI ```json @@ -83,6 +85,5 @@ Human: ___ ``` There are other ways to start TaskWeaver: -- [A Chainlit UI interface](./usage/webui.md): TaskWeaver provides an experimental web-based interface to interact with the system. - [A Library](./usage/library.md): You can also use TaskWeaver as a library in your Python code. - [The all-in-one Docker image](./usage/docker.md): We provide a Docker image that contains all the dependencies to run TaskWeaver. diff --git a/website/docs/usage/webui.md b/website/docs/usage/webui.md deleted file mode 100644 index d1c31daaa..000000000 --- a/website/docs/usage/webui.md +++ /dev/null @@ -1,36 +0,0 @@ -# Web UI - -:::warning -Please note that this Web UI is a playground for development and testing purposes only. -Be cautious when running the Web UI, as anyone can access it if the port is open to the public. -If you want to deploy a Web UI for production, you need to address security concerns, such as authentication and authorization, -making sure the server is secure. -::: - -Follow the instruction in [Quick Start](../quickstart.md) to clone the repository and fill in the necessary configurations. - -Install the `chainlit` package by `pip install -U "chainlit<1.1.300"` if you don't have it in your environment. - -:::note -Chainlit has a major update in version 1.1.300 that may cause compatibility issues. -Please make sure you have the correct version installed. -::: - -Start the service by running the following command. - - -```bash -# assume you are in the TaskWeaver folder -cd playground/UI/ -# make sure you are in playground/UI/ folder -chainlit run app.py -``` - -Open the browser with http://localhost:8000 if it doesn't open automatically. -:::info -We now support uploading files using the Web UI. -::: -Below are some screenshots of the Web UI: -![TaskWeaver UI Screenshot 1](../../static/img/ui_screenshot_1.png) -![TaskWeaver UI Screenshot 2](../../static/img/ui_screenshot_2.png) - diff --git a/website/sidebars.js b/website/sidebars.js index 577af653c..1d60a040c 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -60,7 +60,6 @@ const sidebars = { collapsed: false, items: [ 'usage/cmd', - 'usage/webui', 'usage/library', 'usage/docker', ], diff --git a/website/static/img/ui_screenshot_1.png b/website/static/img/ui_screenshot_1.png deleted file mode 100644 index 0726254b762936bdf44c32ab22a5c8072b100475..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95022 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�pj9O|8tT=pR}`|+f3Dpt2E*f*<&EK#*@YI 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®dH5 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 From ff4ce8321597d12ff4d257bc1eec435d758b60a9 Mon Sep 17 00:00:00 2001 From: liqun Date: Mon, 26 Jan 2026 14:17:15 +0800 Subject: [PATCH 4/5] add user confirmation before code execution --- docs/design/threading_model.md | 332 ++++++++++++++++-- taskweaver/chat/console/chat.py | 116 +++++- .../code_interpreter/code_interpreter.py | 22 ++ taskweaver/module/event_emitter.py | 98 ++++++ taskweaver/planner/planner_prompt.yaml | 6 +- .../test_animation_pause_handshake.py | 230 ++++++++++++ .../test_event_emitter_confirmation.py | 189 ++++++++++ 7 files changed, 961 insertions(+), 32 deletions(-) create mode 100644 tests/unit_tests/test_animation_pause_handshake.py create mode 100644 tests/unit_tests/test_event_emitter_confirmation.py diff --git a/docs/design/threading_model.md b/docs/design/threading_model.md index 23c3e207d..4048c968f 100644 --- a/docs/design/threading_model.md +++ b/docs/design/threading_model.md @@ -20,6 +20,8 @@ These threads communicate via an **event-driven architecture** using a shared up │ │ TaskWeaverChatApp.run() │ │ │ │ └── _handle_message(input) │ │ │ │ └── TaskWeaverRoundUpdater.handle_message() │ │ +│ │ ├── Polls for confirmation requests │ │ +│ │ └── Handles user confirmation input │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌───────────────┴───────────────┐ │ @@ -31,7 +33,11 @@ These threads communicate via an **event-driven architecture** using a shared up │ │ ├── Planner.reply() │ │ ├── Process updates │ │ │ │ ├── CodeInterpreter │ │ ├── Render status bar │ │ │ │ │ .reply() │ │ ├── Display messages │ │ -│ │ └── Event emission ──────┼───┼──► └── Animate spinner │ │ +│ │ │ ├── generate code │ │ ├── Animate spinner │ │ +│ │ │ ├── verify code │ │ └── Pause on confirm │ │ +│ │ │ ├── WAIT confirm ◄─┼───┼──────────────────────────── │ │ +│ │ │ └── execute code │ │ │ │ +│ │ └── Event emission ──────┼───┼──► pending_updates queue │ │ │ │ │ │ │ │ │ └─────────────────────────────┘ └─────────────────────────────┘ │ │ │ │ │ @@ -56,6 +62,11 @@ class TaskWeaverRoundUpdater(SessionEventHandlerBase): self.lock = threading.Lock() # Protects shared state self.pending_updates: List[Tuple[str, str]] = [] # Event queue + + # Pause/resume handshake for animation thread + self.pause_animation = threading.Event() # Main requests pause + self.animation_paused = threading.Event() # Animation acknowledges pause + self.result: Optional[str] = None ``` @@ -137,11 +148,26 @@ def handle_message(self, session, message, files): ## Animation Thread Details -The animation thread (`_animate_thread`) runs a continuous loop: +The animation thread (`_animate_thread`) runs a continuous loop with confirmation-aware synchronization: ```python def _animate_thread(self): while True: + # Check if pause is requested FIRST, before any output + if self.pause_animation.is_set(): + # Signal that animation has paused + self.animation_paused.set() + # Wait until pause is lifted + while self.pause_animation.is_set(): + if self.exit_event.is_set(): + break + with self.update_cond: + self.update_cond.wait(0.1) + continue + + # Animation is running, clear the paused signal + self.animation_paused.clear() + clear_line() # Process all pending updates atomically @@ -151,24 +177,20 @@ def _animate_thread(self): # Display role header: ╭───< Planner > elif action == "end_post": # Display completion: ╰──● sending to User - elif action == "attachment_start": - # Begin attachment display - elif action == "attachment_add": - # Append to current attachment - elif action == "attachment_end": - # Finalize and render attachment - elif action == "status_update": - # Update status message + # ... other actions self.pending_updates.clear() if self.exit_event.is_set(): break + # Check again before printing status line + if self.pause_animation.is_set(): + continue + # Display animated status bar - # " TaskWeaver ▶ [Planner] generating code <=💡=>" display_status_bar(role, status, get_ani_frame(counter)) - # Rate limit animation (~30Hz visual, 5Hz animation) + # Rate limit animation with self.update_cond: self.update_cond.wait(0.2) ``` @@ -194,9 +216,11 @@ def _animate_thread(self): | Primitive | Purpose | |-----------|---------| -| `threading.Lock` | Protects `pending_updates` queue during read/write | -| `threading.Event` | Signals execution completion (`exit_event`) | -| `threading.Condition` | Wakes animation thread when updates available | +| `threading.Lock` (`lock`) | Protects `pending_updates` queue during read/write | +| `threading.Event` (`exit_event`) | Signals execution completion | +| `threading.Event` (`pause_animation`) | Main requests animation to pause | +| `threading.Event` (`animation_paused`) | Animation acknowledges it has paused | +| `threading.Condition` (`update_cond`) | Wakes animation thread when updates available | ### Critical Sections @@ -246,16 +270,36 @@ def _stream_smoother(self, stream_init): ## Thread Lifecycle ``` -Time ──────────────────────────────────────────────────────────► +Time ──────────────────────────────────────────────────────────────────────────────────► + +Main ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████████████░░░░░░░░░░░░░░░░░████████████████ + spawn wait(exit_event) confirm? wait confirm? join + +Execution ░░░░██████████████████████████████░░░░░░░░░░░░██████████████████░░░░░░░░░░░░░░ + Planner → CodeInterpreter WAIT(cond) continue→result + +Animation ░░░░██░██░██░██░██░██░██░██░██░██░░░░░░░░░░░░░██░██░██░██░██░██░░░░░░░░░░░░░░░ + render → sleep → render PAUSED resume → render + +Legend: █ = active, ░ = waiting/idle +``` + +### With Confirmation Flow -Main ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░████████████ - spawn wait(exit_event) join threads +``` +Time ──────────────────────────────────────────────────────────────────► -Execution ░░░░████████████████████████████████████████░░░░░░░░░░ - send_message() → Planner → CodeInterpreter → result +Main ████░░░░░░░░░░░░░░░░████████████████░░░░░░░░░░░░████████████████ + spawn polling show code polling join + get input -Animation ░░░░██░██░██░██░██░██░██░██░██░██░██░██░██░░░░░░░░░░░░ - render → sleep(0.2) → render → sleep → render +Execution ░░░░██████████████████░░░░░░░░░░░░░██████████████░░░░░░░░░░░░░░ + generate code BLOCKED execute code done + request confirm (waiting) (if approved) + +Animation ░░░░██░██░██░██░██░░░░░░░░░░░░░░░░░░██░██░██░██░░░░░░░░░░░░░░░░ + animate STOPPED resume + (no output) animation Legend: █ = active, ░ = waiting/idle ``` @@ -312,12 +356,243 @@ def execution_thread(): | Web/API | Single thread per request | WebSocket/SSE streaming | | Programmatic | Caller's thread | Event callbacks | +## Animation Pause Handshake Pattern + +The console UI uses a simple, extensible handshake pattern to temporarily pause animation output when exclusive console access is needed. + +### The Pattern + +```python +# Two events form the handshake +pause_animation = threading.Event() # Request: "please pause" +animation_paused = threading.Event() # Acknowledgment: "I have paused" +``` + +### How It Works + +**Requester (main thread or any code needing exclusive console):** +```python +# 1. Request pause +self.pause_animation.set() + +# 2. Wait for acknowledgment +self.animation_paused.wait() + +# 3. Safe to use console exclusively +do_exclusive_console_work() + +# 4. Release +self.animation_paused.clear() +self.pause_animation.clear() +``` + +**Animation thread (responder):** +```python +while True: + # Check at START of loop, before any output + if self.pause_animation.is_set(): + self.animation_paused.set() # Acknowledge + while self.pause_animation.is_set(): # Wait for release + wait() + continue + + self.animation_paused.clear() # Signal "I'm running" + do_animation_output() +``` + +### Timing Diagram + +``` +Main Thread Animation Thread +─────────── ──────────────── + [Loop start] + pause_animation? → NO + Clear animation_paused + Print status line... +Set pause_animation ─────────────────────────────────────────► +Wait for animation_paused [Loop start] + │ pause_animation? → YES + │ Set animation_paused + ◄────────────────────────────────────────────────────┘ +(wait returns) Wait in loop... +Show prompt, get input (no output) +Clear animation_paused +Clear pause_animation ───────────────────────────────────────► + [Loop continues] + pause_animation? → NO + Resume output +``` + +### Why This Pattern + +1. **Simple**: Two events, clear semantics +2. **Safe**: Animation always checks before output +3. **Extensible**: Any code can use it, not just confirmation +4. **No locks needed**: Handshake guarantees ordering + +### Current Usage + +| Feature | Uses Handshake | +|---------|----------------| +| Code confirmation prompt | ✓ | +| (Future) Interactive debugging | Can use same pattern | +| (Future) Multi-line input | Can use same pattern | + +### Adding New Features + +To add a new feature that needs exclusive console access: + +```python +def my_new_feature(self): + # Pause animation + self.pause_animation.set() + self.animation_paused.wait(timeout=5.0) + + try: + # Your exclusive console work here + result = get_user_input() + finally: + # Always release, even on error + self.animation_paused.clear() + self.pause_animation.clear() + + return result +``` + +--- + +## Code Execution Confirmation + +When `code_interpreter.require_confirmation` is enabled, TaskWeaver will pause before executing generated code to get user confirmation. + +### Confirmation Flow + +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Execution Thread│ │ Main Thread │ │Animation Thread │ +└────────┬────────┘ └────────┬────────┘ └────────┬────────┘ + │ │ │ + │ generate code │ │ [Loop start] + │ verify code │ │ Check confirmation_active + │ │ │ → false, continue + │ │ │ Clear animation_stopped + │ │ │ Acquire output_lock + │ │ │ Print status line + │ │ │ Release output_lock + │ │ │ │ + │ set _confirmation_event│ │ [Loop start] + │ emit confirmation_req │ │ Check confirmation_active + │ WAIT on _confirm_cond ─┼────────────────────────┼─→ true! + │ (blocked) │ │ Set animation_stopped ◄──┐ + │ │ detect confirmation │ Wait in loop │ + │ │ set confirmation_active│ │ + │ │ wait animation_stopped ─────────────────────────────┘ + │ │ acquire output_lock │ (cannot acquire lock) + │ │ clear line, show code │ │ + │ │ get user input [y/N] │ │ (waiting) + │ │ show result │ │ + │ │ release output_lock │ │ + │ │ clear animation_stopped│ │ + │ │ clear confirmation_active │ + │ │ set _confirmation_result │ + │ │ notify _confirm_cond │ │ + │ ◄──────────────────────┼────────────────────────┤ │ + │ (unblocked) │ │ [Loop continues] + │ read & clear result │ │ confirmation_active=false + │ │ │ Resume normal animation + │ if approved: │ │ │ + │ execute code │ │ │ + │ else: │ │ │ + │ cancel execution │ │ │ + ▼ ▼ ▼ +``` + +### Configuration + +Enable confirmation in your `taskweaver_config.json`: + +```json +{ + "code_interpreter.require_confirmation": true +} +``` + +### Synchronization Primitives + +The confirmation system uses a two-level synchronization approach to prevent race conditions where the animation thread could overwrite user input: + +#### Event Emitter Primitives (in `SessionEventEmitter`) + +| Primitive | Set By | Cleared By | Purpose | +|-----------|--------|------------|---------| +| `_confirmation_event` | Execution thread | Main thread | Signals that confirmation is pending | +| `_confirmation_cond` | Main thread | - | Condition variable for blocking/waking execution thread | +| `_confirmation_result` | Main thread | Execution thread | Stores user's decision (True/False) | + +#### Console UI Primitives (in `TaskWeaverRoundUpdater`) + +| Primitive | Set By | Cleared By | Purpose | +|-----------|--------|------------|---------| +| `pause_animation` | Main thread | Main thread | Requests animation to pause | +| `animation_paused` | Animation thread | Main thread | Confirms animation has paused | + +### Thread Responsibilities + +**Execution Thread:** +- Sets `_confirmation_event` when code needs confirmation +- Emits `post_confirmation_request` event +- Waits on `_confirmation_cond` until user responds +- Reads and clears `_confirmation_result` + +**Main Thread (`_handle_confirmation`):** +1. Sets `pause_animation` to signal animation thread +2. Waits for `animation_paused` to ensure animation has paused +3. Displays code and gets user input (safe from interference) +4. Clears `animation_paused` and `pause_animation` +5. Sets `_confirmation_result` and notifies `_confirmation_cond` + +**Animation Thread (`_animate_thread`):** +1. Checks `pause_animation` at **start of each loop iteration** +2. If set: sets `animation_paused` and waits in a loop until `pause_animation` cleared +3. If not set: clears `animation_paused` and proceeds with output + +### Why This Design Prevents Race Conditions + +The handshake guarantees animation has stopped before main thread shows the prompt: + +``` +Animation Thread Main Thread +──────────────── ─────────── +[Loop iteration] +Check pause_animation → false +Clear animation_paused +Print status line + Set pause_animation + Wait for animation_paused +[Next loop iteration] +Check pause_animation → TRUE +Set animation_paused ───────────────────► animation_paused.wait() returns +Wait in loop Show prompt, get input +(no output) Clear animation_paused + Clear pause_animation +Check pause_animation → false +Resume normal operation +``` + +### Key Implementation Points + +1. **Early check**: Animation thread checks `pause_animation` at the **very start** of its loop, before any output operations +2. **Explicit acknowledgment**: `animation_paused` confirms animation has paused (not just signaled to pause) +3. **Clean display**: Main thread clears any leftover animation before showing code +4. **Extensible**: Any code needing exclusive console access can use the same handshake + ## File References | File | Component | |------|-----------| -| `chat/console/chat.py` | `TaskWeaverRoundUpdater`, `_animate_thread` | -| `module/event_emitter.py` | `SessionEventEmitter`, `TaskWeaverEvent`, `PostEventProxy` | +| `chat/console/chat.py` | `TaskWeaverRoundUpdater`, `_animate_thread`, `_handle_confirmation` | +| `module/event_emitter.py` | `SessionEventEmitter`, `TaskWeaverEvent`, `PostEventProxy`, `ConfirmationHandler` | +| `code_interpreter/code_interpreter/code_interpreter.py` | `CodeInterpreter.reply()` (confirmation request) | | `llm/__init__.py` | `_stream_smoother` (LLM streaming) | | `ces/manager/defer.py` | `deferred_var` (kernel warm-up) | @@ -328,3 +603,12 @@ TaskWeaver's console interface uses a clean dual-thread model: - **Animation thread**: Consumes events and renders real-time console output Communication happens via an event queue (`pending_updates`) protected by a lock, with a condition variable for efficient wake-up. This design provides responsive UI feedback during long-running AI operations while maintaining clean separation of concerns. + +### Animation Pause Handshake + +When exclusive console access is needed (e.g., confirmation prompts), use the handshake: +1. Set `pause_animation` → wait for `animation_paused` +2. Do exclusive work +3. Clear `animation_paused` → clear `pause_animation` + +This pattern is simple, safe, and extensible to future features. diff --git a/taskweaver/chat/console/chat.py b/taskweaver/chat/console/chat.py index b7125425b..9cb6937a2 100644 --- a/taskweaver/chat/console/chat.py +++ b/taskweaver/chat/console/chat.py @@ -9,7 +9,13 @@ import click -from taskweaver.module.event_emitter import PostEventType, RoundEventType, SessionEventHandlerBase, SessionEventType +from taskweaver.module.event_emitter import ( + ConfirmationHandler, + PostEventType, + RoundEventType, + SessionEventHandlerBase, + SessionEventType, +) if TYPE_CHECKING: from taskweaver.memory.attachment import AttachmentType @@ -65,7 +71,30 @@ def user_input_message(prompt: str = " Human ") -> str: continue -class TaskWeaverRoundUpdater(SessionEventHandlerBase): +def user_confirmation_input(prompt: str = "Execute code? [y/N]: ") -> str: + import prompt_toolkit + + session = prompt_toolkit.PromptSession[str]( + multiline=False, + ) + + while True: + try: + user_input: str = session.prompt( + prompt_toolkit.formatted_text.FormattedText( + [ + ("bg:ansiyellow fg:ansiblack", " Confirm "), + ("fg:ansiyellow", "▶"), + ("", f" {prompt}"), + ], + ), + ) + return user_input.strip().lower() + except KeyboardInterrupt: + return "n" + + +class TaskWeaverRoundUpdater(SessionEventHandlerBase, ConfirmationHandler): def __init__(self): self.exit_event = threading.Event() self.update_cond = threading.Condition() @@ -74,10 +103,23 @@ def __init__(self): self.last_attachment_id = "" self.pending_updates: List[Tuple[str, str]] = [] + # Handshake pair for pausing animation (e.g., during confirmation prompts) + self.pause_animation = threading.Event() # Main requests pause + self.animation_paused = threading.Event() # Animation acknowledges pause + self.animation_paused.set() # Initially paused (not animating yet) + self.messages: List[Tuple[str, str]] = [] self.response: List[str] = [] self.result: Optional[str] = None + def request_confirmation( + self, + code: str, + round_id: str, + post_id: Optional[str], + ) -> bool: + return True + def handle_session( self, type: SessionEventType, @@ -153,6 +195,8 @@ def handle_message( message: str, files: List[Dict[Literal["name", "path", "content"], str]], ) -> Optional[str]: + session.event_emitter.confirmation_handler = self + def execution_thread(): try: round = session.send_message( @@ -171,7 +215,7 @@ def execution_thread(): with self.update_cond: self.update_cond.notify_all() - t_ui = threading.Thread(target=lambda: self._animate_thread(), daemon=True) + t_ui = threading.Thread(target=lambda: self._animate_thread(session), daemon=True) t_ex = threading.Thread(target=execution_thread, daemon=True) t_ui.start() @@ -179,6 +223,10 @@ def execution_thread(): exit_no_wait: bool = False try: while True: + if session.event_emitter.confirmation_pending: + self._handle_confirmation(session) + continue + self.exit_event.wait(0.1) if self.exit_event.is_set(): break @@ -186,7 +234,6 @@ def execution_thread(): error_message("Interrupted by user") exit_no_wait = True - # keyboard interrupt leave the session in unknown state, exit directly exit(1) finally: self.exit_event.set() @@ -200,8 +247,45 @@ def execution_thread(): return self.result - def _animate_thread(self): - # get terminal width + def _handle_confirmation(self, session: Session) -> None: + from colorama import ansi + + # Signal animation thread to pause + self.pause_animation.set() + + # Wait for animation thread to acknowledge it has paused + self.animation_paused.wait(timeout=5.0) + + # Clear any leftover animation output + print(ansi.clear_line(), end="\r") + + code = session.event_emitter.pending_confirmation_code or "" + + # Display code in a style consistent with the UI + click.secho( + click.style(" ├─► ", fg="blue") + + click.style("[", fg="blue") + + click.style("confirm", fg="bright_cyan") + + click.style("]", fg="blue"), + ) + for line in code.split("\n"): + click.secho(click.style(" │ ", fg="blue") + click.style(line, fg="bright_black")) + + response = user_confirmation_input() + approved = response in ("y", "yes") + + if approved: + click.secho(click.style(" │ ", fg="blue") + click.style("✓ approved", fg="green")) + else: + click.secho(click.style(" │ ", fg="blue") + click.style("✗ cancelled", fg="red")) + + # Allow animation thread to resume + self.animation_paused.clear() + self.pause_animation.clear() + + session.event_emitter.provide_confirmation(approved) + + def _animate_thread(self, session: Session): terminal_column = shutil.get_terminal_size().columns counter = 0 status_msg = "preparing" @@ -306,6 +390,22 @@ def format_status_message(limit: int): last_time = 0 while True: + # Check if we should pause FIRST, before any output + if self.pause_animation.is_set(): + # Signal that animation has paused + self.animation_paused.set() + # Wait until pause is lifted + while self.pause_animation.is_set(): + if self.exit_event.is_set(): + break + with self.update_cond: + self.update_cond.wait(0.1) + # Reset for next iteration + continue + + # Animation is running, clear the paused signal + self.animation_paused.clear() + clear_line() with self.lock: for action, opt in self.pending_updates: @@ -367,6 +467,10 @@ def format_status_message(limit: int): if self.exit_event.is_set(): break + # Check again before printing status line + if self.pause_animation.is_set(): + continue + cur_message_prefix: str = " TaskWeaver " cur_ani_frame = get_ani_frame(counter) cur_message_display_len = ( diff --git a/taskweaver/code_interpreter/code_interpreter/code_interpreter.py b/taskweaver/code_interpreter/code_interpreter/code_interpreter.py index 9770da325..a5adeaa2e 100644 --- a/taskweaver/code_interpreter/code_interpreter/code_interpreter.py +++ b/taskweaver/code_interpreter/code_interpreter/code_interpreter.py @@ -59,6 +59,7 @@ def _configure(self): ) self.code_prefix = self._get_str("code_prefix", "") + self.require_confirmation = self._get_bool("require_confirmation", False) def update_verification( @@ -234,6 +235,27 @@ def reply( elif len(code_verify_errors) == 0: update_verification(post_proxy, "CORRECT", "No error is found.") + if self.config.require_confirmation: + post_proxy.update_status("awaiting confirmation") + self.logger.info("Requesting user confirmation for code execution") + + confirmed = self.event_emitter.request_code_confirmation( + code.content, + post_proxy.post.id, + ) + + if not confirmed: + self.logger.info("Code execution cancelled by user") + self.tracing.set_span_status("OK", "User cancelled code execution.") + update_execution( + post_proxy, + "NONE", + "Code execution was cancelled by user.", + ) + post_proxy.update_message("Code execution was cancelled.") + self.retry_count = 0 + return post_proxy.end() + executable_code = f"{code.content}" full_code_prefix = None if self.config.code_prefix: diff --git a/taskweaver/module/event_emitter.py b/taskweaver/module/event_emitter.py index 7b7708c89..df1629ba9 100644 --- a/taskweaver/module/event_emitter.py +++ b/taskweaver/module/event_emitter.py @@ -1,6 +1,7 @@ from __future__ import annotations import abc +import threading from contextlib import contextmanager from dataclasses import dataclass from enum import Enum @@ -40,6 +41,8 @@ class PostEventType(Enum): post_send_to_update = "post_send_to_update" post_message_update = "post_message_update" post_attachment_update = "post_attachment_update" + post_confirmation_request = "post_confirmation_request" + post_confirmation_response = "post_confirmation_response" @dataclass @@ -123,6 +126,32 @@ def handle_post( pass +class ConfirmationHandler(abc.ABC): + """Protocol for handling execution confirmations. + + Implementers of this protocol can intercept code execution + and request user confirmation before proceeding. + """ + + @abc.abstractmethod + def request_confirmation( + self, + code: str, + round_id: str, + post_id: Optional[str], + ) -> bool: + """Request confirmation for code execution. + + Args: + code: The code that is about to be executed. + round_id: The current round ID. + post_id: The current post ID (may be None). + + Returns: + True to proceed with execution, False to abort. + """ + + class PostEventProxy: def __init__(self, emitter: SessionEventEmitter, round_id: str, post: Post) -> None: self.emitter = emitter @@ -233,6 +262,75 @@ def __init__(self): self.handlers: List[SessionEventHandler] = [] self.current_round_id: Optional[str] = None + self._confirmation_handler: Optional[ConfirmationHandler] = None + self._confirmation_event = threading.Event() + self._confirmation_cond = threading.Condition() + self._confirmation_result: Optional[bool] = None + self._confirmation_code: Optional[str] = None + self._confirmation_post_id: Optional[str] = None + + @property + def confirmation_handler(self) -> Optional[ConfirmationHandler]: + return self._confirmation_handler + + @confirmation_handler.setter + def confirmation_handler(self, handler: Optional[ConfirmationHandler]): + self._confirmation_handler = handler + + @property + def confirmation_pending(self) -> bool: + return self._confirmation_event.is_set() + + @property + def pending_confirmation_code(self) -> Optional[str]: + return self._confirmation_code + + def request_code_confirmation(self, code: str, post_id: Optional[str] = None) -> bool: + if self._confirmation_handler is None: + return True + + self._confirmation_code = code + self._confirmation_post_id = post_id + self._confirmation_event.set() + + self.emit( + TaskWeaverEvent( + EventScope.post, + PostEventType.post_confirmation_request, + self.current_round_id, + post_id, + code, + extra={"code": code}, + ), + ) + + with self._confirmation_cond: + while self._confirmation_result is None: + self._confirmation_cond.wait() + result = self._confirmation_result + self._confirmation_result = None + self._confirmation_code = None + self._confirmation_post_id = None + + self.emit( + TaskWeaverEvent( + EventScope.post, + PostEventType.post_confirmation_response, + self.current_round_id, + post_id, + "approved" if result else "rejected", + extra={"approved": result}, + ), + ) + + return result + + def provide_confirmation(self, approved: bool): + with self._confirmation_cond: + self._confirmation_result = approved + self._confirmation_event.clear() # Clear immediately so main thread won't see stale True + self._confirmation_cond.notify_all() + def emit(self, event: TaskWeaverEvent): for handler in self.handlers: handler.handle(event) diff --git a/taskweaver/planner/planner_prompt.yaml b/taskweaver/planner/planner_prompt.yaml index 1b87b82c0..b3651dd10 100644 --- a/taskweaver/planner/planner_prompt.yaml +++ b/taskweaver/planner/planner_prompt.yaml @@ -73,6 +73,7 @@ instruction_template: |- + AdditionalInformation: The User's request is incomplete or missing critical information and requires additional information. + SecurityRisks: The User's request contains potential security risks or illegal activities and requires rejection. + TaskFailure: The task fails after few attempts and requires the User's confirmation to proceed. + + UserCancelled: The User has explicitly cancelled the operation (e.g., declined code execution confirmation). Do NOT retry or continue the task - stop immediately and acknowledge the cancellation. ### Examples of planning process @@ -126,6 +127,7 @@ instruction_template: |- - When the request involves loading a file or pulling a table from db, Planner should always set the first subtask to reading the content to understand the structure or schema of the data. - When the request involves text analysis, Planner should always set the first subtask to read and print the text content to understand its content structure. - When the request involves read instructions for task execution, Planner should always update the plan to the steps and sub-steps in the instructions and then follow the updated plan to execute necessary actions. + - When a Worker responds with "Code execution was cancelled by user" or similar cancellation message, Planner must immediately stop the task with stop="UserCancelled" and NOT retry or attempt alternative approaches. ## Planner's response format - Planner must strictly format the response into the following JSON object: @@ -160,10 +162,10 @@ response_json_schema: |- "type": "string", "description": "The current step Planner is executing." }, - "stop": { + "stop": { "type": "string", "description": "The stop reason when the Planner needs to talk to the User. Set it to 'InProcess' if the Planner is not talking to the User.", - "enum": ["InProcess", "Completed", "Clarification", "AdditionalInformation", "SecurityRisks", "TaskFailure"] + "enum": ["InProcess", "Completed", "Clarification", "AdditionalInformation", "SecurityRisks", "TaskFailure", "UserCancelled"] }, "send_to": { "type": "string", diff --git a/tests/unit_tests/test_animation_pause_handshake.py b/tests/unit_tests/test_animation_pause_handshake.py new file mode 100644 index 000000000..8b14b238f --- /dev/null +++ b/tests/unit_tests/test_animation_pause_handshake.py @@ -0,0 +1,230 @@ +"""Tests for the animation pause handshake pattern in TaskWeaverRoundUpdater. + +The handshake uses two events: +- pause_animation: Main thread requests animation to pause +- animation_paused: Animation thread acknowledges it has paused +""" + +import threading +import time + + +class MockAnimationPauseHandshake: + """Minimal implementation of the handshake pattern for testing.""" + + def __init__(self): + self.pause_animation = threading.Event() + self.animation_paused = threading.Event() + self.animation_paused.set() # Initially paused (not running yet) + + self.exit_event = threading.Event() + self.update_cond = threading.Condition() + + # Track what animation thread does + self.output_count = 0 + self.output_log = [] + + def animation_thread_loop(self): + """Simulates the animation thread loop.""" + while not self.exit_event.is_set(): + # Check pause at START of loop + if self.pause_animation.is_set(): + self.animation_paused.set() + while self.pause_animation.is_set(): + if self.exit_event.is_set(): + return + with self.update_cond: + self.update_cond.wait(0.01) + continue + + self.animation_paused.clear() + + # Simulate output + self.output_count += 1 + self.output_log.append(f"output-{self.output_count}") + + with self.update_cond: + self.update_cond.wait(0.05) + + def request_pause(self, timeout: float = 1.0) -> bool: + """Request animation to pause and wait for acknowledgment.""" + self.pause_animation.set() + return self.animation_paused.wait(timeout=timeout) + + def release_pause(self): + """Release the pause and allow animation to resume.""" + self.animation_paused.clear() + self.pause_animation.clear() + + def stop(self): + """Stop the animation thread.""" + self.exit_event.set() + with self.update_cond: + self.update_cond.notify_all() + + +def test_handshake_pauses_animation(): + """Animation should stop outputting when pause is requested.""" + handler = MockAnimationPauseHandshake() + + t = threading.Thread(target=handler.animation_thread_loop, daemon=True) + t.start() + + # Let animation run for a bit + time.sleep(0.1) + count_before_pause = handler.output_count + assert count_before_pause > 0, "Animation should have produced output" + + # Request pause + assert handler.request_pause(), "Pause should be acknowledged" + + # Record count and wait + count_at_pause = handler.output_count + time.sleep(0.1) + count_after_wait = handler.output_count + + # No new output during pause + assert count_after_wait == count_at_pause, "Animation should not output while paused" + + # Release and verify animation resumes + handler.release_pause() + time.sleep(0.1) + count_after_release = handler.output_count + + assert count_after_release > count_at_pause, "Animation should resume after release" + + handler.stop() + t.join(timeout=1) + + +def test_handshake_blocks_until_acknowledged(): + """request_pause should block until animation acknowledges.""" + handler = MockAnimationPauseHandshake() + handler.animation_paused.clear() # Simulate animation running + + acknowledged = threading.Event() + + def delayed_acknowledge(): + time.sleep(0.1) + handler.animation_paused.set() + acknowledged.set() + + t = threading.Thread(target=delayed_acknowledge, daemon=True) + t.start() + + start = time.time() + result = handler.request_pause(timeout=1.0) + elapsed = time.time() - start + + assert result is True + assert elapsed >= 0.1, "Should have waited for acknowledgment" + assert acknowledged.is_set() + + t.join(timeout=1) + + +def test_handshake_timeout(): + """request_pause should timeout if animation doesn't acknowledge.""" + handler = MockAnimationPauseHandshake() + handler.animation_paused.clear() # Simulate animation that never acknowledges + + start = time.time() + result = handler.request_pause(timeout=0.1) + elapsed = time.time() - start + + # Event.wait returns False on timeout + assert result is False + assert elapsed >= 0.1 + + +def test_handshake_multiple_pause_resume_cycles(): + """Handshake should work correctly across multiple pause/resume cycles.""" + handler = MockAnimationPauseHandshake() + + t = threading.Thread(target=handler.animation_thread_loop, daemon=True) + t.start() + + for i in range(3): + # Let animation run + time.sleep(0.05) + handler.output_count + + # Pause + assert handler.request_pause(), f"Cycle {i}: Pause should be acknowledged" + count_at_pause = handler.output_count + time.sleep(0.05) + assert handler.output_count == count_at_pause, f"Cycle {i}: Should not output while paused" + + # Resume + handler.release_pause() + time.sleep(0.05) + assert handler.output_count > count_at_pause, f"Cycle {i}: Should resume after release" + + handler.stop() + t.join(timeout=1) + + +def test_handshake_exit_during_pause(): + """Animation thread should exit cleanly even while paused.""" + handler = MockAnimationPauseHandshake() + + t = threading.Thread(target=handler.animation_thread_loop, daemon=True) + t.start() + + # Pause animation + time.sleep(0.05) + handler.request_pause() + + # Exit while paused + handler.stop() + + # Thread should exit + t.join(timeout=1) + assert not t.is_alive(), "Thread should have exited" + + +def test_handshake_no_output_race(): + """Verify no output occurs between pause request and acknowledgment.""" + handler = MockAnimationPauseHandshake() + + t = threading.Thread(target=handler.animation_thread_loop, daemon=True) + t.start() + + # Let it run + time.sleep(0.05) + + # Pause and immediately record + handler.pause_animation.set() + handler.animation_paused.wait(timeout=1.0) + count_at_ack = handler.output_count + + # Wait and verify no change + time.sleep(0.1) + assert handler.output_count == count_at_ack, "No output should occur after acknowledgment" + + handler.release_pause() + handler.stop() + t.join(timeout=1) + + +def test_animation_paused_initially_set(): + """animation_paused should be set initially (before animation starts).""" + handler = MockAnimationPauseHandshake() + assert handler.animation_paused.is_set(), "Should be paused initially" + + +def test_animation_paused_cleared_when_running(): + """animation_paused should be cleared when animation is actively running.""" + handler = MockAnimationPauseHandshake() + + t = threading.Thread(target=handler.animation_thread_loop, daemon=True) + t.start() + + # Wait for animation to start running + time.sleep(0.1) + + # Should be cleared (running) + assert not handler.animation_paused.is_set(), "Should be cleared when running" + + handler.stop() + t.join(timeout=1) diff --git a/tests/unit_tests/test_event_emitter_confirmation.py b/tests/unit_tests/test_event_emitter_confirmation.py new file mode 100644 index 000000000..45d72af6b --- /dev/null +++ b/tests/unit_tests/test_event_emitter_confirmation.py @@ -0,0 +1,189 @@ +import threading +import time + +from taskweaver.module.event_emitter import ConfirmationHandler, PostEventType, SessionEventEmitter + + +class MockConfirmationHandler(ConfirmationHandler): + def __init__(self, auto_approve: bool = True): + self.auto_approve = auto_approve + self.confirmation_requested = False + self.last_code = None + self.last_round_id = None + self.last_post_id = None + + def request_confirmation(self, code: str, round_id: str, post_id: str | None) -> bool: + self.confirmation_requested = True + self.last_code = code + self.last_round_id = round_id + self.last_post_id = post_id + return self.auto_approve + + +def test_confirmation_auto_approve_when_no_handler(): + emitter = SessionEventEmitter() + emitter.start_round("test-round-1") + + result = emitter.request_code_confirmation("print('hello')", "post-1") + + assert result is True + assert not emitter.confirmation_pending + + +def test_confirmation_pending_property(): + emitter = SessionEventEmitter() + emitter.start_round("test-round-1") + handler = MockConfirmationHandler(auto_approve=True) + emitter.confirmation_handler = handler + + def request_thread(): + emitter.request_code_confirmation("print('hello')", "post-1") + + def provide_thread(): + while not emitter.confirmation_pending: + time.sleep(0.01) + + assert emitter.confirmation_pending + assert emitter.pending_confirmation_code == "print('hello')" + + emitter.provide_confirmation(True) + + t1 = threading.Thread(target=request_thread) + t2 = threading.Thread(target=provide_thread) + + t1.start() + t2.start() + + t1.join(timeout=2) + t2.join(timeout=2) + + assert not t1.is_alive() + assert not t2.is_alive() + + +def test_confirmation_approved(): + emitter = SessionEventEmitter() + emitter.start_round("test-round-1") + handler = MockConfirmationHandler() + emitter.confirmation_handler = handler + + result = None + + def request_thread(): + nonlocal result + result = emitter.request_code_confirmation("print('test')", "post-1") + + def provide_thread(): + while not emitter.confirmation_pending: + time.sleep(0.01) + emitter.provide_confirmation(True) + + t1 = threading.Thread(target=request_thread) + t2 = threading.Thread(target=provide_thread) + + t1.start() + t2.start() + + t1.join(timeout=2) + t2.join(timeout=2) + + assert result is True + + +def test_confirmation_rejected(): + emitter = SessionEventEmitter() + emitter.start_round("test-round-1") + handler = MockConfirmationHandler() + emitter.confirmation_handler = handler + + result = None + + def request_thread(): + nonlocal result + result = emitter.request_code_confirmation("rm -rf /", "post-1") + + def provide_thread(): + while not emitter.confirmation_pending: + time.sleep(0.01) + emitter.provide_confirmation(False) + + t1 = threading.Thread(target=request_thread) + t2 = threading.Thread(target=provide_thread) + + t1.start() + t2.start() + + t1.join(timeout=2) + t2.join(timeout=2) + + assert result is False + + +def test_confirmation_events_emitted(): + emitter = SessionEventEmitter() + emitter.start_round("test-round-1") + handler = MockConfirmationHandler() + emitter.confirmation_handler = handler + + events_captured = [] + + class EventCapture: + def handle(self, event): + events_captured.append(event) + + emitter.register(EventCapture()) + + def request_thread(): + emitter.request_code_confirmation("test_code", "post-1") + + def provide_thread(): + while not emitter.confirmation_pending: + time.sleep(0.01) + emitter.provide_confirmation(True) + + t1 = threading.Thread(target=request_thread) + t2 = threading.Thread(target=provide_thread) + + t1.start() + t2.start() + + t1.join(timeout=2) + t2.join(timeout=2) + + request_events = [e for e in events_captured if e.t == PostEventType.post_confirmation_request] + response_events = [e for e in events_captured if e.t == PostEventType.post_confirmation_response] + + assert len(request_events) == 1 + assert request_events[0].msg == "test_code" + assert request_events[0].extra["code"] == "test_code" + + assert len(response_events) == 1 + assert response_events[0].msg == "approved" + assert response_events[0].extra["approved"] is True + + +def test_confirmation_state_cleared_after_response(): + emitter = SessionEventEmitter() + emitter.start_round("test-round-1") + handler = MockConfirmationHandler() + emitter.confirmation_handler = handler + + def request_thread(): + emitter.request_code_confirmation("code1", "post-1") + + def provide_thread(): + while not emitter.confirmation_pending: + time.sleep(0.01) + emitter.provide_confirmation(True) + + t1 = threading.Thread(target=request_thread) + t2 = threading.Thread(target=provide_thread) + + t1.start() + t2.start() + + t1.join(timeout=2) + t2.join(timeout=2) + + assert not emitter.confirmation_pending + assert emitter.pending_confirmation_code is None From 4a024443d006959f53e70af6404c0683142ba90b Mon Sep 17 00:00:00 2001 From: liqun Date: Mon, 26 Jan 2026 15:15:58 +0800 Subject: [PATCH 5/5] remove init plan --- docs/design/threading_model.md | 1 - .../example-planner-default-1.yaml | 10 --- .../example-planner-default-2.yaml | 5 +- .../example-planner-echo.yaml | 6 -- .../example-planner-recepta.yaml | 20 +----- taskweaver/chat/console/chat.py | 4 +- taskweaver/memory/AGENTS.md | 1 - taskweaver/memory/attachment.py | 7 +- taskweaver/memory/post.py | 10 ++- taskweaver/planner/planner.py | 2 - taskweaver/planner/planner_prompt.yaml | 64 ++++++------------- .../planner_examples/example-planner.yaml | 12 +--- .../planner_examples/sub/example-planner.yaml | 12 +--- .../data/prompts/planner_prompt.yaml | 60 +++++------------ 14 files changed, 54 insertions(+), 160 deletions(-) diff --git a/docs/design/threading_model.md b/docs/design/threading_model.md index 4048c968f..7f766f79c 100644 --- a/docs/design/threading_model.md +++ b/docs/design/threading_model.md @@ -199,7 +199,6 @@ def _animate_thread(self): ``` ╭───< Planner > - ├─► [init_plan] Analyze the user request... ├─► [plan] 1. Parse input data... ├──● The task involves processing the CSV file... ╰──● sending message to CodeInterpreter diff --git a/project/examples/planner_examples/example-planner-default-1.yaml b/project/examples/planner_examples/example-planner-default-1.yaml index 1cd2fde0d..069aae3b6 100644 --- a/project/examples/planner_examples/example-planner-default-1.yaml +++ b/project/examples/planner_examples/example-planner-default-1.yaml @@ -14,11 +14,6 @@ rounds: - type: plan_reasoning content: |- The user wants to count the rows of the data file /home/data.csv. The first step is to load the data file and count the rows of the loaded data. - - type: init_plan - content: |- - 1. Load the data file - 2. Count the rows of the loaded data - 3. Check the execution result and report the result to the user - type: plan content: |- 1. Instruct CodeInterpreter to load the data file and count the rows of the loaded data @@ -40,11 +35,6 @@ rounds: The data file /home/data.csv is loaded and there are 100 rows in the data file The execution result is correct The user query is successfully answered - - type: init_plan - content: |- - 1. Load the data file - 2. Count the rows of the loaded data - 3. Check the execution result and report the result to the user - type: plan content: |- 1. Instruct CodeInterpreter to load the data file and count the rows of the loaded data diff --git a/project/examples/planner_examples/example-planner-default-2.yaml b/project/examples/planner_examples/example-planner-default-2.yaml index ba548245d..86e61a181 100644 --- a/project/examples/planner_examples/example-planner-default-2.yaml +++ b/project/examples/planner_examples/example-planner-default-2.yaml @@ -14,13 +14,10 @@ rounds: - type: plan_reasoning content: |- The user greets the Planner - - type: init_plan - content: |- - 1. Respond to the user's greeting - type: plan content: |- 1. Respond to the user's greeting - type: current_plan_step content: 1. Respond to the user's greeting - type: stop - content: Completed \ No newline at end of file + content: Completed diff --git a/project/examples/planner_examples/example-planner-echo.yaml b/project/examples/planner_examples/example-planner-echo.yaml index f94715e74..54b02d79c 100644 --- a/project/examples/planner_examples/example-planner-echo.yaml +++ b/project/examples/planner_examples/example-planner-echo.yaml @@ -14,9 +14,6 @@ rounds: - type: plan_reasoning content: |- The user wants to echo the input 'Hello World' - - type: init_plan - content: |- - 1. Ask Echo to echo the user's input, 'Hello World' - type: plan content: |- 1. Ask Echo to echo the user's input, 'Hello World' @@ -35,9 +32,6 @@ rounds: - type: plan_reasoning content: |- The user query is successfully answered - - type: init_plan - content: |- - 1. Ask Echo to echo the user's input, 'Hello World' - type: plan content: |- 1. Ask Echo to echo the user's input, 'Hello World' diff --git a/project/examples/planner_examples/example-planner-recepta.yaml b/project/examples/planner_examples/example-planner-recepta.yaml index d32574006..075e0af71 100644 --- a/project/examples/planner_examples/example-planner-recepta.yaml +++ b/project/examples/planner_examples/example-planner-recepta.yaml @@ -48,12 +48,6 @@ rounds: - type: plan_reasoning content: |- The first step is to extract the following information from the employee summary: `Employee ID`, `Department`, `Project Code`, `Role`, `Manager`, `Location`. - - type: init_plan - content: |- - 1. extract the following information from the employee summary: `Employee ID`, `Department`, `Project Code`, `Role`, `Manager`, `Location` - 2. validate the role - 3. construct and print the SQL query using the extracted details - 4. check the execution result and report the result to the user - type: plan content: |- 1. extract information from the employee summary @@ -78,12 +72,6 @@ rounds: - type: plan_reasoning content: |- I have extracted the information from the employee summary. The next step is to verify if the role is one of the recognized roles. - - type: init_plan - content: |- - 1. extract the following information from the employee summary: `Employee ID`, `Department`, `Project Code`, `Role`, `Manager`, `Location` - 2. validate the role - 3. construct and print the SQL query using the extracted details - 4. check the execution result and report the result to the user - type: plan content: |- 1. extract information from the employee summary @@ -119,12 +107,6 @@ rounds: - type: plan_reasoning content: |- I can prepare and print the SQL query using the extracted details to the User. - - type: init_plan - content: |- - 1. extract the following information from the employee summary: `Employee ID`, `Department`, `Project Code`, `Role`, `Manager`, `Location` - 2. validate the role - 3. construct and print the SQL query using the extracted details - 4. check the execution result and report the result to the user - type: plan content: |- 1. extract information from the employee summary @@ -134,4 +116,4 @@ rounds: - type: current_plan_step content: 3. construct and print the SQL query using the extracted details and report the result to the user - type: stop - content: Completed \ No newline at end of file + content: Completed diff --git a/taskweaver/chat/console/chat.py b/taskweaver/chat/console/chat.py index 9cb6937a2..b17622d12 100644 --- a/taskweaver/chat/console/chat.py +++ b/taskweaver/chat/console/chat.py @@ -71,7 +71,7 @@ def user_input_message(prompt: str = " Human ") -> str: continue -def user_confirmation_input(prompt: str = "Execute code? [y/N]: ") -> str: +def user_confirmation_input(prompt: str = "Execute code? [Y/n]: ") -> str: import prompt_toolkit session = prompt_toolkit.PromptSession[str]( @@ -272,7 +272,7 @@ def _handle_confirmation(self, session: Session) -> None: click.secho(click.style(" │ ", fg="blue") + click.style(line, fg="bright_black")) response = user_confirmation_input() - approved = response in ("y", "yes") + approved = response not in ("n", "no") if approved: click.secho(click.style(" │ ", fg="blue") + click.style("✓ approved", fg="green")) diff --git a/taskweaver/memory/AGENTS.md b/taskweaver/memory/AGENTS.md index 355379f46..9cc5dc752 100644 --- a/taskweaver/memory/AGENTS.md +++ b/taskweaver/memory/AGENTS.md @@ -57,7 +57,6 @@ class Post: ```python class AttachmentType(str, Enum): # Planning - init_plan = "init_plan" plan = "plan" current_plan_step = "current_plan_step" diff --git a/taskweaver/memory/attachment.py b/taskweaver/memory/attachment.py index 609f9524c..dad72516e 100644 --- a/taskweaver/memory/attachment.py +++ b/taskweaver/memory/attachment.py @@ -9,7 +9,6 @@ class AttachmentType(Enum): # Planner Type - init_plan = "init_plan" plan = "plan" current_plan_step = "current_plan_step" plan_reasoning = "plan_reasoning" @@ -114,7 +113,7 @@ def to_dict(self) -> AttachmentDict: } @staticmethod - def from_dict(content: AttachmentDict) -> Attachment: + def from_dict(content: AttachmentDict) -> Optional[Attachment]: # deprecated types if content["type"] in ["python", "sample", "text"]: raise ValueError( @@ -123,6 +122,10 @@ def from_dict(content: AttachmentDict) -> Attachment: f"on how to fix it.", ) + removed_types = ["init_plan"] + if content["type"] in removed_types: + return None + type = AttachmentType(content["type"]) return Attachment.create( type=type, diff --git a/taskweaver/memory/post.py b/taskweaver/memory/post.py index 4b053691c..eafb06790 100644 --- a/taskweaver/memory/post.py +++ b/taskweaver/memory/post.py @@ -73,14 +73,18 @@ def to_dict(self) -> Dict[str, Any]: @staticmethod def from_dict(content: Dict[str, Any]) -> Post: """Convert the dict to a post. Will assign a new id to the post.""" + attachments = [] + if content["attachment_list"] is not None: + for attachment in content["attachment_list"]: + parsed = Attachment.from_dict(attachment) + if parsed is not None: + attachments.append(parsed) return Post( id="post-" + secrets.token_hex(6), message=content["message"], send_from=content["send_from"], send_to=content["send_to"], - attachment_list=[Attachment.from_dict(attachment) for attachment in content["attachment_list"]] - if content["attachment_list"] is not None - else [], + attachment_list=attachments, ) def add_attachment(self, attachment: Attachment) -> None: diff --git a/taskweaver/planner/planner.py b/taskweaver/planner/planner.py index 31de46201..c5329222b 100644 --- a/taskweaver/planner/planner.py +++ b/taskweaver/planner/planner.py @@ -268,8 +268,6 @@ def check_post_validity(post: Post): missing_elements.append("message") attachment_types = [attachment.type for attachment in post.attachment_list] - if AttachmentType.init_plan not in attachment_types: - missing_elements.append("init_plan") if AttachmentType.plan not in attachment_types: missing_elements.append("plan") if AttachmentType.current_plan_step not in attachment_types: diff --git a/taskweaver/planner/planner_prompt.yaml b/taskweaver/planner/planner_prompt.yaml index b3651dd10..32ab3a954 100644 --- a/taskweaver/planner/planner_prompt.yaml +++ b/taskweaver/planner/planner_prompt.yaml @@ -44,24 +44,16 @@ instruction_template: |- 2. Planner use its own skills to complete the task step, which is recommended when the task step is simple. ## Planner's planning process - You need to make a step-by-step plan to complete the User's task. The planning process includes 2 phases: `init_plan` and `plan`. - In the `init_plan` phase, you need to decompose the User's task into subtasks and list them as the detailed plan steps. - In the `plan` phase, you need to refine the initial plan by merging adjacent steps that have sequential dependency or no dependency, unless the merged step becomes too complicated. - - ### init_plan - - Decompose User's task into subtasks and list them as the detailed subtask steps. - - Annotate the dependencies between these steps. There are 2 dependency types: - 1. Sequential Dependency: the current subtask depends on the previous subtask, but they can be executed in one step by a Worker, - and no additional information is required. - 2. Interactive Dependency: the current subtask depends on the previous subtask but they cannot be executed in one step by a Worker, - typically without necessary information (e.g., hyperparameters, data path, model name, file content, data schema, etc.). - 3. No Dependency: the current subtask can be executed independently without any dependency. - - The initial plan must contain dependency annotations for sequential and interactive dependencies. - - ### plan - - Planner should try to merge adjacent steps that have sequential dependency or no dependency. - - Planner should not merge steps with interactive dependency. - - The final plan must not contain dependency annotations. + You need to make a step-by-step plan to complete the User's task. + When creating the plan, you should mentally decompose the task into subtasks and consider their dependencies: + - Sequential Dependency: the current subtask depends on the previous subtask, but they can be executed in one step by a Worker, and no additional information is required. + - Interactive Dependency: the current subtask depends on the previous subtask but they cannot be executed in one step by a Worker, typically without necessary information (e.g., hyperparameters, data path, model name, file content, data schema, etc.). + - No Dependency: the current subtask can be executed independently without any dependency. + + Based on this analysis, create a compact plan by: + - Merging adjacent steps that have sequential dependency or no dependency into single steps + - Keeping steps with interactive dependency separate (they require intermediate results before proceeding) + - The final plan should be concise and actionable, without dependency annotations ## Planner's communication process - Planner should communicate with the User and Workers by specifying the `send_to` field in the response. @@ -76,35 +68,27 @@ instruction_template: |- + UserCancelled: The User has explicitly cancelled the operation (e.g., declined code execution confirmation). Do NOT retry or continue the task - stop immediately and acknowledge the cancellation. - ### Examples of planning process + ### Examples of planning + The examples below show how to think about task decomposition and create compact plans: + [Example 1] User: count rows for ./data.csv - init_plan: - 1. Read ./data.csv file - 2. Count the rows of the loaded data - 3. Check the execution result and report the result to the user + Reasoning: Reading and counting can be done in one step (sequential dependency), but we need execution results before reporting (interactive dependency). plan: 1. Read ./data.csv file and count the rows of the loaded data 2. Check the execution result and report the result to the user [Example 2] User: Read a manual file and follow the instructions in it. - init_plan: - 1. Read the file content and show its content to the user - 2. Follow the instructions based on the file content. - 3. Confirm the completion of the instructions and report the result to the user + Reasoning: We must read the file first to know what instructions to follow (interactive dependency), then execute them (interactive dependency). plan: 1. Read the file content and show its content to the user - 2. follow the instructions based on the file content. + 2. Follow the instructions based on the file content 3. Confirm the completion of the instructions and report the result to the user [Example 3] User: detect anomaly on ./data.csv - init_plan: - 1. Read the ./data.csv and show me the top 5 rows to understand the data schema - 2. Confirm the columns to be detected anomalies - 3. Detect anomalies on the loaded data - 4. Check the execution result and report the detected anomalies to the user + Reasoning: Reading data and confirming columns can be merged (sequential), but anomaly detection needs the confirmed columns (interactive). plan: 1. Read the ./data.csv and show me the top 5 rows to understand the data schema and confirm the columns to be detected anomalies 2. Detect anomalies on the loaded data @@ -112,12 +96,7 @@ instruction_template: |- [Example 4] User: read a.csv and b.csv and join them together - init_plan: - 1. Load a.csv as dataframe and show me the top 5 rows to understand the data schema - 2. Load b.csv as dataframe and show me the top 5 rows to understand the data schema - 3. Ask which column to join - 4. Join the two dataframes - 5. Check the execution result and report the joined data to the user + Reasoning: Loading both files and asking about join column can be merged (sequential/no dependency), but joining needs the column choice (interactive). plan: 1. Load a.csv and b.csv as dataframes, show me the top 5 rows to understand the data schema, and ask which column to join 2. Join the two dataframes @@ -150,13 +129,9 @@ response_json_schema: |- "type": "string", "description": "The reasoning of the Planner's decision. It should include the analysis of the User's request, the Workers' responses, and the current environment context." }, - "init_plan": { - "type": "string", - "description": "The initial plan to decompose the User's task into subtasks and list them as the detailed subtask steps. The initial plan must contain dependency annotations for sequential and interactive dependencies." - }, "plan": { "type": "string", - "description": "The refined plan by merging adjacent steps that have sequential dependency or no dependency. The final plan must not contain dependency annotations." + "description": "The step-by-step plan to complete the User's task. Steps with sequential or no dependency should be merged. Steps with interactive dependency should be kept separate." }, "current_plan_step": { "type": "string", @@ -178,7 +153,6 @@ response_json_schema: |- }, "required": [ "plan_reasoning", - "init_plan", "plan", "current_plan_step", "stop", diff --git a/tests/unit_tests/data/examples/planner_examples/example-planner.yaml b/tests/unit_tests/data/examples/planner_examples/example-planner.yaml index 525463ab3..066396022 100644 --- a/tests/unit_tests/data/examples/planner_examples/example-planner.yaml +++ b/tests/unit_tests/data/examples/planner_examples/example-planner.yaml @@ -11,11 +11,6 @@ rounds: send_from: Planner send_to: CodeInterpreter attachment_list: - - type: init_plan - content: |- - 1. load the data file - 2. count the rows of the loaded data - 3. report the result to the user - type: plan content: |- 1. instruct CodeInterpreter to load the data file and count the rows of the loaded data @@ -30,14 +25,9 @@ rounds: send_from: Planner send_to: User attachment_list: - - type: init_plan - content: |- - 1. load the data file - 2. count the rows of the loaded data - 3. report the result to the user - type: plan content: |- 1. instruct CodeInterpreter to load the data file and count the rows of the loaded data 2. report the result to the user - type: current_plan_step - content: 2. report the result to the user \ No newline at end of file + content: 2. report the result to the user diff --git a/tests/unit_tests/data/examples/planner_examples/sub/example-planner.yaml b/tests/unit_tests/data/examples/planner_examples/sub/example-planner.yaml index 525463ab3..066396022 100644 --- a/tests/unit_tests/data/examples/planner_examples/sub/example-planner.yaml +++ b/tests/unit_tests/data/examples/planner_examples/sub/example-planner.yaml @@ -11,11 +11,6 @@ rounds: send_from: Planner send_to: CodeInterpreter attachment_list: - - type: init_plan - content: |- - 1. load the data file - 2. count the rows of the loaded data - 3. report the result to the user - type: plan content: |- 1. instruct CodeInterpreter to load the data file and count the rows of the loaded data @@ -30,14 +25,9 @@ rounds: send_from: Planner send_to: User attachment_list: - - type: init_plan - content: |- - 1. load the data file - 2. count the rows of the loaded data - 3. report the result to the user - type: plan content: |- 1. instruct CodeInterpreter to load the data file and count the rows of the loaded data 2. report the result to the user - type: current_plan_step - content: 2. report the result to the user \ No newline at end of file + content: 2. report the result to the user diff --git a/tests/unit_tests/data/prompts/planner_prompt.yaml b/tests/unit_tests/data/prompts/planner_prompt.yaml index 851daf707..84133a835 100644 --- a/tests/unit_tests/data/prompts/planner_prompt.yaml +++ b/tests/unit_tests/data/prompts/planner_prompt.yaml @@ -33,54 +33,38 @@ instruction_template: |- - Planner can ignore the permission or file access issues since Workers are powerful and can handle them. ## Planner's planning process - You need to make a step-by-step plan to complete the User's task. The planning process includes 2 phases: `init_plan` and `plan`. - In the `init_plan` phase, you need to decompose the User's task into subtasks and list them as the detailed plan steps. - In the `plan` phase, you need to refine the initial plan by merging adjacent steps that have sequential dependency or no dependency, unless the merged step becomes too complicated. + You need to make a step-by-step plan to complete the User's task. + When creating the plan, you should mentally decompose the task into subtasks and consider their dependencies: + - Sequential Dependency: the current subtask depends on the previous subtask, but they can be executed in one step by a Worker, and no additional information is required. + - Interactive Dependency: the current subtask depends on the previous subtask but they cannot be executed in one step by a Worker, typically without necessary information (e.g., hyperparameters, data path, model name, file content, data schema, etc.). + - No Dependency: the current subtask can be executed independently without any dependency. - ### init_plan - - Decompose User's task into subtasks and list them as the detailed subtask steps. - - Annotate the dependencies between these steps. There are 2 dependency types: - 1. Sequential Dependency: the current subtask depends on the previous subtask, but they can be executed in one step by a Worker, - and no additional information is required. - 2. Interactive Dependency: the current subtask depends on the previous subtask but they cannot be executed in one step by a Worker, - typically without necessary information (e.g., hyperparameters, data path, model name, file content, data schema, etc.). - 3. No Dependency: the current subtask can be executed independently without any dependency. - - The initial plan must contain dependency annotations for sequential and interactive dependencies. + Based on this analysis, create a compact plan by: + - Merging adjacent steps that have sequential dependency or no dependency into single steps + - Keeping steps with interactive dependency separate (they require intermediate results before proceeding) + - The final plan should be concise and actionable, without dependency annotations - ### plan - - Planner should try to merge adjacent steps that have sequential dependency or no dependency. - - Planner should not merge steps with interactive dependency. - - The final plan must not contain dependency annotations. + ### Examples of planning + The examples below show how to think about task decomposition and create compact plans: - ### Examples of planning process [Example 1] User: count rows for ./data.csv - init_plan: - 1. Read ./data.csv file - 2. Count the rows of the loaded data - 3. Check the execution result and report the result to the user + Reasoning: Reading and counting can be done in one step (sequential dependency), but we need execution results before reporting (interactive dependency). plan: 1. Read ./data.csv file and count the rows of the loaded data 2. Check the execution result and report the result to the user [Example 2] User: Read a manual file and follow the instructions in it. - init_plan: - 1. Read the file content and show its content to the user - 2. Follow the instructions based on the file content. - 3. Confirm the completion of the instructions and report the result to the user + Reasoning: We must read the file first to know what instructions to follow (interactive dependency), then execute them (interactive dependency). plan: 1. Read the file content and show its content to the user - 2. follow the instructions based on the file content. + 2. Follow the instructions based on the file content 3. Confirm the completion of the instructions and report the result to the user [Example 3] User: detect anomaly on ./data.csv - init_plan: - 1. Read the ./data.csv and show me the top 5 rows to understand the data schema - 2. Confirm the columns to be detected anomalies - 3. Detect anomalies on the loaded data - 4. Check the execution result and report the detected anomalies to the user + Reasoning: Reading data and confirming columns can be merged (sequential), but anomaly detection needs the confirmed columns (interactive). plan: 1. Read the ./data.csv and show me the top 5 rows to understand the data schema and confirm the columns to be detected anomalies 2. Detect anomalies on the loaded data @@ -88,12 +72,7 @@ instruction_template: |- [Example 4] User: read a.csv and b.csv and join them together - init_plan: - 1. Load a.csv as dataframe and show me the top 5 rows to understand the data schema - 2. Load b.csv as dataframe and show me the top 5 rows to understand the data schema - 3. Ask which column to join - 4. Join the two dataframes - 5. Check the execution result and report the joined data to the user + Reasoning: Loading both files and asking about join column can be merged (sequential/no dependency), but joining needs the column choice (interactive). plan: 1. Load a.csv and b.csv as dataframes, show me the top 5 rows to understand the data schema, and ask which column to join 2. Join the two dataframes @@ -120,13 +99,9 @@ response_json_schema: |- "response": { "type": "object", "properties": { - "init_plan": { - "type": "string", - "description": "The initial plan to decompose the User's task into subtasks and list them as the detailed subtask steps. The initial plan must contain dependency annotations for sequential and interactive dependencies." - }, "plan": { "type": "string", - "description": "The refined plan by merging adjacent steps that have sequential dependency or no dependency. The final plan must not contain dependency annotations." + "description": "The step-by-step plan to complete the User's task. Steps with sequential or no dependency should be merged. Steps with interactive dependency should be kept separate." }, "current_plan_step": { "type": "string", @@ -146,7 +121,6 @@ response_json_schema: |- } }, "required": [ - "init_plan", "plan", "current_plan_step", "send_to",