diff --git a/.github/workflows/libraries.yml b/.github/workflows/libraries.yml
index d0bdc258..99db4644 100644
--- a/.github/workflows/libraries.yml
+++ b/.github/workflows/libraries.yml
@@ -36,4 +36,4 @@ jobs:
run: uv python install ${{ matrix.python-version }}
- name: Install and run tests
- run: make test
+ run: make -j $(nproc) test
diff --git a/assistants/document-assistant/assistant/chat.py b/assistants/document-assistant/assistant/chat.py
index 1fdcd738..7fc4ce77 100644
--- a/assistants/document-assistant/assistant/chat.py
+++ b/assistants/document-assistant/assistant/chat.py
@@ -11,7 +11,9 @@
import deepmerge
from assistant_extensions import dashboard_card, navigator
-from assistant_extensions.chat_context_toolkit.archive import ArchiveTaskQueues
+from assistant_extensions.attachments import get_attachments
+from assistant_extensions.chat_context_toolkit.archive import ArchiveTaskQueues, construct_archive_summarizer
+from assistant_extensions.chat_context_toolkit.message_history import construct_attachment_summarizer
from assistant_extensions.mcp import MCPServerConfig
from chat_context_toolkit.archive import ArchiveTaskConfig
from content_safety.evaluators import CombinedContentSafetyEvaluator
@@ -209,11 +211,21 @@ async def on_message_created(
)
)
+ attachments = await get_attachments(
+ context=context,
+ summarizer=construct_attachment_summarizer(
+ service_config=config.generative_ai_fast_client_config.service_config,
+ request_config=config.generative_ai_fast_client_config.request_config,
+ ),
+ )
await archive_task_queues.enqueue_run(
context=context,
- service_config=config.generative_ai_client_config.service_config,
- request_config=config.generative_ai_client_config.request_config,
+ attachments=attachments,
archive_task_config=ArchiveTaskConfig(chunk_token_count_threshold=30_000),
+ archive_summarizer=construct_archive_summarizer(
+ service_config=config.generative_ai_fast_client_config.service_config,
+ request_config=config.generative_ai_fast_client_config.request_config,
+ ),
)
diff --git a/assistants/document-assistant/assistant/filesystem/_file_sources.py b/assistants/document-assistant/assistant/filesystem/_file_sources.py
index a380a4ae..41998cd3 100644
--- a/assistants/document-assistant/assistant/filesystem/_file_sources.py
+++ b/assistants/document-assistant/assistant/filesystem/_file_sources.py
@@ -2,7 +2,7 @@
from typing import Callable, Iterable
from assistant_drive import Drive
-from chat_context_toolkit.virtual_filesystem import DirectoryEntry, FileEntry, MountPoint, WriteToolDefinition
+from chat_context_toolkit.virtual_filesystem import DirectoryEntry, FileEntry, MountPoint
from semantic_workbench_assistant.assistant_app import ConversationContext
from assistant.filesystem._filesystem import AttachmentsExtension, _get_attachments, log_and_send_message_on_error
@@ -17,11 +17,6 @@ def __init__(self, context: ConversationContext, attachments_extension: Attachme
self.context = context
self.attachments_extension = attachments_extension
- @property
- def write_tools(self) -> Iterable[WriteToolDefinition]:
- """Get the list of write tools provided by this file system provider."""
- return []
-
async def list_directory(self, path: str) -> Iterable[DirectoryEntry | FileEntry]:
"""
List files and directories at the specified path.
@@ -86,11 +81,6 @@ def __init__(self, context: ConversationContext, drive_provider: Callable[[Conve
self.context = context
self.drive_provider = drive_provider
- @property
- def write_tools(self) -> Iterable[WriteToolDefinition]:
- """Get the list of write tools provided by this file system provider."""
- return []
-
async def list_directory(self, path: str) -> Iterable[DirectoryEntry | FileEntry]:
"""
List files and directories at the specified path.
diff --git a/assistants/document-assistant/assistant/response/completion_handler.py b/assistants/document-assistant/assistant/response/completion_handler.py
index 619051c7..45da0833 100644
--- a/assistants/document-assistant/assistant/response/completion_handler.py
+++ b/assistants/document-assistant/assistant/response/completion_handler.py
@@ -44,16 +44,13 @@
async def handle_completion(
- sampling_handler: OpenAISamplingHandler,
step_result: StepResult,
completion: ParsedChatCompletion | ChatCompletion,
mcp_sessions: List[MCPSession],
context: ConversationContext,
request_config: OpenAIRequestConfig,
- silence_token: str,
metadata_key: str,
response_start_time: float,
- attachments_extension: AttachmentsExtension,
guidance_enabled: bool,
virtual_filesystem: VirtualFileSystem,
) -> StepResult:
diff --git a/assistants/document-assistant/assistant/response/responder.py b/assistants/document-assistant/assistant/response/responder.py
index 7653b1a9..17902dea 100644
--- a/assistants/document-assistant/assistant/response/responder.py
+++ b/assistants/document-assistant/assistant/response/responder.py
@@ -324,16 +324,13 @@ async def _step(self, step_count) -> StepResult:
await update_dynamic_ui_state(self.context, tool_call.arguments)
step_result = await handle_completion(
- self.sampling_handler,
step_result,
completion,
self.mcp_sessions,
self.context,
self.config.generative_ai_client_config.request_config,
- "SILENCE", # TODO: This is not being used correctly.
f"respond_to_conversation:step_{step_count}",
response_start_time,
- self.attachments_extension,
self.config.orchestration.guidance.enabled,
self.virtual_filesystem,
)
diff --git a/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/__init__.py b/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/__init__.py
index 0fe11475..12d00361 100644
--- a/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/__init__.py
+++ b/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/__init__.py
@@ -1,5 +1,5 @@
-from ._ls_tool import LsTool
+from ._ls_tool import LsTool, LsToolOptions
from ._tools import ToolCollection, tool_result_to_string
from ._view_tool import ViewTool
-__all__ = ["LsTool", "ToolCollection", "ViewTool", "tool_result_to_string"]
+__all__ = ["LsTool", "ToolCollection", "ViewTool", "tool_result_to_string", "LsToolOptions"]
diff --git a/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_ls_tool.py b/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_ls_tool.py
index 30b9c9c3..3ca95102 100644
--- a/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_ls_tool.py
+++ b/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_ls_tool.py
@@ -1,15 +1,28 @@
+from dataclasses import dataclass
from typing import Iterable
+
from openai.types.chat import ChatCompletionContentPartTextParam, ChatCompletionToolParam
from chat_context_toolkit.virtual_filesystem._types import DirectoryEntry, FileEntry, ToolDefinition
from chat_context_toolkit.virtual_filesystem._virtual_filesystem import VirtualFileSystem
+@dataclass
+class LsToolOptions:
+ tool_name: str = "ls"
+ """Name of the tool provided to the LLM."""
+ tool_description: str = "List files and directories at the specified path. Root directories: {root_path_list}"
+ """Description of the tool provided to the LLM."""
+ path_argument_description: str = "The path to list (e.g., '/', '/docs', '/docs/subdir)"
+ """Description of the 'path' argument."""
+
+
class LsTool(ToolDefinition):
"""Tool for listing files and directories in the virtual file system."""
- def __init__(self, virtual_filesystem: VirtualFileSystem):
+ def __init__(self, virtual_filesystem: VirtualFileSystem, options: LsToolOptions = LsToolOptions()) -> None:
self.virtual_filesystem = virtual_filesystem
+ self.options = options
@property
def tool_param(self) -> ChatCompletionToolParam:
@@ -20,14 +33,14 @@ def tool_param(self) -> ChatCompletionToolParam:
return ChatCompletionToolParam(
type="function",
function={
- "name": "ls",
- "description": "List files and directories at the specified path. Root directories: " + mount_list,
+ "name": self.options.tool_name,
+ "description": self.options.tool_description.format(root_path_list=mount_list),
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
- "description": "The path to list (e.g., '/', '/docs', '/docs/subdir')",
+ "description": self.options.path_argument_description.format(root_path_list=mount_list),
}
},
"required": ["path"],
@@ -39,7 +52,7 @@ async def execute(self, args: dict) -> str | Iterable[ChatCompletionContentPartT
"""Execute the built-in ls tool to list directory contents."""
path = args.get("path")
if not path:
- return "Error: 'path' argument is required for the ls tool"
+ return f"Error: 'path' argument is required for the {self.options.tool_name} tool"
try:
entries = await self.virtual_filesystem.list_directory(path)
diff --git a/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_view_tool.py b/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_view_tool.py
index 0ef7db35..9be60ba1 100644
--- a/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_view_tool.py
+++ b/libraries/python/chat-context-toolkit/chat_context_toolkit/virtual_filesystem/tools/_view_tool.py
@@ -1,29 +1,42 @@
+from dataclasses import dataclass
from typing import Iterable
+
+from openai.types.chat import ChatCompletionContentPartTextParam, ChatCompletionToolParam
+
from chat_context_toolkit.virtual_filesystem._types import ToolDefinition
from chat_context_toolkit.virtual_filesystem._virtual_filesystem import VirtualFileSystem
-from openai.types.chat import ChatCompletionContentPartTextParam, ChatCompletionToolParam
+
+
+@dataclass
+class ViewToolOptions:
+ tool_name: str = "view"
+ """Name of the tool provided to the LLM."""
+ tool_description: str = "Read the contents of a file at the specified path"
+ """Description of the tool provided to the LLM."""
+ path_argument_description: str = "The path to the file to read (e.g., '/docs/file.txt')"
+ """Description of the 'path' argument."""
class ViewTool(ToolDefinition):
"""Tool for viewing the contents of a file in the virtual file system."""
- def __init__(self, virtual_filesystem: VirtualFileSystem, tool_name: str = "view"):
+ def __init__(self, virtual_filesystem: VirtualFileSystem, options: ViewToolOptions = ViewToolOptions()) -> None:
self.virtual_filesystem = virtual_filesystem
- self.tool_name = tool_name
+ self.options = options
@property
def tool_param(self) -> ChatCompletionToolParam:
return ChatCompletionToolParam(
type="function",
function={
- "name": self.tool_name,
- "description": "Read the contents of a file at the specified path",
+ "name": self.options.tool_name,
+ "description": self.options.tool_description,
"parameters": {
"type": "object",
"properties": {
"path": {
"type": "string",
- "description": "The path to the file to read (e.g., '/docs/file.txt')",
+ "description": self.options.path_argument_description,
}
},
"required": ["path"],
@@ -35,12 +48,12 @@ async def execute(self, args: dict) -> str | Iterable[ChatCompletionContentPartT
"""Execute the built-in view tool to read file contents."""
path = args.get("path")
if not path:
- return "Error: 'path' argument is required for the view tool"
+ return f"Error: 'path' argument is required for the {self.options.tool_name} tool"
try:
file_content = await self.virtual_filesystem.read_file(path)
except FileNotFoundError:
return f"Error: File at path {path} not found. Please pay attention to the available files and try again."
- result = f"\n{file_content}\n"
+ result = f'\n{file_content}\n'
return result
diff --git a/libraries/python/chat-context-toolkit/test/virtual_filesystem/tools/test_view_tool.py b/libraries/python/chat-context-toolkit/test/virtual_filesystem/tools/test_view_tool.py
index 6d1f4aee..7a6a666b 100644
--- a/libraries/python/chat-context-toolkit/test/virtual_filesystem/tools/test_view_tool.py
+++ b/libraries/python/chat-context-toolkit/test/virtual_filesystem/tools/test_view_tool.py
@@ -14,7 +14,7 @@ async def test_builtin_view_tool_reads_file():
result = await view_tool.execute({"path": "/docs/file1.txt"})
mock_vfs.read_file.assert_called_once_with("/docs/file1.txt")
- assert result == "\nHello World\n"
+ assert result == '\nHello World\n'
async def test_view_tool_error_handling():
@@ -25,4 +25,7 @@ async def test_view_tool_error_handling():
# view on non-existent file should raise error
view_tool = ViewTool(mock_vfs)
result = await view_tool.execute({"path": "/nonexistent.txt"})
- assert result == "Error: File at path /nonexistent.txt not found. Please pay attention to the available files and try again."
+ assert (
+ result
+ == "Error: File at path /nonexistent.txt not found. Please pay attention to the available files and try again."
+ )