langroid 0.16.7__tar.gz → 0.17.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langroid-0.16.7 → langroid-0.17.0}/PKG-INFO +6 -3
- {langroid-0.16.7 → langroid-0.17.0}/README.md +3 -1
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/base.py +45 -21
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/chat_agent.py +22 -14
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/chat_document.py +22 -13
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tool_message.py +11 -11
- langroid-0.17.0/langroid/agent/tools/file_tools.py +234 -0
- langroid-0.17.0/langroid/agent/xml_tool_message.py +239 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/constants.py +2 -0
- langroid-0.17.0/langroid/utils/git_utils.py +251 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/system.py +78 -0
- {langroid-0.16.7 → langroid-0.17.0}/pyproject.toml +3 -2
- langroid-0.16.7/langroid/agent/md_tool_message_grammar.py +0 -455
- langroid-0.16.7/langroid/agent/tools/code_file_tool_parse.py +0 -150
- langroid-0.16.7/langroid/agent/tools/code_file_tool_pyparsing.py +0 -194
- langroid-0.16.7/langroid/agent/tools/code_file_tool_pyparsing2.py +0 -199
- langroid-0.16.7/langroid/agent/tools/extract_tool.py +0 -96
- langroid-0.16.7/langroid/agent/tools/formatted_model_custom.py +0 -150
- langroid-0.16.7/langroid/agent/tools/formatted_model_custom2.py +0 -168
- langroid-0.16.7/langroid/agent/tools/formatted_model_custom3.py +0 -279
- langroid-0.16.7/langroid/agent/tools/formatted_model_custom4.py +0 -395
- langroid-0.16.7/langroid/agent/tools/formatted_model_jinja.py +0 -133
- langroid-0.16.7/langroid/agent/tools/formatted_model_jinja.py-e +0 -122
- langroid-0.16.7/langroid/agent/tools/formatted_model_jinja2.py +0 -145
- langroid-0.16.7/langroid/agent/tools/formatted_model_jinja2.py-e +0 -135
- langroid-0.16.7/langroid/agent/tools/formatted_model_lark.py +0 -0
- langroid-0.16.7/langroid/agent/tools/formatted_model_lark2.py +0 -168
- langroid-0.16.7/langroid/agent/tools/formatted_model_parse.py +0 -105
- langroid-0.16.7/langroid/agent/tools/formatted_model_parse.py-e +0 -98
- langroid-0.16.7/langroid/agent/tools/formatted_model_parse2.py +0 -113
- langroid-0.16.7/langroid/agent/tools/formatted_model_parse2.py-e +0 -109
- langroid-0.16.7/langroid/agent/tools/formatted_model_parse3.py +0 -114
- langroid-0.16.7/langroid/agent/tools/formatted_model_parse3.py-e +0 -110
- langroid-0.16.7/langroid/agent/tools/formatted_model_parsimon.py +0 -194
- langroid-0.16.7/langroid/agent/tools/formatted_model_parsimon.py-e +0 -186
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing.py +0 -169
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing.py-e +0 -149
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing2.py +0 -159
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing2.py-e +0 -143
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing3.py +0 -133
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing3.py-e +0 -121
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing4.py +0 -213
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing4.py-e +0 -176
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing5.py +0 -173
- langroid-0.16.7/langroid/agent/tools/formatted_model_pyparsing5.py-e +0 -142
- langroid-0.16.7/langroid/agent/tools/formatted_model_regex.py +0 -246
- langroid-0.16.7/langroid/agent/tools/formatted_model_regex.py-e +0 -248
- langroid-0.16.7/langroid/agent/tools/formatted_model_regex2.py +0 -250
- langroid-0.16.7/langroid/agent/tools/formatted_model_regex2.py-e +0 -253
- langroid-0.16.7/langroid/agent/tools/formatted_model_tatsu.py +0 -172
- langroid-0.16.7/langroid/agent/tools/formatted_model_tatsu.py-e +0 -160
- langroid-0.16.7/langroid/agent/tools/formatted_model_template.py +0 -217
- langroid-0.16.7/langroid/agent/tools/formatted_model_template.py-e +0 -200
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml.py +0 -178
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml2.py +0 -178
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml3.py +0 -132
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml4.py +0 -130
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml5.py +0 -130
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml6.py +0 -113
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml7.py +0 -117
- langroid-0.16.7/langroid/agent/tools/formatted_model_xml8.py +0 -164
- langroid-0.16.7/langroid/agent/tools/generator_tool.py +0 -20
- langroid-0.16.7/langroid/agent/tools/generic_tool.py +0 -165
- langroid-0.16.7/langroid/agent/tools/generic_tool_tatsu.py +0 -275
- langroid-0.16.7/langroid/agent/tools/grammar_based_model.py +0 -132
- langroid-0.16.7/langroid/agent/tools/grammar_based_model.py-e +0 -128
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_lark.py +0 -156
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_lark.py-e +0 -153
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_parse.py +0 -86
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_parse.py-e +0 -80
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_parsimonious.py +0 -129
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_parsimonious.py-e +0 -120
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_pyparsing.py +0 -105
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_pyparsing.py-e +0 -103
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_regex.py +0 -139
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_regex.py-e +0 -130
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_regex2.py +0 -124
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_regex2.py-e +0 -116
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_tatsu.py +0 -80
- langroid-0.16.7/langroid/agent/tools/grammar_based_model_tatsu.py-e +0 -77
- langroid-0.16.7/langroid/agent/tools/lark_earley_example.py +0 -135
- langroid-0.16.7/langroid/agent/tools/lark_earley_example.py-e +0 -117
- langroid-0.16.7/langroid/agent/tools/lark_example.py +0 -72
- langroid-0.16.7/langroid/agent/tools/note_tool.py +0 -0
- langroid-0.16.7/langroid/agent/tools/parse_example.py +0 -76
- langroid-0.16.7/langroid/agent/tools/parse_example2.py +0 -87
- langroid-0.16.7/langroid/agent/tools/parse_example3.py +0 -42
- langroid-0.16.7/langroid/agent/tools/parse_test.py +0 -791
- langroid-0.16.7/langroid/agent/tools/run_python_code.py +0 -60
- langroid-0.16.7/langroid/agent/xml_tool_message.py +0 -106
- {langroid-0.16.7 → langroid-0.17.0}/LICENSE +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/batch.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/callbacks/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/callbacks/chainlit.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/helpers.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/junk +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/openai_assistant.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/doc_chat_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/lance_doc_chat_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/lance_rag/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/lance_rag/critic_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/lance_rag/lance_rag_task.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/lance_rag/query_planner_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/lance_tools.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/neo4j/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/neo4j/csv_kg_chat.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/neo4j/neo4j_chat_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/neo4j/utils/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/neo4j/utils/system_message.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/relevance_extractor_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/retriever_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/sql_chat_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/utils/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/utils/description_extractors.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/utils/populate_metadata.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/utils/system_message.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/sql/utils/tools.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/special/table_chat_agent.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/structured_message.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/task.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/duckduckgo_search_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/google_search_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/metaphor_search_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/orchestration.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/recipient_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/retrieval_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/rewind_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/tools/segment_extract_tool.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent/typed_task.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/agent_config.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/cachedb/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/cachedb/base.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/cachedb/momento_cachedb.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/cachedb/redis_cachedb.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/base.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/clustering.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/models.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/protoc/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/protoc/embeddings.proto +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/protoc/embeddings_pb2.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/protoc/embeddings_pb2.pyi +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/protoc/embeddings_pb2_grpc.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/embedding_models/remote_embeds.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/exceptions.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/.chainlit/config.toml +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/.chainlit/translations/en-US.json +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/azure_openai.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/base.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/config.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/mock_lm.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/openai_gpt.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/prompt_formatter/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/prompt_formatter/base.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/prompt_formatter/hf_formatter.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/prompt_formatter/llama2_formatter.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/language_models/utils.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/mytypes.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/agent_chats.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/code-parsing.md +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/code_parser.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/config.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/document_parser.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/image_text.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/para_sentence_split.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/parse_json.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/parser.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/repo_loader.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/routing.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/search.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/spider.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/table_loader.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/url_loader.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/url_loader_cookies.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/urls.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/utils.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/parsing/web_search.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/prompts/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/prompts/chat-gpt4-system-prompt.md +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/prompts/dialog.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/prompts/prompts_config.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/prompts/templates.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/py.typed +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/pydantic_v1/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/pydantic_v1/main.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/.chainlit/config.toml +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/.chainlit/translations/en-US.json +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/algorithms/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/algorithms/graph.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/configuration.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/docker.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/globals.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/llms/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/llms/strings.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/logging.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/object_registry.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/output/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/output/citations.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/output/printing.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/output/status.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/pandas_utils.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/pydantic_utils.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/types.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/web/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/utils/web/login.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/__init__.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/base.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/chromadb.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/lancedb.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/meilisearch.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/momento.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/qdrant_cloud.py +0 -0
- {langroid-0.16.7 → langroid-0.17.0}/langroid/vector_store/qdrantdb.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: langroid
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.17.0
|
4
4
|
Summary: Harness LLMs with Multi-Agent Programming
|
5
5
|
License: MIT
|
6
6
|
Author: Prasad Chalasani
|
@@ -48,6 +48,7 @@ Requires-Dist: faker (>=18.9.0,<19.0.0)
|
|
48
48
|
Requires-Dist: fakeredis (>=2.12.1,<3.0.0)
|
49
49
|
Requires-Dist: fastembed (>=0.3.1,<0.4.0) ; extra == "all" or extra == "fastembed"
|
50
50
|
Requires-Dist: fire (>=0.5.0,<0.6.0)
|
51
|
+
Requires-Dist: gitpython (>=3.1.43,<4.0.0)
|
51
52
|
Requires-Dist: google-api-python-client (>=2.95.0,<3.0.0)
|
52
53
|
Requires-Dist: google-generativeai (>=0.5.2,<0.6.0)
|
53
54
|
Requires-Dist: groq (>=0.5.0,<0.6.0)
|
@@ -55,7 +56,7 @@ Requires-Dist: grpcio (>=1.62.1,<2.0.0)
|
|
55
56
|
Requires-Dist: halo (>=0.0.31,<0.0.32)
|
56
57
|
Requires-Dist: huggingface-hub (>=0.21.2,<0.22.0) ; extra == "hf-transformers" or extra == "all" or extra == "transformers"
|
57
58
|
Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
|
58
|
-
Requires-Dist: json-repair (>=0.29.
|
59
|
+
Requires-Dist: json-repair (>=0.29.9,<0.30.0)
|
59
60
|
Requires-Dist: lancedb (>=0.8.2,<0.9.0) ; extra == "vecdbs" or extra == "lancedb"
|
60
61
|
Requires-Dist: litellm (>=1.30.1,<2.0.0) ; extra == "all" or extra == "litellm"
|
61
62
|
Requires-Dist: lxml (>=4.9.3,<5.0.0)
|
@@ -143,7 +144,7 @@ Description-Content-Type: text/markdown
|
|
143
144
|
</h3>
|
144
145
|
|
145
146
|
`Langroid` is an intuitive, lightweight, extensible and principled
|
146
|
-
Python framework to easily build LLM-powered applications, from
|
147
|
+
Python framework to easily build LLM-powered applications, from CMU and UW-Madison researchers.
|
147
148
|
You set up Agents, equip them with optional components (LLM,
|
148
149
|
vector-store and tools/functions), assign them tasks, and have them
|
149
150
|
collaboratively solve a problem by exchanging messages.
|
@@ -242,6 +243,8 @@ teacher_task.run()
|
|
242
243
|
<details>
|
243
244
|
<summary> <b>Click to expand</b></summary>
|
244
245
|
|
246
|
+
- **Oct 2024:**
|
247
|
+
- **[0.17.0]** XML-based tools, see [docs](https://langroid.github.io/langroid/tutorials/xml-tools/).
|
245
248
|
- **Sep 2024:**
|
246
249
|
- **[0.16.0](https://github.com/langroid/langroid/releases/tag/0.16.0)** Support for OpenAI `o1-mini` and `o1-preview` models.
|
247
250
|
- **[0.15.0](https://github.com/langroid/langroid/releases/tag/0.15.0)** Cerebras API support -- run llama-3.1 models hosted on Cerebras Cloud (very fast inference).
|
@@ -35,7 +35,7 @@
|
|
35
35
|
</h3>
|
36
36
|
|
37
37
|
`Langroid` is an intuitive, lightweight, extensible and principled
|
38
|
-
Python framework to easily build LLM-powered applications, from
|
38
|
+
Python framework to easily build LLM-powered applications, from CMU and UW-Madison researchers.
|
39
39
|
You set up Agents, equip them with optional components (LLM,
|
40
40
|
vector-store and tools/functions), assign them tasks, and have them
|
41
41
|
collaboratively solve a problem by exchanging messages.
|
@@ -134,6 +134,8 @@ teacher_task.run()
|
|
134
134
|
<details>
|
135
135
|
<summary> <b>Click to expand</b></summary>
|
136
136
|
|
137
|
+
- **Oct 2024:**
|
138
|
+
- **[0.17.0]** XML-based tools, see [docs](https://langroid.github.io/langroid/tutorials/xml-tools/).
|
137
139
|
- **Sep 2024:**
|
138
140
|
- **[0.16.0](https://github.com/langroid/langroid/releases/tag/0.16.0)** Support for OpenAI `o1-mini` and `o1-preview` models.
|
139
141
|
- **[0.15.0](https://github.com/langroid/langroid/releases/tag/0.15.0)** Cerebras API support -- run llama-3.1 models hosted on Cerebras Cloud (very fast inference).
|
@@ -32,6 +32,7 @@ from rich.prompt import Prompt
|
|
32
32
|
|
33
33
|
from langroid.agent.chat_document import ChatDocMetaData, ChatDocument
|
34
34
|
from langroid.agent.tool_message import ToolMessage
|
35
|
+
from langroid.agent.xml_tool_message import XMLToolMessage
|
35
36
|
from langroid.language_models.base import (
|
36
37
|
LanguageModel,
|
37
38
|
LLMConfig,
|
@@ -55,7 +56,13 @@ from langroid.pydantic_v1 import (
|
|
55
56
|
validator,
|
56
57
|
)
|
57
58
|
from langroid.utils.configuration import settings
|
58
|
-
from langroid.utils.constants import
|
59
|
+
from langroid.utils.constants import (
|
60
|
+
DONE,
|
61
|
+
NO_ANSWER,
|
62
|
+
PASS,
|
63
|
+
PASS_TO,
|
64
|
+
SEND_TO,
|
65
|
+
)
|
59
66
|
from langroid.utils.object_registry import ObjectRegistry
|
60
67
|
from langroid.utils.output import status
|
61
68
|
from langroid.utils.types import from_string, to_string
|
@@ -910,7 +917,7 @@ class Agent(ABC):
|
|
910
917
|
return []
|
911
918
|
|
912
919
|
if isinstance(msg, str):
|
913
|
-
json_tools = self.
|
920
|
+
json_tools = self.get_formatted_tool_messages(msg)
|
914
921
|
if all_tools:
|
915
922
|
return json_tools
|
916
923
|
else:
|
@@ -938,7 +945,7 @@ class Agent(ABC):
|
|
938
945
|
and msg.function_call is None
|
939
946
|
):
|
940
947
|
|
941
|
-
tools = self.
|
948
|
+
tools = self.get_formatted_tool_messages(msg.content)
|
942
949
|
msg.all_tool_messages = tools
|
943
950
|
my_tools = [t for t in tools if self._tool_recipient_match(t)]
|
944
951
|
msg.tool_messages = my_tools
|
@@ -966,9 +973,16 @@ class Agent(ABC):
|
|
966
973
|
else:
|
967
974
|
return my_tools
|
968
975
|
|
969
|
-
def
|
976
|
+
def get_formatted_tool_messages(self, input_str: str) -> List[ToolMessage]:
|
970
977
|
"""
|
971
|
-
Returns ToolMessage objects (tools) corresponding to
|
978
|
+
Returns ToolMessage objects (tools) corresponding to
|
979
|
+
tool-formatted substrings, if any.
|
980
|
+
ASSUMPTION - These tools are either ALL JSON-based, or ALL XML-based
|
981
|
+
(i.e. not a mix of both).
|
982
|
+
Terminology: a "formatted tool msg" is one which the LLM generates as
|
983
|
+
part of its raw string output, rather than within a JSON object
|
984
|
+
in the API response (i.e. this method does not extract tools/fns returned
|
985
|
+
by OpenAI's tools/fns API or similar APIs).
|
972
986
|
|
973
987
|
Args:
|
974
988
|
input_str (str): input string, typically a message sent by an LLM
|
@@ -976,10 +990,15 @@ class Agent(ABC):
|
|
976
990
|
Returns:
|
977
991
|
List[ToolMessage]: list of ToolMessage objects
|
978
992
|
"""
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
993
|
+
substrings = XMLToolMessage.find_candidates(input_str)
|
994
|
+
is_json = False
|
995
|
+
if len(substrings) == 0:
|
996
|
+
substrings = extract_top_level_json(input_str)
|
997
|
+
is_json = len(substrings) > 0
|
998
|
+
if not is_json:
|
999
|
+
return []
|
1000
|
+
|
1001
|
+
results = [self._get_one_tool_message(j, is_json) for j in substrings]
|
983
1002
|
return [r for r in results if r is not None]
|
984
1003
|
|
985
1004
|
def get_function_call_class(self, msg: ChatDocument) -> Optional[ToolMessage]:
|
@@ -1200,17 +1219,22 @@ class Agent(ABC):
|
|
1200
1219
|
"""
|
1201
1220
|
return None
|
1202
1221
|
|
1203
|
-
def _get_one_tool_message(
|
1222
|
+
def _get_one_tool_message(
|
1223
|
+
self, tool_candidate_str: str, is_json: bool = True
|
1224
|
+
) -> Optional[ToolMessage]:
|
1204
1225
|
"""
|
1205
|
-
Parse the
|
1226
|
+
Parse the tool_candidate_str into ANY ToolMessage KNOWN to agent --
|
1206
1227
|
This includes non-used/handled tools, i.e. any tool in self.llm_tools_known.
|
1207
1228
|
The exception to this is below where we try our best to infer the tool
|
1208
|
-
when the LLM has "forgotten" to include the "request" field in the
|
1229
|
+
when the LLM has "forgotten" to include the "request" field in the tool str ---
|
1209
1230
|
in this case we ONLY look at the possible set of HANDLED tools, i.e.
|
1210
1231
|
self.llm_tools_handled.
|
1211
1232
|
"""
|
1212
|
-
|
1213
|
-
|
1233
|
+
if is_json:
|
1234
|
+
maybe_tool_dict = json.loads(tool_candidate_str)
|
1235
|
+
else:
|
1236
|
+
maybe_tool_dict = XMLToolMessage.extract_field_values(tool_candidate_str)
|
1237
|
+
# check if the maybe_tool_dict contains a "properties" field
|
1214
1238
|
# which further contains the actual tool-call
|
1215
1239
|
# (some weak LLMs do this). E.g. gpt-4o sometimes generates this:
|
1216
1240
|
# TOOL: {
|
@@ -1225,17 +1249,17 @@ class Agent(ABC):
|
|
1225
1249
|
# ]
|
1226
1250
|
# }
|
1227
1251
|
|
1228
|
-
if not isinstance(
|
1252
|
+
if not isinstance(maybe_tool_dict, dict):
|
1229
1253
|
return None
|
1230
1254
|
|
1231
|
-
properties =
|
1255
|
+
properties = maybe_tool_dict.get("properties")
|
1232
1256
|
if isinstance(properties, dict):
|
1233
|
-
|
1234
|
-
request =
|
1257
|
+
maybe_tool_dict = properties
|
1258
|
+
request = maybe_tool_dict.get("request")
|
1235
1259
|
if request is None:
|
1236
1260
|
possible = [self.llm_tools_map[r] for r in self.llm_tools_handled]
|
1237
1261
|
default_keys = set(ToolMessage.__fields__.keys())
|
1238
|
-
request_keys = set(
|
1262
|
+
request_keys = set(maybe_tool_dict.keys())
|
1239
1263
|
|
1240
1264
|
def maybe_parse(tool: type[ToolMessage]) -> Optional[ToolMessage]:
|
1241
1265
|
all_keys = set(tool.__fields__.keys())
|
@@ -1250,7 +1274,7 @@ class Agent(ABC):
|
|
1250
1274
|
return None
|
1251
1275
|
|
1252
1276
|
try:
|
1253
|
-
return tool.parse_obj(
|
1277
|
+
return tool.parse_obj(maybe_tool_dict)
|
1254
1278
|
except ValidationError:
|
1255
1279
|
return None
|
1256
1280
|
|
@@ -1277,7 +1301,7 @@ class Agent(ABC):
|
|
1277
1301
|
return None
|
1278
1302
|
|
1279
1303
|
try:
|
1280
|
-
message = message_class.parse_obj(
|
1304
|
+
message = message_class.parse_obj(maybe_tool_dict)
|
1281
1305
|
except ValidationError as ve:
|
1282
1306
|
raise ve
|
1283
1307
|
return message
|
@@ -12,6 +12,7 @@ from rich.markup import escape
|
|
12
12
|
from langroid.agent.base import Agent, AgentConfig, noop_fn
|
13
13
|
from langroid.agent.chat_document import ChatDocument
|
14
14
|
from langroid.agent.tool_message import ToolMessage
|
15
|
+
from langroid.agent.xml_tool_message import XMLToolMessage
|
15
16
|
from langroid.language_models.base import (
|
16
17
|
LLMFunctionSpec,
|
17
18
|
LLMMessage,
|
@@ -141,7 +142,7 @@ class ChatAgent(Agent):
|
|
141
142
|
# if they are specified in a ToolMessage class as a classmethod `instructions`
|
142
143
|
self.system_tool_instructions: str = ""
|
143
144
|
# (b) these are only for the builtin in Langroid TOOLS mechanism:
|
144
|
-
self.
|
145
|
+
self.system_tool_format_instructions: str = ""
|
145
146
|
|
146
147
|
self.llm_functions_map: Dict[str, LLMFunctionSpec] = {}
|
147
148
|
self.llm_functions_handled: Set[str] = set()
|
@@ -207,7 +208,7 @@ class ChatAgent(Agent):
|
|
207
208
|
config_copy.name = f"{config_copy.name}-{i}"
|
208
209
|
new_agent = agent_cls(config_copy)
|
209
210
|
new_agent.system_tool_instructions = self.system_tool_instructions
|
210
|
-
new_agent.
|
211
|
+
new_agent.system_tool_format_instructions = self.system_tool_format_instructions
|
211
212
|
new_agent.llm_tools_map = self.llm_tools_map
|
212
213
|
new_agent.llm_functions_map = self.llm_functions_map
|
213
214
|
new_agent.llm_functions_handled = self.llm_functions_handled
|
@@ -303,10 +304,11 @@ class ChatAgent(Agent):
|
|
303
304
|
]
|
304
305
|
)
|
305
306
|
|
306
|
-
def
|
307
|
+
def tool_format_rules(self) -> str:
|
307
308
|
"""
|
308
|
-
Specification of
|
309
|
-
|
309
|
+
Specification of tool formatting rules
|
310
|
+
(typically JSON-based but can be non-JSON, e.g. XMLToolMessage),
|
311
|
+
based on the currently enabled usable `ToolMessage`s
|
310
312
|
|
311
313
|
Returns:
|
312
314
|
str: formatting rules
|
@@ -320,9 +322,9 @@ class ChatAgent(Agent):
|
|
320
322
|
|
321
323
|
if len(usable_tool_classes) == 0:
|
322
324
|
return "You can ask questions in natural language."
|
323
|
-
|
325
|
+
format_instructions = "\n\n".join(
|
324
326
|
[
|
325
|
-
msg_cls.
|
327
|
+
msg_cls.format_instructions(tool=self.config.use_tools)
|
326
328
|
for msg_cls in usable_tool_classes
|
327
329
|
]
|
328
330
|
)
|
@@ -332,11 +334,11 @@ class ChatAgent(Agent):
|
|
332
334
|
if hasattr(msg_cls, "json_group_instructions") and callable(
|
333
335
|
getattr(msg_cls, "json_group_instructions")
|
334
336
|
):
|
335
|
-
return msg_cls.
|
336
|
-
|
337
|
+
return msg_cls.group_format_instructions().format(
|
338
|
+
format_instructions=format_instructions
|
337
339
|
)
|
338
|
-
return ToolMessage.
|
339
|
-
|
340
|
+
return ToolMessage.group_format_instructions().format(
|
341
|
+
format_instructions=format_instructions
|
340
342
|
)
|
341
343
|
|
342
344
|
def tool_instructions(self) -> str:
|
@@ -358,7 +360,7 @@ class ChatAgent(Agent):
|
|
358
360
|
and inspect.ismethod(msg_cls.instructions)
|
359
361
|
and msg_cls.default_value("request") in self.llm_tools_usable
|
360
362
|
):
|
361
|
-
# example will be shown in
|
363
|
+
# example will be shown in tool_format_rules() when using TOOLs,
|
362
364
|
# so we don't need to show it here.
|
363
365
|
example = "" if self.config.use_tools else (msg_cls.usage_examples())
|
364
366
|
if example != "":
|
@@ -457,7 +459,7 @@ class ChatAgent(Agent):
|
|
457
459
|
|
458
460
|
{self.system_tool_instructions}
|
459
461
|
|
460
|
-
{self.
|
462
|
+
{self.system_tool_format_instructions}
|
461
463
|
|
462
464
|
""".lstrip()
|
463
465
|
)
|
@@ -520,6 +522,12 @@ class ChatAgent(Agent):
|
|
520
522
|
return None
|
521
523
|
if require_recipient and message_class is not None:
|
522
524
|
message_class = message_class.require_recipient()
|
525
|
+
if isinstance(message_class, XMLToolMessage):
|
526
|
+
# XMLToolMessage is not compatible with OpenAI's Tools/functions API,
|
527
|
+
# so we disable use of functions API, enable langroid-native Tools,
|
528
|
+
# which are prompt-based.
|
529
|
+
self.config.use_functions_api = False
|
530
|
+
self.config.use_tools = True
|
523
531
|
super().enable_message_handling(message_class) # enables handling only
|
524
532
|
tools = self._get_tool_list(message_class)
|
525
533
|
if message_class is not None:
|
@@ -570,7 +578,7 @@ class ChatAgent(Agent):
|
|
570
578
|
|
571
579
|
# Set tool instructions and JSON format instructions
|
572
580
|
if self.config.use_tools:
|
573
|
-
self.
|
581
|
+
self.system_tool_format_instructions = self.tool_format_rules()
|
574
582
|
self.system_tool_instructions = self.tool_instructions()
|
575
583
|
|
576
584
|
def disable_message_handling(
|
@@ -7,6 +7,7 @@ from enum import Enum
|
|
7
7
|
from typing import Any, Dict, List, Optional, Union, cast
|
8
8
|
|
9
9
|
from langroid.agent.tool_message import ToolMessage
|
10
|
+
from langroid.agent.xml_tool_message import XMLToolMessage
|
10
11
|
from langroid.language_models.base import (
|
11
12
|
LLMFunctionCall,
|
12
13
|
LLMMessage,
|
@@ -181,21 +182,29 @@ class ChatDocument(Document):
|
|
181
182
|
f"{recipient_str}{tool_str}{fields.content}"
|
182
183
|
)
|
183
184
|
|
184
|
-
def
|
185
|
+
def get_tool_names(self) -> List[str]:
|
185
186
|
"""
|
186
|
-
Get names of attempted
|
187
|
+
Get names of attempted tool usages (JSON or non-JSON) in the content
|
187
188
|
of the message.
|
188
189
|
Returns:
|
189
|
-
List[str]: list of
|
190
|
+
List[str]: list of *attempted* tool names
|
191
|
+
(We say "attempted" since we ONLY look at the `request` component of the
|
192
|
+
tool-call representation, and we're not fully parsing it into the
|
193
|
+
corresponding tool message class)
|
194
|
+
|
190
195
|
"""
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
196
|
+
tool_candidates = XMLToolMessage.find_candidates(self.content)
|
197
|
+
if len(tool_candidates) == 0:
|
198
|
+
tool_candidates = extract_top_level_json(self.content)
|
199
|
+
if len(tool_candidates) == 0:
|
200
|
+
return []
|
201
|
+
tools = [json.loads(tc).get("request") for tc in tool_candidates]
|
202
|
+
else:
|
203
|
+
tool_dicts = [
|
204
|
+
XMLToolMessage.extract_field_values(tc) for tc in tool_candidates
|
205
|
+
]
|
206
|
+
tools = [td.get("request") for td in tool_dicts if td is not None]
|
207
|
+
return [str(tool) for tool in tools if tool is not None]
|
199
208
|
|
200
209
|
def log_fields(self) -> ChatDocLoggerFields:
|
201
210
|
"""
|
@@ -208,9 +217,9 @@ class ChatDocument(Document):
|
|
208
217
|
if self.function_call is not None:
|
209
218
|
tool_type = "FUNC"
|
210
219
|
tool = self.function_call.name
|
211
|
-
elif self.
|
220
|
+
elif (json_tools := self.get_tool_names()) != []:
|
212
221
|
tool_type = "TOOL"
|
213
|
-
tool =
|
222
|
+
tool = json_tools[0]
|
214
223
|
recipient = self.metadata.recipient
|
215
224
|
content = self.content
|
216
225
|
sender_entity = self.metadata.sender
|
@@ -72,7 +72,7 @@ class ToolMessage(ABC, BaseModel):
|
|
72
72
|
@classmethod
|
73
73
|
def examples(cls) -> List["ToolMessage" | Tuple[str, "ToolMessage"]]:
|
74
74
|
"""
|
75
|
-
Examples to use in few-shot demos with
|
75
|
+
Examples to use in few-shot demos with formatting instructions.
|
76
76
|
Each example can be either:
|
77
77
|
- just a ToolMessage instance, e.g. MyTool(param1=1, param2="hello"), or
|
78
78
|
- a tuple (description, ToolMessage instance), where the description is
|
@@ -104,20 +104,20 @@ class ToolMessage(ABC, BaseModel):
|
|
104
104
|
examples = [choice(cls.examples())]
|
105
105
|
else:
|
106
106
|
examples = cls.examples()
|
107
|
-
|
107
|
+
formatted_examples = [
|
108
108
|
(
|
109
|
-
f"EXAMPLE {i}: (THOUGHT: {ex[0]}) => \n{ex[1].
|
109
|
+
f"EXAMPLE {i}: (THOUGHT: {ex[0]}) => \n{ex[1].format_example()}"
|
110
110
|
if isinstance(ex, tuple)
|
111
|
-
else f"EXAMPLE {i}:\n {ex.
|
111
|
+
else f"EXAMPLE {i}:\n {ex.format_example()}"
|
112
112
|
)
|
113
113
|
for i, ex in enumerate(examples, 1)
|
114
114
|
]
|
115
|
-
return "\n\n".join(
|
115
|
+
return "\n\n".join(formatted_examples)
|
116
116
|
|
117
117
|
def to_json(self) -> str:
|
118
118
|
return self.json(indent=4, exclude=self.Config.schema_extra["exclude"])
|
119
119
|
|
120
|
-
def
|
120
|
+
def format_example(self) -> str:
|
121
121
|
return self.json(indent=4, exclude=self.Config.schema_extra["exclude"])
|
122
122
|
|
123
123
|
def dict_example(self) -> Dict[str, Any]:
|
@@ -148,7 +148,7 @@ class ToolMessage(ABC, BaseModel):
|
|
148
148
|
return properties.get(f, {}).get("default", None)
|
149
149
|
|
150
150
|
@classmethod
|
151
|
-
def
|
151
|
+
def format_instructions(cls, tool: bool = False) -> str:
|
152
152
|
"""
|
153
153
|
Default Instructions to the LLM showing how to use the tool/function-call.
|
154
154
|
Works for GPT4 but override this for weaker LLMs if needed.
|
@@ -181,19 +181,19 @@ class ToolMessage(ABC, BaseModel):
|
|
181
181
|
)
|
182
182
|
|
183
183
|
@staticmethod
|
184
|
-
def
|
184
|
+
def group_format_instructions() -> str:
|
185
185
|
"""Template for instructions for a group of tools.
|
186
186
|
Works with GPT4 but override this for weaker LLMs if needed.
|
187
187
|
"""
|
188
188
|
return textwrap.dedent(
|
189
189
|
"""
|
190
|
-
=== ALL AVAILABLE TOOLS and THEIR
|
190
|
+
=== ALL AVAILABLE TOOLS and THEIR FORMAT INSTRUCTIONS ===
|
191
191
|
You have access to the following TOOLS to accomplish your task:
|
192
192
|
|
193
|
-
{
|
193
|
+
{format_instructions}
|
194
194
|
|
195
195
|
When one of the above TOOLs is applicable, you must express your
|
196
|
-
request as "TOOL:" followed by the request in the above
|
196
|
+
request as "TOOL:" followed by the request in the above format.
|
197
197
|
"""
|
198
198
|
)
|
199
199
|
|
@@ -0,0 +1,234 @@
|
|
1
|
+
from contextlib import chdir
|
2
|
+
from pathlib import Path
|
3
|
+
from textwrap import dedent
|
4
|
+
from typing import Callable, List, Tuple, Type
|
5
|
+
|
6
|
+
import git
|
7
|
+
|
8
|
+
from langroid.agent.tool_message import ToolMessage
|
9
|
+
from langroid.agent.xml_tool_message import XMLToolMessage
|
10
|
+
from langroid.pydantic_v1 import Field
|
11
|
+
from langroid.utils.git_utils import git_commit_file
|
12
|
+
from langroid.utils.system import create_file, list_dir, read_file
|
13
|
+
|
14
|
+
|
15
|
+
class ReadFileTool(ToolMessage):
|
16
|
+
request: str = "read_file_tool"
|
17
|
+
purpose: str = "Read the contents of a <file_path>"
|
18
|
+
file_path: str
|
19
|
+
|
20
|
+
_line_nums: bool = True # whether to add line numbers to the content
|
21
|
+
_curr_dir: Callable[[], str] | None = None
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def create(
|
25
|
+
cls,
|
26
|
+
get_curr_dir: Callable[[], str] | None,
|
27
|
+
) -> Type["ReadFileTool"]:
|
28
|
+
"""
|
29
|
+
Create a subclass of ReadFileTool for a specific directory
|
30
|
+
|
31
|
+
Args:
|
32
|
+
get_curr_dir (callable): A function that returns the current directory.
|
33
|
+
|
34
|
+
Returns:
|
35
|
+
Type[ReadFileTool]: A subclass of the ReadFileTool class, specifically
|
36
|
+
for the current directory.
|
37
|
+
"""
|
38
|
+
|
39
|
+
class CustomReadFileTool(cls): # type: ignore
|
40
|
+
_curr_dir: Callable[[], str] | None = (
|
41
|
+
staticmethod(get_curr_dir) if get_curr_dir else None
|
42
|
+
)
|
43
|
+
|
44
|
+
return CustomReadFileTool
|
45
|
+
|
46
|
+
@classmethod
|
47
|
+
def examples(cls) -> List[ToolMessage | tuple[str, ToolMessage]]:
|
48
|
+
return [
|
49
|
+
cls(file_path="src/lib.rs"),
|
50
|
+
(
|
51
|
+
"I want to read the contents of src/main.rs",
|
52
|
+
cls(file_path="src/main.rs"),
|
53
|
+
),
|
54
|
+
]
|
55
|
+
|
56
|
+
def handle(self) -> str:
|
57
|
+
# return contents as str for LLM to read
|
58
|
+
# ASSUME: file_path should be relative to the curr_dir
|
59
|
+
try:
|
60
|
+
dir = (self._curr_dir and self._curr_dir()) or Path.cwd()
|
61
|
+
with chdir(dir):
|
62
|
+
# if file doesn't exist, return an error message
|
63
|
+
content = read_file(self.file_path, self._line_nums)
|
64
|
+
line_num_str = ""
|
65
|
+
if self._line_nums:
|
66
|
+
line_num_str = "(Line numbers added for reference only!)"
|
67
|
+
return f"""
|
68
|
+
CONTENTS of {self.file_path}:
|
69
|
+
{line_num_str}
|
70
|
+
---------------------------
|
71
|
+
{content}
|
72
|
+
"""
|
73
|
+
except FileNotFoundError:
|
74
|
+
return f"File not found: {self.file_path}"
|
75
|
+
|
76
|
+
|
77
|
+
class WriteFileTool(XMLToolMessage):
|
78
|
+
request: str = "write_file_tool"
|
79
|
+
purpose: str = """
|
80
|
+
Tool for writing <content> in a certain <language> to a <file_path>
|
81
|
+
"""
|
82
|
+
|
83
|
+
file_path: str = Field(..., description="The path to the file to write the content")
|
84
|
+
|
85
|
+
language: str = Field(
|
86
|
+
default="",
|
87
|
+
description="""
|
88
|
+
The language of the content; could be human language or programming language
|
89
|
+
""",
|
90
|
+
)
|
91
|
+
content: str = Field(
|
92
|
+
...,
|
93
|
+
description="The content to write to the file",
|
94
|
+
verbatim=True, # preserve the content as is; uses CDATA section in XML
|
95
|
+
)
|
96
|
+
_curr_dir: Callable[[], str] | None = None
|
97
|
+
_git_repo: Callable[[], git.Repo] | None = None
|
98
|
+
_commit_message: str = "Agent write file tool"
|
99
|
+
|
100
|
+
@classmethod
|
101
|
+
def create(
|
102
|
+
cls,
|
103
|
+
get_curr_dir: Callable[[], str] | None,
|
104
|
+
get_git_repo: Callable[[], str] | None,
|
105
|
+
) -> Type["WriteFileTool"]:
|
106
|
+
"""
|
107
|
+
Create a subclass of WriteFileTool with the current directory and git repo.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
get_curr_dir (callable): A function that returns the current directory.
|
111
|
+
get_git_repo (callable): A function that returns the git repo.
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
Type[WriteFileTool]: A subclass of the WriteFileTool class, specifically
|
115
|
+
for the current directory and git repo.
|
116
|
+
"""
|
117
|
+
|
118
|
+
class CustomWriteFileTool(cls): # type: ignore
|
119
|
+
_curr_dir: Callable[[], str] | None = (
|
120
|
+
staticmethod(get_curr_dir) if get_curr_dir else None
|
121
|
+
)
|
122
|
+
_git_repo: Callable[[], str] | None = (
|
123
|
+
staticmethod(get_git_repo) if get_git_repo else None
|
124
|
+
)
|
125
|
+
|
126
|
+
return CustomWriteFileTool
|
127
|
+
|
128
|
+
@classmethod
|
129
|
+
def examples(cls) -> List[ToolMessage | Tuple[str, ToolMessage]]:
|
130
|
+
return [
|
131
|
+
(
|
132
|
+
"""
|
133
|
+
I want to define a simple hello world python function
|
134
|
+
in a file "mycode/hello.py"
|
135
|
+
""",
|
136
|
+
cls(
|
137
|
+
file_path="mycode/hello.py",
|
138
|
+
language="python",
|
139
|
+
content="""
|
140
|
+
def hello():
|
141
|
+
print("Hello, World!")
|
142
|
+
""",
|
143
|
+
),
|
144
|
+
),
|
145
|
+
cls(
|
146
|
+
file_path="src/lib.rs",
|
147
|
+
language="rust",
|
148
|
+
content="""
|
149
|
+
fn main() {
|
150
|
+
println!("Hello, World!");
|
151
|
+
}
|
152
|
+
""",
|
153
|
+
),
|
154
|
+
cls(
|
155
|
+
file_path="docs/intro.txt",
|
156
|
+
content="""
|
157
|
+
# Introduction
|
158
|
+
This is the first sentence of the introduction.
|
159
|
+
""",
|
160
|
+
),
|
161
|
+
]
|
162
|
+
|
163
|
+
def handle(self) -> str:
|
164
|
+
curr_dir = (self._curr_dir and self._curr_dir()) or Path.cwd()
|
165
|
+
with chdir(curr_dir):
|
166
|
+
create_file(self.file_path, self.content)
|
167
|
+
msg = f"Content written to {self.file_path}"
|
168
|
+
# possibly commit the file
|
169
|
+
if self._git_repo:
|
170
|
+
git_commit_file(
|
171
|
+
self._git_repo(),
|
172
|
+
self.file_path,
|
173
|
+
self._commit_message,
|
174
|
+
)
|
175
|
+
msg += " and committed"
|
176
|
+
return msg
|
177
|
+
|
178
|
+
|
179
|
+
class ListDirTool(ToolMessage):
|
180
|
+
request: str = "list_dir_tool"
|
181
|
+
purpose: str = "List the contents of a <dir_path>"
|
182
|
+
dir_path: str
|
183
|
+
|
184
|
+
_curr_dir: Callable[[], str] | None = None
|
185
|
+
|
186
|
+
@classmethod
|
187
|
+
def create(
|
188
|
+
cls,
|
189
|
+
get_curr_dir: Callable[[], str] | None,
|
190
|
+
) -> Type["ReadFileTool"]:
|
191
|
+
"""
|
192
|
+
Create a subclass of ListDirTool for a specific directory
|
193
|
+
|
194
|
+
Args:
|
195
|
+
get_curr_dir (callable): A function that returns the current directory.
|
196
|
+
|
197
|
+
Returns:
|
198
|
+
Type[ReadFileTool]: A subclass of the ReadFileTool class, specifically
|
199
|
+
for the current directory.
|
200
|
+
"""
|
201
|
+
|
202
|
+
class CustomListDirTool(cls): # type: ignore
|
203
|
+
_curr_dir: Callable[[], str] | None = (
|
204
|
+
staticmethod(get_curr_dir) if get_curr_dir else None
|
205
|
+
)
|
206
|
+
|
207
|
+
return CustomListDirTool
|
208
|
+
|
209
|
+
@classmethod
|
210
|
+
def examples(cls) -> List[ToolMessage | tuple[str, ToolMessage]]:
|
211
|
+
return [
|
212
|
+
cls(dir_path="src"),
|
213
|
+
(
|
214
|
+
"I want to list the contents of src",
|
215
|
+
cls(dir_path="src"),
|
216
|
+
),
|
217
|
+
]
|
218
|
+
|
219
|
+
def handle(self) -> str:
|
220
|
+
# ASSUME: dir_path should be relative to the curr_dir_path
|
221
|
+
dir = (self._curr_dir and self._curr_dir()) or Path.cwd()
|
222
|
+
with chdir(dir):
|
223
|
+
contents = list_dir(self.dir_path)
|
224
|
+
|
225
|
+
if not contents:
|
226
|
+
return f"Directory not found or empty: {self.dir_path}"
|
227
|
+
contents_str = "\n".join(contents)
|
228
|
+
return dedent(
|
229
|
+
f"""
|
230
|
+
LISTING of directory {self.dir_path}:
|
231
|
+
---------------------------
|
232
|
+
{contents_str}
|
233
|
+
""".strip()
|
234
|
+
)
|