agno 2.4.5__py3-none-any.whl → 2.4.6__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.
- agno/agent/agent.py +2 -1
- agno/db/surrealdb/models.py +1 -1
- agno/knowledge/chunking/agentic.py +1 -5
- agno/knowledge/chunking/code.py +1 -1
- agno/knowledge/chunking/document.py +22 -42
- agno/knowledge/chunking/fixed.py +1 -5
- agno/knowledge/chunking/markdown.py +9 -25
- agno/knowledge/chunking/recursive.py +1 -3
- agno/knowledge/chunking/row.py +3 -2
- agno/knowledge/chunking/semantic.py +1 -1
- agno/knowledge/chunking/strategy.py +19 -0
- agno/knowledge/knowledge.py +173 -14
- agno/knowledge/reader/text_reader.py +1 -1
- agno/learn/stores/learned_knowledge.py +108 -131
- agno/utils/print_response/agent.py +8 -8
- agno/utils/print_response/team.py +8 -8
- {agno-2.4.5.dist-info → agno-2.4.6.dist-info}/METADATA +33 -58
- {agno-2.4.5.dist-info → agno-2.4.6.dist-info}/RECORD +21 -21
- {agno-2.4.5.dist-info → agno-2.4.6.dist-info}/WHEEL +0 -0
- {agno-2.4.5.dist-info → agno-2.4.6.dist-info}/licenses/LICENSE +0 -0
- {agno-2.4.5.dist-info → agno-2.4.6.dist-info}/top_level.txt +0 -0
|
@@ -75,9 +75,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
75
75
|
self._schema = self.config.schema or LearnedKnowledge
|
|
76
76
|
|
|
77
77
|
if self.config.mode == LearningMode.HITL:
|
|
78
|
-
log_warning(
|
|
79
|
-
"LearnedKnowledgeStore does not support HITL mode. Use PROPOSE mode for human-in-the-loop approval. "
|
|
80
|
-
)
|
|
78
|
+
log_warning("LearnedKnowledgeStore does not support HITL mode. Use PROPOSE mode for soft approval.")
|
|
81
79
|
|
|
82
80
|
# =========================================================================
|
|
83
81
|
# LearningStore Protocol Implementation
|
|
@@ -178,6 +176,9 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
178
176
|
namespace: Namespace to save learnings to (default: "global").
|
|
179
177
|
**kwargs: Additional context (ignored).
|
|
180
178
|
"""
|
|
179
|
+
# Reset state for this operation
|
|
180
|
+
self.learning_saved = False
|
|
181
|
+
|
|
181
182
|
# process only supported in ALWAYS mode
|
|
182
183
|
# for programmatic extraction, use extract_and_save directly
|
|
183
184
|
if self.config.mode != LearningMode.ALWAYS:
|
|
@@ -204,6 +205,9 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
204
205
|
**kwargs,
|
|
205
206
|
) -> None:
|
|
206
207
|
"""Async version of process."""
|
|
208
|
+
# Reset state for this operation
|
|
209
|
+
self.learning_saved = False
|
|
210
|
+
|
|
207
211
|
if self.config.mode != LearningMode.ALWAYS:
|
|
208
212
|
return
|
|
209
213
|
|
|
@@ -250,35 +254,45 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
250
254
|
→ Then incorporate any relevant findings into your response
|
|
251
255
|
|
|
252
256
|
**RULE 2: ALWAYS search before saving.**
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
257
|
+
Before saving anything, first call `search_learnings` to check if similar knowledge exists.
|
|
258
|
+
Only save if it's genuinely new (not a duplicate or minor variation).
|
|
259
|
+
|
|
260
|
+
**RULE 3: ALWAYS save when explicitly asked.**
|
|
261
|
+
When the user says "remember", "save", "note", "keep in mind", or similar:
|
|
262
|
+
→ These are explicit directives - save what they asked (after searching for duplicates)
|
|
263
|
+
|
|
264
|
+
**RULE 4: ALWAYS save team/org goals, constraints, and policies.**
|
|
265
|
+
When the user shares organizational context:
|
|
266
|
+
→ "We're trying to..." / "Our goal is..." (team goals)
|
|
267
|
+
→ "We can't use..." / "We need to avoid..." (constraints)
|
|
268
|
+
→ "Our policy is..." / "We always..." (policies)
|
|
269
|
+
→ "Our priority is..." / "We prefer..." at org level (priorities)
|
|
270
|
+
These are shared context - save them so other users benefit too.
|
|
256
271
|
|
|
257
272
|
## Tools
|
|
258
273
|
|
|
259
274
|
`search_learnings(query)` - Search for relevant prior insights. Use liberally.
|
|
260
|
-
`save_learning(title, learning, context, tags)` - Save
|
|
275
|
+
`save_learning(title, learning, context, tags)` - Save new insights or context.
|
|
261
276
|
|
|
262
277
|
## When to Search
|
|
263
278
|
|
|
264
|
-
|
|
279
|
+
Search when the user:
|
|
265
280
|
- Asks for recommendations or best practices
|
|
266
281
|
- Asks how to approach a problem
|
|
267
282
|
- Asks about trade-offs or considerations
|
|
268
283
|
- Mentions a technology, domain, or problem area
|
|
269
|
-
- Asks you to save something (
|
|
284
|
+
- Asks you to save something (check for duplicates first)
|
|
270
285
|
|
|
271
|
-
## When to Save
|
|
286
|
+
## When to Save (Self-Discovered Insights)
|
|
272
287
|
|
|
273
|
-
|
|
288
|
+
For insights you discover yourself (not explicit requests or org context), only save if:
|
|
274
289
|
- Non-obvious (required investigation to discover)
|
|
275
290
|
- Reusable (applies to a category of problems)
|
|
276
291
|
- Actionable (specific enough to apply directly)
|
|
277
|
-
- Not already in the knowledge base (you checked by searching first!)
|
|
278
292
|
|
|
279
293
|
Do NOT save:
|
|
280
294
|
- Raw facts or common knowledge
|
|
281
|
-
-
|
|
295
|
+
- Individual user preferences (use user memory instead)
|
|
282
296
|
- Duplicates of existing learnings
|
|
283
297
|
</learning_system>\
|
|
284
298
|
""")
|
|
@@ -308,7 +322,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
308
322
|
If you discover something worth preserving, propose it at the end of your response:
|
|
309
323
|
|
|
310
324
|
---
|
|
311
|
-
|
|
325
|
+
**Proposed Learning**
|
|
312
326
|
**Title:** [Concise title]
|
|
313
327
|
**Context:** [When this applies]
|
|
314
328
|
**Insight:** [The learning - specific and actionable]
|
|
@@ -484,15 +498,17 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
484
498
|
tools = []
|
|
485
499
|
|
|
486
500
|
if self.config.agent_can_search:
|
|
487
|
-
tools.append(
|
|
501
|
+
tools.append(
|
|
502
|
+
self._create_search_learnings_tool(namespace=namespace or self.config.namespace, user_id=user_id)
|
|
503
|
+
)
|
|
488
504
|
|
|
489
505
|
if self.config.agent_can_save:
|
|
490
506
|
tools.append(
|
|
491
507
|
self._create_save_learning_tool(
|
|
508
|
+
namespace=namespace or self.config.namespace,
|
|
492
509
|
user_id=user_id,
|
|
493
510
|
agent_id=agent_id,
|
|
494
511
|
team_id=team_id,
|
|
495
|
-
default_namespace=namespace,
|
|
496
512
|
)
|
|
497
513
|
)
|
|
498
514
|
|
|
@@ -509,15 +525,17 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
509
525
|
tools = []
|
|
510
526
|
|
|
511
527
|
if self.config.agent_can_search:
|
|
512
|
-
tools.append(
|
|
528
|
+
tools.append(
|
|
529
|
+
self._create_async_search_learnings_tool(namespace=namespace or self.config.namespace, user_id=user_id)
|
|
530
|
+
)
|
|
513
531
|
|
|
514
532
|
if self.config.agent_can_save:
|
|
515
533
|
tools.append(
|
|
516
534
|
self._create_async_save_learning_tool(
|
|
535
|
+
namespace=namespace or self.config.namespace,
|
|
517
536
|
user_id=user_id,
|
|
518
537
|
agent_id=agent_id,
|
|
519
538
|
team_id=team_id,
|
|
520
|
-
default_namespace=namespace,
|
|
521
539
|
)
|
|
522
540
|
)
|
|
523
541
|
|
|
@@ -529,10 +547,10 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
529
547
|
|
|
530
548
|
def _create_save_learning_tool(
|
|
531
549
|
self,
|
|
550
|
+
namespace: str,
|
|
532
551
|
user_id: Optional[str] = None,
|
|
533
552
|
agent_id: Optional[str] = None,
|
|
534
553
|
team_id: Optional[str] = None,
|
|
535
|
-
default_namespace: Optional[str] = None,
|
|
536
554
|
) -> Callable:
|
|
537
555
|
"""Create the save_learning tool for the agent."""
|
|
538
556
|
|
|
@@ -541,31 +559,20 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
541
559
|
learning: str,
|
|
542
560
|
context: Optional[str] = None,
|
|
543
561
|
tags: Optional[List[str]] = None,
|
|
544
|
-
namespace: Optional[str] = None,
|
|
545
562
|
) -> str:
|
|
546
|
-
"""Save a reusable insight to the knowledge base.
|
|
563
|
+
"""Save a reusable insight or organizational context to the knowledge base.
|
|
547
564
|
|
|
548
|
-
IMPORTANT:
|
|
549
|
-
if similar knowledge already exists. Do not save duplicates!
|
|
550
|
-
|
|
551
|
-
Only save insights that are:
|
|
552
|
-
- Non-obvious (not common knowledge)
|
|
553
|
-
- Reusable (applies beyond this specific case)
|
|
554
|
-
- Actionable (specific enough to apply directly)
|
|
555
|
-
- Not already saved (you searched first, right?)
|
|
565
|
+
IMPORTANT: You MUST call search_learnings first to check for duplicates.
|
|
556
566
|
|
|
557
567
|
Args:
|
|
558
|
-
title: Concise, searchable title
|
|
559
|
-
learning: The insight - specific and actionable.
|
|
560
|
-
context: When/where this applies
|
|
561
|
-
tags: Categories for organization
|
|
562
|
-
namespace: Access scope - "global" (shared) or "user" (private).
|
|
568
|
+
title: Concise, searchable title.
|
|
569
|
+
learning: The insight or context - specific and actionable.
|
|
570
|
+
context: When/where this applies.
|
|
571
|
+
tags: Categories for organization.
|
|
563
572
|
|
|
564
573
|
Returns:
|
|
565
574
|
Confirmation message.
|
|
566
575
|
"""
|
|
567
|
-
effective_namespace = namespace or default_namespace or "global"
|
|
568
|
-
|
|
569
576
|
success = self.save(
|
|
570
577
|
title=title,
|
|
571
578
|
learning=learning,
|
|
@@ -574,21 +581,21 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
574
581
|
user_id=user_id,
|
|
575
582
|
agent_id=agent_id,
|
|
576
583
|
team_id=team_id,
|
|
577
|
-
namespace=
|
|
584
|
+
namespace=namespace,
|
|
578
585
|
)
|
|
579
586
|
if success:
|
|
580
587
|
self.learning_saved = True
|
|
581
|
-
return f"Learning saved: {title} (namespace: {
|
|
588
|
+
return f"Learning saved: {title} (namespace: {namespace})"
|
|
582
589
|
return "Failed to save learning"
|
|
583
590
|
|
|
584
591
|
return save_learning
|
|
585
592
|
|
|
586
593
|
def _create_async_save_learning_tool(
|
|
587
594
|
self,
|
|
595
|
+
namespace: str,
|
|
588
596
|
user_id: Optional[str] = None,
|
|
589
597
|
agent_id: Optional[str] = None,
|
|
590
598
|
team_id: Optional[str] = None,
|
|
591
|
-
default_namespace: Optional[str] = None,
|
|
592
599
|
) -> Callable:
|
|
593
600
|
"""Create the async save_learning tool for the agent."""
|
|
594
601
|
|
|
@@ -597,31 +604,20 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
597
604
|
learning: str,
|
|
598
605
|
context: Optional[str] = None,
|
|
599
606
|
tags: Optional[List[str]] = None,
|
|
600
|
-
namespace: Optional[str] = None,
|
|
601
607
|
) -> str:
|
|
602
|
-
"""Save a reusable insight to the knowledge base.
|
|
608
|
+
"""Save a reusable insight or organizational context to the knowledge base.
|
|
603
609
|
|
|
604
|
-
IMPORTANT:
|
|
605
|
-
if similar knowledge already exists. Do not save duplicates!
|
|
606
|
-
|
|
607
|
-
Only save insights that are:
|
|
608
|
-
- Non-obvious (not common knowledge)
|
|
609
|
-
- Reusable (applies beyond this specific case)
|
|
610
|
-
- Actionable (specific enough to apply directly)
|
|
611
|
-
- Not already saved (you searched first, right?)
|
|
610
|
+
IMPORTANT: You MUST call search_learnings first to check for duplicates.
|
|
612
611
|
|
|
613
612
|
Args:
|
|
614
|
-
title: Concise, searchable title
|
|
615
|
-
learning: The insight - specific and actionable.
|
|
616
|
-
context: When/where this applies
|
|
617
|
-
tags: Categories for organization
|
|
618
|
-
namespace: Access scope - "global" (shared) or "user" (private).
|
|
613
|
+
title: Concise, searchable title.
|
|
614
|
+
learning: The insight or context - specific and actionable.
|
|
615
|
+
context: When/where this applies.
|
|
616
|
+
tags: Categories for organization.
|
|
619
617
|
|
|
620
618
|
Returns:
|
|
621
619
|
Confirmation message.
|
|
622
620
|
"""
|
|
623
|
-
effective_namespace = namespace or default_namespace or "global"
|
|
624
|
-
|
|
625
621
|
success = await self.asave(
|
|
626
622
|
title=title,
|
|
627
623
|
learning=learning,
|
|
@@ -630,11 +626,11 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
630
626
|
user_id=user_id,
|
|
631
627
|
agent_id=agent_id,
|
|
632
628
|
team_id=team_id,
|
|
633
|
-
namespace=
|
|
629
|
+
namespace=namespace,
|
|
634
630
|
)
|
|
635
631
|
if success:
|
|
636
632
|
self.learning_saved = True
|
|
637
|
-
return f"Learning saved: {title} (namespace: {
|
|
633
|
+
return f"Learning saved: {title} (namespace: {namespace})"
|
|
638
634
|
return "Failed to save learning"
|
|
639
635
|
|
|
640
636
|
return save_learning
|
|
@@ -645,6 +641,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
645
641
|
|
|
646
642
|
def _create_search_learnings_tool(
|
|
647
643
|
self,
|
|
644
|
+
namespace: str,
|
|
648
645
|
user_id: Optional[str] = None,
|
|
649
646
|
) -> Callable:
|
|
650
647
|
"""Create the search_learnings tool for the agent."""
|
|
@@ -652,7 +649,6 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
652
649
|
def search_learnings(
|
|
653
650
|
query: str,
|
|
654
651
|
limit: int = 5,
|
|
655
|
-
namespace: Optional[str] = None,
|
|
656
652
|
) -> str:
|
|
657
653
|
"""Search for relevant insights in the knowledge base.
|
|
658
654
|
|
|
@@ -662,9 +658,8 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
662
658
|
|
|
663
659
|
Args:
|
|
664
660
|
query: Keywords describing what you're looking for.
|
|
665
|
-
Examples: "cloud costs", "API rate limiting", "
|
|
661
|
+
Examples: "cloud costs", "API rate limiting", "team goals"
|
|
666
662
|
limit: Maximum results (default: 5)
|
|
667
|
-
namespace: Filter by scope (None = all, "global", "user", or custom)
|
|
668
663
|
|
|
669
664
|
Returns:
|
|
670
665
|
List of relevant learnings, or message if none found.
|
|
@@ -686,6 +681,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
686
681
|
|
|
687
682
|
def _create_async_search_learnings_tool(
|
|
688
683
|
self,
|
|
684
|
+
namespace: str,
|
|
689
685
|
user_id: Optional[str] = None,
|
|
690
686
|
) -> Callable:
|
|
691
687
|
"""Create the async search_learnings tool for the agent."""
|
|
@@ -693,7 +689,6 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
693
689
|
async def search_learnings(
|
|
694
690
|
query: str,
|
|
695
691
|
limit: int = 5,
|
|
696
|
-
namespace: Optional[str] = None,
|
|
697
692
|
) -> str:
|
|
698
693
|
"""Search for relevant insights in the knowledge base.
|
|
699
694
|
|
|
@@ -703,9 +698,8 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
703
698
|
|
|
704
699
|
Args:
|
|
705
700
|
query: Keywords describing what you're looking for.
|
|
706
|
-
Examples: "cloud costs", "API rate limiting", "
|
|
701
|
+
Examples: "cloud costs", "API rate limiting", "team goals"
|
|
707
702
|
limit: Maximum results (default: 5)
|
|
708
|
-
namespace: Filter by scope (None = all, "global", "user", or custom)
|
|
709
703
|
|
|
710
704
|
Returns:
|
|
711
705
|
List of relevant learnings, or message if none found.
|
|
@@ -893,7 +887,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
893
887
|
log_warning("LearnedKnowledgeStore.save: no knowledge base configured")
|
|
894
888
|
return False
|
|
895
889
|
|
|
896
|
-
effective_namespace = namespace or
|
|
890
|
+
effective_namespace = namespace or self.config.namespace
|
|
897
891
|
|
|
898
892
|
# Validate "user" namespace has user_id
|
|
899
893
|
if effective_namespace == "user" and not user_id:
|
|
@@ -963,7 +957,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
963
957
|
log_warning("LearnedKnowledgeStore.asave: no knowledge base configured")
|
|
964
958
|
return False
|
|
965
959
|
|
|
966
|
-
effective_namespace = namespace or
|
|
960
|
+
effective_namespace = namespace or self.config.namespace
|
|
967
961
|
|
|
968
962
|
# Validate "user" namespace has user_id
|
|
969
963
|
if effective_namespace == "user" and not user_id:
|
|
@@ -988,7 +982,7 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
988
982
|
learning_obj = self.schema(**learning_data)
|
|
989
983
|
text_content = self._to_text_content(learning=learning_obj)
|
|
990
984
|
|
|
991
|
-
# Build metadata for filtering
|
|
985
|
+
# Build metadata for filtering
|
|
992
986
|
# Metadata must be passed separately to insert for filters to work
|
|
993
987
|
filter_metadata: dict[str, Any] = {
|
|
994
988
|
"namespace": effective_namespace,
|
|
@@ -1181,49 +1175,48 @@ class LearnedKnowledgeStore(LearningStore):
|
|
|
1181
1175
|
from agno.models.message import Message
|
|
1182
1176
|
|
|
1183
1177
|
system_prompt = dedent("""\
|
|
1184
|
-
You are a Learning Extractor. Your job is to identify
|
|
1185
|
-
from conversations
|
|
1178
|
+
You are a Learning Extractor. Your job is to identify knowledge worth preserving
|
|
1179
|
+
from conversations for future use.
|
|
1180
|
+
|
|
1181
|
+
## What to Save
|
|
1186
1182
|
|
|
1187
|
-
|
|
1183
|
+
**1. Discovered Insights** - Knowledge that emerged through the conversation:
|
|
1184
|
+
- Non-obvious (required reasoning or investigation)
|
|
1185
|
+
- Reusable (applies to a category of problems)
|
|
1186
|
+
- Actionable (specific enough to apply directly)
|
|
1187
|
+
- Durable (won't become outdated quickly)
|
|
1188
1188
|
|
|
1189
|
-
|
|
1190
|
-
-
|
|
1191
|
-
-
|
|
1192
|
-
-
|
|
1193
|
-
-
|
|
1194
|
-
- **Durable**: It won't become outdated quickly
|
|
1189
|
+
**2. Organizational Context** - Explicit directives shared by the user:
|
|
1190
|
+
- Explicit save requests: "remember that...", "note that...", "keep in mind..."
|
|
1191
|
+
- Team/org goals: "we're trying to...", "our goal is...", "our priority is..."
|
|
1192
|
+
- Constraints: "we can't use...", "we need to avoid..."
|
|
1193
|
+
- Policies: "our policy is...", "we always...", "we never..."
|
|
1195
1194
|
|
|
1196
1195
|
## What NOT to Save
|
|
1197
1196
|
|
|
1198
|
-
-
|
|
1199
|
-
-
|
|
1200
|
-
-
|
|
1201
|
-
-
|
|
1202
|
-
-
|
|
1203
|
-
-
|
|
1197
|
+
- Raw facts (use search for retrieval)
|
|
1198
|
+
- Individual user preferences (belongs in user memory)
|
|
1199
|
+
- Common knowledge (everyone knows this)
|
|
1200
|
+
- One-off answers (not generalizable)
|
|
1201
|
+
- Summaries without insight
|
|
1202
|
+
- Uncertain conclusions
|
|
1204
1203
|
|
|
1205
|
-
## Examples
|
|
1204
|
+
## Examples
|
|
1206
1205
|
|
|
1207
|
-
|
|
1206
|
+
Good - Discovered insight:
|
|
1208
1207
|
> **Title:** Debugging intermittent PostgreSQL connection timeouts
|
|
1209
|
-
> **Learning:**
|
|
1210
|
-
>
|
|
1211
|
-
> long-running transactions that hold connections.
|
|
1212
|
-
> **Context:** Diagnosing database connectivity issues in production
|
|
1208
|
+
> **Learning:** Check for connection pool exhaustion before investigating network issues.
|
|
1209
|
+
> **Context:** Diagnosing database connectivity issues
|
|
1213
1210
|
|
|
1214
|
-
|
|
1215
|
-
> **Title:**
|
|
1216
|
-
> **Learning:**
|
|
1217
|
-
>
|
|
1218
|
-
> data model unchanged - you get audit without the full event sourcing overhead.
|
|
1219
|
-
> **Context:** Evaluating architecture patterns when audit trails are required
|
|
1211
|
+
Good - Organizational context:
|
|
1212
|
+
> **Title:** Team goal: reduce cloud egress costs
|
|
1213
|
+
> **Learning:** Factor egress costs into architecture decisions.
|
|
1214
|
+
> **Context:** Infrastructure and vendor decisions
|
|
1220
1215
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
- "
|
|
1224
|
-
- "
|
|
1225
|
-
- "We discussed three options for the database" (summary, no insight)
|
|
1226
|
-
- "Always write tests" (too vague to be actionable)
|
|
1216
|
+
Bad (don't save):
|
|
1217
|
+
- "The error was a typo on line 42" (one-off)
|
|
1218
|
+
- "React is popular" (common knowledge)
|
|
1219
|
+
- "We discussed options" (summary, no insight)
|
|
1227
1220
|
|
|
1228
1221
|
""")
|
|
1229
1222
|
|
|
@@ -1239,14 +1232,14 @@ These insights are already in the knowledge base. Do not save variations of thes
|
|
|
1239
1232
|
system_prompt += dedent("""\
|
|
1240
1233
|
## Your Task
|
|
1241
1234
|
|
|
1242
|
-
Review the conversation below.
|
|
1243
|
-
|
|
1235
|
+
Review the conversation below. Save anything that fits the criteria above:
|
|
1236
|
+
- Discovered insights worth preserving
|
|
1237
|
+
- Organizational context the user shared (goals, constraints, policies)
|
|
1244
1238
|
|
|
1245
1239
|
**Important:**
|
|
1246
|
-
- Most conversations will NOT produce a learning. That's expected
|
|
1240
|
+
- Most conversations will NOT produce a learning. That's expected.
|
|
1247
1241
|
- When in doubt, don't save. Quality over quantity.
|
|
1248
|
-
-
|
|
1249
|
-
- It's perfectly fine to do nothing if there's nothing worth saving.\
|
|
1242
|
+
- It's fine to do nothing if there's nothing worth saving.\
|
|
1250
1243
|
""")
|
|
1251
1244
|
|
|
1252
1245
|
return [
|
|
@@ -1262,7 +1255,7 @@ These insights are already in the knowledge base. Do not save variations of thes
|
|
|
1262
1255
|
namespace: Optional[str] = None,
|
|
1263
1256
|
) -> List[Callable]:
|
|
1264
1257
|
"""Get sync extraction tools."""
|
|
1265
|
-
effective_namespace = namespace or
|
|
1258
|
+
effective_namespace = namespace or self.config.namespace
|
|
1266
1259
|
|
|
1267
1260
|
def save_learning(
|
|
1268
1261
|
title: str,
|
|
@@ -1270,18 +1263,12 @@ These insights are already in the knowledge base. Do not save variations of thes
|
|
|
1270
1263
|
context: Optional[str] = None,
|
|
1271
1264
|
tags: Optional[List[str]] = None,
|
|
1272
1265
|
) -> str:
|
|
1273
|
-
"""Save a
|
|
1274
|
-
|
|
1275
|
-
Only call this if you've identified something that:
|
|
1276
|
-
- Required investigation or reasoning to discover
|
|
1277
|
-
- Would help with similar future tasks
|
|
1278
|
-
- Isn't already captured in existing learnings
|
|
1279
|
-
- Is specific and actionable enough to apply directly
|
|
1266
|
+
"""Save a reusable insight or organizational context.
|
|
1280
1267
|
|
|
1281
1268
|
Args:
|
|
1282
|
-
title: Concise, searchable title
|
|
1283
|
-
learning: The insight
|
|
1284
|
-
context: When/where this applies
|
|
1269
|
+
title: Concise, searchable title.
|
|
1270
|
+
learning: The insight or context - specific and actionable.
|
|
1271
|
+
context: When/where this applies.
|
|
1285
1272
|
tags: Categories for organization.
|
|
1286
1273
|
|
|
1287
1274
|
Returns:
|
|
@@ -1309,7 +1296,7 @@ These insights are already in the knowledge base. Do not save variations of thes
|
|
|
1309
1296
|
namespace: Optional[str] = None,
|
|
1310
1297
|
) -> List[Callable]:
|
|
1311
1298
|
"""Get async extraction tools."""
|
|
1312
|
-
effective_namespace = namespace or
|
|
1299
|
+
effective_namespace = namespace or self.config.namespace
|
|
1313
1300
|
|
|
1314
1301
|
async def save_learning(
|
|
1315
1302
|
title: str,
|
|
@@ -1317,18 +1304,12 @@ These insights are already in the knowledge base. Do not save variations of thes
|
|
|
1317
1304
|
context: Optional[str] = None,
|
|
1318
1305
|
tags: Optional[List[str]] = None,
|
|
1319
1306
|
) -> str:
|
|
1320
|
-
"""Save a
|
|
1321
|
-
|
|
1322
|
-
Only call this if you've identified something that:
|
|
1323
|
-
- Required investigation or reasoning to discover
|
|
1324
|
-
- Would help with similar future tasks
|
|
1325
|
-
- Isn't already captured in existing learnings
|
|
1326
|
-
- Is specific and actionable enough to apply directly
|
|
1307
|
+
"""Save a reusable insight or organizational context.
|
|
1327
1308
|
|
|
1328
1309
|
Args:
|
|
1329
|
-
title: Concise, searchable title
|
|
1330
|
-
learning: The insight
|
|
1331
|
-
context: When/where this applies
|
|
1310
|
+
title: Concise, searchable title.
|
|
1311
|
+
learning: The insight or context - specific and actionable.
|
|
1312
|
+
context: When/where this applies.
|
|
1332
1313
|
tags: Categories for organization.
|
|
1333
1314
|
|
|
1334
1315
|
Returns:
|
|
@@ -1399,10 +1380,6 @@ These insights are already in the knowledge base. Do not save variations of thes
|
|
|
1399
1380
|
# Private Helpers
|
|
1400
1381
|
# =========================================================================
|
|
1401
1382
|
|
|
1402
|
-
def _build_learning_id(self, title: str) -> str:
|
|
1403
|
-
"""Build a unique learning ID from title."""
|
|
1404
|
-
return f"learning_{title.lower().replace(' ', '_')[:32]}"
|
|
1405
|
-
|
|
1406
1383
|
def _parse_result(self, result: Any) -> Optional[Any]:
|
|
1407
1384
|
"""Parse a search result into a learning object."""
|
|
1408
1385
|
import json
|
|
@@ -57,7 +57,7 @@ def print_response_stream(
|
|
|
57
57
|
accumulated_tool_calls: List = []
|
|
58
58
|
|
|
59
59
|
with Live(console=console) as live_log:
|
|
60
|
-
status = Status("
|
|
60
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
61
61
|
live_log.update(status)
|
|
62
62
|
response_timer = Timer()
|
|
63
63
|
response_timer.start()
|
|
@@ -224,7 +224,7 @@ def print_response_stream(
|
|
|
224
224
|
|
|
225
225
|
response_timer.stop()
|
|
226
226
|
|
|
227
|
-
# Final update to remove the "
|
|
227
|
+
# Final update to remove the "Working..." status
|
|
228
228
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
229
229
|
live_log.update(Group(*panels))
|
|
230
230
|
|
|
@@ -262,7 +262,7 @@ async def aprint_response_stream(
|
|
|
262
262
|
accumulated_tool_calls: List = []
|
|
263
263
|
|
|
264
264
|
with Live(console=console) as live_log:
|
|
265
|
-
status = Status("
|
|
265
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
266
266
|
live_log.update(status)
|
|
267
267
|
response_timer = Timer()
|
|
268
268
|
response_timer.start()
|
|
@@ -429,7 +429,7 @@ async def aprint_response_stream(
|
|
|
429
429
|
|
|
430
430
|
response_timer.stop()
|
|
431
431
|
|
|
432
|
-
# Final update to remove the "
|
|
432
|
+
# Final update to remove the "Working..." status
|
|
433
433
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
434
434
|
live_log.update(Group(*panels))
|
|
435
435
|
|
|
@@ -571,7 +571,7 @@ def print_response(
|
|
|
571
571
|
**kwargs: Any,
|
|
572
572
|
):
|
|
573
573
|
with Live(console=console) as live_log:
|
|
574
|
-
status = Status("
|
|
574
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
575
575
|
live_log.update(status)
|
|
576
576
|
response_timer = Timer()
|
|
577
577
|
response_timer.start()
|
|
@@ -659,7 +659,7 @@ def print_response(
|
|
|
659
659
|
live_log.update(Group(*panels))
|
|
660
660
|
agent.session_summary_manager.summaries_updated = False
|
|
661
661
|
|
|
662
|
-
# Final update to remove the "
|
|
662
|
+
# Final update to remove the "Working..." status
|
|
663
663
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
664
664
|
live_log.update(Group(*panels))
|
|
665
665
|
|
|
@@ -691,7 +691,7 @@ async def aprint_response(
|
|
|
691
691
|
**kwargs: Any,
|
|
692
692
|
):
|
|
693
693
|
with Live(console=console) as live_log:
|
|
694
|
-
status = Status("
|
|
694
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
695
695
|
live_log.update(status)
|
|
696
696
|
response_timer = Timer()
|
|
697
697
|
response_timer.start()
|
|
@@ -779,7 +779,7 @@ async def aprint_response(
|
|
|
779
779
|
panels.append(summary_panel)
|
|
780
780
|
live_log.update(Group(*panels))
|
|
781
781
|
|
|
782
|
-
# Final update to remove the "
|
|
782
|
+
# Final update to remove the "Working..." status
|
|
783
783
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
784
784
|
live_log.update(Group(*panels))
|
|
785
785
|
|
|
@@ -61,7 +61,7 @@ def print_response(
|
|
|
61
61
|
tags_to_include_in_markdown = {"think", "thinking"}
|
|
62
62
|
|
|
63
63
|
with Live(console=console) as live_console:
|
|
64
|
-
status = Status("
|
|
64
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
65
65
|
live_console.update(status)
|
|
66
66
|
|
|
67
67
|
response_timer = Timer()
|
|
@@ -349,7 +349,7 @@ def print_response(
|
|
|
349
349
|
panels.append(summary_panel)
|
|
350
350
|
team.session_summary_manager.summaries_updated = False
|
|
351
351
|
|
|
352
|
-
# Final update to remove the "
|
|
352
|
+
# Final update to remove the "Working..." status
|
|
353
353
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
354
354
|
live_console.update(Group(*panels))
|
|
355
355
|
|
|
@@ -410,7 +410,7 @@ def print_response_stream(
|
|
|
410
410
|
processed_tool_calls = set()
|
|
411
411
|
|
|
412
412
|
with Live(console=console) as live_console:
|
|
413
|
-
status = Status("
|
|
413
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
414
414
|
live_console.update(status)
|
|
415
415
|
response_timer = Timer()
|
|
416
416
|
response_timer.start()
|
|
@@ -735,7 +735,7 @@ def print_response_stream(
|
|
|
735
735
|
live_console.update(Group(*panels))
|
|
736
736
|
team.session_summary_manager.summaries_updated = False
|
|
737
737
|
|
|
738
|
-
# Final update to remove the "
|
|
738
|
+
# Final update to remove the "Working..." status
|
|
739
739
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
740
740
|
|
|
741
741
|
if markdown:
|
|
@@ -992,7 +992,7 @@ async def aprint_response(
|
|
|
992
992
|
tags_to_include_in_markdown = {"think", "thinking"}
|
|
993
993
|
|
|
994
994
|
with Live(console=console) as live_console:
|
|
995
|
-
status = Status("
|
|
995
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
996
996
|
live_console.update(status)
|
|
997
997
|
|
|
998
998
|
response_timer = Timer()
|
|
@@ -1278,7 +1278,7 @@ async def aprint_response(
|
|
|
1278
1278
|
panels.append(summary_panel)
|
|
1279
1279
|
team.session_summary_manager.summaries_updated = False
|
|
1280
1280
|
|
|
1281
|
-
# Final update to remove the "
|
|
1281
|
+
# Final update to remove the "Working..." status
|
|
1282
1282
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
1283
1283
|
live_console.update(Group(*panels))
|
|
1284
1284
|
|
|
@@ -1340,7 +1340,7 @@ async def aprint_response_stream(
|
|
|
1340
1340
|
final_panels = [] # type: ignore
|
|
1341
1341
|
|
|
1342
1342
|
with Live(console=console) as live_console:
|
|
1343
|
-
status = Status("
|
|
1343
|
+
status = Status("Working...", spinner="aesthetic", speed=0.4, refresh_per_second=10)
|
|
1344
1344
|
live_console.update(status)
|
|
1345
1345
|
response_timer = Timer()
|
|
1346
1346
|
response_timer.start()
|
|
@@ -1663,7 +1663,7 @@ async def aprint_response_stream(
|
|
|
1663
1663
|
live_console.update(Group(*panels))
|
|
1664
1664
|
team.session_summary_manager.summaries_updated = False
|
|
1665
1665
|
|
|
1666
|
-
# Final update to remove the "
|
|
1666
|
+
# Final update to remove the "Working..." status
|
|
1667
1667
|
panels = [p for p in panels if not isinstance(p, Status)]
|
|
1668
1668
|
|
|
1669
1669
|
if markdown:
|