hammad-python 0.0.21__py3-none-any.whl → 0.0.22__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.
- hammad/genai/agents/agent.py +111 -48
- hammad/genai/agents/types/agent_response.py +9 -7
- hammad/genai/agents/types/agent_stream.py +23 -14
- hammad/genai/models/language/model.py +3 -1
- hammad/genai/models/language/types/language_model_response.py +4 -1
- hammad/logging/logger.py +1 -1
- {hammad_python-0.0.21.dist-info → hammad_python-0.0.22.dist-info}/METADATA +1 -1
- {hammad_python-0.0.21.dist-info → hammad_python-0.0.22.dist-info}/RECORD +10 -10
- {hammad_python-0.0.21.dist-info → hammad_python-0.0.22.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.21.dist-info → hammad_python-0.0.22.dist-info}/licenses/LICENSE +0 -0
hammad/genai/agents/agent.py
CHANGED
@@ -354,22 +354,43 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
354
354
|
) -> dict:
|
355
355
|
"""Get effective context settings, using provided parameters or defaults."""
|
356
356
|
return {
|
357
|
-
"context_updates": context_updates
|
358
|
-
|
359
|
-
|
360
|
-
"
|
361
|
-
|
362
|
-
|
363
|
-
"
|
364
|
-
|
357
|
+
"context_updates": context_updates
|
358
|
+
if context_updates is not None
|
359
|
+
else self.context_updates,
|
360
|
+
"context_confirm": context_confirm
|
361
|
+
if context_confirm is not None
|
362
|
+
else self.context_confirm,
|
363
|
+
"context_strategy": context_strategy
|
364
|
+
if context_strategy is not None
|
365
|
+
else self.context_strategy,
|
366
|
+
"context_max_retries": context_max_retries
|
367
|
+
if context_max_retries is not None
|
368
|
+
else self.context_max_retries,
|
369
|
+
"context_confirm_instructions": context_confirm_instructions
|
370
|
+
if context_confirm_instructions is not None
|
371
|
+
else self.context_confirm_instructions,
|
372
|
+
"context_selection_instructions": context_selection_instructions
|
373
|
+
if context_selection_instructions is not None
|
374
|
+
else self.context_selection_instructions,
|
375
|
+
"context_update_instructions": context_update_instructions
|
376
|
+
if context_update_instructions is not None
|
377
|
+
else self.context_update_instructions,
|
378
|
+
"context_format": context_format
|
379
|
+
if context_format is not None
|
380
|
+
else self.context_format,
|
365
381
|
}
|
366
382
|
|
367
383
|
def _should_update_context(
|
368
|
-
self,
|
384
|
+
self,
|
385
|
+
context: AgentContext,
|
386
|
+
timing: Literal["before", "after"],
|
387
|
+
context_updates=None,
|
369
388
|
) -> bool:
|
370
389
|
"""Determine if context should be updated based on timing and configuration."""
|
371
|
-
effective_context_updates =
|
372
|
-
|
390
|
+
effective_context_updates = (
|
391
|
+
context_updates if context_updates is not None else self.context_updates
|
392
|
+
)
|
393
|
+
|
373
394
|
if not effective_context_updates:
|
374
395
|
return False
|
375
396
|
|
@@ -405,7 +426,9 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
405
426
|
if isinstance(context, BaseModel):
|
406
427
|
field_type = context.__class__.model_fields[field_name].annotation
|
407
428
|
field_info = context.__class__.model_fields[field_name]
|
408
|
-
description = getattr(
|
429
|
+
description = getattr(
|
430
|
+
field_info, "description", f"Update the {field_name} field"
|
431
|
+
)
|
409
432
|
elif isinstance(context, dict):
|
410
433
|
field_type = type(context[field_name])
|
411
434
|
description = f"Update the {field_name} field"
|
@@ -415,7 +438,7 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
415
438
|
|
416
439
|
return create_model(
|
417
440
|
f"Update{field_name.capitalize()}",
|
418
|
-
**{field_name: (field_type, Field(description=description))}
|
441
|
+
**{field_name: (field_type, Field(description=description))},
|
419
442
|
)
|
420
443
|
else:
|
421
444
|
# All fields update - create a model with the exact same fields as the context
|
@@ -425,9 +448,14 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
425
448
|
for field_name, field_info in context.model_fields.items():
|
426
449
|
field_type = field_info.annotation
|
427
450
|
current_value = getattr(context, field_name)
|
428
|
-
description = getattr(
|
429
|
-
|
430
|
-
|
451
|
+
description = getattr(
|
452
|
+
field_info, "description", f"Current value: {current_value}"
|
453
|
+
)
|
454
|
+
field_definitions[field_name] = (
|
455
|
+
field_type,
|
456
|
+
Field(description=description),
|
457
|
+
)
|
458
|
+
|
431
459
|
return create_model("ContextUpdate", **field_definitions)
|
432
460
|
elif isinstance(context, dict):
|
433
461
|
# Create a model with the same keys as the dict
|
@@ -435,12 +463,21 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
435
463
|
for key, value in context.items():
|
436
464
|
field_type = type(value)
|
437
465
|
description = f"Current value: {value}"
|
438
|
-
field_definitions[key] = (
|
439
|
-
|
466
|
+
field_definitions[key] = (
|
467
|
+
field_type,
|
468
|
+
Field(description=description),
|
469
|
+
)
|
470
|
+
|
440
471
|
return create_model("ContextUpdate", **field_definitions)
|
441
472
|
else:
|
442
473
|
# Fallback to generic updates
|
443
|
-
return create_model(
|
474
|
+
return create_model(
|
475
|
+
"ContextUpdate",
|
476
|
+
updates=(
|
477
|
+
Dict[str, Any],
|
478
|
+
Field(description="Dictionary of field updates"),
|
479
|
+
),
|
480
|
+
)
|
444
481
|
|
445
482
|
def _perform_context_update(
|
446
483
|
self,
|
@@ -452,7 +489,7 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
452
489
|
) -> AgentContext:
|
453
490
|
"""Perform context update with retries and error handling."""
|
454
491
|
updated_context = context
|
455
|
-
|
492
|
+
|
456
493
|
# Use effective settings or defaults
|
457
494
|
if effective_settings is None:
|
458
495
|
effective_settings = {
|
@@ -470,16 +507,18 @@ class Agent(BaseGenAIModel, Generic[T]):
|
|
470
507
|
# Check if update is needed (if confirmation is enabled)
|
471
508
|
if effective_settings["context_confirm"]:
|
472
509
|
confirm_model = self._create_context_confirm_model()
|
473
|
-
|
510
|
+
|
474
511
|
# Create detailed instructions with context structure
|
475
|
-
context_structure = _format_context_for_instructions(
|
512
|
+
context_structure = _format_context_for_instructions(
|
513
|
+
updated_context, effective_settings["context_format"]
|
514
|
+
)
|
476
515
|
confirm_instructions = f"""Based on the conversation, determine if the context should be updated {timing} processing.
|
477
516
|
|
478
517
|
Current context structure:
|
479
518
|
{context_structure}
|
480
519
|
|
481
520
|
Should the context be updated based on the new information provided in the conversation?"""
|
482
|
-
|
521
|
+
|
483
522
|
if effective_settings["context_confirm_instructions"]:
|
484
523
|
confirm_instructions += f"\n\nAdditional instructions: {effective_settings['context_confirm_instructions']}"
|
485
524
|
|
@@ -499,16 +538,18 @@ Should the context be updated based on the new information provided in the conve
|
|
499
538
|
selection_model = self._create_context_selection_model(
|
500
539
|
updated_context
|
501
540
|
)
|
502
|
-
|
541
|
+
|
503
542
|
# Create detailed instructions with context structure
|
504
|
-
context_structure = _format_context_for_instructions(
|
543
|
+
context_structure = _format_context_for_instructions(
|
544
|
+
updated_context, effective_settings["context_format"]
|
545
|
+
)
|
505
546
|
selection_instructions = f"""Select which fields in the context should be updated {timing} processing based on the conversation.
|
506
547
|
|
507
548
|
Current context structure:
|
508
549
|
{context_structure}
|
509
550
|
|
510
551
|
Choose only the fields that need to be updated based on the new information provided in the conversation."""
|
511
|
-
|
552
|
+
|
512
553
|
if effective_settings["context_selection_instructions"]:
|
513
554
|
selection_instructions += f"\n\nAdditional instructions: {effective_settings['context_selection_instructions']}"
|
514
555
|
|
@@ -526,14 +567,18 @@ Choose only the fields that need to be updated based on the new information prov
|
|
526
567
|
updated_context, field_name
|
527
568
|
)
|
528
569
|
# Get current field value for context
|
529
|
-
current_value =
|
530
|
-
|
570
|
+
current_value = (
|
571
|
+
getattr(updated_context, field_name)
|
572
|
+
if isinstance(updated_context, BaseModel)
|
573
|
+
else updated_context.get(field_name)
|
574
|
+
)
|
575
|
+
|
531
576
|
field_instructions = f"""Update the {field_name} field in the context based on the conversation.
|
532
577
|
|
533
578
|
Current value of {field_name}: {current_value}
|
534
579
|
|
535
580
|
Please provide the new value for {field_name} based on the information from the conversation."""
|
536
|
-
|
581
|
+
|
537
582
|
if effective_settings["context_update_instructions"]:
|
538
583
|
field_instructions += f"\n\nAdditional instructions: {effective_settings['context_update_instructions']}"
|
539
584
|
|
@@ -555,16 +600,18 @@ Please provide the new value for {field_name} based on the information from the
|
|
555
600
|
else: # strategy == "all"
|
556
601
|
# Update all fields at once
|
557
602
|
update_model = self._create_context_update_model(updated_context)
|
558
|
-
|
603
|
+
|
559
604
|
# Create detailed instructions with context structure
|
560
|
-
context_structure = _format_context_for_instructions(
|
605
|
+
context_structure = _format_context_for_instructions(
|
606
|
+
updated_context, effective_settings["context_format"]
|
607
|
+
)
|
561
608
|
update_instructions = f"""Update the context {timing} processing based on the conversation.
|
562
609
|
|
563
610
|
Current context structure:
|
564
611
|
{context_structure}
|
565
612
|
|
566
613
|
Please update the appropriate fields based on the conversation. Only update fields that need to be changed based on the new information provided."""
|
567
|
-
|
614
|
+
|
568
615
|
if effective_settings["context_update_instructions"]:
|
569
616
|
update_instructions += f"\n\nAdditional instructions: {effective_settings['context_update_instructions']}"
|
570
617
|
|
@@ -576,7 +623,7 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
576
623
|
)
|
577
624
|
|
578
625
|
# Apply the updates
|
579
|
-
if hasattr(update_response.output,
|
626
|
+
if hasattr(update_response.output, "updates"):
|
580
627
|
# Legacy fallback for generic updates
|
581
628
|
updated_context = _update_context_object(
|
582
629
|
updated_context, update_response.output.updates
|
@@ -584,10 +631,18 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
584
631
|
else:
|
585
632
|
# New approach - extract field values directly from the response
|
586
633
|
updates_dict = {}
|
587
|
-
for field_name in (
|
634
|
+
for field_name in (
|
635
|
+
context.model_fields.keys()
|
636
|
+
if isinstance(context, BaseModel)
|
637
|
+
else context.keys()
|
638
|
+
):
|
588
639
|
if hasattr(update_response.output, field_name):
|
589
|
-
updates_dict[field_name] = getattr(
|
590
|
-
|
640
|
+
updates_dict[field_name] = getattr(
|
641
|
+
update_response.output, field_name
|
642
|
+
)
|
643
|
+
updated_context = _update_context_object(
|
644
|
+
updated_context, updates_dict
|
645
|
+
)
|
591
646
|
|
592
647
|
# Trigger context update hooks
|
593
648
|
self.hook_manager.trigger_hooks("context_update", updated_context)
|
@@ -808,7 +863,9 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
808
863
|
# RUN MAIN AGENTIC LOOP
|
809
864
|
for step in range(max_steps):
|
810
865
|
# Update context before processing if configured
|
811
|
-
if context and self._should_update_context(
|
866
|
+
if context and self._should_update_context(
|
867
|
+
context, "before", effective_context_settings["context_updates"]
|
868
|
+
):
|
812
869
|
context = self._perform_context_update(
|
813
870
|
context=context,
|
814
871
|
model=working_model,
|
@@ -836,9 +893,7 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
836
893
|
# Get language model response
|
837
894
|
response = working_model.run(
|
838
895
|
messages=formatted_messages,
|
839
|
-
tools=[tool.to_dict() for tool in self.tools]
|
840
|
-
if self.tools
|
841
|
-
else None,
|
896
|
+
tools=[tool.to_dict() for tool in self.tools] if self.tools else None,
|
842
897
|
**model_kwargs,
|
843
898
|
)
|
844
899
|
|
@@ -860,7 +915,9 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
860
915
|
else:
|
861
916
|
# No tool calls - this is the final step
|
862
917
|
# Update context after processing if configured
|
863
|
-
if context and self._should_update_context(
|
918
|
+
if context and self._should_update_context(
|
919
|
+
context, "after", effective_context_settings["context_updates"]
|
920
|
+
):
|
864
921
|
context = self._perform_context_update(
|
865
922
|
context=context,
|
866
923
|
model=working_model,
|
@@ -886,7 +943,9 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
886
943
|
)
|
887
944
|
|
888
945
|
# Update context after processing if configured
|
889
|
-
if context and self._should_update_context(
|
946
|
+
if context and self._should_update_context(
|
947
|
+
context, "after", effective_context_settings["context_updates"]
|
948
|
+
):
|
890
949
|
context = self._perform_context_update(
|
891
950
|
context=context,
|
892
951
|
model=working_model,
|
@@ -1017,7 +1076,9 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
1017
1076
|
# RUN MAIN AGENTIC LOOP
|
1018
1077
|
for step in range(max_steps):
|
1019
1078
|
# Update context before processing if configured
|
1020
|
-
if context and self._should_update_context(
|
1079
|
+
if context and self._should_update_context(
|
1080
|
+
context, "before", effective_context_settings["context_updates"]
|
1081
|
+
):
|
1021
1082
|
context = self._perform_context_update(
|
1022
1083
|
context=context,
|
1023
1084
|
model=working_model,
|
@@ -1045,9 +1106,7 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
1045
1106
|
# Get language model response
|
1046
1107
|
response = await working_model.async_run(
|
1047
1108
|
messages=formatted_messages,
|
1048
|
-
tools=[tool.to_dict() for tool in self.tools]
|
1049
|
-
if self.tools
|
1050
|
-
else None,
|
1109
|
+
tools=[tool.to_dict() for tool in self.tools] if self.tools else None,
|
1051
1110
|
**model_kwargs,
|
1052
1111
|
)
|
1053
1112
|
|
@@ -1069,7 +1128,9 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
1069
1128
|
else:
|
1070
1129
|
# No tool calls - this is the final step
|
1071
1130
|
# Update context after processing if configured
|
1072
|
-
if context and self._should_update_context(
|
1131
|
+
if context and self._should_update_context(
|
1132
|
+
context, "after", effective_context_settings["context_updates"]
|
1133
|
+
):
|
1073
1134
|
context = self._perform_context_update(
|
1074
1135
|
context=context,
|
1075
1136
|
model=working_model,
|
@@ -1095,7 +1156,9 @@ Please update the appropriate fields based on the conversation. Only update fiel
|
|
1095
1156
|
)
|
1096
1157
|
|
1097
1158
|
# Update context after processing if configured
|
1098
|
-
if context and self._should_update_context(
|
1159
|
+
if context and self._should_update_context(
|
1160
|
+
context, "after", effective_context_settings["context_updates"]
|
1161
|
+
):
|
1099
1162
|
context = self._perform_context_update(
|
1100
1163
|
context=context,
|
1101
1164
|
model=working_model,
|
@@ -57,7 +57,7 @@ class AgentResponse(LanguageModelResponse[T], Generic[T, AgentContext]):
|
|
57
57
|
empty.
|
58
58
|
"""
|
59
59
|
|
60
|
-
context: AgentContext = None
|
60
|
+
context: AgentContext | None = None
|
61
61
|
"""
|
62
62
|
The final context object after agent execution.
|
63
63
|
|
@@ -68,7 +68,7 @@ class AgentResponse(LanguageModelResponse[T], Generic[T, AgentContext]):
|
|
68
68
|
@cached
|
69
69
|
def __str__(self) -> str:
|
70
70
|
"""Pretty prints the response object."""
|
71
|
-
output = "AgentResponse:"
|
71
|
+
output = ">>> AgentResponse:"
|
72
72
|
|
73
73
|
if self.output or self.content:
|
74
74
|
output += f"\n{self.output if self.output else self.content}"
|
@@ -91,7 +91,9 @@ class AgentResponse(LanguageModelResponse[T], Generic[T, AgentContext]):
|
|
91
91
|
|
92
92
|
# Show context if available
|
93
93
|
if self.context:
|
94
|
-
output +=
|
94
|
+
output += (
|
95
|
+
f"\n>>> Final Context: {self._format_context_display(self.context)}"
|
96
|
+
)
|
95
97
|
|
96
98
|
return output
|
97
99
|
|
@@ -99,16 +101,16 @@ class AgentResponse(LanguageModelResponse[T], Generic[T, AgentContext]):
|
|
99
101
|
"""Format context for display in string representation."""
|
100
102
|
if context is None:
|
101
103
|
return "None"
|
102
|
-
|
104
|
+
|
103
105
|
try:
|
104
106
|
# For Pydantic models, show as dict
|
105
|
-
if hasattr(context,
|
107
|
+
if hasattr(context, "model_dump"):
|
106
108
|
context_dict = context.model_dump()
|
107
109
|
elif isinstance(context, dict):
|
108
110
|
context_dict = context
|
109
111
|
else:
|
110
112
|
return str(context)
|
111
|
-
|
113
|
+
|
112
114
|
# Format as compact JSON-like string
|
113
115
|
items = []
|
114
116
|
for key, value in context_dict.items():
|
@@ -116,7 +118,7 @@ class AgentResponse(LanguageModelResponse[T], Generic[T, AgentContext]):
|
|
116
118
|
items.append(f"{key}='{value}'")
|
117
119
|
else:
|
118
120
|
items.append(f"{key}={value}")
|
119
|
-
|
121
|
+
|
120
122
|
return "{" + ", ".join(items) + "}"
|
121
123
|
except Exception:
|
122
124
|
return str(context)
|
@@ -87,18 +87,20 @@ class AgentResponseChunk(LanguageModelResponseChunk[T], Generic[T]):
|
|
87
87
|
def __str__(self) -> str:
|
88
88
|
"""String representation of the chunk."""
|
89
89
|
output = f"AgentResponseChunk(step={self.step_number}, final={self.is_final})"
|
90
|
-
|
90
|
+
|
91
91
|
# Show content if available
|
92
92
|
if self.output or self.content:
|
93
93
|
content_preview = str(self.output if self.output else self.content)
|
94
94
|
if len(content_preview) > 100:
|
95
95
|
content_preview = content_preview[:100] + "..."
|
96
96
|
output += f"\nContent: {content_preview}"
|
97
|
-
|
97
|
+
|
98
98
|
return output
|
99
99
|
|
100
100
|
|
101
|
-
class AgentStream(
|
101
|
+
class AgentStream(
|
102
|
+
BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentContext]
|
103
|
+
):
|
102
104
|
"""Stream of agent responses that can be used in sync and async contexts."""
|
103
105
|
|
104
106
|
def __init__(
|
@@ -151,16 +153,17 @@ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentC
|
|
151
153
|
def _format_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
152
154
|
if self.agent.instructions:
|
153
155
|
system_content = self.agent.instructions
|
154
|
-
|
156
|
+
|
155
157
|
# Add context if available
|
156
158
|
if self.current_context is not None:
|
157
159
|
from ..agent import _format_context_for_instructions
|
160
|
+
|
158
161
|
context_str = _format_context_for_instructions(
|
159
162
|
self.current_context, self.agent.context_format
|
160
163
|
)
|
161
164
|
if context_str:
|
162
165
|
system_content += f"\n\nContext:\n{context_str}"
|
163
|
-
|
166
|
+
|
164
167
|
system_message = {"role": "system", "content": system_content}
|
165
168
|
messages = [system_message] + messages
|
166
169
|
return consolidate_system_messages(messages)
|
@@ -184,16 +187,18 @@ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentC
|
|
184
187
|
else:
|
185
188
|
self.is_done = True
|
186
189
|
self._final_response = response
|
187
|
-
|
190
|
+
|
188
191
|
# Update context after processing if configured
|
189
|
-
if self.current_context and self.agent._should_update_context(
|
192
|
+
if self.current_context and self.agent._should_update_context(
|
193
|
+
self.current_context, "after"
|
194
|
+
):
|
190
195
|
self.current_context = self.agent._perform_context_update(
|
191
196
|
context=self.current_context,
|
192
197
|
model=self.model,
|
193
198
|
current_messages=self.current_messages,
|
194
199
|
timing="after",
|
195
200
|
)
|
196
|
-
|
201
|
+
|
197
202
|
return AgentResponseChunk(
|
198
203
|
step_number=self.current_step, response=response, is_final=True
|
199
204
|
)
|
@@ -204,7 +209,9 @@ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentC
|
|
204
209
|
self.current_step += 1
|
205
210
|
|
206
211
|
# Update context before processing if configured
|
207
|
-
if self.current_context and self.agent._should_update_context(
|
212
|
+
if self.current_context and self.agent._should_update_context(
|
213
|
+
self.current_context, "before"
|
214
|
+
):
|
208
215
|
self.current_context = self.agent._perform_context_update(
|
209
216
|
context=self.current_context,
|
210
217
|
model=self.model,
|
@@ -240,7 +247,9 @@ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentC
|
|
240
247
|
self.current_step += 1
|
241
248
|
|
242
249
|
# Update context before processing if configured
|
243
|
-
if self.current_context and self.agent._should_update_context(
|
250
|
+
if self.current_context and self.agent._should_update_context(
|
251
|
+
self.current_context, "before"
|
252
|
+
):
|
244
253
|
self.current_context = self.agent._perform_context_update(
|
245
254
|
context=self.current_context,
|
246
255
|
model=self.model,
|
@@ -283,16 +292,16 @@ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentC
|
|
283
292
|
"""Format context for display in string representation."""
|
284
293
|
if context is None:
|
285
294
|
return "None"
|
286
|
-
|
295
|
+
|
287
296
|
try:
|
288
297
|
# For Pydantic models, show as dict
|
289
|
-
if hasattr(context,
|
298
|
+
if hasattr(context, "model_dump"):
|
290
299
|
context_dict = context.model_dump()
|
291
300
|
elif isinstance(context, dict):
|
292
301
|
context_dict = context
|
293
302
|
else:
|
294
303
|
return str(context)
|
295
|
-
|
304
|
+
|
296
305
|
# Format as compact JSON-like string
|
297
306
|
items = []
|
298
307
|
for key, value in context_dict.items():
|
@@ -300,7 +309,7 @@ class AgentStream(BaseGenAIModelStream[AgentResponseChunk[T]], Generic[T, AgentC
|
|
300
309
|
items.append(f"{key}='{value}'")
|
301
310
|
else:
|
302
311
|
items.append(f"{key}={value}")
|
303
|
-
|
312
|
+
|
304
313
|
return "{" + ", ".join(items) + "}"
|
305
314
|
except Exception:
|
306
315
|
return str(context)
|
@@ -130,7 +130,9 @@ class LanguageModel(BaseGenAIModel, Generic[T]):
|
|
130
130
|
self._instructor_client is None
|
131
131
|
or getattr(self._instructor_client, "_mode", None) != effective_mode
|
132
132
|
):
|
133
|
-
logger.debug(
|
133
|
+
logger.debug(
|
134
|
+
f"Creating new instructor client for mode: {effective_mode} from old mode: {getattr(self._instructor_client, '_mode', None)}"
|
135
|
+
)
|
134
136
|
|
135
137
|
self._instructor_client = instructor.from_litellm(
|
136
138
|
completion=litellm.completion, mode=instructor.Mode(effective_mode)
|
@@ -12,6 +12,8 @@ from typing import (
|
|
12
12
|
Literal,
|
13
13
|
)
|
14
14
|
|
15
|
+
from .....cache import cached
|
16
|
+
|
15
17
|
from ...model_provider import litellm
|
16
18
|
from ....types.base import BaseGenAIModelResponse
|
17
19
|
from openai.types.chat import (
|
@@ -197,9 +199,10 @@ class LanguageModelResponse(BaseGenAIModelResponse[T]):
|
|
197
199
|
content part object."""
|
198
200
|
return {"type": "text", "text": self.content}
|
199
201
|
|
202
|
+
@cached
|
200
203
|
def __str__(self) -> str:
|
201
204
|
"""Pretty prints the response object."""
|
202
|
-
output = "LanguageModelResponse:"
|
205
|
+
output = ">>> LanguageModelResponse:"
|
203
206
|
|
204
207
|
if self.output or self.content:
|
205
208
|
output += f"\n{self.output if self.output else self.content}"
|
hammad/logging/logger.py
CHANGED
@@ -55,15 +55,15 @@ hammad/formatting/yaml/__init__.py,sha256=4dBeXPi0jx7ELT2_sC2fUYaiY8b8wFiUScLODc
|
|
55
55
|
hammad/formatting/yaml/converters.py,sha256=zvSB8QGb56uvwO0KjXllfTj9g1FmNINOKR06DTjvXw8,153
|
56
56
|
hammad/genai/__init__.py,sha256=16L9z0U73uUhBB7JHSL0tHWie2-rI7GAUtQSY94IeZk,3579
|
57
57
|
hammad/genai/agents/__init__.py,sha256=R_wW_fbZqMXZZYSErAb81UDRMTaNDlAFzNKfTOm4XYg,1235
|
58
|
-
hammad/genai/agents/agent.py,sha256=
|
58
|
+
hammad/genai/agents/agent.py,sha256=xtb-xexCA7XzoHCR20zCTAEsgjTo0C-i701WQGzIXgA,55884
|
59
59
|
hammad/genai/agents/run.py,sha256=G3NLJgg8nXFHfOrh_XR1NpVjGzAgjnA_Ojc_rrMHz9E,23278
|
60
60
|
hammad/genai/agents/types/__init__.py,sha256=6X6_P82qe15dyqs-vAcXUk4na4tB-7oMdMf484v87io,1119
|
61
61
|
hammad/genai/agents/types/agent_context.py,sha256=u4evwx9B-UKEHMtNcsNlN9q8i12bsW9HhtyvmU0NNTw,313
|
62
62
|
hammad/genai/agents/types/agent_event.py,sha256=zNKXXPKKOsIO9MAhE-YNCOxeNg00O7j1mE0R1pA_Xr8,3925
|
63
63
|
hammad/genai/agents/types/agent_hooks.py,sha256=wgys4ixiHjX5oux4zVSr9OPXyAZ-iJGk_MhaOKEgMxo,7853
|
64
64
|
hammad/genai/agents/types/agent_messages.py,sha256=csjEq42bElaTZYZW2dE6nlFZc142-HgT3bB6h1KMg_w,846
|
65
|
-
hammad/genai/agents/types/agent_response.py,sha256=
|
66
|
-
hammad/genai/agents/types/agent_stream.py,sha256=
|
65
|
+
hammad/genai/agents/types/agent_response.py,sha256=vRR9bWwzSA6Y6a_cpf7KrrmJqoAwh5OuuNThTERNVwY,3806
|
66
|
+
hammad/genai/agents/types/agent_stream.py,sha256=VIfqZp55wq6jQh_OtPzZjiL_K4cEoVCkeEZS3s_MIXI,11069
|
67
67
|
hammad/genai/models/__init__.py,sha256=e4TbEsiKIoXENOEsdIdQcWWt0RnFdTEqCz0nICHQHtM,26
|
68
68
|
hammad/genai/models/model_provider.py,sha256=2RdOeqr7KpjyrMqq4YH4OYy1pk6sjzf2CPu1ZHa1Pdk,75
|
69
69
|
hammad/genai/models/multimodal.py,sha256=KXUyLXqM1eBgBGZFEbMw3dYbakZFAXoko2xYprronxY,1276
|
@@ -77,14 +77,14 @@ hammad/genai/models/embeddings/types/embedding_model_response.py,sha256=V2H_VTl1
|
|
77
77
|
hammad/genai/models/embeddings/types/embedding_model_run_params.py,sha256=ZGhCXrEEzMF5y-V8neF2a73Gh1emzrYUHVxWkybg5uE,1570
|
78
78
|
hammad/genai/models/embeddings/types/embedding_model_settings.py,sha256=KEwvoElXhPMSVCKW2uKwqqT2lSAAthQXmGXaV7Qk5cU,1268
|
79
79
|
hammad/genai/models/language/__init__.py,sha256=B92q9f5UIQBMIFoYUja9V61bn5Lzdrk12_bf3DHw6Is,1838
|
80
|
-
hammad/genai/models/language/model.py,sha256=
|
80
|
+
hammad/genai/models/language/model.py,sha256=h3V-Z_AUlVRn_pFbC0wchMajk7tyJjK0dIpZxq3lYy8,39408
|
81
81
|
hammad/genai/models/language/run.py,sha256=nqqQYi3iBpkNxW3_JHyyZBNpn79LVWLpnebCBYOaEbA,21468
|
82
82
|
hammad/genai/models/language/types/__init__.py,sha256=cdLnoCiVmK6T86-5CZrUJg2rxXKoSk-svyCSviUdgao,1534
|
83
83
|
hammad/genai/models/language/types/language_model_instructor_mode.py,sha256=7ywBaY24m-UKRynnX6XsfVf_hsQrM2xHAHugTgV0Vho,1008
|
84
84
|
hammad/genai/models/language/types/language_model_messages.py,sha256=e-HZ_YKXq17gwmMlpOmYUYUpBFm7Mu3aRawtjSslWXs,504
|
85
85
|
hammad/genai/models/language/types/language_model_name.py,sha256=2V70cZ47L9yIcug6LCcMHcvEJaee7gRN6DUPhLUBlsE,8056
|
86
86
|
hammad/genai/models/language/types/language_model_request.py,sha256=ZtzhCx8o6zkEBS3uTFXFLf_poDD7MnIp1y7MbKckOmI,3911
|
87
|
-
hammad/genai/models/language/types/language_model_response.py,sha256=
|
87
|
+
hammad/genai/models/language/types/language_model_response.py,sha256=YHDEDJuhQ_ULs9qse2b-h5cx1ELWgfPc2BHk34OPVxE,7540
|
88
88
|
hammad/genai/models/language/types/language_model_response_chunk.py,sha256=wIzGZw732KsI-a1-uASjATA6qvBuq-7rupWoFjsAgQo,1796
|
89
89
|
hammad/genai/models/language/types/language_model_settings.py,sha256=C0EvLXZoOLgPZ4bX7mVFs_CWP-jam27qkseJRGsBAfQ,2794
|
90
90
|
hammad/genai/models/language/types/language_model_stream.py,sha256=XgJ83JSbtTdf7jeLQMrDhMfI7zp0pRrdY7JWYbZV_h0,22043
|
@@ -97,7 +97,7 @@ hammad/genai/types/history.py,sha256=zsfBvGMoFTHZCT7Igae-5_jszu409dVJ_wEmNw7alCk
|
|
97
97
|
hammad/genai/types/tools.py,sha256=3p7qhZcilP_NOCOnufCkubTeYN0yC7Ij5bqrUy-FYow,16554
|
98
98
|
hammad/logging/__init__.py,sha256=VtskZx0bKEAJ9FHTMflhB1CzeFUxLpDT5HPgcecAXUo,701
|
99
99
|
hammad/logging/decorators.py,sha256=VbI1x3P4ft0-0BGjXq7nQgiuNqcXAA51CGmoSn47iSw,30122
|
100
|
-
hammad/logging/logger.py,sha256=
|
100
|
+
hammad/logging/logger.py,sha256=5Y41gCtH7APxNjIXtsZg1E9nwpi2xTgRAoC2l-QKil4,31706
|
101
101
|
hammad/mcp/__init__.py,sha256=5oTU-BLYjfz6fBHDH9cyWg3DpQ6Qar-jodbCR05SuWo,1123
|
102
102
|
hammad/mcp/client/__init__.py,sha256=_SfnKvd5Za-FfFoE5GcXkBY9WcwprZND9SyZ6RY--no,795
|
103
103
|
hammad/mcp/client/client.py,sha256=auKCiIJfcZkuVFRapTpqYP4PxoyIfx40gVbMYLBdTzI,20565
|
@@ -121,7 +121,7 @@ hammad/web/openapi/__init__.py,sha256=JhJQ6_laBmB2djIYFc0vgGha2GsdUe4FP1LDdZCQ5J
|
|
121
121
|
hammad/web/openapi/client.py,sha256=1pXz7KAO_0pN4kQZoWKWskXDYGiJ535TsPO1GGCiC0E,26816
|
122
122
|
hammad/web/search/__init__.py,sha256=e9A6znPIiZCz-4secyHbUs0uUGf5yAqW6wGacgx961U,24
|
123
123
|
hammad/web/search/client.py,sha256=LIx2MsHhn6cRTuq5i1mWowRTdIhPobY4GQV3S3bk9lk,36694
|
124
|
-
hammad_python-0.0.
|
125
|
-
hammad_python-0.0.
|
126
|
-
hammad_python-0.0.
|
127
|
-
hammad_python-0.0.
|
124
|
+
hammad_python-0.0.22.dist-info/METADATA,sha256=OFmPfD3CcZq0Et0hWl2dBUjRNm4IcYZKL1EX8aTJPsU,6570
|
125
|
+
hammad_python-0.0.22.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
126
|
+
hammad_python-0.0.22.dist-info/licenses/LICENSE,sha256=h74yFUWjbBaodcWG5wNmm30npjl8obVcxD-1nQfUp2I,1069
|
127
|
+
hammad_python-0.0.22.dist-info/RECORD,,
|
File without changes
|
File without changes
|