Packages

A comprehensive Elixir object system with AI integration, hierarchical coordination, and meta-schema evolution capabilities

Current section

Files

Jump to
object lib object_llm_integration.ex
Raw

lib/object_llm_integration.ex

defmodule Object.LLMIntegration do
@moduledoc """
Enhanced LLM integration for AAOS objects using DSPy.
This module enables objects to:
1. Respond to messages using LLM-powered natural language
2. Generate contextual responses based on object state and history
3. Adapt their communication style based on interaction patterns
4. Use structured reasoning for complex decisions
Usage Examples:
# Basic LLM response generation
{:ok, response} = Object.LLMIntegration.generate_response(object, incoming_message)
# Contextual conversation
{:ok, response} = Object.LLMIntegration.conversational_response(object, message, conversation_history)
# Goal-oriented reasoning
{:ok, plan} = Object.LLMIntegration.reason_about_goal(object, goal, current_situation)
"""
alias Object.DSPyBridge
@doc """
Generates an LLM-powered response to an incoming message.
## Parameters
- `object`: The object generating the response
- `message`: Incoming message to respond to
- `opts`: Options like `:style`, `:max_length`
## Returns
`{:ok, response, updated_object}` with generated response and updated object state
## Examples
iex> Object.LLMIntegration.generate_response(object, message)
{:ok, %{content: "I understand your request...", tone: "helpful"}, updated_object}
"""
def generate_response(object, message, opts \\ []) do
signature = create_response_signature(object, message, opts)
case DSPyBridge.execute_signature(object.id, signature) do
{:ok, result} ->
response = %{
content: result.response_text,
tone: result.tone,
intent: result.intent,
confidence: result.confidence,
follow_up_suggested: result.suggests_follow_up,
metadata: %{
generated_at: DateTime.utc_now(),
model_used: result.model_info,
reasoning_chain: result.reasoning_steps
}
}
# Update object's interaction history with LLM response
updated_object = Object.interact(object, %{
type: :llm_response,
original_message: message,
generated_response: response,
success: true
})
{:ok, response, updated_object}
{:error, _reason} ->
# Fallback to rule-based response
fallback_response = generate_fallback_response(object, message)
{:ok, fallback_response, object}
end
end
@doc """
Generates contextual conversation responses maintaining conversation state.
## Parameters
- `object`: The object in conversation
- `message`: Current message to respond to
- `conversation_history`: Previous messages in conversation (default: [])
## Returns
`{:ok, response, updated_object}` with conversational response
"""
def conversational_response(object, message, conversation_history \\ []) do
# Extract conversation context
context = extract_conversation_context(conversation_history)
personality = get_object_personality(object)
signature = %{
description: "Generate a conversational response maintaining context and personality",
inputs: [
current_message: message.content,
sender_info: message.sender,
conversation_context: context,
object_personality: personality,
object_state: summarize_object_state(object),
interaction_goals: object.goal
],
outputs: [
response_text: "Natural language response",
emotional_tone: "Emotional tone of the response",
conversation_direction: "How this response guides the conversation",
relationship_impact: "How this response affects the relationship",
memory_updates: "What should be remembered from this exchange"
],
instructions: """
Generate a natural, contextually appropriate response that:
1. Acknowledges the conversation history and context
2. Reflects the object's personality and current state
3. Advances the conversation toward mutual goals
4. Maintains appropriate emotional tone
5. Builds positive relationships while being authentic
Consider the object's role, capabilities, and current objectives.
"""
}
case DSPyBridge.execute_signature(object.id, signature) do
{:ok, result} ->
# Update conversation memory
updated_object = update_conversation_memory(object, message, result)
response = %{
content: result.response_text,
tone: result.emotional_tone,
conversation_direction: result.conversation_direction,
relationship_impact: result.relationship_impact,
memory_updates: result.memory_updates,
timestamp: DateTime.utc_now()
}
{:ok, response, updated_object}
{:error, reason} ->
{:error, "Failed to generate conversational response: #{reason}"}
end
end
@doc """
Uses LLM reasoning for complex goal-oriented decisions.
## Parameters
- `object`: The reasoning object
- `goal`: Goal to reason about
- `current_situation`: Current state and context
- `constraints`: Limitations to consider (default: [])
## Returns
`{:ok, reasoning_result, updated_object}` with detailed reasoning analysis
"""
def reason_about_goal(object, goal, current_situation, constraints \\ []) do
signature = %{
description: "Reason about achieving a goal given current situation and constraints",
inputs: [
goal_description: goal,
current_situation: current_situation,
object_capabilities: object.methods,
available_resources: Map.get(object.state, :resources, %{}),
constraints: constraints,
past_experience: extract_relevant_experience(object, goal)
],
outputs: [
reasoning_chain: "Step-by-step reasoning process",
action_plan: "Concrete steps to achieve the goal",
resource_requirements: "Resources needed for each step",
risk_assessment: "Potential risks and mitigation strategies",
success_probability: "Estimated probability of success",
alternative_approaches: "Alternative methods if primary plan fails"
],
instructions: """
Provide comprehensive reasoning about achieving the specified goal:
1. Analyze the current situation and identify key factors
2. Break down the goal into achievable sub-goals
3. Develop a step-by-step action plan
4. Assess resource requirements and availability
5. Identify potential risks and mitigation strategies
6. Estimate success probability based on available information
7. Suggest alternative approaches for resilience
Be specific, practical, and consider the object's actual capabilities.
"""
}
case DSPyBridge.execute_signature(object.id, signature) do
{:ok, result} ->
reasoning_result = %{
reasoning_chain: parse_reasoning_chain(result.reasoning_chain),
action_plan: parse_action_plan(result.action_plan),
resource_requirements: result.resource_requirements,
risk_assessment: result.risk_assessment,
success_probability: parse_probability(result.success_probability),
alternatives: result.alternative_approaches,
generated_at: DateTime.utc_now()
}
# Update object's meta-learning with reasoning experience
updated_object = Object.MetaDSL.execute(
object.meta_dsl,
:learn,
object,
{:reasoning_experience, reasoning_result}
)
case updated_object do
{_meta_dsl_result, updated_meta_dsl} ->
final_object = %{object | meta_dsl: updated_meta_dsl}
{:ok, reasoning_result, final_object}
_ ->
{:ok, reasoning_result, object}
end
{:error, reason} ->
{:error, "Goal reasoning failed: #{reason}"}
end
end
@doc """
Enables objects to engage in collaborative reasoning with other objects.
## Parameters
- `objects`: List of objects participating in reasoning
- `shared_problem`: Problem to solve collaboratively
- `collaboration_type`: Type of collaboration (`:consensus`, `:negotiation`, etc.)
## Returns
`{:ok, collaboration_result}` with synthesized solution and role assignments
"""
def collaborative_reasoning(objects, shared_problem, collaboration_type \\ :consensus) do
signature = %{
description: "Facilitate collaborative reasoning between multiple objects",
inputs: [
problem_description: shared_problem,
participating_objects: Enum.map(objects, &summarize_object_for_collaboration/1),
collaboration_type: collaboration_type,
individual_perspectives: gather_individual_perspectives(objects, shared_problem)
],
outputs: [
synthesis: "Synthesized understanding incorporating all perspectives",
collaborative_solution: "Proposed solution leveraging collective capabilities",
role_assignments: "Specific roles for each participating object",
coordination_plan: "How objects should coordinate their efforts",
consensus_level: "Level of agreement achieved among objects"
],
instructions: """
Facilitate collaborative reasoning by:
1. Analyzing each object's unique perspective and capabilities
2. Identifying complementary strengths and potential conflicts
3. Synthesizing insights into a coherent understanding
4. Developing a solution that leverages collective capabilities
5. Assigning specific roles based on object strengths
6. Creating a coordination plan for implementation
7. Assessing the level of consensus achieved
Ensure the solution is practical and respects each object's constraints.
"""
}
# Use the first object's DSPy bridge for coordination
coordinator_object = hd(objects)
case DSPyBridge.execute_signature(coordinator_object.id, signature) do
{:ok, result} ->
collaboration_result = %{
synthesis: result.synthesis,
solution: parse_collaborative_solution(result.collaborative_solution),
role_assignments: parse_role_assignments(result.role_assignments, objects),
coordination_plan: result.coordination_plan,
consensus_level: result.consensus_level,
participants: Enum.map(objects, & &1.id),
timestamp: DateTime.utc_now()
}
{:ok, collaboration_result}
{:error, reason} ->
{:error, "Collaborative reasoning failed: #{reason}"}
end
end
@doc """
Creates a custom DSPy signature for specific object interactions.
## Parameters
- `name`: Name for the signature
- `description`: Description of what the signature does
- `inputs`: List of input fields
- `outputs`: List of output fields
- `instructions`: Instructions for the LLM
## Returns
Signature specification map
"""
def create_custom_signature(name, description, inputs, outputs, instructions) do
%{
name: name,
description: description,
inputs: inputs,
outputs: outputs,
instructions: instructions,
created_at: DateTime.utc_now()
}
end
@doc """
Registers a custom signature for reuse across objects.
## Parameters
- `signature`: Signature specification to register
## Returns
`{:ok, signature_name}` on successful registration
"""
def register_signature(signature) do
# Ensure ETS table exists
case :ets.whereis(:custom_signatures) do
:undefined ->
:ets.new(:custom_signatures, [:set, :public, :named_table])
_ ->
:ok
end
# Store in ETS table for quick access
:ets.insert(:custom_signatures, {signature.name, signature})
{:ok, signature.name}
end
# Private helper functions
defp create_response_signature(object, message, opts) do
response_style = Keyword.get(opts, :style, :professional)
max_length = Keyword.get(opts, :max_length, 200)
%{
description: "Generate an appropriate response to an incoming message",
inputs: [
message_content: message.content,
sender_id: message.sender,
object_state: summarize_object_state(object),
object_role: get_object_role(object),
recent_interactions: get_recent_interactions(object),
response_style: response_style
],
outputs: [
response_text: "The response message content",
tone: "Emotional tone of the response",
intent: "Primary intent of the response",
confidence: "Confidence in this response",
suggests_follow_up: "Whether a follow-up interaction is suggested"
],
instructions: """
Generate a response that:
1. Directly addresses the message content
2. Reflects the object's current state and role
3. Maintains appropriate tone for the context
4. Is concise (under #{max_length} words) but complete
5. Aligns with the object's goals and capabilities
Response style: #{response_style}
"""
}
end
defp generate_fallback_response(object, _message) do
%{
content: "I received your message and am processing it. My current state: #{object.subtype}",
tone: "neutral",
intent: "acknowledgment",
confidence: 0.5,
follow_up_suggested: false,
metadata: %{
fallback: true,
generated_at: DateTime.utc_now()
}
}
end
defp extract_conversation_context(history) do
recent_messages = Enum.take(history, -5)
%{
message_count: length(history),
recent_topics: extract_topics(recent_messages),
sentiment_trend: analyze_sentiment_trend(recent_messages),
interaction_frequency: calculate_interaction_frequency(history)
}
end
defp get_object_personality(object) do
# Extract personality traits from object's behavior patterns
%{
communication_style: infer_communication_style(object),
cooperation_tendency: analyze_cooperation_patterns(object),
problem_solving_approach: analyze_problem_solving(object),
emotional_expression: analyze_emotional_patterns(object)
}
end
defp summarize_object_state(object) do
%{
type: object.subtype,
current_energy: Map.get(object.state, :energy, "unknown"),
active_goals: summarize_goals(object.goal),
recent_performance: get_recent_performance(object),
available_methods: object.methods
}
end
defp update_conversation_memory(object, message, llm_result) do
memory_update = %{
type: :conversation_memory,
message: message,
response: llm_result,
relationship_impact: llm_result.relationship_impact,
timestamp: DateTime.utc_now()
}
Object.interact(object, memory_update)
end
defp extract_relevant_experience(object, goal) do
# Filter interaction history for relevant experiences
object.interaction_history
|> Enum.filter(fn interaction ->
case interaction.data do
%{goal: past_goal} -> goal_similarity(goal, past_goal) > 0.5
_ -> false
end
end)
|> Enum.take(-3) # Last 3 relevant experiences
end
defp parse_reasoning_chain(reasoning_text) do
# Parse structured reasoning from LLM output
reasoning_text
|> String.split("\n")
|> Enum.filter(&(String.trim(&1) != ""))
|> Enum.with_index(1)
|> Enum.map(fn {step, index} -> %{step: index, reasoning: String.trim(step)} end)
end
defp parse_action_plan(plan_text) do
# Parse action plan into structured format
plan_text
|> String.split("\n")
|> Enum.filter(&String.contains?(&1, "."))
|> Enum.map(fn step ->
[number, action] = String.split(step, ".", parts: 2)
%{step: String.to_integer(String.trim(number)), action: String.trim(action)}
end)
end
defp parse_probability(prob_text) do
# Extract probability from text
case Regex.run(~r/(\d+(?:\.\d+)?)%?/, prob_text) do
[_, number] ->
{prob, _} = Float.parse(number)
if prob > 1, do: prob / 100, else: prob
_ -> 0.5 # Default probability
end
end
defp gather_individual_perspectives(objects, problem) do
for object <- objects do
# Get each object's perspective on the problem
case reason_about_goal(object, problem, summarize_object_state(object)) do
{:ok, reasoning, _} -> %{object_id: object.id, perspective: reasoning}
_ -> %{object_id: object.id, perspective: "No perspective available"}
end
end
end
defp summarize_object_for_collaboration(object) do
%{
id: object.id,
type: object.subtype,
capabilities: object.methods,
strengths: identify_strengths(object),
current_load: assess_current_load(object)
}
end
defp parse_collaborative_solution(solution_text) do
# Parse the collaborative solution into actionable components
%{
overview: extract_overview(solution_text),
key_components: extract_components(solution_text),
implementation_steps: extract_steps(solution_text)
}
end
defp parse_role_assignments(assignments_text, objects) do
# Parse role assignments and match to objects
for object <- objects do
role = extract_role_for_object(assignments_text, object.id)
%{object_id: object.id, assigned_role: role}
end
end
# Simplified helper implementations
defp extract_topics(_messages), do: ["general", "collaboration"]
defp analyze_sentiment_trend(_messages), do: "neutral"
defp calculate_interaction_frequency(history), do: length(history) / max(1, div(length(history), 10))
defp infer_communication_style(_object), do: "direct"
defp analyze_cooperation_patterns(_object), do: "collaborative"
defp analyze_problem_solving(_object), do: "systematic"
defp analyze_emotional_patterns(_object), do: "stable"
defp summarize_goals(goal_function), do: "#{goal_function}"
defp get_recent_performance(_object), do: "stable"
defp goal_similarity(_goal1, _goal2), do: 0.7
defp identify_strengths(object), do: object.methods
defp assess_current_load(_object), do: "moderate"
defp extract_overview(text), do: String.slice(text, 0..100)
defp extract_components(text), do: String.split(text, ",") |> Enum.take(3)
defp extract_steps(text), do: String.split(text, "\n") |> Enum.take(5)
defp extract_role_for_object(_text, object_id), do: "participant_#{object_id}"
defp get_object_role(object), do: object.subtype
defp get_recent_interactions(object), do: Enum.take(object.interaction_history, -3)
end