@elizaos/python 2.0.0-alpha.10
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.
- package/LICENSE +26 -0
- package/README.md +239 -0
- package/elizaos/__init__.py +280 -0
- package/elizaos/action_docs.py +149 -0
- package/elizaos/advanced_capabilities/__init__.py +85 -0
- package/elizaos/advanced_capabilities/actions/__init__.py +54 -0
- package/elizaos/advanced_capabilities/actions/add_contact.py +139 -0
- package/elizaos/advanced_capabilities/actions/follow_room.py +151 -0
- package/elizaos/advanced_capabilities/actions/image_generation.py +148 -0
- package/elizaos/advanced_capabilities/actions/mute_room.py +164 -0
- package/elizaos/advanced_capabilities/actions/remove_contact.py +145 -0
- package/elizaos/advanced_capabilities/actions/roles.py +207 -0
- package/elizaos/advanced_capabilities/actions/schedule_follow_up.py +154 -0
- package/elizaos/advanced_capabilities/actions/search_contacts.py +145 -0
- package/elizaos/advanced_capabilities/actions/send_message.py +187 -0
- package/elizaos/advanced_capabilities/actions/settings.py +151 -0
- package/elizaos/advanced_capabilities/actions/unfollow_room.py +164 -0
- package/elizaos/advanced_capabilities/actions/unmute_room.py +164 -0
- package/elizaos/advanced_capabilities/actions/update_contact.py +164 -0
- package/elizaos/advanced_capabilities/actions/update_entity.py +161 -0
- package/elizaos/advanced_capabilities/evaluators/__init__.py +18 -0
- package/elizaos/advanced_capabilities/evaluators/reflection.py +134 -0
- package/elizaos/advanced_capabilities/evaluators/relationship_extraction.py +203 -0
- package/elizaos/advanced_capabilities/providers/__init__.py +36 -0
- package/elizaos/advanced_capabilities/providers/agent_settings.py +60 -0
- package/elizaos/advanced_capabilities/providers/contacts.py +77 -0
- package/elizaos/advanced_capabilities/providers/facts.py +82 -0
- package/elizaos/advanced_capabilities/providers/follow_ups.py +113 -0
- package/elizaos/advanced_capabilities/providers/knowledge.py +83 -0
- package/elizaos/advanced_capabilities/providers/relationships.py +112 -0
- package/elizaos/advanced_capabilities/providers/roles.py +97 -0
- package/elizaos/advanced_capabilities/providers/settings.py +51 -0
- package/elizaos/advanced_capabilities/services/__init__.py +18 -0
- package/elizaos/advanced_capabilities/services/follow_up.py +138 -0
- package/elizaos/advanced_capabilities/services/rolodex.py +244 -0
- package/elizaos/advanced_memory/__init__.py +3 -0
- package/elizaos/advanced_memory/evaluators.py +97 -0
- package/elizaos/advanced_memory/memory_service.py +556 -0
- package/elizaos/advanced_memory/plugin.py +30 -0
- package/elizaos/advanced_memory/prompts.py +12 -0
- package/elizaos/advanced_memory/providers.py +90 -0
- package/elizaos/advanced_memory/types.py +65 -0
- package/elizaos/advanced_planning/__init__.py +10 -0
- package/elizaos/advanced_planning/actions.py +145 -0
- package/elizaos/advanced_planning/message_classifier.py +127 -0
- package/elizaos/advanced_planning/planning_service.py +712 -0
- package/elizaos/advanced_planning/plugin.py +40 -0
- package/elizaos/advanced_planning/prompts.py +4 -0
- package/elizaos/basic_capabilities/__init__.py +66 -0
- package/elizaos/basic_capabilities/actions/__init__.py +24 -0
- package/elizaos/basic_capabilities/actions/choice.py +140 -0
- package/elizaos/basic_capabilities/actions/ignore.py +66 -0
- package/elizaos/basic_capabilities/actions/none.py +56 -0
- package/elizaos/basic_capabilities/actions/reply.py +120 -0
- package/elizaos/basic_capabilities/providers/__init__.py +54 -0
- package/elizaos/basic_capabilities/providers/action_state.py +113 -0
- package/elizaos/basic_capabilities/providers/actions.py +263 -0
- package/elizaos/basic_capabilities/providers/attachments.py +76 -0
- package/elizaos/basic_capabilities/providers/capabilities.py +62 -0
- package/elizaos/basic_capabilities/providers/character.py +113 -0
- package/elizaos/basic_capabilities/providers/choice.py +73 -0
- package/elizaos/basic_capabilities/providers/context_bench.py +44 -0
- package/elizaos/basic_capabilities/providers/current_time.py +58 -0
- package/elizaos/basic_capabilities/providers/entities.py +99 -0
- package/elizaos/basic_capabilities/providers/evaluators.py +54 -0
- package/elizaos/basic_capabilities/providers/providers_list.py +55 -0
- package/elizaos/basic_capabilities/providers/recent_messages.py +85 -0
- package/elizaos/basic_capabilities/providers/time.py +45 -0
- package/elizaos/basic_capabilities/providers/world.py +93 -0
- package/elizaos/basic_capabilities/services/__init__.py +18 -0
- package/elizaos/basic_capabilities/services/embedding.py +122 -0
- package/elizaos/basic_capabilities/services/task.py +178 -0
- package/elizaos/bootstrap/__init__.py +12 -0
- package/elizaos/bootstrap/actions/__init__.py +68 -0
- package/elizaos/bootstrap/actions/add_contact.py +149 -0
- package/elizaos/bootstrap/actions/choice.py +147 -0
- package/elizaos/bootstrap/actions/follow_room.py +151 -0
- package/elizaos/bootstrap/actions/ignore.py +80 -0
- package/elizaos/bootstrap/actions/image_generation.py +135 -0
- package/elizaos/bootstrap/actions/mute_room.py +151 -0
- package/elizaos/bootstrap/actions/none.py +71 -0
- package/elizaos/bootstrap/actions/remove_contact.py +159 -0
- package/elizaos/bootstrap/actions/reply.py +140 -0
- package/elizaos/bootstrap/actions/roles.py +193 -0
- package/elizaos/bootstrap/actions/schedule_follow_up.py +164 -0
- package/elizaos/bootstrap/actions/search_contacts.py +159 -0
- package/elizaos/bootstrap/actions/send_message.py +173 -0
- package/elizaos/bootstrap/actions/settings.py +165 -0
- package/elizaos/bootstrap/actions/unfollow_room.py +151 -0
- package/elizaos/bootstrap/actions/unmute_room.py +151 -0
- package/elizaos/bootstrap/actions/update_contact.py +178 -0
- package/elizaos/bootstrap/actions/update_entity.py +175 -0
- package/elizaos/bootstrap/autonomy/__init__.py +18 -0
- package/elizaos/bootstrap/autonomy/action.py +197 -0
- package/elizaos/bootstrap/autonomy/providers.py +165 -0
- package/elizaos/bootstrap/autonomy/routes.py +171 -0
- package/elizaos/bootstrap/autonomy/service.py +562 -0
- package/elizaos/bootstrap/autonomy/types.py +18 -0
- package/elizaos/bootstrap/evaluators/__init__.py +19 -0
- package/elizaos/bootstrap/evaluators/reflection.py +118 -0
- package/elizaos/bootstrap/evaluators/relationship_extraction.py +192 -0
- package/elizaos/bootstrap/plugin.py +140 -0
- package/elizaos/bootstrap/providers/__init__.py +80 -0
- package/elizaos/bootstrap/providers/action_state.py +71 -0
- package/elizaos/bootstrap/providers/actions.py +256 -0
- package/elizaos/bootstrap/providers/agent_settings.py +63 -0
- package/elizaos/bootstrap/providers/attachments.py +76 -0
- package/elizaos/bootstrap/providers/capabilities.py +66 -0
- package/elizaos/bootstrap/providers/character.py +128 -0
- package/elizaos/bootstrap/providers/choice.py +77 -0
- package/elizaos/bootstrap/providers/contacts.py +78 -0
- package/elizaos/bootstrap/providers/context_bench.py +49 -0
- package/elizaos/bootstrap/providers/current_time.py +56 -0
- package/elizaos/bootstrap/providers/entities.py +99 -0
- package/elizaos/bootstrap/providers/evaluators.py +58 -0
- package/elizaos/bootstrap/providers/facts.py +86 -0
- package/elizaos/bootstrap/providers/follow_ups.py +116 -0
- package/elizaos/bootstrap/providers/knowledge.py +73 -0
- package/elizaos/bootstrap/providers/providers_list.py +59 -0
- package/elizaos/bootstrap/providers/recent_messages.py +85 -0
- package/elizaos/bootstrap/providers/relationships.py +106 -0
- package/elizaos/bootstrap/providers/roles.py +95 -0
- package/elizaos/bootstrap/providers/settings.py +55 -0
- package/elizaos/bootstrap/providers/time.py +45 -0
- package/elizaos/bootstrap/providers/world.py +97 -0
- package/elizaos/bootstrap/services/__init__.py +26 -0
- package/elizaos/bootstrap/services/embedding.py +122 -0
- package/elizaos/bootstrap/services/follow_up.py +138 -0
- package/elizaos/bootstrap/services/rolodex.py +244 -0
- package/elizaos/bootstrap/services/task.py +585 -0
- package/elizaos/bootstrap/types.py +54 -0
- package/elizaos/bootstrap/utils/__init__.py +7 -0
- package/elizaos/bootstrap/utils/xml.py +69 -0
- package/elizaos/character.py +149 -0
- package/elizaos/logger.py +179 -0
- package/elizaos/media/__init__.py +45 -0
- package/elizaos/media/mime.py +315 -0
- package/elizaos/media/search.py +161 -0
- package/elizaos/media/tests/__init__.py +1 -0
- package/elizaos/media/tests/test_mime.py +117 -0
- package/elizaos/media/tests/test_search.py +156 -0
- package/elizaos/plugin.py +191 -0
- package/elizaos/prompts.py +1071 -0
- package/elizaos/py.typed +0 -0
- package/elizaos/runtime.py +2572 -0
- package/elizaos/services/__init__.py +49 -0
- package/elizaos/services/hook_service.py +511 -0
- package/elizaos/services/message_service.py +1248 -0
- package/elizaos/settings.py +182 -0
- package/elizaos/streaming_context.py +159 -0
- package/elizaos/trajectory_context.py +18 -0
- package/elizaos/types/__init__.py +512 -0
- package/elizaos/types/agent.py +31 -0
- package/elizaos/types/components.py +208 -0
- package/elizaos/types/database.py +64 -0
- package/elizaos/types/environment.py +46 -0
- package/elizaos/types/events.py +47 -0
- package/elizaos/types/memory.py +45 -0
- package/elizaos/types/model.py +393 -0
- package/elizaos/types/plugin.py +188 -0
- package/elizaos/types/primitives.py +100 -0
- package/elizaos/types/runtime.py +460 -0
- package/elizaos/types/service.py +113 -0
- package/elizaos/types/service_interfaces.py +244 -0
- package/elizaos/types/state.py +188 -0
- package/elizaos/types/task.py +29 -0
- package/elizaos/utils/__init__.py +108 -0
- package/elizaos/utils/spec_examples.py +48 -0
- package/elizaos/utils/streaming.py +426 -0
- package/elizaos_atropos_shared/__init__.py +1 -0
- package/elizaos_atropos_shared/canonical_eliza.py +282 -0
- package/package.json +19 -0
- package/pyproject.toml +143 -0
- package/requirements-dev.in +11 -0
- package/requirements-dev.lock +134 -0
- package/requirements.in +9 -0
- package/requirements.lock +64 -0
- package/tests/__init__.py +0 -0
- package/tests/test_action_parameters.py +154 -0
- package/tests/test_actions_provider_examples.py +39 -0
- package/tests/test_advanced_memory_behavior.py +96 -0
- package/tests/test_advanced_memory_flag.py +30 -0
- package/tests/test_advanced_planning_behavior.py +225 -0
- package/tests/test_advanced_planning_flag.py +26 -0
- package/tests/test_autonomy.py +445 -0
- package/tests/test_bootstrap_initialize.py +37 -0
- package/tests/test_character.py +163 -0
- package/tests/test_character_provider.py +231 -0
- package/tests/test_dynamic_prompt_exec.py +561 -0
- package/tests/test_logger_redaction.py +43 -0
- package/tests/test_plugin.py +117 -0
- package/tests/test_runtime.py +422 -0
- package/tests/test_salt_production_enforcement.py +22 -0
- package/tests/test_settings_crypto.py +118 -0
- package/tests/test_streaming.py +295 -0
- package/tests/test_types.py +221 -0
- package/tests/test_uuid_parity.py +46 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from elizaos.types import Provider, ProviderResult
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def long_term_memory_get(runtime, message, _state=None) -> ProviderResult:
|
|
7
|
+
svc = runtime.get_service("memory")
|
|
8
|
+
if svc is None:
|
|
9
|
+
return ProviderResult(text="", values={"longTermMemories": ""}, data={"memoryCount": 0})
|
|
10
|
+
|
|
11
|
+
entity_id = message.entity_id
|
|
12
|
+
if entity_id == runtime.agent_id:
|
|
13
|
+
return ProviderResult(text="", values={"longTermMemories": ""}, data={"memoryCount": 0})
|
|
14
|
+
|
|
15
|
+
memories = await svc.get_long_term_memories(entity_id, None, 25)
|
|
16
|
+
if not memories:
|
|
17
|
+
return ProviderResult(text="", values={"longTermMemories": ""}, data={"memoryCount": 0})
|
|
18
|
+
|
|
19
|
+
formatted = await svc.get_formatted_long_term_memories(entity_id)
|
|
20
|
+
text = f"# What I Know About You\n\n{formatted}"
|
|
21
|
+
|
|
22
|
+
category_counts: dict[str, int] = {}
|
|
23
|
+
for m in memories:
|
|
24
|
+
category_counts[m.category.value] = category_counts.get(m.category.value, 0) + 1
|
|
25
|
+
category_list = ", ".join(f"{k}: {v}" for k, v in category_counts.items())
|
|
26
|
+
|
|
27
|
+
return ProviderResult(
|
|
28
|
+
text=text,
|
|
29
|
+
values={"longTermMemories": text, "memoryCategories": category_list},
|
|
30
|
+
data={"memoryCount": len(memories), "categories": category_list},
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def context_summary_get(runtime, message, _state=None) -> ProviderResult:
|
|
35
|
+
svc = runtime.get_service("memory")
|
|
36
|
+
if svc is None:
|
|
37
|
+
return ProviderResult(
|
|
38
|
+
text="",
|
|
39
|
+
values={"sessionSummaries": "", "sessionSummariesWithTopics": ""},
|
|
40
|
+
data={},
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
current = await svc.get_current_session_summary(message.room_id)
|
|
44
|
+
if current is None:
|
|
45
|
+
return ProviderResult(
|
|
46
|
+
text="",
|
|
47
|
+
values={"sessionSummaries": "", "sessionSummariesWithTopics": ""},
|
|
48
|
+
data={},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
summary_only = (
|
|
52
|
+
f"**Previous Conversation** ({current.message_count} messages)\n{current.summary}"
|
|
53
|
+
)
|
|
54
|
+
summary_with_topics = (
|
|
55
|
+
summary_only + f"\n*Topics: {', '.join(current.topics)}*"
|
|
56
|
+
if current.topics
|
|
57
|
+
else summary_only
|
|
58
|
+
)
|
|
59
|
+
session_summaries = f"# Conversation Summary\n\n{summary_only}" if summary_only else ""
|
|
60
|
+
session_summaries_with_topics = (
|
|
61
|
+
f"# Conversation Summary\n\n{summary_with_topics}" if summary_with_topics else ""
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return ProviderResult(
|
|
65
|
+
text=session_summaries_with_topics,
|
|
66
|
+
values={
|
|
67
|
+
"sessionSummaries": session_summaries,
|
|
68
|
+
"sessionSummariesWithTopics": session_summaries_with_topics,
|
|
69
|
+
},
|
|
70
|
+
data={
|
|
71
|
+
"summaryText": current.summary,
|
|
72
|
+
"messageCount": current.message_count,
|
|
73
|
+
"topics": ", ".join(current.topics),
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
long_term_memory_provider = Provider(
|
|
79
|
+
name="LONG_TERM_MEMORY",
|
|
80
|
+
description="Persistent facts and preferences about the user",
|
|
81
|
+
position=50,
|
|
82
|
+
get=long_term_memory_get,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
context_summary_provider = Provider(
|
|
86
|
+
name="SUMMARIZED_CONTEXT",
|
|
87
|
+
description="Provides summarized context from previous conversations",
|
|
88
|
+
position=96,
|
|
89
|
+
get=context_summary_get,
|
|
90
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LongTermMemoryCategory(str, Enum):
|
|
9
|
+
EPISODIC = "episodic"
|
|
10
|
+
SEMANTIC = "semantic"
|
|
11
|
+
PROCEDURAL = "procedural"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class MemoryConfig:
|
|
16
|
+
short_term_summarization_threshold: int = 16
|
|
17
|
+
short_term_retain_recent: int = 6
|
|
18
|
+
short_term_summarization_interval: int = 10
|
|
19
|
+
long_term_extraction_enabled: bool = True
|
|
20
|
+
long_term_vector_search_enabled: bool = False
|
|
21
|
+
long_term_confidence_threshold: float = 0.85
|
|
22
|
+
long_term_extraction_threshold: int = 30
|
|
23
|
+
long_term_extraction_interval: int = 10
|
|
24
|
+
summary_model_type: str = "TEXT_LARGE"
|
|
25
|
+
summary_max_tokens: int = 2500
|
|
26
|
+
summary_max_new_messages: int = 20
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class LongTermMemory:
|
|
31
|
+
id: UUID
|
|
32
|
+
agent_id: UUID
|
|
33
|
+
entity_id: UUID
|
|
34
|
+
category: LongTermMemoryCategory
|
|
35
|
+
content: str
|
|
36
|
+
confidence: float = 1.0
|
|
37
|
+
source: str | None = None
|
|
38
|
+
metadata: dict[str, object] = field(default_factory=dict)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class SessionSummary:
|
|
43
|
+
id: UUID
|
|
44
|
+
agent_id: UUID
|
|
45
|
+
room_id: UUID
|
|
46
|
+
entity_id: UUID | None
|
|
47
|
+
summary: str
|
|
48
|
+
message_count: int
|
|
49
|
+
last_message_offset: int
|
|
50
|
+
topics: list[str] = field(default_factory=list)
|
|
51
|
+
metadata: dict[str, object] = field(default_factory=dict)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@dataclass
|
|
55
|
+
class SummaryResult:
|
|
56
|
+
summary: str
|
|
57
|
+
topics: list[str]
|
|
58
|
+
key_points: list[str]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class MemoryExtraction:
|
|
63
|
+
category: LongTermMemoryCategory
|
|
64
|
+
content: str
|
|
65
|
+
confidence: float
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Built-in advanced planning (gated by Character.advancedPlanning)."""
|
|
2
|
+
|
|
3
|
+
from .planning_service import PlanningService
|
|
4
|
+
from .plugin import advanced_planning_plugin, create_advanced_planning_plugin
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"advanced_planning_plugin",
|
|
8
|
+
"create_advanced_planning_plugin",
|
|
9
|
+
"PlanningService",
|
|
10
|
+
]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import time
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from elizaos.types import Action, ActionResult
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def _always_validate(_runtime, _message, _state=None) -> bool:
|
|
11
|
+
return True
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def analyze_input_handler(
|
|
15
|
+
_runtime, message, _state=None, options=None, _callback=None, _responses=None
|
|
16
|
+
):
|
|
17
|
+
abort_signal = getattr(options, "abort_signal", None)
|
|
18
|
+
if abort_signal is not None and getattr(abort_signal, "aborted", False):
|
|
19
|
+
raise RuntimeError("Analysis aborted")
|
|
20
|
+
|
|
21
|
+
text = message.content.text or ""
|
|
22
|
+
words = text.split() if text.strip() else []
|
|
23
|
+
sentiment = "neutral"
|
|
24
|
+
lower = text.lower()
|
|
25
|
+
if any(w in lower for w in ["urgent", "emergency", "critical"]):
|
|
26
|
+
sentiment = "urgent"
|
|
27
|
+
elif "good" in lower:
|
|
28
|
+
sentiment = "positive"
|
|
29
|
+
elif "bad" in lower:
|
|
30
|
+
sentiment = "negative"
|
|
31
|
+
|
|
32
|
+
return ActionResult(
|
|
33
|
+
success=True,
|
|
34
|
+
text=f"Analyzed {len(words)} words with {sentiment} sentiment",
|
|
35
|
+
data={
|
|
36
|
+
"wordCount": len(words),
|
|
37
|
+
"hasNumbers": bool(re.search(r"\d", text)),
|
|
38
|
+
"sentiment": sentiment,
|
|
39
|
+
"topics": [w.lower() for w in words if len(w) >= 5],
|
|
40
|
+
"timestamp": int(time.time() * 1000),
|
|
41
|
+
},
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async def process_analysis_handler(
|
|
46
|
+
_runtime, _message, _state=None, options=None, _callback=None, _responses=None
|
|
47
|
+
):
|
|
48
|
+
previous = getattr(options, "previous_results", None) or []
|
|
49
|
+
prev0 = previous[0] if previous else None
|
|
50
|
+
analysis = getattr(prev0, "data", None) or {}
|
|
51
|
+
word_count = int(analysis.get("wordCount") or 0)
|
|
52
|
+
sentiment = str(analysis.get("sentiment") or "neutral")
|
|
53
|
+
|
|
54
|
+
decisions = {
|
|
55
|
+
"needsMoreInfo": word_count < 5,
|
|
56
|
+
"isComplex": word_count > 20,
|
|
57
|
+
"requiresAction": sentiment != "neutral" or word_count > 8,
|
|
58
|
+
"suggestedResponse": (
|
|
59
|
+
"Thank you for the positive feedback!"
|
|
60
|
+
if sentiment == "positive"
|
|
61
|
+
else "I understand your concerns and will help address them."
|
|
62
|
+
if sentiment == "negative"
|
|
63
|
+
else "I can help you with that."
|
|
64
|
+
),
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return ActionResult(
|
|
68
|
+
success=True,
|
|
69
|
+
text=str(decisions["suggestedResponse"]),
|
|
70
|
+
data={
|
|
71
|
+
"analysis": analysis,
|
|
72
|
+
"decisions": decisions,
|
|
73
|
+
"processedAt": int(time.time() * 1000),
|
|
74
|
+
"shouldContinue": not decisions["needsMoreInfo"],
|
|
75
|
+
},
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def execute_final_handler(
|
|
80
|
+
_runtime, _message, _state=None, options=None, callback=None, _responses=None
|
|
81
|
+
):
|
|
82
|
+
previous = getattr(options, "previous_results", None) or []
|
|
83
|
+
decisions = None
|
|
84
|
+
for r in previous:
|
|
85
|
+
data = getattr(r, "data", None) or {}
|
|
86
|
+
if "decisions" in data:
|
|
87
|
+
decisions = data.get("decisions")
|
|
88
|
+
break
|
|
89
|
+
if not isinstance(decisions, dict):
|
|
90
|
+
raise RuntimeError("No processing results available")
|
|
91
|
+
|
|
92
|
+
msg = str(decisions.get("suggestedResponse") or "Done")
|
|
93
|
+
if callback is not None:
|
|
94
|
+
await callback({"text": msg, "source": "chain_example"})
|
|
95
|
+
|
|
96
|
+
return ActionResult(success=True, text=msg, data={"action": "RESPOND", "message": msg})
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
async def create_plan_validate(_runtime, message, _state=None) -> bool:
|
|
100
|
+
text = (message.content.text or "").lower()
|
|
101
|
+
return any(k in text for k in ["plan", "project", "comprehensive", "organize", "strategy"])
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
async def create_plan_handler(
|
|
105
|
+
_runtime, _message, _state=None, _options=None, callback=None, _responses=None
|
|
106
|
+
):
|
|
107
|
+
plan_id = str(uuid4())
|
|
108
|
+
if callback is not None:
|
|
109
|
+
await callback(
|
|
110
|
+
{
|
|
111
|
+
"text": "I've created a comprehensive project plan.",
|
|
112
|
+
"actions": ["CREATE_PLAN"],
|
|
113
|
+
"source": "planning",
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
return ActionResult(success=True, text="Created plan", data={"planId": plan_id})
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
analyze_input_action = Action(
|
|
120
|
+
name="ANALYZE_INPUT",
|
|
121
|
+
description="Analyzes user input and extracts key information",
|
|
122
|
+
validate=_always_validate,
|
|
123
|
+
handler=analyze_input_handler,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
process_analysis_action = Action(
|
|
127
|
+
name="PROCESS_ANALYSIS",
|
|
128
|
+
description="Processes the analysis results and makes decisions",
|
|
129
|
+
validate=_always_validate,
|
|
130
|
+
handler=process_analysis_handler,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
execute_final_action = Action(
|
|
134
|
+
name="EXECUTE_FINAL",
|
|
135
|
+
description="Executes the final action based on processing results",
|
|
136
|
+
validate=_always_validate,
|
|
137
|
+
handler=execute_final_handler,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
create_plan_action = Action(
|
|
141
|
+
name="CREATE_PLAN",
|
|
142
|
+
description="Creates a comprehensive project plan",
|
|
143
|
+
validate=create_plan_validate,
|
|
144
|
+
handler=create_plan_handler,
|
|
145
|
+
)
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from elizaos.types import Provider, ProviderResult
|
|
6
|
+
from elizaos.types.model import ModelType
|
|
7
|
+
|
|
8
|
+
from .prompts import MESSAGE_CLASSIFIER_TEMPLATE
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def get_message_classification(runtime, message, _state=None) -> ProviderResult:
|
|
12
|
+
text = message.content.text or ""
|
|
13
|
+
|
|
14
|
+
if not text.strip():
|
|
15
|
+
return ProviderResult(
|
|
16
|
+
text="Message classified as: general (empty message)",
|
|
17
|
+
data={
|
|
18
|
+
"classification": "general",
|
|
19
|
+
"confidence": 0.1,
|
|
20
|
+
"complexity": "simple",
|
|
21
|
+
"planningRequired": False,
|
|
22
|
+
"stakeholders": [],
|
|
23
|
+
"constraints": [],
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
prompt = MESSAGE_CLASSIFIER_TEMPLATE.format(text=text)
|
|
29
|
+
response = await runtime.use_model(
|
|
30
|
+
ModelType.TEXT_SMALL,
|
|
31
|
+
{
|
|
32
|
+
"prompt": prompt,
|
|
33
|
+
"temperature": 0.3,
|
|
34
|
+
"maxTokens": 300,
|
|
35
|
+
},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
response_text = str(response)
|
|
39
|
+
lines = response_text.splitlines()
|
|
40
|
+
|
|
41
|
+
def _parse_list(prefix: str) -> list[str]:
|
|
42
|
+
line = next((ln for ln in lines if ln.startswith(prefix)), "")
|
|
43
|
+
if not line:
|
|
44
|
+
return []
|
|
45
|
+
raw = line[len(prefix) :].strip()
|
|
46
|
+
if not raw:
|
|
47
|
+
return []
|
|
48
|
+
return [s.strip() for s in raw.split(",") if s.strip()]
|
|
49
|
+
|
|
50
|
+
complexity = next(
|
|
51
|
+
(ln[len("COMPLEXITY:") :].strip() for ln in lines if ln.startswith("COMPLEXITY:")),
|
|
52
|
+
"simple",
|
|
53
|
+
)
|
|
54
|
+
planning_type = next(
|
|
55
|
+
(ln[len("PLANNING:") :].strip() for ln in lines if ln.startswith("PLANNING:")),
|
|
56
|
+
"direct_action",
|
|
57
|
+
)
|
|
58
|
+
confidence_str = next(
|
|
59
|
+
(ln[len("CONFIDENCE:") :].strip() for ln in lines if ln.startswith("CONFIDENCE:")),
|
|
60
|
+
"0.5",
|
|
61
|
+
)
|
|
62
|
+
try:
|
|
63
|
+
confidence = float(confidence_str)
|
|
64
|
+
except Exception:
|
|
65
|
+
confidence = 0.5
|
|
66
|
+
confidence = max(0.0, min(1.0, confidence))
|
|
67
|
+
|
|
68
|
+
capabilities = _parse_list("CAPABILITIES:")
|
|
69
|
+
stakeholders = _parse_list("STAKEHOLDERS:")
|
|
70
|
+
constraints = _parse_list("CONSTRAINTS:")
|
|
71
|
+
dependencies = _parse_list("DEPENDENCIES:")
|
|
72
|
+
|
|
73
|
+
planning_required = planning_type != "direct_action" and complexity != "simple"
|
|
74
|
+
|
|
75
|
+
classification = "general"
|
|
76
|
+
lower = text.lower()
|
|
77
|
+
if "strategic" in lower or planning_type == "strategic_planning":
|
|
78
|
+
classification = "strategic"
|
|
79
|
+
elif "analyz" in lower:
|
|
80
|
+
classification = "analysis"
|
|
81
|
+
elif "process" in lower:
|
|
82
|
+
classification = "processing"
|
|
83
|
+
elif "execute" in lower:
|
|
84
|
+
classification = "execution"
|
|
85
|
+
|
|
86
|
+
return ProviderResult(
|
|
87
|
+
text=f"Message classified as: {classification} ({complexity} complexity, {planning_type}) with confidence: {confidence}",
|
|
88
|
+
data={
|
|
89
|
+
"classification": classification,
|
|
90
|
+
"confidence": confidence,
|
|
91
|
+
"originalText": text,
|
|
92
|
+
"complexity": complexity,
|
|
93
|
+
"planningType": planning_type,
|
|
94
|
+
"planningRequired": planning_required,
|
|
95
|
+
"capabilities": capabilities,
|
|
96
|
+
"stakeholders": stakeholders,
|
|
97
|
+
"constraints": constraints,
|
|
98
|
+
"dependencies": dependencies,
|
|
99
|
+
"analyzedAt": int(time.time() * 1000),
|
|
100
|
+
"modelUsed": "TEXT_SMALL",
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
except Exception as e:
|
|
104
|
+
return ProviderResult(
|
|
105
|
+
text="Message classified as: general with confidence: 0.5 (fallback)",
|
|
106
|
+
data={
|
|
107
|
+
"classification": "general",
|
|
108
|
+
"confidence": 0.5,
|
|
109
|
+
"originalText": text,
|
|
110
|
+
"complexity": "simple",
|
|
111
|
+
"planningRequired": False,
|
|
112
|
+
"planningType": "direct_action",
|
|
113
|
+
"capabilities": [],
|
|
114
|
+
"stakeholders": [],
|
|
115
|
+
"constraints": [],
|
|
116
|
+
"dependencies": [],
|
|
117
|
+
"error": str(e),
|
|
118
|
+
"fallback": True,
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
message_classifier_provider = Provider(
|
|
124
|
+
name="messageClassifier",
|
|
125
|
+
description="Classifies messages by complexity and planning requirements",
|
|
126
|
+
get=get_message_classification,
|
|
127
|
+
)
|