unique_toolkit 1.8.1__py3-none-any.whl → 1.23.0__py3-none-any.whl
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.
Potentially problematic release.
This version of unique_toolkit might be problematic. Click here for more details.
- unique_toolkit/__init__.py +20 -0
- unique_toolkit/_common/api_calling/human_verification_manager.py +121 -28
- unique_toolkit/_common/chunk_relevancy_sorter/config.py +3 -3
- unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +2 -5
- unique_toolkit/_common/default_language_model.py +9 -3
- unique_toolkit/_common/docx_generator/__init__.py +7 -0
- unique_toolkit/_common/docx_generator/config.py +12 -0
- unique_toolkit/_common/docx_generator/schemas.py +80 -0
- unique_toolkit/_common/docx_generator/service.py +252 -0
- unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
- unique_toolkit/_common/endpoint_builder.py +138 -117
- unique_toolkit/_common/endpoint_requestor.py +240 -14
- unique_toolkit/_common/exception.py +20 -0
- unique_toolkit/_common/feature_flags/schema.py +1 -5
- unique_toolkit/_common/referencing.py +53 -0
- unique_toolkit/_common/string_utilities.py +52 -1
- unique_toolkit/_common/tests/test_referencing.py +521 -0
- unique_toolkit/_common/tests/test_string_utilities.py +506 -0
- unique_toolkit/_common/utils/files.py +43 -0
- unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +16 -6
- unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +278 -0
- unique_toolkit/agentic/evaluation/config.py +3 -2
- unique_toolkit/agentic/evaluation/context_relevancy/service.py +2 -2
- unique_toolkit/agentic/evaluation/evaluation_manager.py +9 -5
- unique_toolkit/agentic/evaluation/hallucination/constants.py +1 -1
- unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +26 -3
- unique_toolkit/agentic/history_manager/history_manager.py +14 -11
- unique_toolkit/agentic/history_manager/loop_token_reducer.py +3 -4
- unique_toolkit/agentic/history_manager/utils.py +10 -87
- unique_toolkit/agentic/postprocessor/postprocessor_manager.py +107 -16
- unique_toolkit/agentic/reference_manager/reference_manager.py +1 -1
- unique_toolkit/agentic/responses_api/__init__.py +19 -0
- unique_toolkit/agentic/responses_api/postprocessors/code_display.py +63 -0
- unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +145 -0
- unique_toolkit/agentic/responses_api/stream_handler.py +15 -0
- unique_toolkit/agentic/tools/a2a/__init__.py +18 -2
- unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +2 -0
- unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +3 -3
- unique_toolkit/agentic/tools/a2a/evaluation/config.py +1 -1
- unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +143 -91
- unique_toolkit/agentic/tools/a2a/manager.py +7 -1
- unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +11 -3
- unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +185 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +73 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/config.py +21 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/display.py +180 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/references.py +101 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +1335 -0
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +603 -0
- unique_toolkit/agentic/tools/a2a/prompts.py +46 -0
- unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +6 -0
- unique_toolkit/agentic/tools/a2a/response_watcher/service.py +91 -0
- unique_toolkit/agentic/tools/a2a/tool/config.py +15 -5
- unique_toolkit/agentic/tools/a2a/tool/service.py +69 -36
- unique_toolkit/agentic/tools/config.py +16 -2
- unique_toolkit/agentic/tools/factory.py +4 -0
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py +7 -35
- unique_toolkit/agentic/tools/openai_builtin/__init__.py +11 -0
- unique_toolkit/agentic/tools/openai_builtin/base.py +30 -0
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +8 -0
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +57 -0
- unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +230 -0
- unique_toolkit/agentic/tools/openai_builtin/manager.py +62 -0
- unique_toolkit/agentic/tools/test/test_mcp_manager.py +95 -7
- unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +240 -0
- unique_toolkit/agentic/tools/tool.py +0 -11
- unique_toolkit/agentic/tools/tool_manager.py +337 -122
- unique_toolkit/agentic/tools/tool_progress_reporter.py +81 -15
- unique_toolkit/agentic/tools/utils/__init__.py +18 -0
- unique_toolkit/agentic/tools/utils/execution/execution.py +8 -4
- unique_toolkit/agentic/tools/utils/source_handling/schema.py +1 -1
- unique_toolkit/chat/__init__.py +8 -1
- unique_toolkit/chat/deprecated/service.py +232 -0
- unique_toolkit/chat/functions.py +54 -40
- unique_toolkit/chat/rendering.py +34 -0
- unique_toolkit/chat/responses_api.py +461 -0
- unique_toolkit/chat/schemas.py +1 -1
- unique_toolkit/chat/service.py +96 -1569
- unique_toolkit/content/functions.py +116 -1
- unique_toolkit/content/schemas.py +59 -0
- unique_toolkit/content/service.py +5 -37
- unique_toolkit/content/smart_rules.py +301 -0
- unique_toolkit/framework_utilities/langchain/client.py +27 -3
- unique_toolkit/framework_utilities/openai/client.py +12 -1
- unique_toolkit/framework_utilities/openai/message_builder.py +85 -1
- unique_toolkit/language_model/default_language_model.py +3 -0
- unique_toolkit/language_model/functions.py +25 -9
- unique_toolkit/language_model/infos.py +72 -4
- unique_toolkit/language_model/schemas.py +246 -40
- unique_toolkit/protocols/support.py +91 -9
- unique_toolkit/services/__init__.py +7 -0
- unique_toolkit/services/chat_service.py +1630 -0
- unique_toolkit/services/knowledge_base.py +861 -0
- unique_toolkit/smart_rules/compile.py +56 -301
- unique_toolkit/test_utilities/events.py +197 -0
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/METADATA +173 -3
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/RECORD +99 -67
- unique_toolkit/agentic/tools/a2a/postprocessing/_display.py +0 -122
- unique_toolkit/agentic/tools/a2a/postprocessing/_utils.py +0 -19
- unique_toolkit/agentic/tools/a2a/postprocessing/postprocessor.py +0 -230
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_consolidate_references.py +0 -665
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -391
- unique_toolkit/agentic/tools/a2a/postprocessing/test/test_postprocessor_reference_functions.py +0 -256
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/LICENSE +0 -0
- {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/WHEEL +0 -0
|
@@ -7,6 +7,7 @@ from unique_toolkit.agentic.tools.tool_progress_reporter import (
|
|
|
7
7
|
ProgressState,
|
|
8
8
|
ToolExecutionStatus,
|
|
9
9
|
ToolProgressReporter,
|
|
10
|
+
ToolProgressReporterConfig,
|
|
10
11
|
ToolWithToolProgressReporter,
|
|
11
12
|
track_tool_progress,
|
|
12
13
|
)
|
|
@@ -203,3 +204,242 @@ class TestToolProgressDecorator:
|
|
|
203
204
|
|
|
204
205
|
status = tool_progress_reporter.tool_statuses[tool_call.id]
|
|
205
206
|
assert status.state == ProgressState.FAILED
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class TestToolProgressReporterConfig:
|
|
210
|
+
"""Tests for ToolProgressReporterConfig and custom display configuration."""
|
|
211
|
+
|
|
212
|
+
@pytest.mark.ai
|
|
213
|
+
@pytest.mark.asyncio
|
|
214
|
+
async def test_config__uses_default_templates__when_no_config_provided(
|
|
215
|
+
self, chat_service, tool_call
|
|
216
|
+
) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Purpose: Verify that default state-to-display templates are used when no config is provided.
|
|
219
|
+
Why this matters: Ensures backward compatibility and default behavior.
|
|
220
|
+
Setup summary: Create reporter without config, add status, verify default template is used.
|
|
221
|
+
"""
|
|
222
|
+
# Arrange
|
|
223
|
+
reporter = ToolProgressReporter(chat_service)
|
|
224
|
+
|
|
225
|
+
# Act
|
|
226
|
+
await reporter.notify_from_tool_call(
|
|
227
|
+
tool_call=tool_call,
|
|
228
|
+
name="Test Tool",
|
|
229
|
+
message="Processing data",
|
|
230
|
+
state=ProgressState.RUNNING,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Assert
|
|
234
|
+
assert tool_call.id in reporter.tool_statuses
|
|
235
|
+
chat_service.modify_assistant_message_async.assert_called()
|
|
236
|
+
call_args = chat_service.modify_assistant_message_async.call_args
|
|
237
|
+
content = call_args.kwargs["content"]
|
|
238
|
+
assert "Test Tool" in content
|
|
239
|
+
assert "🟡" in content # Default emoji for RUNNING state
|
|
240
|
+
assert "Processing data" in content
|
|
241
|
+
|
|
242
|
+
@pytest.mark.ai
|
|
243
|
+
@pytest.mark.asyncio
|
|
244
|
+
async def test_config__uses_custom_templates__when_config_provided(
|
|
245
|
+
self, chat_service, tool_call
|
|
246
|
+
) -> None:
|
|
247
|
+
"""
|
|
248
|
+
Purpose: Verify that custom templates are used when provided via config.
|
|
249
|
+
Why this matters: Enables customization of progress display format.
|
|
250
|
+
Setup summary: Create reporter with custom template, verify custom format is used.
|
|
251
|
+
"""
|
|
252
|
+
# Arrange
|
|
253
|
+
custom_config = ToolProgressReporterConfig(
|
|
254
|
+
state_to_display_template={
|
|
255
|
+
"started": "⚪ {tool_name}: {message}",
|
|
256
|
+
"running": "⏳ {tool_name}: {message}",
|
|
257
|
+
"finished": "✅ {tool_name}: {message}",
|
|
258
|
+
"failed": "❌ {tool_name}: {message}",
|
|
259
|
+
}
|
|
260
|
+
)
|
|
261
|
+
reporter = ToolProgressReporter(chat_service, config=custom_config)
|
|
262
|
+
|
|
263
|
+
# Act
|
|
264
|
+
await reporter.notify_from_tool_call(
|
|
265
|
+
tool_call=tool_call,
|
|
266
|
+
name="My Tool",
|
|
267
|
+
message="Working on it",
|
|
268
|
+
state=ProgressState.RUNNING,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
# Assert
|
|
272
|
+
chat_service.modify_assistant_message_async.assert_called()
|
|
273
|
+
call_args = chat_service.modify_assistant_message_async.call_args
|
|
274
|
+
content = call_args.kwargs["content"]
|
|
275
|
+
assert "⏳ My Tool: Working on it" in content
|
|
276
|
+
assert "🟡" not in content # Default emoji should not appear
|
|
277
|
+
|
|
278
|
+
@pytest.mark.ai
|
|
279
|
+
@pytest.mark.asyncio
|
|
280
|
+
async def test_config__skips_states_with_empty_template__when_state_hidden(
|
|
281
|
+
self, chat_service, tool_call
|
|
282
|
+
) -> None:
|
|
283
|
+
"""
|
|
284
|
+
Purpose: Verify that states with empty string templates are not displayed.
|
|
285
|
+
Why this matters: Allows selective display of only certain states (e.g., hide STARTED).
|
|
286
|
+
Setup summary: Create config with empty string for RUNNING state, verify message is not displayed.
|
|
287
|
+
"""
|
|
288
|
+
# Arrange
|
|
289
|
+
custom_config = ToolProgressReporterConfig(
|
|
290
|
+
state_to_display_template={
|
|
291
|
+
"started": "",
|
|
292
|
+
"running": "", # Empty string hides RUNNING state
|
|
293
|
+
"finished": "✅ {tool_name}: {message}",
|
|
294
|
+
"failed": "❌ {tool_name}: {message}",
|
|
295
|
+
}
|
|
296
|
+
)
|
|
297
|
+
reporter = ToolProgressReporter(chat_service, config=custom_config)
|
|
298
|
+
|
|
299
|
+
# Act
|
|
300
|
+
await reporter.notify_from_tool_call(
|
|
301
|
+
tool_call=tool_call,
|
|
302
|
+
name="Test Tool",
|
|
303
|
+
message="Processing",
|
|
304
|
+
state=ProgressState.RUNNING,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
# Assert
|
|
308
|
+
chat_service.modify_assistant_message_async.assert_called()
|
|
309
|
+
call_args = chat_service.modify_assistant_message_async.call_args
|
|
310
|
+
content = call_args.kwargs["content"]
|
|
311
|
+
# Content should not contain the message since RUNNING template is empty
|
|
312
|
+
assert "Processing" not in content
|
|
313
|
+
assert "Test Tool" not in content
|
|
314
|
+
|
|
315
|
+
@pytest.mark.ai
|
|
316
|
+
@pytest.mark.asyncio
|
|
317
|
+
async def test_config__formats_placeholders_correctly__with_multiple_tools(
|
|
318
|
+
self, chat_service
|
|
319
|
+
) -> None:
|
|
320
|
+
"""
|
|
321
|
+
Purpose: Verify that {tool_name} and {message} placeholders are replaced correctly for multiple tools.
|
|
322
|
+
Why this matters: Ensures template formatting works correctly in multi-tool scenarios.
|
|
323
|
+
Setup summary: Add multiple tool statuses with different names/messages, verify formatting.
|
|
324
|
+
"""
|
|
325
|
+
# Arrange
|
|
326
|
+
custom_config = ToolProgressReporterConfig(
|
|
327
|
+
state_to_display_template={
|
|
328
|
+
"started": "○ {tool_name} - {message}",
|
|
329
|
+
"running": "▶️ {tool_name} - {message}",
|
|
330
|
+
"finished": "✓ {tool_name} - {message}",
|
|
331
|
+
"failed": "✗ {tool_name} - {message}",
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
reporter = ToolProgressReporter(chat_service, config=custom_config)
|
|
335
|
+
tool_call_1 = LanguageModelFunction(id="tool_1", name="search")
|
|
336
|
+
tool_call_2 = LanguageModelFunction(id="tool_2", name="analyze")
|
|
337
|
+
|
|
338
|
+
# Act
|
|
339
|
+
await reporter.notify_from_tool_call(
|
|
340
|
+
tool_call=tool_call_1,
|
|
341
|
+
name="Search Tool",
|
|
342
|
+
message="Searching database",
|
|
343
|
+
state=ProgressState.RUNNING,
|
|
344
|
+
)
|
|
345
|
+
await reporter.notify_from_tool_call(
|
|
346
|
+
tool_call=tool_call_2,
|
|
347
|
+
name="Analysis Tool",
|
|
348
|
+
message="Analyzing results",
|
|
349
|
+
state=ProgressState.FINISHED,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# Assert
|
|
353
|
+
call_args = chat_service.modify_assistant_message_async.call_args
|
|
354
|
+
content = call_args.kwargs["content"]
|
|
355
|
+
assert "▶️ Search Tool - Searching database" in content
|
|
356
|
+
assert "✓ Analysis Tool - Analyzing results" in content
|
|
357
|
+
|
|
358
|
+
@pytest.mark.ai
|
|
359
|
+
@pytest.mark.asyncio
|
|
360
|
+
async def test_config__shows_only_finished_state__when_only_finished_configured(
|
|
361
|
+
self, chat_service, tool_call
|
|
362
|
+
) -> None:
|
|
363
|
+
"""
|
|
364
|
+
Purpose: Verify selective state display shows only FINISHED when other states use empty templates.
|
|
365
|
+
Why this matters: Use case where user only wants final results, not intermediate steps.
|
|
366
|
+
Setup summary: Configure only FINISHED with content, send STARTED and FINISHED, verify only FINISHED appears.
|
|
367
|
+
"""
|
|
368
|
+
# Arrange
|
|
369
|
+
custom_config = ToolProgressReporterConfig(
|
|
370
|
+
state_to_display_template={
|
|
371
|
+
"started": "", # Empty template hides STARTED
|
|
372
|
+
"running": "", # Empty template hides RUNNING
|
|
373
|
+
"finished": "Done: {tool_name} - {message}",
|
|
374
|
+
"failed": "Failed: {tool_name} - {message}",
|
|
375
|
+
}
|
|
376
|
+
)
|
|
377
|
+
reporter = ToolProgressReporter(chat_service, config=custom_config)
|
|
378
|
+
|
|
379
|
+
# Act - Send STARTED state (should not appear)
|
|
380
|
+
await reporter.notify_from_tool_call(
|
|
381
|
+
tool_call=tool_call,
|
|
382
|
+
name="Test Tool",
|
|
383
|
+
message="Starting",
|
|
384
|
+
state=ProgressState.STARTED,
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
# Get first call content
|
|
388
|
+
first_call_args = chat_service.modify_assistant_message_async.call_args
|
|
389
|
+
first_content = first_call_args.kwargs["content"]
|
|
390
|
+
|
|
391
|
+
# Act - Update to FINISHED state (should appear)
|
|
392
|
+
await reporter.notify_from_tool_call(
|
|
393
|
+
tool_call=tool_call,
|
|
394
|
+
name="Test Tool",
|
|
395
|
+
message="Completed successfully",
|
|
396
|
+
state=ProgressState.FINISHED,
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# Assert
|
|
400
|
+
final_call_args = chat_service.modify_assistant_message_async.call_args
|
|
401
|
+
final_content = final_call_args.kwargs["content"]
|
|
402
|
+
|
|
403
|
+
# STARTED state should not appear in first call
|
|
404
|
+
assert "Starting" not in first_content
|
|
405
|
+
|
|
406
|
+
# FINISHED state should appear in final call
|
|
407
|
+
assert "Done: Test Tool - Completed successfully" in final_content
|
|
408
|
+
|
|
409
|
+
@pytest.mark.ai
|
|
410
|
+
@pytest.mark.asyncio
|
|
411
|
+
async def test_config__handles_all_empty_templates__when_all_states_hidden(
|
|
412
|
+
self, chat_service, tool_call
|
|
413
|
+
) -> None:
|
|
414
|
+
"""
|
|
415
|
+
Purpose: Verify that all empty string templates result in no messages being displayed.
|
|
416
|
+
Why this matters: Edge case handling and allows disabling all progress display.
|
|
417
|
+
Setup summary: Create config with all empty templates, verify no tool messages appear.
|
|
418
|
+
"""
|
|
419
|
+
# Arrange
|
|
420
|
+
custom_config = ToolProgressReporterConfig(
|
|
421
|
+
state_to_display_template={
|
|
422
|
+
"started": "",
|
|
423
|
+
"running": "",
|
|
424
|
+
"finished": "",
|
|
425
|
+
"failed": "",
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
reporter = ToolProgressReporter(chat_service, config=custom_config)
|
|
429
|
+
|
|
430
|
+
# Act
|
|
431
|
+
await reporter.notify_from_tool_call(
|
|
432
|
+
tool_call=tool_call,
|
|
433
|
+
name="Test Tool",
|
|
434
|
+
message="Processing",
|
|
435
|
+
state=ProgressState.RUNNING,
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
# Assert
|
|
439
|
+
chat_service.modify_assistant_message_async.assert_called()
|
|
440
|
+
call_args = chat_service.modify_assistant_message_async.call_args
|
|
441
|
+
content = call_args.kwargs["content"]
|
|
442
|
+
|
|
443
|
+
# Should only have the progress start text and newlines, no actual messages
|
|
444
|
+
assert "Test Tool" not in content
|
|
445
|
+
assert "Processing" not in content
|
|
@@ -5,7 +5,6 @@ from typing import Any, Generic, TypeVar, cast
|
|
|
5
5
|
from typing_extensions import deprecated
|
|
6
6
|
|
|
7
7
|
from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
|
|
8
|
-
from unique_toolkit.agentic.tools.agent_chunks_hanlder import AgentChunksHandler
|
|
9
8
|
from unique_toolkit.agentic.tools.config import ToolBuildConfig, ToolSelectionPolicy
|
|
10
9
|
from unique_toolkit.agentic.tools.schemas import (
|
|
11
10
|
BaseToolConfig,
|
|
@@ -20,7 +19,6 @@ from unique_toolkit.chat.service import (
|
|
|
20
19
|
from unique_toolkit.language_model import LanguageModelToolDescription
|
|
21
20
|
from unique_toolkit.language_model.schemas import (
|
|
22
21
|
LanguageModelFunction,
|
|
23
|
-
LanguageModelMessage,
|
|
24
22
|
)
|
|
25
23
|
from unique_toolkit.language_model.service import LanguageModelService
|
|
26
24
|
|
|
@@ -100,15 +98,6 @@ class Tool(ABC, Generic[ConfigType]):
|
|
|
100
98
|
"""
|
|
101
99
|
return ""
|
|
102
100
|
|
|
103
|
-
@deprecated("Do not use as is bound to loop agent only")
|
|
104
|
-
@abstractmethod
|
|
105
|
-
def get_tool_call_result_for_loop_history(
|
|
106
|
-
self,
|
|
107
|
-
tool_response: ToolCallResponse,
|
|
108
|
-
agent_chunks_handler: AgentChunksHandler,
|
|
109
|
-
) -> LanguageModelMessage:
|
|
110
|
-
raise NotImplementedError
|
|
111
|
-
|
|
112
101
|
@deprecated(
|
|
113
102
|
"Do not use. The tool should not determine how"
|
|
114
103
|
"it is checked. This should be defined by the user"
|