letta-nightly 0.11.0.dev20250807104511__py3-none-any.whl → 0.11.0.dev20250808104456__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.
- letta/agent.py +2 -1
- letta/agents/letta_agent.py +215 -143
- letta/constants.py +4 -1
- letta/embeddings.py +6 -5
- letta/functions/function_sets/base.py +2 -2
- letta/functions/function_sets/files.py +22 -9
- letta/interfaces/anthropic_streaming_interface.py +291 -265
- letta/interfaces/openai_streaming_interface.py +270 -250
- letta/llm_api/anthropic.py +3 -10
- letta/llm_api/openai_client.py +6 -1
- letta/orm/__init__.py +1 -0
- letta/orm/step.py +14 -0
- letta/orm/step_metrics.py +71 -0
- letta/schemas/enums.py +9 -0
- letta/schemas/llm_config.py +8 -6
- letta/schemas/providers/lmstudio.py +2 -2
- letta/schemas/providers/ollama.py +42 -54
- letta/schemas/providers/openai.py +1 -1
- letta/schemas/step.py +6 -0
- letta/schemas/step_metrics.py +23 -0
- letta/schemas/tool_rule.py +10 -29
- letta/services/step_manager.py +179 -1
- letta/services/tool_executor/builtin_tool_executor.py +4 -1
- letta/services/tool_executor/core_tool_executor.py +2 -10
- letta/services/tool_executor/files_tool_executor.py +89 -40
- {letta_nightly-0.11.0.dev20250807104511.dist-info → letta_nightly-0.11.0.dev20250808104456.dist-info}/METADATA +1 -1
- {letta_nightly-0.11.0.dev20250807104511.dist-info → letta_nightly-0.11.0.dev20250808104456.dist-info}/RECORD +30 -28
- {letta_nightly-0.11.0.dev20250807104511.dist-info → letta_nightly-0.11.0.dev20250808104456.dist-info}/LICENSE +0 -0
- {letta_nightly-0.11.0.dev20250807104511.dist-info → letta_nightly-0.11.0.dev20250808104456.dist-info}/WHEEL +0 -0
- {letta_nightly-0.11.0.dev20250807104511.dist-info → letta_nightly-0.11.0.dev20250808104456.dist-info}/entry_points.txt +0 -0
letta/agent.py
CHANGED
@@ -45,7 +45,7 @@ from letta.otel.tracing import log_event, trace_method
|
|
45
45
|
from letta.schemas.agent import AgentState, AgentStepResponse, UpdateAgent, get_prompt_template_for_agent_type
|
46
46
|
from letta.schemas.block import BlockUpdate
|
47
47
|
from letta.schemas.embedding_config import EmbeddingConfig
|
48
|
-
from letta.schemas.enums import MessageRole, ProviderType, ToolType
|
48
|
+
from letta.schemas.enums import MessageRole, ProviderType, StepStatus, ToolType
|
49
49
|
from letta.schemas.letta_message_content import ImageContent, TextContent
|
50
50
|
from letta.schemas.memory import ContextWindowOverview, Memory
|
51
51
|
from letta.schemas.message import Message, MessageCreate, ToolReturn
|
@@ -991,6 +991,7 @@ class Agent(BaseAgent):
|
|
991
991
|
job_id=job_id,
|
992
992
|
step_id=step_id,
|
993
993
|
project_id=self.agent_state.project_id,
|
994
|
+
status=StepStatus.SUCCESS, # Set to SUCCESS since we're logging after successful completion
|
994
995
|
)
|
995
996
|
for message in all_new_messages:
|
996
997
|
message.step_id = step.id
|
letta/agents/letta_agent.py
CHANGED
@@ -34,7 +34,7 @@ from letta.otel.context import get_ctx_attributes
|
|
34
34
|
from letta.otel.metric_registry import MetricRegistry
|
35
35
|
from letta.otel.tracing import log_event, trace_method, tracer
|
36
36
|
from letta.schemas.agent import AgentState, UpdateAgent
|
37
|
-
from letta.schemas.enums import JobStatus, MessageRole, ProviderType, ToolType
|
37
|
+
from letta.schemas.enums import JobStatus, MessageRole, ProviderType, StepStatus, ToolType
|
38
38
|
from letta.schemas.letta_message import MessageType
|
39
39
|
from letta.schemas.letta_message_content import OmittedReasoningContent, ReasoningContent, RedactedReasoningContent, TextContent
|
40
40
|
from letta.schemas.letta_response import LettaResponse
|
@@ -241,6 +241,26 @@ class LettaAgent(BaseAgent):
|
|
241
241
|
|
242
242
|
step_progression = StepProgression.START
|
243
243
|
should_continue = False
|
244
|
+
|
245
|
+
# Create step early with PENDING status
|
246
|
+
logged_step = await self.step_manager.log_step_async(
|
247
|
+
actor=self.actor,
|
248
|
+
agent_id=agent_state.id,
|
249
|
+
provider_name=agent_state.llm_config.model_endpoint_type,
|
250
|
+
provider_category=agent_state.llm_config.provider_category or "base",
|
251
|
+
model=agent_state.llm_config.model,
|
252
|
+
model_endpoint=agent_state.llm_config.model_endpoint,
|
253
|
+
context_window_limit=agent_state.llm_config.context_window,
|
254
|
+
usage=UsageStatistics(completion_tokens=0, prompt_tokens=0, total_tokens=0),
|
255
|
+
provider_id=None,
|
256
|
+
job_id=self.current_run_id if self.current_run_id else None,
|
257
|
+
step_id=step_id,
|
258
|
+
project_id=agent_state.project_id,
|
259
|
+
status=StepStatus.PENDING,
|
260
|
+
)
|
261
|
+
# Only use step_id in messages if step was actually created
|
262
|
+
effective_step_id = step_id if logged_step else None
|
263
|
+
|
244
264
|
try:
|
245
265
|
request_data, response_data, current_in_context_messages, new_in_context_messages, valid_tool_names = (
|
246
266
|
await self._build_and_request_from_llm(
|
@@ -295,13 +315,17 @@ class LettaAgent(BaseAgent):
|
|
295
315
|
tool_rules_solver,
|
296
316
|
response.usage,
|
297
317
|
reasoning_content=reasoning,
|
298
|
-
step_id=
|
318
|
+
step_id=effective_step_id,
|
299
319
|
initial_messages=initial_messages,
|
300
320
|
agent_step_span=agent_step_span,
|
301
321
|
is_final_step=(i == max_steps - 1),
|
302
322
|
)
|
303
323
|
step_progression = StepProgression.STEP_LOGGED
|
304
324
|
|
325
|
+
# Update step with actual usage now that we have it (if step was created)
|
326
|
+
if logged_step:
|
327
|
+
await self.step_manager.update_step_success_async(self.actor, step_id, response.usage, stop_reason)
|
328
|
+
|
305
329
|
# TODO (cliandy): handle message contexts with larger refactor and dedupe logic
|
306
330
|
new_message_idx = len(initial_messages) if initial_messages else 0
|
307
331
|
self.response_messages.extend(persisted_messages[new_message_idx:])
|
@@ -321,7 +345,7 @@ class LettaAgent(BaseAgent):
|
|
321
345
|
provider_trace_create=ProviderTraceCreate(
|
322
346
|
request_json=request_data,
|
323
347
|
response_json=response_data,
|
324
|
-
step_id=step_id,
|
348
|
+
step_id=step_id, # Use original step_id for telemetry
|
325
349
|
organization_id=self.actor.organization_id,
|
326
350
|
),
|
327
351
|
)
|
@@ -358,54 +382,57 @@ class LettaAgent(BaseAgent):
|
|
358
382
|
|
359
383
|
# Update step if it needs to be updated
|
360
384
|
finally:
|
361
|
-
if
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
385
|
+
if step_progression == StepProgression.FINISHED and should_continue:
|
386
|
+
continue
|
387
|
+
|
388
|
+
self.logger.debug("Running cleanup for agent loop run: %s", self.current_run_id)
|
389
|
+
self.logger.info("Running final update. Step Progression: %s", step_progression)
|
390
|
+
try:
|
391
|
+
if step_progression == StepProgression.FINISHED and not should_continue:
|
392
|
+
# Successfully completed - update with final usage and stop reason
|
393
|
+
if stop_reason is None:
|
394
|
+
stop_reason = LettaStopReason(stop_reason=StopReasonType.end_turn.value)
|
395
|
+
# Note: step already updated with success status after _handle_ai_response
|
396
|
+
if logged_step:
|
371
397
|
await self.step_manager.update_step_stop_reason(self.actor, step_id, stop_reason.stop_reason)
|
372
|
-
|
398
|
+
break
|
373
399
|
|
374
|
-
|
375
|
-
|
400
|
+
# Handle error cases
|
401
|
+
if step_progression < StepProgression.STEP_LOGGED:
|
402
|
+
# Error occurred before step was fully logged
|
403
|
+
import traceback
|
404
|
+
|
405
|
+
if logged_step:
|
406
|
+
await self.step_manager.update_step_error_async(
|
376
407
|
actor=self.actor,
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
model_endpoint=agent_state.llm_config.model_endpoint,
|
382
|
-
context_window_limit=agent_state.llm_config.context_window,
|
383
|
-
usage=UsageStatistics(completion_tokens=0, prompt_tokens=0, total_tokens=0),
|
384
|
-
provider_id=None,
|
385
|
-
job_id=self.current_run_id if self.current_run_id else None,
|
386
|
-
step_id=step_id,
|
387
|
-
project_id=agent_state.project_id,
|
408
|
+
step_id=step_id, # Use original step_id for telemetry
|
409
|
+
error_type=type(e).__name__ if "e" in locals() else "Unknown",
|
410
|
+
error_message=str(e) if "e" in locals() else "Unknown error",
|
411
|
+
error_traceback=traceback.format_exc(),
|
388
412
|
stop_reason=stop_reason,
|
389
413
|
)
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
414
|
+
|
415
|
+
if step_progression <= StepProgression.RESPONSE_RECEIVED:
|
416
|
+
# TODO (cliandy): persist response if we get it back
|
417
|
+
if settings.track_errored_messages:
|
418
|
+
for message in initial_messages:
|
419
|
+
message.is_err = True
|
420
|
+
message.step_id = effective_step_id
|
421
|
+
await self.message_manager.create_many_messages_async(initial_messages, actor=self.actor)
|
422
|
+
elif step_progression <= StepProgression.LOGGED_TRACE:
|
423
|
+
if stop_reason is None:
|
424
|
+
self.logger.error("Error in step after logging step")
|
425
|
+
stop_reason = LettaStopReason(stop_reason=StopReasonType.error.value)
|
426
|
+
if logged_step:
|
401
427
|
await self.step_manager.update_step_stop_reason(self.actor, step_id, stop_reason.stop_reason)
|
402
|
-
|
403
|
-
|
428
|
+
else:
|
429
|
+
self.logger.error("Invalid StepProgression value")
|
404
430
|
|
431
|
+
if settings.track_stop_reason:
|
405
432
|
await self._log_request(request_start_timestamp_ns, request_span)
|
406
433
|
|
407
|
-
|
408
|
-
|
434
|
+
except Exception as e:
|
435
|
+
self.logger.error("Failed to update step: %s", e)
|
409
436
|
|
410
437
|
if not should_continue:
|
411
438
|
break
|
@@ -484,6 +511,25 @@ class LettaAgent(BaseAgent):
|
|
484
511
|
step_progression = StepProgression.START
|
485
512
|
should_continue = False
|
486
513
|
|
514
|
+
# Create step early with PENDING status
|
515
|
+
logged_step = await self.step_manager.log_step_async(
|
516
|
+
actor=self.actor,
|
517
|
+
agent_id=agent_state.id,
|
518
|
+
provider_name=agent_state.llm_config.model_endpoint_type,
|
519
|
+
provider_category=agent_state.llm_config.provider_category or "base",
|
520
|
+
model=agent_state.llm_config.model,
|
521
|
+
model_endpoint=agent_state.llm_config.model_endpoint,
|
522
|
+
context_window_limit=agent_state.llm_config.context_window,
|
523
|
+
usage=UsageStatistics(completion_tokens=0, prompt_tokens=0, total_tokens=0),
|
524
|
+
provider_id=None,
|
525
|
+
job_id=run_id if run_id else self.current_run_id,
|
526
|
+
step_id=step_id,
|
527
|
+
project_id=agent_state.project_id,
|
528
|
+
status=StepStatus.PENDING,
|
529
|
+
)
|
530
|
+
# Only use step_id in messages if step was actually created
|
531
|
+
effective_step_id = step_id if logged_step else None
|
532
|
+
|
487
533
|
try:
|
488
534
|
request_data, response_data, current_in_context_messages, new_in_context_messages, valid_tool_names = (
|
489
535
|
await self._build_and_request_from_llm(
|
@@ -533,7 +579,7 @@ class LettaAgent(BaseAgent):
|
|
533
579
|
tool_rules_solver,
|
534
580
|
response.usage,
|
535
581
|
reasoning_content=reasoning,
|
536
|
-
step_id=
|
582
|
+
step_id=effective_step_id,
|
537
583
|
initial_messages=initial_messages,
|
538
584
|
agent_step_span=agent_step_span,
|
539
585
|
is_final_step=(i == max_steps - 1),
|
@@ -541,6 +587,10 @@ class LettaAgent(BaseAgent):
|
|
541
587
|
)
|
542
588
|
step_progression = StepProgression.STEP_LOGGED
|
543
589
|
|
590
|
+
# Update step with actual usage now that we have it (if step was created)
|
591
|
+
if logged_step:
|
592
|
+
await self.step_manager.update_step_success_async(self.actor, step_id, response.usage, stop_reason)
|
593
|
+
|
544
594
|
new_message_idx = len(initial_messages) if initial_messages else 0
|
545
595
|
self.response_messages.extend(persisted_messages[new_message_idx:])
|
546
596
|
new_in_context_messages.extend(persisted_messages[new_message_idx:])
|
@@ -560,7 +610,7 @@ class LettaAgent(BaseAgent):
|
|
560
610
|
provider_trace_create=ProviderTraceCreate(
|
561
611
|
request_json=request_data,
|
562
612
|
response_json=response_data,
|
563
|
-
step_id=step_id,
|
613
|
+
step_id=step_id, # Use original step_id for telemetry
|
564
614
|
organization_id=self.actor.organization_id,
|
565
615
|
),
|
566
616
|
)
|
@@ -584,54 +634,56 @@ class LettaAgent(BaseAgent):
|
|
584
634
|
|
585
635
|
# Update step if it needs to be updated
|
586
636
|
finally:
|
587
|
-
if
|
588
|
-
|
589
|
-
continue
|
590
|
-
|
591
|
-
self.logger.debug("Running cleanup for agent loop run: %s", self.current_run_id)
|
592
|
-
self.logger.info("Running final update. Step Progression: %s", step_progression)
|
593
|
-
try:
|
594
|
-
if step_progression == StepProgression.FINISHED and not should_continue:
|
595
|
-
if stop_reason is None:
|
596
|
-
stop_reason = LettaStopReason(stop_reason=StopReasonType.end_turn.value)
|
597
|
-
await self.step_manager.update_step_stop_reason(self.actor, step_id, stop_reason.stop_reason)
|
598
|
-
break
|
637
|
+
if step_progression == StepProgression.FINISHED and should_continue:
|
638
|
+
continue
|
599
639
|
|
600
|
-
|
601
|
-
|
640
|
+
self.logger.debug("Running cleanup for agent loop run: %s", self.current_run_id)
|
641
|
+
self.logger.info("Running final update. Step Progression: %s", step_progression)
|
642
|
+
try:
|
643
|
+
if step_progression == StepProgression.FINISHED and not should_continue:
|
644
|
+
# Successfully completed - update with final usage and stop reason
|
645
|
+
if stop_reason is None:
|
646
|
+
stop_reason = LettaStopReason(stop_reason=StopReasonType.end_turn.value)
|
647
|
+
if logged_step:
|
648
|
+
await self.step_manager.update_step_success_async(self.actor, step_id, usage, stop_reason)
|
649
|
+
break
|
650
|
+
|
651
|
+
# Handle error cases
|
652
|
+
if step_progression < StepProgression.STEP_LOGGED:
|
653
|
+
# Error occurred before step was fully logged
|
654
|
+
import traceback
|
655
|
+
|
656
|
+
if logged_step:
|
657
|
+
await self.step_manager.update_step_error_async(
|
602
658
|
actor=self.actor,
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
model_endpoint=agent_state.llm_config.model_endpoint,
|
608
|
-
context_window_limit=agent_state.llm_config.context_window,
|
609
|
-
usage=UsageStatistics(completion_tokens=0, prompt_tokens=0, total_tokens=0),
|
610
|
-
provider_id=None,
|
611
|
-
job_id=self.current_run_id if self.current_run_id else None,
|
612
|
-
step_id=step_id,
|
613
|
-
project_id=agent_state.project_id,
|
659
|
+
step_id=step_id, # Use original step_id for telemetry
|
660
|
+
error_type=type(e).__name__ if "e" in locals() else "Unknown",
|
661
|
+
error_message=str(e) if "e" in locals() else "Unknown error",
|
662
|
+
error_traceback=traceback.format_exc(),
|
614
663
|
stop_reason=stop_reason,
|
615
664
|
)
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
665
|
+
|
666
|
+
if step_progression <= StepProgression.RESPONSE_RECEIVED:
|
667
|
+
# TODO (cliandy): persist response if we get it back
|
668
|
+
if settings.track_errored_messages:
|
669
|
+
for message in initial_messages:
|
670
|
+
message.is_err = True
|
671
|
+
message.step_id = effective_step_id
|
672
|
+
await self.message_manager.create_many_messages_async(initial_messages, actor=self.actor)
|
673
|
+
elif step_progression <= StepProgression.LOGGED_TRACE:
|
674
|
+
if stop_reason is None:
|
675
|
+
self.logger.error("Error in step after logging step")
|
676
|
+
stop_reason = LettaStopReason(stop_reason=StopReasonType.error.value)
|
677
|
+
if logged_step:
|
627
678
|
await self.step_manager.update_step_stop_reason(self.actor, step_id, stop_reason.stop_reason)
|
628
|
-
|
629
|
-
|
679
|
+
else:
|
680
|
+
self.logger.error("Invalid StepProgression value")
|
630
681
|
|
682
|
+
if settings.track_stop_reason:
|
631
683
|
await self._log_request(request_start_timestamp_ns, request_span)
|
632
684
|
|
633
|
-
|
634
|
-
|
685
|
+
except Exception as e:
|
686
|
+
self.logger.error("Failed to update step: %s", e)
|
635
687
|
|
636
688
|
if not should_continue:
|
637
689
|
break
|
@@ -717,6 +769,26 @@ class LettaAgent(BaseAgent):
|
|
717
769
|
|
718
770
|
step_progression = StepProgression.START
|
719
771
|
should_continue = False
|
772
|
+
|
773
|
+
# Create step early with PENDING status
|
774
|
+
logged_step = await self.step_manager.log_step_async(
|
775
|
+
actor=self.actor,
|
776
|
+
agent_id=agent_state.id,
|
777
|
+
provider_name=agent_state.llm_config.model_endpoint_type,
|
778
|
+
provider_category=agent_state.llm_config.provider_category or "base",
|
779
|
+
model=agent_state.llm_config.model,
|
780
|
+
model_endpoint=agent_state.llm_config.model_endpoint,
|
781
|
+
context_window_limit=agent_state.llm_config.context_window,
|
782
|
+
usage=UsageStatistics(completion_tokens=0, prompt_tokens=0, total_tokens=0),
|
783
|
+
provider_id=None,
|
784
|
+
job_id=self.current_run_id if self.current_run_id else None,
|
785
|
+
step_id=step_id,
|
786
|
+
project_id=agent_state.project_id,
|
787
|
+
status=StepStatus.PENDING,
|
788
|
+
)
|
789
|
+
# Only use step_id in messages if step was actually created
|
790
|
+
effective_step_id = step_id if logged_step else None
|
791
|
+
|
720
792
|
try:
|
721
793
|
(
|
722
794
|
request_data,
|
@@ -827,13 +899,26 @@ class LettaAgent(BaseAgent):
|
|
827
899
|
),
|
828
900
|
reasoning_content=reasoning_content,
|
829
901
|
pre_computed_assistant_message_id=interface.letta_message_id,
|
830
|
-
step_id=
|
902
|
+
step_id=effective_step_id,
|
831
903
|
initial_messages=initial_messages,
|
832
904
|
agent_step_span=agent_step_span,
|
833
905
|
is_final_step=(i == max_steps - 1),
|
834
906
|
)
|
835
907
|
step_progression = StepProgression.STEP_LOGGED
|
836
908
|
|
909
|
+
# Update step with actual usage now that we have it (if step was created)
|
910
|
+
if logged_step:
|
911
|
+
await self.step_manager.update_step_success_async(
|
912
|
+
self.actor,
|
913
|
+
step_id,
|
914
|
+
UsageStatistics(
|
915
|
+
completion_tokens=usage.completion_tokens,
|
916
|
+
prompt_tokens=usage.prompt_tokens,
|
917
|
+
total_tokens=usage.total_tokens,
|
918
|
+
),
|
919
|
+
stop_reason,
|
920
|
+
)
|
921
|
+
|
837
922
|
new_message_idx = len(initial_messages) if initial_messages else 0
|
838
923
|
self.response_messages.extend(persisted_messages[new_message_idx:])
|
839
924
|
new_in_context_messages.extend(persisted_messages[new_message_idx:])
|
@@ -872,7 +957,7 @@ class LettaAgent(BaseAgent):
|
|
872
957
|
"output_tokens": usage.completion_tokens,
|
873
958
|
},
|
874
959
|
},
|
875
|
-
step_id=step_id,
|
960
|
+
step_id=step_id, # Use original step_id for telemetry
|
876
961
|
organization_id=self.actor.organization_id,
|
877
962
|
),
|
878
963
|
)
|
@@ -907,54 +992,57 @@ class LettaAgent(BaseAgent):
|
|
907
992
|
|
908
993
|
# Update step if it needs to be updated
|
909
994
|
finally:
|
910
|
-
if
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
995
|
+
if step_progression == StepProgression.FINISHED and should_continue:
|
996
|
+
continue
|
997
|
+
|
998
|
+
self.logger.debug("Running cleanup for agent loop run: %s", self.current_run_id)
|
999
|
+
self.logger.info("Running final update. Step Progression: %s", step_progression)
|
1000
|
+
try:
|
1001
|
+
if step_progression == StepProgression.FINISHED and not should_continue:
|
1002
|
+
# Successfully completed - update with final usage and stop reason
|
1003
|
+
if stop_reason is None:
|
1004
|
+
stop_reason = LettaStopReason(stop_reason=StopReasonType.end_turn.value)
|
1005
|
+
# Note: step already updated with success status after _handle_ai_response
|
1006
|
+
if logged_step:
|
920
1007
|
await self.step_manager.update_step_stop_reason(self.actor, step_id, stop_reason.stop_reason)
|
921
|
-
|
1008
|
+
break
|
1009
|
+
|
1010
|
+
# Handle error cases
|
1011
|
+
if step_progression < StepProgression.STEP_LOGGED:
|
1012
|
+
# Error occurred before step was fully logged
|
1013
|
+
import traceback
|
922
1014
|
|
923
|
-
if
|
924
|
-
await self.step_manager.
|
1015
|
+
if logged_step:
|
1016
|
+
await self.step_manager.update_step_error_async(
|
925
1017
|
actor=self.actor,
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
model_endpoint=agent_state.llm_config.model_endpoint,
|
931
|
-
context_window_limit=agent_state.llm_config.context_window,
|
932
|
-
usage=UsageStatistics(completion_tokens=0, prompt_tokens=0, total_tokens=0),
|
933
|
-
provider_id=None,
|
934
|
-
job_id=self.current_run_id if self.current_run_id else None,
|
935
|
-
step_id=step_id,
|
936
|
-
project_id=agent_state.project_id,
|
1018
|
+
step_id=step_id, # Use original step_id for telemetry
|
1019
|
+
error_type=type(e).__name__ if "e" in locals() else "Unknown",
|
1020
|
+
error_message=str(e) if "e" in locals() else "Unknown error",
|
1021
|
+
error_traceback=traceback.format_exc(),
|
937
1022
|
stop_reason=stop_reason,
|
938
1023
|
)
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
1024
|
+
|
1025
|
+
if step_progression <= StepProgression.STREAM_RECEIVED:
|
1026
|
+
if first_chunk and settings.track_errored_messages:
|
1027
|
+
for message in initial_messages:
|
1028
|
+
message.is_err = True
|
1029
|
+
message.step_id = effective_step_id
|
1030
|
+
await self.message_manager.create_many_messages_async(initial_messages, actor=self.actor)
|
1031
|
+
elif step_progression <= StepProgression.LOGGED_TRACE:
|
1032
|
+
if stop_reason is None:
|
1033
|
+
self.logger.error("Error in step after logging step")
|
1034
|
+
stop_reason = LettaStopReason(stop_reason=StopReasonType.error.value)
|
1035
|
+
if logged_step:
|
949
1036
|
await self.step_manager.update_step_stop_reason(self.actor, step_id, stop_reason.stop_reason)
|
950
|
-
|
951
|
-
|
1037
|
+
else:
|
1038
|
+
self.logger.error("Invalid StepProgression value")
|
952
1039
|
|
953
|
-
|
1040
|
+
# Do tracking for failure cases. Can consolidate with success conditions later.
|
1041
|
+
if settings.track_stop_reason:
|
954
1042
|
await self._log_request(request_start_timestamp_ns, request_span)
|
955
1043
|
|
956
|
-
|
957
|
-
|
1044
|
+
except Exception as e:
|
1045
|
+
self.logger.error("Failed to update step: %s", e)
|
958
1046
|
|
959
1047
|
if not should_continue:
|
960
1048
|
break
|
@@ -1315,23 +1403,7 @@ class LettaAgent(BaseAgent):
|
|
1315
1403
|
is_final_step=is_final_step,
|
1316
1404
|
)
|
1317
1405
|
|
1318
|
-
# 5.
|
1319
|
-
logged_step = await self.step_manager.log_step_async(
|
1320
|
-
actor=self.actor,
|
1321
|
-
agent_id=agent_state.id,
|
1322
|
-
provider_name=agent_state.llm_config.model_endpoint_type,
|
1323
|
-
provider_category=agent_state.llm_config.provider_category or "base",
|
1324
|
-
model=agent_state.llm_config.model,
|
1325
|
-
model_endpoint=agent_state.llm_config.model_endpoint,
|
1326
|
-
context_window_limit=agent_state.llm_config.context_window,
|
1327
|
-
usage=usage,
|
1328
|
-
provider_id=None,
|
1329
|
-
job_id=run_id if run_id else self.current_run_id,
|
1330
|
-
step_id=step_id,
|
1331
|
-
project_id=agent_state.project_id,
|
1332
|
-
stop_reason=stop_reason,
|
1333
|
-
)
|
1334
|
-
|
1406
|
+
# 5. Create messages (step was already created at the beginning)
|
1335
1407
|
tool_call_messages = create_letta_messages_from_llm_response(
|
1336
1408
|
agent_id=agent_state.id,
|
1337
1409
|
model=agent_state.llm_config.model,
|
@@ -1347,7 +1419,7 @@ class LettaAgent(BaseAgent):
|
|
1347
1419
|
heartbeat_reason=heartbeat_reason,
|
1348
1420
|
reasoning_content=reasoning_content,
|
1349
1421
|
pre_computed_assistant_message_id=pre_computed_assistant_message_id,
|
1350
|
-
step_id=
|
1422
|
+
step_id=step_id,
|
1351
1423
|
)
|
1352
1424
|
|
1353
1425
|
persisted_messages = await self.message_manager.create_many_messages_async(
|
letta/constants.py
CHANGED
@@ -10,6 +10,7 @@ DEFAULT_TIMEZONE = "UTC"
|
|
10
10
|
|
11
11
|
ADMIN_PREFIX = "/v1/admin"
|
12
12
|
API_PREFIX = "/v1"
|
13
|
+
OLLAMA_API_PREFIX = "/v1"
|
13
14
|
OPENAI_API_PREFIX = "/openai"
|
14
15
|
|
15
16
|
COMPOSIO_ENTITY_ENV_VAR_KEY = "COMPOSIO_ENTITY"
|
@@ -50,8 +51,9 @@ TOOL_CALL_ID_MAX_LEN = 29
|
|
50
51
|
# Max steps for agent loop
|
51
52
|
DEFAULT_MAX_STEPS = 50
|
52
53
|
|
53
|
-
#
|
54
|
+
# context window size
|
54
55
|
MIN_CONTEXT_WINDOW = 4096
|
56
|
+
DEFAULT_CONTEXT_WINDOW = 32000
|
55
57
|
|
56
58
|
# number of concurrent embedding requests to sent
|
57
59
|
EMBEDDING_BATCH_SIZE = 200
|
@@ -63,6 +65,7 @@ DEFAULT_MIN_MESSAGE_BUFFER_LENGTH = 15
|
|
63
65
|
# embeddings
|
64
66
|
MAX_EMBEDDING_DIM = 4096 # maximum supported embeding size - do NOT change or else DBs will need to be reset
|
65
67
|
DEFAULT_EMBEDDING_CHUNK_SIZE = 300
|
68
|
+
DEFAULT_EMBEDDING_DIM = 1024
|
66
69
|
|
67
70
|
# tokenizers
|
68
71
|
EMBEDDING_TO_TOKENIZER_MAP = {
|
letta/embeddings.py
CHANGED
@@ -139,10 +139,11 @@ class AzureOpenAIEmbedding:
|
|
139
139
|
|
140
140
|
class OllamaEmbeddings:
|
141
141
|
|
142
|
+
# Uses OpenAI API standard
|
142
143
|
# Format:
|
143
|
-
# curl http://localhost:11434/
|
144
|
+
# curl http://localhost:11434/v1/embeddings -d '{
|
144
145
|
# "model": "mxbai-embed-large",
|
145
|
-
# "
|
146
|
+
# "input": "Llamas are members of the camelid family"
|
146
147
|
# }'
|
147
148
|
|
148
149
|
def __init__(self, model: str, base_url: str, ollama_additional_kwargs: dict):
|
@@ -154,18 +155,18 @@ class OllamaEmbeddings:
|
|
154
155
|
import httpx
|
155
156
|
|
156
157
|
headers = {"Content-Type": "application/json"}
|
157
|
-
json_data = {"model": self.model, "
|
158
|
+
json_data = {"model": self.model, "input": text}
|
158
159
|
json_data.update(self.ollama_additional_kwargs)
|
159
160
|
|
160
161
|
with httpx.Client() as client:
|
161
162
|
response = client.post(
|
162
|
-
f"{self.base_url}/
|
163
|
+
f"{self.base_url}/embeddings",
|
163
164
|
headers=headers,
|
164
165
|
json=json_data,
|
165
166
|
)
|
166
167
|
|
167
168
|
response_json = response.json()
|
168
|
-
return response_json["embedding"]
|
169
|
+
return response_json["data"][0]["embedding"]
|
169
170
|
|
170
171
|
|
171
172
|
class GoogleEmbeddings:
|
@@ -191,14 +191,14 @@ SNIPPET_LINES: int = 4
|
|
191
191
|
|
192
192
|
|
193
193
|
# Based off of: https://github.com/anthropics/anthropic-quickstarts/blob/main/computer-use-demo/computer_use_demo/tools/edit.py?ref=musings.yasyf.com#L154
|
194
|
-
def memory_replace(agent_state: "AgentState", label: str, old_str: str, new_str:
|
194
|
+
def memory_replace(agent_state: "AgentState", label: str, old_str: str, new_str: str) -> str: # type: ignore
|
195
195
|
"""
|
196
196
|
The memory_replace command allows you to replace a specific string in a memory block with a new string. This is used for making precise edits.
|
197
197
|
|
198
198
|
Args:
|
199
199
|
label (str): Section of the memory to be edited, identified by its label.
|
200
200
|
old_str (str): The text to replace (must match exactly, including whitespace and indentation).
|
201
|
-
new_str (
|
201
|
+
new_str (str): The new text to insert in place of the old text. Do not include line number prefixes.
|
202
202
|
|
203
203
|
Returns:
|
204
204
|
str: The success message
|